geometric-library 1.3.0 → 1.4.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 (143) hide show
  1. package/README.md +49 -23
  2. package/dist/cjs/abstracts/{Angle.js → angle/Angle.js} +11 -11
  3. package/dist/cjs/abstracts/angle/Angle.types.js +2 -0
  4. package/dist/cjs/abstracts/angle/index.js +18 -0
  5. package/dist/cjs/abstracts/{Figure.js → figure/Figure.js} +45 -30
  6. package/dist/cjs/abstracts/figure/Figure.types.js +2 -0
  7. package/dist/cjs/abstracts/figure/index.js +18 -0
  8. package/dist/cjs/abstracts/{Flag.js → flag/Flag.js} +1 -0
  9. package/dist/cjs/abstracts/flag/Flag.types.js +2 -0
  10. package/dist/cjs/abstracts/flag/index.js +18 -0
  11. package/dist/cjs/abstracts/index.js +22 -0
  12. package/dist/cjs/abstracts/{Magnitude.js → magnitude/Magnitude.js} +6 -2
  13. package/dist/cjs/abstracts/magnitude/Magnitude.types.js +2 -0
  14. package/dist/cjs/abstracts/magnitude/index.js +18 -0
  15. package/dist/cjs/abstracts/{Point.js → point/Point.js} +8 -7
  16. package/dist/cjs/abstracts/point/Point.types.js +2 -0
  17. package/dist/cjs/abstracts/point/index.js +18 -0
  18. package/dist/cjs/abstracts/{Vector.js → vector/Vector.js} +16 -15
  19. package/dist/cjs/abstracts/vector/Vector.types.js +2 -0
  20. package/dist/cjs/abstracts/vector/index.js +18 -0
  21. package/dist/cjs/figures/arc-curve/ArcCurve.js +174 -0
  22. package/dist/cjs/figures/arc-curve/ArcCurve.types.js +2 -0
  23. package/dist/cjs/figures/arc-curve/index.js +18 -0
  24. package/dist/cjs/figures/{Circle.js → circle/Circle.js} +8 -9
  25. package/dist/cjs/figures/circle/Circle.types.js +2 -0
  26. package/dist/cjs/figures/circle/index.js +18 -0
  27. package/dist/cjs/figures/{CubicBezierCurve.js → cubic-bezier-curve/CubicBezierCurve.js} +22 -17
  28. package/dist/cjs/figures/cubic-bezier-curve/CubicBezierCurve.types.js +2 -0
  29. package/dist/cjs/figures/cubic-bezier-curve/index.js +18 -0
  30. package/dist/cjs/figures/ellipse/Ellipse.js +129 -0
  31. package/dist/cjs/figures/ellipse/Ellipse.types.js +2 -0
  32. package/dist/cjs/figures/ellipse/index.js +18 -0
  33. package/dist/cjs/figures/index.js +23 -0
  34. package/dist/cjs/figures/{Line.js → line/Line.js} +78 -59
  35. package/dist/cjs/figures/line/Line.types.js +2 -0
  36. package/dist/cjs/figures/line/index.js +18 -0
  37. package/dist/cjs/figures/polygon/Polygon.js +51 -0
  38. package/dist/cjs/figures/polygon/Polygon.types.js +2 -0
  39. package/dist/cjs/figures/polygon/index.js +18 -0
  40. package/dist/cjs/figures/{QuadraticBezierCurve.js → quadratic-bezier-curve/QuadraticBezierCurve.js} +12 -8
  41. package/dist/cjs/figures/quadratic-bezier-curve/QuadraticBezierCurve.types.js +2 -0
  42. package/dist/cjs/figures/quadratic-bezier-curve/index.js +18 -0
  43. package/dist/cjs/index.js +2 -29
  44. package/dist/cjs/utilities/{Calculator.js → calculator/Calculator.js} +9 -1
  45. package/dist/cjs/utilities/calculator/index.js +17 -0
  46. package/dist/cjs/utilities/index.js +20 -8
  47. package/dist/esm/abstracts/{Angle.js → angle/Angle.js} +4 -4
  48. package/dist/esm/abstracts/angle/Angle.types.js +1 -0
  49. package/dist/esm/abstracts/angle/index.js +2 -0
  50. package/dist/esm/abstracts/{Figure.js → figure/Figure.js} +37 -22
  51. package/dist/esm/abstracts/figure/Figure.types.js +1 -0
  52. package/dist/esm/abstracts/figure/index.js +2 -0
  53. package/dist/esm/abstracts/{Flag.js → flag/Flag.js} +1 -0
  54. package/dist/esm/abstracts/flag/Flag.types.js +1 -0
  55. package/dist/esm/abstracts/flag/index.js +2 -0
  56. package/dist/esm/abstracts/index.js +6 -0
  57. package/dist/esm/abstracts/{Magnitude.js → magnitude/Magnitude.js} +5 -1
  58. package/dist/esm/abstracts/magnitude/Magnitude.types.js +1 -0
  59. package/dist/esm/abstracts/magnitude/index.js +2 -0
  60. package/dist/esm/abstracts/{Point.js → point/Point.js} +2 -1
  61. package/dist/esm/abstracts/point/Point.types.js +1 -0
  62. package/dist/esm/abstracts/point/index.js +2 -0
  63. package/dist/esm/abstracts/{Vector.js → vector/Vector.js} +3 -2
  64. package/dist/esm/abstracts/vector/Vector.types.js +1 -0
  65. package/dist/esm/abstracts/vector/index.js +2 -0
  66. package/dist/esm/figures/{ArcCurve.js → arc-curve/ArcCurve.js} +50 -8
  67. package/dist/esm/figures/arc-curve/ArcCurve.types.js +1 -0
  68. package/dist/esm/figures/arc-curve/index.js +2 -0
  69. package/dist/esm/figures/{Circle.js → circle/Circle.js} +3 -4
  70. package/dist/esm/figures/circle/Circle.types.js +1 -0
  71. package/dist/esm/figures/circle/index.js +2 -0
  72. package/dist/esm/figures/{CubicBezierCurve.js → cubic-bezier-curve/CubicBezierCurve.js} +11 -6
  73. package/dist/esm/figures/cubic-bezier-curve/CubicBezierCurve.types.js +1 -0
  74. package/dist/esm/figures/cubic-bezier-curve/index.js +2 -0
  75. package/dist/esm/figures/{Ellipse.js → ellipse/Ellipse.js} +24 -6
  76. package/dist/esm/figures/ellipse/Ellipse.types.js +1 -0
  77. package/dist/esm/figures/ellipse/index.js +2 -0
  78. package/dist/esm/figures/index.js +7 -0
  79. package/dist/esm/figures/{Line.js → line/Line.js} +57 -38
  80. package/dist/esm/figures/line/Line.types.js +1 -0
  81. package/dist/esm/figures/line/index.js +2 -0
  82. package/dist/esm/figures/polygon/Polygon.js +47 -0
  83. package/dist/esm/figures/polygon/Polygon.types.js +1 -0
  84. package/dist/esm/figures/polygon/index.js +2 -0
  85. package/dist/esm/figures/{QuadraticBezierCurve.js → quadratic-bezier-curve/QuadraticBezierCurve.js} +7 -3
  86. package/dist/esm/figures/quadratic-bezier-curve/QuadraticBezierCurve.types.js +1 -0
  87. package/dist/esm/figures/quadratic-bezier-curve/index.js +2 -0
  88. package/dist/esm/index.js +2 -14
  89. package/dist/esm/utilities/{Calculator.js → calculator/Calculator.js} +9 -1
  90. package/dist/esm/utilities/calculator/index.js +1 -0
  91. package/dist/esm/utilities/index.js +4 -6
  92. package/dist/types/abstracts/{Angle.d.ts → angle/Angle.d.ts} +2 -1
  93. package/dist/types/abstracts/angle/Angle.types.d.ts +16 -0
  94. package/dist/types/abstracts/angle/index.d.ts +2 -0
  95. package/dist/types/abstracts/{Figure.d.ts → figure/Figure.d.ts} +4 -4
  96. package/dist/types/abstracts/figure/Figure.types.d.ts +14 -0
  97. package/dist/types/abstracts/figure/index.d.ts +2 -0
  98. package/dist/types/abstracts/{Flag.d.ts → flag/Flag.d.ts} +2 -1
  99. package/dist/types/abstracts/flag/Flag.types.d.ts +8 -0
  100. package/dist/types/abstracts/flag/index.d.ts +2 -0
  101. package/dist/types/abstracts/index.d.ts +6 -0
  102. package/dist/types/abstracts/{Magnitude.d.ts → magnitude/Magnitude.d.ts} +3 -1
  103. package/dist/types/abstracts/magnitude/Magnitude.types.d.ts +8 -0
  104. package/dist/types/abstracts/magnitude/index.d.ts +2 -0
  105. package/dist/types/abstracts/{Point.d.ts → point/Point.d.ts} +2 -1
  106. package/dist/types/abstracts/point/Point.types.d.ts +13 -0
  107. package/dist/types/abstracts/point/index.d.ts +2 -0
  108. package/dist/types/abstracts/{Vector.d.ts → vector/Vector.d.ts} +3 -1
  109. package/dist/types/abstracts/vector/Vector.types.d.ts +19 -0
  110. package/dist/types/abstracts/vector/index.d.ts +2 -0
  111. package/dist/types/figures/{ArcCurve.d.ts → arc-curve/ArcCurve.d.ts} +7 -2
  112. package/dist/types/figures/arc-curve/ArcCurve.types.d.ts +11 -0
  113. package/dist/types/figures/arc-curve/index.d.ts +2 -0
  114. package/dist/types/figures/{Circle.d.ts → circle/Circle.d.ts} +3 -2
  115. package/dist/types/figures/circle/Circle.types.d.ts +9 -0
  116. package/dist/types/figures/circle/index.d.ts +2 -0
  117. package/dist/types/figures/{CubicBezierCurve.d.ts → cubic-bezier-curve/CubicBezierCurve.d.ts} +4 -2
  118. package/dist/types/figures/cubic-bezier-curve/CubicBezierCurve.types.d.ts +8 -0
  119. package/dist/types/figures/cubic-bezier-curve/index.d.ts +2 -0
  120. package/dist/types/figures/{Ellipse.d.ts → ellipse/Ellipse.d.ts} +5 -2
  121. package/dist/types/figures/ellipse/Ellipse.types.d.ts +16 -0
  122. package/dist/types/figures/ellipse/index.d.ts +2 -0
  123. package/dist/types/figures/index.d.ts +7 -0
  124. package/dist/types/figures/{Line.d.ts → line/Line.d.ts} +6 -4
  125. package/dist/types/figures/line/Line.types.d.ts +30 -0
  126. package/dist/types/figures/line/index.d.ts +2 -0
  127. package/dist/types/figures/polygon/Polygon.d.ts +17 -0
  128. package/dist/types/figures/polygon/Polygon.types.d.ts +8 -0
  129. package/dist/types/figures/polygon/index.d.ts +2 -0
  130. package/dist/types/figures/{QuadraticBezierCurve.d.ts → quadratic-bezier-curve/QuadraticBezierCurve.d.ts} +4 -2
  131. package/dist/types/figures/quadratic-bezier-curve/QuadraticBezierCurve.types.d.ts +8 -0
  132. package/dist/types/figures/quadratic-bezier-curve/index.d.ts +2 -0
  133. package/dist/types/index.d.ts +2 -14
  134. package/dist/types/types/index.d.ts +0 -129
  135. package/dist/types/utilities/{Calculator.d.ts → calculator/Calculator.d.ts} +4 -0
  136. package/dist/types/utilities/calculator/index.d.ts +1 -0
  137. package/dist/types/utilities/index.d.ts +2 -4
  138. package/package.json +24 -18
  139. package/dist/cjs/figures/ArcCurve.js +0 -132
  140. package/dist/cjs/figures/Ellipse.js +0 -111
  141. package/dist/cjs/figures/Polygon.js +0 -17
  142. package/dist/esm/figures/Polygon.js +0 -13
  143. package/dist/types/figures/Polygon.d.ts +0 -7
