geometric-library 1.3.0

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 (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/cjs/abstracts/Angle.js +60 -0
  4. package/dist/cjs/abstracts/Figure.js +147 -0
  5. package/dist/cjs/abstracts/Flag.js +27 -0
  6. package/dist/cjs/abstracts/Magnitude.js +25 -0
  7. package/dist/cjs/abstracts/Point.js +50 -0
  8. package/dist/cjs/abstracts/Vector.js +74 -0
  9. package/dist/cjs/figures/ArcCurve.js +132 -0
  10. package/dist/cjs/figures/Circle.js +43 -0
  11. package/dist/cjs/figures/CubicBezierCurve.js +149 -0
  12. package/dist/cjs/figures/Ellipse.js +111 -0
  13. package/dist/cjs/figures/Line.js +264 -0
  14. package/dist/cjs/figures/Polygon.js +17 -0
  15. package/dist/cjs/figures/QuadraticBezierCurve.js +104 -0
  16. package/dist/cjs/index.js +48 -0
  17. package/dist/cjs/types/index.js +2 -0
  18. package/dist/cjs/utilities/Calculator.js +153 -0
  19. package/dist/cjs/utilities/index.js +10 -0
  20. package/dist/esm/abstracts/Angle.js +56 -0
  21. package/dist/esm/abstracts/Figure.js +143 -0
  22. package/dist/esm/abstracts/Flag.js +23 -0
  23. package/dist/esm/abstracts/Magnitude.js +21 -0
  24. package/dist/esm/abstracts/Point.js +46 -0
  25. package/dist/esm/abstracts/Vector.js +70 -0
  26. package/dist/esm/figures/ArcCurve.js +128 -0
  27. package/dist/esm/figures/Circle.js +39 -0
  28. package/dist/esm/figures/CubicBezierCurve.js +145 -0
  29. package/dist/esm/figures/Ellipse.js +107 -0
  30. package/dist/esm/figures/Line.js +260 -0
  31. package/dist/esm/figures/Polygon.js +13 -0
  32. package/dist/esm/figures/QuadraticBezierCurve.js +100 -0
  33. package/dist/esm/index.js +17 -0
  34. package/dist/esm/types/index.js +1 -0
  35. package/dist/esm/utilities/Calculator.js +149 -0
  36. package/dist/esm/utilities/index.js +7 -0
  37. package/dist/types/abstracts/Angle.d.ts +18 -0
  38. package/dist/types/abstracts/Figure.d.ts +22 -0
  39. package/dist/types/abstracts/Flag.d.ts +10 -0
  40. package/dist/types/abstracts/Magnitude.d.ts +9 -0
  41. package/dist/types/abstracts/Point.d.ts +14 -0
  42. package/dist/types/abstracts/Vector.d.ts +20 -0
  43. package/dist/types/figures/ArcCurve.d.ts +23 -0
  44. package/dist/types/figures/Circle.d.ts +12 -0
  45. package/dist/types/figures/CubicBezierCurve.d.ts +23 -0
  46. package/dist/types/figures/Ellipse.d.ts +26 -0
  47. package/dist/types/figures/Line.d.ts +44 -0
  48. package/dist/types/figures/Polygon.d.ts +7 -0
  49. package/dist/types/figures/QuadraticBezierCurve.d.ts +21 -0
  50. package/dist/types/index.d.ts +16 -0
  51. package/dist/types/types/index.d.ts +144 -0
  52. package/dist/types/utilities/Calculator.d.ts +49 -0
  53. package/dist/types/utilities/index.d.ts +6 -0
  54. package/package.json +60 -0
@@ -0,0 +1,145 @@
1
+ import { Calculator } from '../utilities/Calculator';
2
+ import { Point } from '../abstracts/Point';
3
+ import { Figure } from '../abstracts/Figure';
4
+ export class CubicBezierCurve extends Figure {
5
+ _criticalPoints;
6
+ constructor(values) {
7
+ super(values);
8
+ this._criticalPoints = this.computeCriticalPoints();
9
+ }
10
+ get boundingBox() {
11
+ const [P0, , , P3] = this.values;
12
+ const points = [P0, P3, ...this._criticalPoints];
13
+ return Figure.computeBoundingBox(points);
14
+ }
15
+ get criticalPoints() {
16
+ return this._criticalPoints;
17
+ }
18
+ get P0() {
19
+ return this.points[0];
20
+ }
21
+ get P1() {
22
+ if (this.isRelative) {
23
+ return this.P0.clone().translate(this.vectors[0]);
24
+ }
25
+ return this.points[1];
26
+ }
27
+ get P2() {
28
+ if (this.isRelative) {
29
+ return this.P0.clone().translate(this.vectors[1]);
30
+ }
31
+ return this.points[2];
32
+ }
33
+ get P3() {
34
+ if (this.isRelative) {
35
+ return this.P0.clone().translate(this.vectors[2]);
36
+ }
37
+ return this.points[3];
38
+ }
39
+ clone() {
40
+ const values = this.values.map((value) => value.clone());
41
+ return new CubicBezierCurve(values);
42
+ }
43
+ recompute() {
44
+ this._criticalPoints = this.computeCriticalPoints();
45
+ }
46
+ reflect(about) {
47
+ super.reflect(about);
48
+ this.recompute();
49
+ return this;
50
+ }
51
+ rotate(phi, about) {
52
+ super.rotate(phi, about);
53
+ this.recompute();
54
+ return this;
55
+ }
56
+ scale(factor, about) {
57
+ super.scale(factor, about);
58
+ this.recompute();
59
+ return this;
60
+ }
61
+ translate(vector) {
62
+ super.translate(vector);
63
+ this.recompute();
64
+ return this;
65
+ }
66
+ computeCriticalPoints() {
67
+ const tValues = this.computeCriticalPointsTValues();
68
+ if (!tValues) {
69
+ return [];
70
+ }
71
+ const criticalPoints = tValues.reduce((criticalPoints, t) => {
72
+ const criticalPoint = this.getPointAtParameter(t);
73
+ criticalPoint && criticalPoints.push(criticalPoint);
74
+ return criticalPoints;
75
+ }, []);
76
+ return criticalPoints;
77
+ }
78
+ computeCriticalPointsTValues() {
79
+ const axii = ['x', 'y'];
80
+ const { P0, P1, P2, P3 } = this;
81
+ const signs = [1, -1];
82
+ const tValues = [];
83
+ for (let i = 0; i < axii.length; i++) {
84
+ const axis = axii[i];
85
+ const p0 = new Calculator(P0[axis]);
86
+ const p1 = new Calculator(P1[axis]);
87
+ const p2 = new Calculator(P2[axis]);
88
+ const p3 = new Calculator(P3[axis]);
89
+ const a = p3.sub(p2.mul(3)).add(p1.mul(3)).sub(p0).mul(3);
90
+ const b = p2.sub(p1.mul(2)).add(p0).mul(6);
91
+ const c = p1.sub(p0).mul(3);
92
+ for (let n = 0; n < signs.length; n++) {
93
+ const sign = signs[n];
94
+ let tValue;
95
+ if (+a === 0) {
96
+ // 1st degree equation to avoid n/0
97
+ tValue = c.neg().div(b);
98
+ }
99
+ else {
100
+ // 2nd degree equation
101
+ tValue = b
102
+ .neg()
103
+ .add(Calculator.mul(sign, b.pow(2).sub(a.mul(c).mul(4)).sqrt()))
104
+ .div(a.mul(2));
105
+ }
106
+ if (this.isValidParameter(tValue)) {
107
+ tValues.push(tValue);
108
+ }
109
+ }
110
+ }
111
+ if (!tValues.length) {
112
+ return;
113
+ }
114
+ return tValues.filter((value, index, array) => index === array.findIndex((v) => +value === +v));
115
+ }
116
+ getCoordinateAtParameter(t, axis) {
117
+ const { P0, P1, P2, P3 } = this;
118
+ const p0 = P0[axis];
119
+ const p1 = P1[axis];
120
+ const p2 = P2[axis];
121
+ const p3 = P3[axis];
122
+ // parametric cubic bezier equation
123
+ const coordinate = Calculator.sub(1, t)
124
+ .pow(3)
125
+ .mul(p0)
126
+ .add(Calculator.sub(1, t).pow(2).mul(3).mul(t).mul(p1))
127
+ .add(Calculator.sub(1, t).mul(3).mul(t.pow(2)).mul(p2))
128
+ .add(t.pow(3).mul(p3));
129
+ if (!coordinate.isFinite()) {
130
+ return;
131
+ }
132
+ return coordinate;
133
+ }
134
+ getPointAtParameter(t) {
135
+ const x = this.getCoordinateAtParameter(t, 'x');
136
+ const y = this.getCoordinateAtParameter(t, 'y');
137
+ if (typeof x === 'undefined' || typeof y === 'undefined') {
138
+ return;
139
+ }
140
+ return new Point([+x, +y]);
141
+ }
142
+ isValidParameter(t) {
143
+ return t.isFinite() && +t > 0 && +t < 1;
144
+ }
145
+ }
@@ -0,0 +1,107 @@
1
+ import { Calculator } from '../utilities/Calculator';
2
+ import { Angle } from '../abstracts/Angle';
3
+ import { Point } from '../abstracts/Point';
4
+ import { Figure } from '../abstracts/Figure';
5
+ import { xAxis } from '../utilities';
6
+ export class Ellipse extends Figure {
7
+ _center;
8
+ _criticalPoints;
9
+ _phi;
10
+ _rx;
11
+ _ry;
12
+ constructor(values) {
13
+ super(values);
14
+ const [center, rx, ry, phi] = values;
15
+ this._center = center;
16
+ this._rx = rx;
17
+ this._ry = ry;
18
+ this._phi = phi;
19
+ this._criticalPoints = this.computeCriticalPoints({ center, rx, ry, phi });
20
+ }
21
+ get boundingBox() {
22
+ return Figure.computeBoundingBox(this.criticalPoints);
23
+ }
24
+ get center() {
25
+ return this._center;
26
+ }
27
+ get criticalPoints() {
28
+ return this._criticalPoints;
29
+ }
30
+ get isCircle() {
31
+ return +this.rx === +this.ry;
32
+ }
33
+ get phi() {
34
+ return this._phi;
35
+ }
36
+ get rx() {
37
+ return this._rx;
38
+ }
39
+ get ry() {
40
+ return this._ry;
41
+ }
42
+ clone() {
43
+ const values = this.values.map((value) => value.clone());
44
+ return new Ellipse(values);
45
+ }
46
+ computePointForTheta(theta, ellipse = this) {
47
+ const { center, rx, ry, phi } = ellipse;
48
+ const x = +Calculator.mul(+rx, phi.cos).mul(theta.cos).sub(Calculator.mul(+ry, phi.sin).mul(theta.sin)).add(center.x);
49
+ const y = +Calculator.mul(+rx, phi.sin).mul(theta.cos).add(Calculator.mul(+ry, phi.cos).mul(theta.sin)).add(center.y);
50
+ return new Point([x, y]);
51
+ }
52
+ computeThetaForPoint({ x, y }) {
53
+ const { center, phi, rx, ry } = this;
54
+ const { x: cx, y: cy } = center;
55
+ const dy = Calculator.sub(y, cy);
56
+ const dx = Calculator.sub(x, cx);
57
+ const sinTheta = dy.mul(phi.cos).sub(dx.mul(phi.sin)).div(+ry);
58
+ const cosTheta = dx.mul(phi.cos).add(dy.mul(phi.sin)).div(+rx);
59
+ const theta = new Angle(+Calculator.atan2(sinTheta, cosTheta), 'radians').normalize();
60
+ return theta;
61
+ }
62
+ reflect(about) {
63
+ super.reflect(about);
64
+ if (!this.isCircle && 'V' in about) {
65
+ const alpha = about.angleTo(xAxis);
66
+ this._phi.replace(+Calculator.mul(2, alpha.radians).sub(this.phi.radians), 'radians');
67
+ this._phi.normalize();
68
+ }
69
+ this.recompute();
70
+ return this;
71
+ }
72
+ rotate(alpha, about) {
73
+ this._center.rotate(alpha, about);
74
+ if (!this.isCircle) {
75
+ this._phi.replace(+Calculator.add(this.phi.radians, alpha.radians), 'radians');
76
+ this._phi.normalize();
77
+ }
78
+ this.recompute();
79
+ return this;
80
+ }
81
+ scale(factor, about = new Point([0, 0])) {
82
+ super.scale(factor, about);
83
+ this.recompute();
84
+ return this;
85
+ }
86
+ translate(vector) {
87
+ this._center.translate(vector);
88
+ this.recompute();
89
+ return this;
90
+ }
91
+ computeCriticalPoints(ellipse = this) {
92
+ const { rx, ry, phi } = ellipse;
93
+ const { computePointForTheta } = this;
94
+ const xThetaPrincipal = new Angle(+Calculator.neg(+ry).mul(phi.tan).div(+rx).atan(), 'radians');
95
+ const yThetaPrincipal = new Angle(+Calculator.mul(+ry, phi.cot).div(+rx).atan(), 'radians');
96
+ const xThetaSecondary = new Angle(+Calculator.add(+xThetaPrincipal, Math.PI), 'radians');
97
+ const yThetaSecondary = new Angle(+Calculator.add(+yThetaPrincipal, Math.PI), 'radians');
98
+ const firstPoint = computePointForTheta(xThetaPrincipal, ellipse);
99
+ const secondPoint = computePointForTheta(yThetaPrincipal, ellipse);
100
+ const thirdPoint = computePointForTheta(xThetaSecondary, ellipse);
101
+ const fourthPoint = computePointForTheta(yThetaSecondary, ellipse);
102
+ return [firstPoint, secondPoint, thirdPoint, fourthPoint];
103
+ }
104
+ recompute() {
105
+ this._criticalPoints = this.computeCriticalPoints();
106
+ }
107
+ }
@@ -0,0 +1,260 @@
1
+ import { Calculator } from '../utilities/Calculator';
2
+ import { Angle } from '../abstracts/Angle';
3
+ import { Point } from '../abstracts/Point';
4
+ import { Vector } from '../abstracts/Vector';
5
+ import { Figure } from '../abstracts/Figure';
6
+ export class Line extends Figure {
7
+ _P0;
8
+ _P1;
9
+ _V;
10
+ _reciprocal;
11
+ _slope;
12
+ _xIntercept;
13
+ _yIntercept;
14
+ constructor(values) {
15
+ super(values);
16
+ const [P0, anchor] = values;
17
+ if (anchor instanceof Vector) {
18
+ this._V = anchor;
19
+ this._P1 = P0.clone().translate(anchor);
20
+ // anchor instanceof Point
21
+ }
22
+ else {
23
+ this._V = new Vector([P0, anchor]);
24
+ this._P1 = anchor;
25
+ }
26
+ this._P0 = P0;
27
+ this._slope = this.computeSlope();
28
+ this._yIntercept = this.computeYIntercept();
29
+ this._reciprocal = this.computeReciprocal();
30
+ this._xIntercept = this.computeXIntercept();
31
+ this.points = [this.P0, this.P1];
32
+ this.vectors = [this.V];
33
+ }
34
+ get P0() {
35
+ return this._P0;
36
+ }
37
+ get P1() {
38
+ return this._P1;
39
+ }
40
+ get V() {
41
+ return this._V;
42
+ }
43
+ // STANDARD EQUATION PARAMETERS (ax + by - c = 0)
44
+ get a() {
45
+ const { slope, isVertical, isHorizontal } = this;
46
+ if (isVertical) {
47
+ return 1;
48
+ }
49
+ if (isHorizontal) {
50
+ return 0;
51
+ }
52
+ return slope >= 0 ? slope : -slope;
53
+ }
54
+ get b() {
55
+ const { slope, isVertical, isHorizontal } = this;
56
+ if (isVertical) {
57
+ return 0;
58
+ }
59
+ if (isHorizontal) {
60
+ return 1;
61
+ }
62
+ return slope >= 0 ? -1 : 1;
63
+ }
64
+ get c() {
65
+ const { slope, isVertical, isHorizontal, yIntercept, xIntercept } = this;
66
+ if (isVertical) {
67
+ return xIntercept;
68
+ }
69
+ if (isHorizontal) {
70
+ return yIntercept;
71
+ }
72
+ return slope >= 0 ? -yIntercept : yIntercept;
73
+ }
74
+ get isHorizontal() {
75
+ const { slope, isVertical } = this;
76
+ return !isVertical && slope === 0;
77
+ }
78
+ get isVertical() {
79
+ const { slope } = this;
80
+ return typeof slope === 'undefined';
81
+ }
82
+ get reciprocal() {
83
+ return this._reciprocal;
84
+ }
85
+ get slope() {
86
+ return this._slope;
87
+ }
88
+ get xIntercept() {
89
+ return this._xIntercept;
90
+ }
91
+ get yIntercept() {
92
+ return this._yIntercept;
93
+ }
94
+ angleTo(line) {
95
+ if (this.isParallelTo(line)) {
96
+ return new Angle(0, 'radians');
97
+ }
98
+ if (this.isPerpendicularTo(line)) {
99
+ return new Angle(+Calculator.div(Math.PI, 2), 'radians');
100
+ }
101
+ if (typeof this.slope === 'undefined') {
102
+ return new Angle(+Calculator.atan(line.slope), 'radians');
103
+ }
104
+ if (typeof line.slope === 'undefined') {
105
+ return new Angle(+Calculator.atan(this.slope), 'radians');
106
+ }
107
+ const thisSlope = new Calculator(this.slope);
108
+ const lineSlope = new Calculator(line.slope);
109
+ return new Angle(+lineSlope.sub(thisSlope).div(thisSlope.mul(lineSlope).add(1)).abs().atan(), 'radians');
110
+ }
111
+ clone() {
112
+ const values = this.values.map((value) => value.clone());
113
+ return new Line(values);
114
+ }
115
+ getIntersectionPoint(line) {
116
+ if (this.isParallelTo(line)) {
117
+ return;
118
+ }
119
+ const denominator = Calculator.mul(this.a, line.b).sub(Calculator.mul(line.a, this.b));
120
+ const x = +Calculator.mul(this.b, line.c).sub(Calculator.mul(line.b, this.c)).div(denominator);
121
+ const y = +Calculator.mul(this.c, line.a).sub(Calculator.mul(line.c, this.a)).div(denominator);
122
+ return new Point([x, y]);
123
+ }
124
+ getPerpendicularProjection(point) {
125
+ const { P0, slope, isVertical, isHorizontal } = this;
126
+ let perpendicularProjection;
127
+ if (this.hasPoint(point)) {
128
+ return point.clone();
129
+ }
130
+ if (isVertical) {
131
+ perpendicularProjection = new Point([P0.x, point.y]);
132
+ }
133
+ else if (isHorizontal) {
134
+ perpendicularProjection = new Point([point.x, P0.y]);
135
+ }
136
+ else {
137
+ const x = new Calculator(1);
138
+ const y = x.mul(1).div(slope).neg().add(Calculator.div(point.x, slope)).add(point.y);
139
+ perpendicularProjection = new Point([+x, +y]);
140
+ }
141
+ return perpendicularProjection;
142
+ }
143
+ getPerpendicularThrough(point) {
144
+ if (this.hasPoint(point)) {
145
+ const phi = new Angle(+Calculator.div(Math.PI, 2), 'radians');
146
+ return this.clone().rotate(phi, point);
147
+ }
148
+ return new Line([point, this.getPerpendicularProjection(point)]);
149
+ }
150
+ getPointAtParameter(t) {
151
+ const { P0, V } = this;
152
+ const x = +Calculator.add(P0.x, Calculator.mul(V.dx, t));
153
+ const y = +Calculator.add(P0.y, Calculator.mul(V.dy, t));
154
+ return new Point([x, y]);
155
+ }
156
+ getXValueAtY(y) {
157
+ const { reciprocal, xIntercept } = this;
158
+ if (typeof reciprocal === 'undefined') {
159
+ return;
160
+ }
161
+ if (typeof xIntercept === 'undefined') {
162
+ return +Calculator.mul(reciprocal, y);
163
+ }
164
+ return +Calculator.mul(reciprocal, y).add(xIntercept);
165
+ }
166
+ getYValueAtX(x) {
167
+ const { slope, yIntercept } = this;
168
+ if (typeof slope === 'undefined') {
169
+ return;
170
+ }
171
+ if (typeof yIntercept === 'undefined') {
172
+ return +Calculator.mul(slope, x);
173
+ }
174
+ return +Calculator.mul(slope, x).add(yIntercept);
175
+ }
176
+ hasPoint(P) {
177
+ const potentialY = this.getYValueAtX(P.x);
178
+ return typeof potentialY === 'number' && potentialY === P.y;
179
+ }
180
+ isParallelTo(line) {
181
+ return this.slope == line.slope;
182
+ }
183
+ isPerpendicularTo(line) {
184
+ if (this.isVertical) {
185
+ return line.isHorizontal;
186
+ }
187
+ if (this.isHorizontal) {
188
+ return line.isVertical;
189
+ }
190
+ if (line.isVertical) {
191
+ return this.isHorizontal;
192
+ }
193
+ if (line.isHorizontal) {
194
+ return this.isVertical;
195
+ }
196
+ const thisSlope = new Calculator(this.slope);
197
+ const lineSlope = new Calculator(line.slope);
198
+ return +thisSlope === +Calculator.div(-1, lineSlope);
199
+ }
200
+ reflect(about) {
201
+ super.reflect(about);
202
+ this.recompute();
203
+ return this;
204
+ }
205
+ rotate(phi, about) {
206
+ super.rotate(phi, about);
207
+ this.recompute();
208
+ return this;
209
+ }
210
+ scale(factor, about) {
211
+ super.scale(factor, about);
212
+ this.recompute();
213
+ return this;
214
+ }
215
+ translate(vector) {
216
+ super.translate(vector);
217
+ this.recompute();
218
+ return this;
219
+ }
220
+ computeReciprocal() {
221
+ const { P0, P1 } = this;
222
+ const reciprocal = Calculator.sub(P1.x, P0.x).div(Calculator.sub(P1.y, P0.y));
223
+ if (reciprocal.isFinite()) {
224
+ return +reciprocal;
225
+ }
226
+ }
227
+ computeSlope() {
228
+ const { P0, P1 } = this;
229
+ const slope = Calculator.sub(P1.y, P0.y).div(Calculator.sub(P1.x, P0.x));
230
+ if (slope.isFinite()) {
231
+ return +slope;
232
+ }
233
+ }
234
+ computeXIntercept() {
235
+ const { P0, reciprocal, isHorizontal, isVertical } = this;
236
+ if (isVertical) {
237
+ return P0.x;
238
+ }
239
+ if (isHorizontal) {
240
+ return;
241
+ }
242
+ return +Calculator.sub(P0.x, Calculator.mul(reciprocal, P0.y));
243
+ }
244
+ computeYIntercept() {
245
+ const { P0, slope, isVertical, isHorizontal } = this;
246
+ if (isVertical) {
247
+ return;
248
+ }
249
+ if (isHorizontal) {
250
+ return P0.y;
251
+ }
252
+ return +Calculator.sub(P0.y, Calculator.mul(slope, P0.x));
253
+ }
254
+ recompute() {
255
+ this._slope = this.computeSlope();
256
+ this._yIntercept = this.computeYIntercept();
257
+ this._reciprocal = this.computeReciprocal();
258
+ this._xIntercept = this.computeXIntercept();
259
+ }
260
+ }
@@ -0,0 +1,13 @@
1
+ import { Figure } from '../abstracts/Figure';
2
+ export class Polygon extends Figure {
3
+ constructor(values) {
4
+ super(values);
5
+ }
6
+ get sides() {
7
+ return this.points.length;
8
+ }
9
+ clone() {
10
+ const values = this.values.map((value) => value.clone());
11
+ return new Polygon(values);
12
+ }
13
+ }
@@ -0,0 +1,100 @@
1
+ import { Calculator } from '../utilities/Calculator';
2
+ import { Point } from '../abstracts/Point';
3
+ import { Figure } from '../abstracts/Figure';
4
+ export class QuadraticBezierCurve extends Figure {
5
+ _criticalPoints;
6
+ constructor(values) {
7
+ super(values);
8
+ this._criticalPoints = this.computeCriticalPoints();
9
+ }
10
+ get boundingBox() {
11
+ const [P0, , P2] = this.values;
12
+ const points = [P0, P2, ...this._criticalPoints];
13
+ return Figure.computeBoundingBox(points);
14
+ }
15
+ get criticalPoints() {
16
+ return this._criticalPoints;
17
+ }
18
+ get P0() {
19
+ return this.points[0];
20
+ }
21
+ get P1() {
22
+ if (this.isRelative) {
23
+ return this.P0.clone().translate(this.vectors[0]);
24
+ }
25
+ return this.points[1];
26
+ }
27
+ get P2() {
28
+ if (this.isRelative) {
29
+ return this.P0.clone().translate(this.vectors[1]);
30
+ }
31
+ return this.points[2];
32
+ }
33
+ clone() {
34
+ const values = this.values.map((value) => value.clone());
35
+ return new QuadraticBezierCurve(values);
36
+ }
37
+ recompute() {
38
+ this._criticalPoints = this.computeCriticalPoints();
39
+ }
40
+ reflect(about) {
41
+ super.reflect(about);
42
+ this.recompute();
43
+ return this;
44
+ }
45
+ rotate(phi, about) {
46
+ super.rotate(phi, about);
47
+ this.recompute();
48
+ return this;
49
+ }
50
+ scale(factor, about) {
51
+ super.scale(factor, about);
52
+ this.recompute();
53
+ return this;
54
+ }
55
+ translate(vector) {
56
+ super.translate(vector);
57
+ this.recompute();
58
+ return this;
59
+ }
60
+ computeCriticalPoints() {
61
+ const t = this.getCriticalPointTValue();
62
+ if (typeof t === 'undefined') {
63
+ return [];
64
+ }
65
+ const point = this.getPointAtParameter(t);
66
+ if (!point) {
67
+ return [];
68
+ }
69
+ return [point];
70
+ }
71
+ getCoordinateAtParameter(t, axis) {
72
+ const { P0, P1, P2 } = this;
73
+ const coordinate = Calculator.sub(1, t).pow(2).mul(P0[axis]).add(Calculator.sub(1, t).mul(2).mul(t).mul(P1[axis])).add(t.pow(2).mul(P2[axis]));
74
+ if (coordinate.isFinite()) {
75
+ return coordinate;
76
+ }
77
+ }
78
+ getCriticalPointTValue() {
79
+ const axii = ['x', 'y'];
80
+ const { P0, P1, P2 } = this;
81
+ let value;
82
+ for (let i = 0; i < axii.length; i++) {
83
+ const axis = axii[i];
84
+ const potentialValue = Calculator.sub(P0[axis], P1[axis]).div(Calculator.sub(P0[axis], Calculator.mul(P1[axis], 2)).add(P2[axis]));
85
+ if (+potentialValue > 0 && +potentialValue < 1) {
86
+ value = potentialValue;
87
+ break;
88
+ }
89
+ }
90
+ return value;
91
+ }
92
+ getPointAtParameter(t) {
93
+ const x = this.getCoordinateAtParameter(t, 'x');
94
+ const y = this.getCoordinateAtParameter(t, 'y');
95
+ if (typeof x === 'undefined' || typeof y === 'undefined') {
96
+ return;
97
+ }
98
+ return new Point([+x, +y]);
99
+ }
100
+ }
@@ -0,0 +1,17 @@
1
+ /* v8 ignore */
2
+ export { Angle } from './abstracts/Angle';
3
+ export { Figure } from './abstracts/Figure';
4
+ export { Flag } from './abstracts/Flag';
5
+ export { Magnitude } from './abstracts/Magnitude';
6
+ export { Point } from './abstracts/Point';
7
+ export { Vector } from './abstracts/Vector.js';
8
+ export { ArcCurve } from './figures/ArcCurve';
9
+ export { Circle } from './figures/Circle';
10
+ export { CubicBezierCurve } from './figures/CubicBezierCurve';
11
+ export { Ellipse } from './figures/Ellipse';
12
+ export { Line } from './figures/Line';
13
+ export { Polygon } from './figures/Polygon';
14
+ export { QuadraticBezierCurve } from './figures/QuadraticBezierCurve';
15
+ export { Calculator } from './utilities/Calculator';
16
+ export * from './utilities';
17
+ export * from './types';
@@ -0,0 +1 @@
1
+ export {};