@@ -1,7 +1,5 @@
1
- import { Calculator } from '../utilities/Calculator';
2
- import { Magnitude } from './Magnitude';
3
- import { Point } from './Point';
4
- import { Vector } from './Vector';
1
+ import { Point, Vector } from '..';
2
+ import { Calculator } from '../../utilities/calculator';
5
3
  export class Figure {
6
4
  angles = [];
7
5
  isRelative = false;
@@ -19,23 +17,22 @@ export class Figure {
19
17
  get values() {
20
18
  return this._values;
21
19
  }
22
- /**
23
- * @todo Figure out a better way to type narrow than iterating again.
24
- */
25
20
  set values(values) {
26
21
  this._values = values;
27
22
  const [points, vectors, magnitudes, angles] = values.reduce((result, value) => {
28
- if (value instanceof Point) {
29
- result[0].push(value);
30
- }
31
- if (value instanceof Vector) {
32
- result[1].push(value);
33
- }
34
- if (value instanceof Magnitude) {
35
- result[2].push(value);
36
- }
37
- if (typeof value === 'object' && 'radians' in value) {
38
- result[3].push(value);
23
+ switch (value.kind) {
24
+ case 'point':
25
+ result[0].push(value);
26
+ break;
27
+ case 'vector':
28
+ result[1].push(value);
29
+ break;
30
+ case 'magnitude':
31
+ result[2].push(value);
32
+ break;
33
+ case 'angle':
34
+ result[3].push(value);
35
+ break;
39
36
  }
40
37
  return result;
41
38
  }, [[], [], [], []]);
@@ -74,10 +71,13 @@ export class Figure {
74
71
  point.reflect(perpendicularRoot);
75
72
  });
76
73
  vectors.forEach((vector) => {
77
- vector.reflect({
78
- x: !about.isHorizontal,
79
- y: !about.isVertical
80
- });
74
+ const referenceProjection = about.getPerpendicularProjection(points[0]);
75
+ const referencePoint = points[0].clone().reflect(referenceProjection);
76
+ const endPoint = points[0].clone().translate(vector);
77
+ const endProjection = about.getPerpendicularProjection(endPoint);
78
+ const positionalPoint = endPoint.reflect(endProjection);
79
+ const reflectedVector = new Vector([referencePoint, positionalPoint]);
80
+ vector.replace(reflectedVector);
81
81
  });
82
82
  return this;
83
83
  }
@@ -130,6 +130,21 @@ export class Figure {
130
130
  });
131
131
  return this;
132
132
  }
133
+ scaleXY(factorX, factorY, about = new Point([0, 0])) {
134
+ const { points, vectors } = this;
135
+ if (!points) {
136
+ throw new Error(Figure.getNoPointsErrorMessage('scaleXY'));
137
+ }
138
+ points.forEach((point) => {
139
+ const scaledX = +Calculator.add(about.x, Calculator.sub(point.x, about.x).mul(factorX));
140
+ const scaledY = +Calculator.add(about.y, Calculator.sub(point.y, about.y).mul(factorY));
141
+ point.replace(new Point([scaledX, scaledY]));
142
+ });
143
+ vectors.forEach((vector) => {
144
+ vector.replace(new Vector([+Calculator.mul(vector.dx, factorX), +Calculator.mul(vector.dy, factorY)]));
145
+ });
146
+ return this;
147
+ }
133
148
  translate(vector) {
134
149
  const { points } = this;
135
150
  if (!points) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './Figure';
2
+ export * from './Figure.types';
@@ -1,4 +1,5 @@
1
1
  export class Flag {
2
+ kind = 'flag';
2
3
  _value;
3
4
  constructor(value) {
4
5
  this._value = value;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './Flag';
2
+ export * from './Flag.types';
@@ -0,0 +1,6 @@
1
+ export * from './angle';
2
+ export * from './figure';
3
+ export * from './flag';
4
+ export * from './magnitude';
5
+ export * from './point';
6
+ export * from './vector';
@@ -1,9 +1,13 @@
1
- import { Calculator } from '../utilities/Calculator';
1
+ import { Calculator } from '../../utilities/calculator';
2
2
  export class Magnitude {
3
+ kind = 'magnitude';
3
4
  _value;
4
5
  constructor(value) {
5
6
  this._value = value;
6
7
  }
8
+ get value() {
9
+ return this._value;
10
+ }
7
11
  clone() {
8
12
  return new Magnitude(+this);
9
13
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './Magnitude';
2
+ export * from './Magnitude.types';
@@ -1,5 +1,6 @@
1
- import { Calculator } from '../utilities/Calculator';
1
+ import { Calculator } from '../../utilities/calculator';
2
2
  export class Point {
3
+ kind = 'point';
3
4
  _x;
4
5
  _y;
5
6
  constructor([x, y]) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './Point';
2
+ export * from './Point.types';
@@ -1,6 +1,7 @@
1
- import { Calculator } from '../utilities/Calculator';
2
- import { Angle } from './Angle';
1
+ import { Angle } from '..';
2
+ import { Calculator } from '../../utilities/calculator';
3
3
  export class Vector {
4
+ kind = 'vector';
4
5
  _dx;
5
6
  _dy;
6
7
  constructor(values) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './Vector';
2
+ export * from './Vector.types';
@@ -1,7 +1,7 @@
1
- import { Calculator } from '../utilities/Calculator';
2
- import { Point } from '../abstracts/Point';
3
- import { Figure } from '../abstracts/Figure';
4
- import { Ellipse } from './Ellipse';
1
+ import { Angle, Figure, Point } from '../../abstracts';
2
+ import { CubicBezierCurve } from '../cubic-bezier-curve/CubicBezierCurve';
3
+ import { Ellipse } from '../ellipse/Ellipse';
4
+ import { Calculator } from '../../utilities/calculator';
5
5
  export class ArcCurve extends Figure {
6
6
  ellipse;
7
7
  largeArcFlag;
@@ -34,7 +34,7 @@ export class ArcCurve extends Figure {
34
34
  const [minTheta, maxTheta] = this.computeThetaRange();
35
35
  return ellipse.criticalPoints.filter((point) => {
36
36
  const { P0, P1 } = this;
37
- if ((point.x === P0.x && point.y === P0.y) || (point.x === P1.x && point.y === P1.y)) {
37
+ if ((Calculator.isEqual(point.x, P0.x) && Calculator.isEqual(point.y, P0.y)) || (Calculator.isEqual(point.x, P1.x) && Calculator.isEqual(point.y, P1.y))) {
38
38
  return false;
39
39
  }
40
40
  const theta = ellipse.computeThetaForPoint(point);
@@ -51,7 +51,7 @@ export class ArcCurve extends Figure {
51
51
  return this.points[1];
52
52
  }
53
53
  clone() {
54
- const values = this.values.map((value) => (typeof value === 'object' && 'clone' in value ? value.clone() : value));
54
+ const values = this.values.map((value) => (typeof value === 'object' && 'clone' in value ? value.clone() : /* v8 ignore next */ value));
55
55
  return new ArcCurve(values);
56
56
  }
57
57
  reflect(about) {
@@ -59,6 +59,30 @@ export class ArcCurve extends Figure {
59
59
  this.sweepFlag.invert();
60
60
  return this;
61
61
  }
62
+ toCubicBezierCurves() {
63
+ const [minTheta, maxTheta] = this.computeThetaRange();
64
+ const p0Theta = this.ellipse.computeThetaForPoint(this.P0);
65
+ const p0IsMin = Calculator.isEqual(+p0Theta.radians, +minTheta.radians);
66
+ const span = +Calculator.sub(maxTheta.radians, minTheta.radians);
67
+ const halfPi = Math.PI / 2;
68
+ const numSegments = Math.max(1, Math.ceil(span / halfPi));
69
+ const segmentAngle = span / numSegments;
70
+ const curves = [];
71
+ for (let i = 0; i < numSegments; i++) {
72
+ let t1Rad;
73
+ let t2Rad;
74
+ if (p0IsMin) {
75
+ t1Rad = +Calculator.add(minTheta.radians, Calculator.mul(segmentAngle, i));
76
+ t2Rad = +Calculator.add(minTheta.radians, Calculator.mul(segmentAngle, i + 1));
77
+ }
78
+ else {
79
+ t1Rad = +Calculator.sub(maxTheta.radians, Calculator.mul(segmentAngle, i));
80
+ t2Rad = +Calculator.sub(maxTheta.radians, Calculator.mul(segmentAngle, i + 1));
81
+ }
82
+ curves.push(this.computeBezierSegment(new Angle(t1Rad, 'radians'), new Angle(t2Rad, 'radians')));
83
+ }
84
+ return curves;
85
+ }
62
86
  adjustRadii() {
63
87
  const { rx, ry } = this;
64
88
  const P0_prime = this.computeP0Prime();
@@ -73,6 +97,18 @@ export class ArcCurve extends Figure {
73
97
  ry.replace(+Calculator.mul(+ry, radii_check.sqrt()));
74
98
  }
75
99
  }
100
+ computeBezierSegment(theta1, theta2) {
101
+ const { ellipse } = this;
102
+ const alpha = +Calculator.sub(theta2.radians, theta1.radians);
103
+ const k = +Calculator.mul(4, Calculator.tan(Calculator.div(alpha, 4))).div(3);
104
+ const p0 = ellipse.computePointForTheta(theta1);
105
+ const p3 = ellipse.computePointForTheta(theta2);
106
+ const [t1x, t1y] = this.computeTangentForTheta(theta1);
107
+ const [t2x, t2y] = this.computeTangentForTheta(theta2);
108
+ const p1 = new Point([+Calculator.add(p0.x, Calculator.mul(k, t1x)), +Calculator.add(p0.y, Calculator.mul(k, t1y))]);
109
+ const p2 = new Point([+Calculator.sub(p3.x, Calculator.mul(k, t2x)), +Calculator.sub(p3.y, Calculator.mul(k, t2y))]);
110
+ return new CubicBezierCurve([p0, p1, p2, p3]);
111
+ }
76
112
  computeCenter() {
77
113
  const { P0, P1, phi } = this;
78
114
  const center_prime = this.computeCenterPrime();
@@ -99,7 +135,7 @@ export class ArcCurve extends Figure {
99
135
  .sub(rx_sq.mul(y1_prime_sq))
100
136
  .sub(ry_sq.mul(x1_prime_sq))
101
137
  .div(rx_sq.mul(y1_prime_sq).add(ry_sq.mul(x1_prime_sq)));
102
- sq = +sq < 0 ? new Calculator(0) : sq;
138
+ sq = +sq < 0 ? /* v8 ignore next */ new Calculator(0) : sq;
103
139
  const coef = sign.mul(sq.sqrt());
104
140
  const cx_prime = coef.mul(Calculator.mul(+rx, y1_prime).div(+ry));
105
141
  const cy_prime = coef.mul(Calculator.mul(+ry, x1_prime).div(+rx).neg());
@@ -115,11 +151,17 @@ export class ArcCurve extends Figure {
115
151
  const y1_prime = Calculator.mul(phi.sin, mx).neg().add(Calculator.mul(phi.cos, my));
116
152
  return new Point([+x1_prime, +y1_prime]);
117
153
  }
154
+ computeTangentForTheta(theta) {
155
+ const { phi, rx, ry } = this.ellipse;
156
+ const tx = +Calculator.neg(Calculator.mul(+rx, theta.sin).mul(phi.cos)).sub(Calculator.mul(+ry, theta.cos).mul(phi.sin));
157
+ const ty = +Calculator.neg(Calculator.mul(+rx, theta.sin).mul(phi.sin)).add(Calculator.mul(+ry, theta.cos).mul(phi.cos));
158
+ return [tx, ty];
159
+ }
118
160
  computeThetaRange() {
119
161
  const { P0, P1, ellipse, sweepFlag } = this;
120
162
  const theta1 = ellipse.computeThetaForPoint(P0);
121
163
  const theta2 = ellipse.computeThetaForPoint(P1);
122
- if (+theta2 === 0 && !sweepFlag.value) {
164
+ if (Calculator.isNearZero(+theta2) && !sweepFlag.value) {
123
165
  theta2.replace(360, 'degrees');
124
166
  }
125
167
  const thetaRange = [theta1, theta2].sort((a, b) => +Calculator.sub(a.radians, b.radians));
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './ArcCurve';
2
+ export * from './ArcCurve.types';
@@ -1,7 +1,6 @@
1
- import { Calculator } from '../utilities/Calculator';
2
- import { Ellipse } from './Ellipse';
3
- import { Point } from '../abstracts/Point';
4
- import { Angle } from '../abstracts/Angle';
1
+ import { Angle, Point } from '../../abstracts';
2
+ import { Ellipse } from '../ellipse/Ellipse';
3
+ import { Calculator } from '../../utilities/calculator';
5
4
  export class Circle extends Ellipse {
6
5
  _radius;
7
6
  constructor(values) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './Circle';
2
+ export * from './Circle.types';
@@ -1,6 +1,5 @@
1
- import { Calculator } from '../utilities/Calculator';
2
- import { Point } from '../abstracts/Point';
3
- import { Figure } from '../abstracts/Figure';
1
+ import { Figure, Point } from '../../abstracts';
2
+ import { Calculator } from '../../utilities/calculator';
4
3
  export class CubicBezierCurve extends Figure {
5
4
  _criticalPoints;
6
5
  constructor(values) {
@@ -58,6 +57,11 @@ export class CubicBezierCurve extends Figure {
58
57
  this.recompute();
59
58
  return this;
60
59
  }
60
+ scaleXY(factorX, factorY, about) {
61
+ super.scaleXY(factorX, factorY, about);
62
+ this.recompute();
63
+ return this;
64
+ }
61
65
  translate(vector) {
62
66
  super.translate(vector);
63
67
  this.recompute();
@@ -70,7 +74,8 @@ export class CubicBezierCurve extends Figure {
70
74
  }
71
75
  const criticalPoints = tValues.reduce((criticalPoints, t) => {
72
76
  const criticalPoint = this.getPointAtParameter(t);
73
- criticalPoint && criticalPoints.push(criticalPoint);
77
+ if (criticalPoint)
78
+ criticalPoints.push(criticalPoint);
74
79
  return criticalPoints;
75
80
  }, []);
76
81
  return criticalPoints;
@@ -92,7 +97,7 @@ export class CubicBezierCurve extends Figure {
92
97
  for (let n = 0; n < signs.length; n++) {
93
98
  const sign = signs[n];
94
99
  let tValue;
95
- if (+a === 0) {
100
+ if (Calculator.isNearZero(+a)) {
96
101
  // 1st degree equation to avoid n/0
97
102
  tValue = c.neg().div(b);
98
103
  }
@@ -111,7 +116,7 @@ export class CubicBezierCurve extends Figure {
111
116
  if (!tValues.length) {
112
117
  return;
113
118
  }
114
- return tValues.filter((value, index, array) => index === array.findIndex((v) => +value === +v));
119
+ return tValues.filter((value, index, array) => index === array.findIndex((v) => Calculator.isEqual(+value, +v)));
115
120
  }
116
121
  getCoordinateAtParameter(t, axis) {
117
122
  const { P0, P1, P2, P3 } = this;
@@ -0,0 +1,2 @@
1
+ export * from './CubicBezierCurve';
2
+ export * from './CubicBezierCurve.types';
@@ -1,8 +1,15 @@
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';
1
+ import { Angle, Figure, Point, Vector } from '../../abstracts';
2
+ import { CubicBezierCurve } from '../cubic-bezier-curve/CubicBezierCurve';
3
+ import { Calculator } from '../../utilities/calculator';
4
+ import { Line } from '../line/Line';
5
+ const KAPPA = 0.5522847498307936;
6
+ const xAxis = new Line([new Point([0, 0]), new Point([1, 0])]);
7
+ const unitCircleCubicBezierCurves = [
8
+ new CubicBezierCurve([new Point([1, 0]), new Point([1, KAPPA]), new Point([KAPPA, 1]), new Point([0, 1])]),
9
+ new CubicBezierCurve([new Point([0, 1]), new Point([-KAPPA, 1]), new Point([-1, KAPPA]), new Point([-1, 0])]),
10
+ new CubicBezierCurve([new Point([-1, 0]), new Point([-1, -KAPPA]), new Point([-KAPPA, -1]), new Point([0, -1])]),
11
+ new CubicBezierCurve([new Point([0, -1]), new Point([KAPPA, -1]), new Point([1, -KAPPA]), new Point([1, 0])])
12
+ ];
6
13
  export class Ellipse extends Figure {
7
14
  _center;
8
15
  _criticalPoints;
@@ -28,7 +35,7 @@ export class Ellipse extends Figure {
28
35
  return this._criticalPoints;
29
36
  }
30
37
  get isCircle() {
31
- return +this.rx === +this.ry;
38
+ return Calculator.isEqual(+this.rx, +this.ry);
32
39
  }
33
40
  get phi() {
34
41
  return this._phi;
@@ -83,6 +90,17 @@ export class Ellipse extends Figure {
83
90
  this.recompute();
84
91
  return this;
85
92
  }
93
+ toCubicBezierCurves() {
94
+ const { rx, ry, phi, center } = this;
95
+ const curves = unitCircleCubicBezierCurves.map((curve) => {
96
+ return curve
97
+ .clone()
98
+ .scaleXY(+rx, +ry)
99
+ .rotate(phi)
100
+ .translate(new Vector([center.x, center.y]));
101
+ });
102
+ return curves;
103
+ }
86
104
  translate(vector) {
87
105
  this._center.translate(vector);
88
106
  this.recompute();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './Ellipse';
2
+ export * from './Ellipse.types';
@@ -0,0 +1,7 @@
1
+ export * from './arc-curve';
2
+ export * from './circle';
3
+ export * from './cubic-bezier-curve';
4
+ export * from './ellipse';
5
+ export * from './line';
6
+ export * from './polygon';
7
+ export * from './quadratic-bezier-curve';
@@ -1,12 +1,10 @@
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';
1
+ import { Angle, Figure, Point, Vector } from '../../abstracts';
2
+ import { Calculator } from '../../utilities/calculator';
6
3
  export class Line extends Figure {
7
4
  _P0;
8
5
  _P1;
9
6
  _V;
7
+ _dirty = true;
10
8
  _reciprocal;
11
9
  _slope;
12
10
  _xIntercept;
@@ -24,10 +22,6 @@ export class Line extends Figure {
24
22
  this._P1 = anchor;
25
23
  }
26
24
  this._P0 = P0;
27
- this._slope = this.computeSlope();
28
- this._yIntercept = this.computeYIntercept();
29
- this._reciprocal = this.computeReciprocal();
30
- this._xIntercept = this.computeXIntercept();
31
25
  this.points = [this.P0, this.P1];
32
26
  this.vectors = [this.V];
33
27
  }
@@ -80,33 +74,41 @@ export class Line extends Figure {
80
74
  return typeof slope === 'undefined';
81
75
  }
82
76
  get reciprocal() {
77
+ this.ensureComputed();
83
78
  return this._reciprocal;
84
79
  }
85
80
  get slope() {
81
+ this.ensureComputed();
86
82
  return this._slope;
87
83
  }
88
84
  get xIntercept() {
85
+ this.ensureComputed();
89
86
  return this._xIntercept;
90
87
  }
91
88
  get yIntercept() {
89
+ this.ensureComputed();
92
90
  return this._yIntercept;
93
91
  }
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');
92
+ angleTo(reference) {
93
+ if ('slope' in reference) {
94
+ const line = reference;
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
+ return this.V.angleTo(reference);
110
112
  }
111
113
  clone() {
112
114
  const values = this.values.map((value) => value.clone());
@@ -134,9 +136,11 @@ export class Line extends Figure {
134
136
  perpendicularProjection = new Point([point.x, P0.y]);
135
137
  }
136
138
  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]);
139
+ const perpendicularSlope = +Calculator.div(-1, slope);
140
+ const perpendicularYIntercept = +Calculator.sub(point.y, Calculator.mul(perpendicularSlope, point.x));
141
+ const x = +Calculator.sub(perpendicularYIntercept, this.yIntercept).div(Calculator.sub(slope, perpendicularSlope));
142
+ const y = +Calculator.mul(slope, x).add(this.yIntercept);
143
+ perpendicularProjection = new Point([x, y]);
140
144
  }
141
145
  return perpendicularProjection;
142
146
  }
@@ -174,11 +178,17 @@ export class Line extends Figure {
174
178
  return +Calculator.mul(slope, x).add(yIntercept);
175
179
  }
176
180
  hasPoint(P) {
181
+ if (this.isVertical) {
182
+ return Calculator.isEqual(P.x, this.P0.x);
183
+ }
177
184
  const potentialY = this.getYValueAtX(P.x);
178
- return typeof potentialY === 'number' && potentialY === P.y;
185
+ return typeof potentialY === 'number' && Calculator.isEqual(potentialY, P.y);
179
186
  }
180
187
  isParallelTo(line) {
181
- return this.slope == line.slope;
188
+ if (typeof this.slope === 'undefined' || typeof line.slope === 'undefined') {
189
+ return typeof this.slope === typeof line.slope;
190
+ }
191
+ return Calculator.isEqual(this.slope, line.slope);
182
192
  }
183
193
  isPerpendicularTo(line) {
184
194
  if (this.isVertical) {
@@ -187,34 +197,39 @@ export class Line extends Figure {
187
197
  if (this.isHorizontal) {
188
198
  return line.isVertical;
189
199
  }
200
+ /* v8 ignore next 3 */
190
201
  if (line.isVertical) {
191
202
  return this.isHorizontal;
192
203
  }
204
+ /* v8 ignore next 3 */
193
205
  if (line.isHorizontal) {
194
206
  return this.isVertical;
195
207
  }
196
- const thisSlope = new Calculator(this.slope);
197
- const lineSlope = new Calculator(line.slope);
198
- return +thisSlope === +Calculator.div(-1, lineSlope);
208
+ return Calculator.isEqual(this.slope, +Calculator.div(-1, line.slope));
199
209
  }
200
210
  reflect(about) {
201
211
  super.reflect(about);
202
- this.recompute();
212
+ this._dirty = true;
203
213
  return this;
204
214
  }
205
215
  rotate(phi, about) {
206
216
  super.rotate(phi, about);
207
- this.recompute();
217
+ this._dirty = true;
208
218
  return this;
209
219
  }
210
220
  scale(factor, about) {
211
221
  super.scale(factor, about);
212
- this.recompute();
222
+ this._dirty = true;
223
+ return this;
224
+ }
225
+ scaleXY(factorX, factorY, about) {
226
+ super.scaleXY(factorX, factorY, about);
227
+ this._dirty = true;
213
228
  return this;
214
229
  }
215
230
  translate(vector) {
216
231
  super.translate(vector);
217
- this.recompute();
232
+ this._dirty = true;
218
233
  return this;
219
234
  }
220
235
  computeReciprocal() {
@@ -251,7 +266,11 @@ export class Line extends Figure {
251
266
  }
252
267
  return +Calculator.sub(P0.y, Calculator.mul(slope, P0.x));
253
268
  }
254
- recompute() {
269
+ ensureComputed() {
270
+ if (!this._dirty) {
271
+ return;
272
+ }
273
+ this._dirty = false;
255
274
  this._slope = this.computeSlope();
256
275
  this._yIntercept = this.computeYIntercept();
257
276
  this._reciprocal = this.computeReciprocal();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './Line';
2
+ export * from './Line.types';