@interstellar-tools/equations 0.1.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.
Files changed (78) hide show
  1. package/README.md +18 -0
  2. package/dist/__tests__/compute-angle.int.spec.d.ts +2 -0
  3. package/dist/__tests__/compute-angle.int.spec.d.ts.map +1 -0
  4. package/dist/__tests__/compute-angle.int.spec.js +62 -0
  5. package/dist/__tests__/compute-angle.int.spec.js.map +1 -0
  6. package/dist/__tests__/compute-mean-anomaly.int.spec.d.ts +2 -0
  7. package/dist/__tests__/compute-mean-anomaly.int.spec.d.ts.map +1 -0
  8. package/dist/__tests__/compute-mean-anomaly.int.spec.js +175 -0
  9. package/dist/__tests__/compute-mean-anomaly.int.spec.js.map +1 -0
  10. package/dist/__tests__/eccentric-to-true-anomaly.spec.d.ts +2 -0
  11. package/dist/__tests__/eccentric-to-true-anomaly.spec.d.ts.map +1 -0
  12. package/dist/__tests__/eccentric-to-true-anomaly.spec.js +33 -0
  13. package/dist/__tests__/eccentric-to-true-anomaly.spec.js.map +1 -0
  14. package/dist/__tests__/solve-kepler-bisection.spec.d.ts +2 -0
  15. package/dist/__tests__/solve-kepler-bisection.spec.d.ts.map +1 -0
  16. package/dist/__tests__/solve-kepler-bisection.spec.js +41 -0
  17. package/dist/__tests__/solve-kepler-bisection.spec.js.map +1 -0
  18. package/dist/__tests__/solve-kepler-high-eccentricity.spec.d.ts +2 -0
  19. package/dist/__tests__/solve-kepler-high-eccentricity.spec.d.ts.map +1 -0
  20. package/dist/__tests__/solve-kepler-high-eccentricity.spec.js +81 -0
  21. package/dist/__tests__/solve-kepler-high-eccentricity.spec.js.map +1 -0
  22. package/dist/__tests__/solve-kepler-newton-raphson.spec.d.ts +2 -0
  23. package/dist/__tests__/solve-kepler-newton-raphson.spec.d.ts.map +1 -0
  24. package/dist/__tests__/solve-kepler-newton-raphson.spec.js +50 -0
  25. package/dist/__tests__/solve-kepler-newton-raphson.spec.js.map +1 -0
  26. package/dist/__tests__/solve-kepler.int.spec.d.ts +2 -0
  27. package/dist/__tests__/solve-kepler.int.spec.d.ts.map +1 -0
  28. package/dist/__tests__/solve-kepler.int.spec.js +76 -0
  29. package/dist/__tests__/solve-kepler.int.spec.js.map +1 -0
  30. package/dist/__tests__/true-anomaly-to-mean-anomaly.int.spec.d.ts +2 -0
  31. package/dist/__tests__/true-anomaly-to-mean-anomaly.int.spec.d.ts.map +1 -0
  32. package/dist/__tests__/true-anomaly-to-mean-anomaly.int.spec.js +46 -0
  33. package/dist/__tests__/true-anomaly-to-mean-anomaly.int.spec.js.map +1 -0
  34. package/dist/__tests__/wrap-angle.spec.d.ts +2 -0
  35. package/dist/__tests__/wrap-angle.spec.d.ts.map +1 -0
  36. package/dist/__tests__/wrap-angle.spec.js +60 -0
  37. package/dist/__tests__/wrap-angle.spec.js.map +1 -0
  38. package/dist/compute-angle.d.ts +69 -0
  39. package/dist/compute-angle.d.ts.map +1 -0
  40. package/dist/compute-angle.js +79 -0
  41. package/dist/compute-angle.js.map +1 -0
  42. package/dist/compute-mean-anomaly.d.ts +47 -0
  43. package/dist/compute-mean-anomaly.d.ts.map +1 -0
  44. package/dist/compute-mean-anomaly.js +86 -0
  45. package/dist/compute-mean-anomaly.js.map +1 -0
  46. package/dist/eccentric-to-true-anomaly.d.ts +43 -0
  47. package/dist/eccentric-to-true-anomaly.d.ts.map +1 -0
  48. package/dist/eccentric-to-true-anomaly.js +63 -0
  49. package/dist/eccentric-to-true-anomaly.js.map +1 -0
  50. package/dist/index.d.ts +16 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +16 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/solve-kepler-bisection.d.ts +75 -0
  55. package/dist/solve-kepler-bisection.d.ts.map +1 -0
  56. package/dist/solve-kepler-bisection.js +94 -0
  57. package/dist/solve-kepler-bisection.js.map +1 -0
  58. package/dist/solve-kepler-high-eccentricity.d.ts +99 -0
  59. package/dist/solve-kepler-high-eccentricity.d.ts.map +1 -0
  60. package/dist/solve-kepler-high-eccentricity.js +150 -0
  61. package/dist/solve-kepler-high-eccentricity.js.map +1 -0
  62. package/dist/solve-kepler-newton-raphson.d.ts +87 -0
  63. package/dist/solve-kepler-newton-raphson.d.ts.map +1 -0
  64. package/dist/solve-kepler-newton-raphson.js +118 -0
  65. package/dist/solve-kepler-newton-raphson.js.map +1 -0
  66. package/dist/solve-kepler.d.ts +82 -0
  67. package/dist/solve-kepler.d.ts.map +1 -0
  68. package/dist/solve-kepler.js +99 -0
  69. package/dist/solve-kepler.js.map +1 -0
  70. package/dist/true-anomaly-to-mean-anomaly.d.ts +74 -0
  71. package/dist/true-anomaly-to-mean-anomaly.d.ts.map +1 -0
  72. package/dist/true-anomaly-to-mean-anomaly.js +91 -0
  73. package/dist/true-anomaly-to-mean-anomaly.js.map +1 -0
  74. package/dist/wrap-angle.d.ts +82 -0
  75. package/dist/wrap-angle.d.ts.map +1 -0
  76. package/dist/wrap-angle.js +97 -0
  77. package/dist/wrap-angle.js.map +1 -0
  78. package/package.json +58 -0
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Solves **Kepler's Equation** for the **Eccentric Anomaly** ($E$) using the **Newton-Raphson method**
3
+ * with Householder acceleration for fast convergence.
4
+ *
5
+ * ---
6
+ *
7
+ * **Mathematical Explanation:**
8
+ *
9
+ * Kepler's equation relates the **mean anomaly** ($M$), the **eccentric anomaly** ($E$),
10
+ * and the **orbital eccentricity** ($e$) as:
11
+ * $$
12
+ * M = E - e \sin(E)
13
+ * $$
14
+ * Since this equation **cannot be solved algebraically**, iterative numerical methods are required.
15
+ *
16
+ * ---
17
+ *
18
+ * **Solving Strategy:**
19
+ * 1. **Handle Special Cases:**
20
+ * - If the orbit is **circular** ($e = 0$), then $E = M$ directly.
21
+ * - If the orbit is **nearly parabolic** ($e \geq 0.97$), a special approximation is used.
22
+ * - If **eccentricity is out of range** ($e < 0$ or $e \geq 1$), a `RangeError` is thrown.
23
+ *
24
+ * 2. **Initial Approximation:**
25
+ * - **For small eccentricities ($e < 0.8$):** $E_0 = M$.
26
+ * - **For moderate eccentricities ($0.8 \leq e < 0.97$):** $E_0 = M + e \sin(M) (1 + e \cos(M))$.
27
+ * - **For nearly parabolic orbits ($e \geq 0.97$):** $E_0 = \frac{6M}{e}$.
28
+ *
29
+ * 3. **Newton-Raphson Iteration with Householder Acceleration:**
30
+ * - The **Newton-Raphson method** iterates using:
31
+ * $$
32
+ * E_{n+1} = E_n - \frac{f(E_n)}{f'(E_n)}
33
+ * $$
34
+ * where:
35
+ * - $f(E) = E - e \sin(E) - M$
36
+ * - $f'(E) = 1 - e \cos(E)$
37
+ *
38
+ * - **Householder acceleration** refines the correction:
39
+ * $$
40
+ * \Delta E = \frac{f(E)}{f'(E)} \left( 1 - \frac{1}{2} \frac{f''(E)}{f'(E)} \Delta E \right)^{-1}
41
+ * $$
42
+ *
43
+ * 4. **Convergence Check:**
44
+ * - The iteration stops when:
45
+ * $$
46
+ * |E_{n+1} - E_n| < \text{tolerance}
47
+ * $$
48
+ * (default tolerance is **1e-9**).
49
+ *
50
+ * 5. **Failure Handling:**
51
+ * - If the method **does not converge**, `NaN` is returned, signaling that a fallback method should be used.
52
+ *
53
+ * ---
54
+ *
55
+ * **Performance Considerations:**
56
+ * - **Typically converges in 4-5 iterations for most eccentricities.**
57
+ * - **Time complexity:** $O(1)$ for Newton-Raphson.
58
+ *
59
+ * ---
60
+ *
61
+ * @param {Radians} M - Mean anomaly ($M$) in **radians**.
62
+ * @param {number} e - Orbital eccentricity ($0 \leq e < 1$).
63
+ * @param {number} maxIter - Maximum number of **iterations** before failure.
64
+ * @param {number} tolerance - Convergence criterion for stopping the iteration.
65
+ * @returns {Radians} The **eccentric anomaly** ($E$) in **radians** (or `NaN` if the method fails).
66
+ *
67
+ * @throws {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} If the **eccentricity ($e$) is invalid** ($e < 0$ or $e \geq 1$).
68
+ *
69
+ * ---
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * const M = Math.PI / 4; // 45 degrees in radians
74
+ * const e = 0.1; // Orbital eccentricity
75
+ * console.log(solveKeplerNewtonRaphson(M, e, 50, 1e-9)); // Output: Eccentric anomaly in radians
76
+ * ```
77
+ *
78
+ * ---
79
+ *
80
+ * @see [Kepler's Equation (Wikipedia)](https://en.wikipedia.org/wiki/Kepler%27s_equation)
81
+ * @see [Newton-Raphson Method (Wikipedia)](https://en.wikipedia.org/wiki/Newton%27s_method)
82
+ * @see [Eccentric Anomaly (Wikipedia)](https://en.wikipedia.org/wiki/Mean_anomaly#Eccentric_anomaly)
83
+ * @category Solve for Kepler
84
+ */
85
+ export const solveKeplerNewtonRaphson = (M, e, maxIter, tolerance) => {
86
+ if (e < 0 || e >= 1) {
87
+ throw new RangeError(`Invalid eccentricity: ${e}. Must be in range [0,1].`);
88
+ }
89
+ let E;
90
+ // Smart initial guess
91
+ if (e < 0.8) {
92
+ E = M;
93
+ }
94
+ else if (e < 0.97) {
95
+ E = M + e * Math.sin(M) * (1 + e * Math.cos(M));
96
+ }
97
+ else {
98
+ E = (6 * M) / e; // Nearly parabolic case
99
+ }
100
+ let iter = 0;
101
+ while (iter < maxIter) {
102
+ const F = E - e * Math.sin(E) - M;
103
+ const dF = 1 - e * Math.cos(E);
104
+ const d2F = e * Math.sin(E);
105
+ const d3F = e * Math.cos(E);
106
+ const deltaE = -F / dF; // Newton’s step
107
+ // Apply Householder's method for faster convergence
108
+ let correction = deltaE / (1 - (0.5 * deltaE * d2F) / dF);
109
+ correction /= 1 - ((1 / 6) * correction * correction * d3F) / dF;
110
+ E += correction;
111
+ if (Math.abs(correction) < tolerance) {
112
+ return E; // Converged
113
+ }
114
+ iter++;
115
+ }
116
+ return NaN; // Indicate failure
117
+ };
118
+ //# sourceMappingURL=solve-kepler-newton-raphson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solve-kepler-newton-raphson.js","sourceRoot":"","sources":["../src/solve-kepler-newton-raphson.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmFG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,CAAU,EACV,CAAS,EACT,OAAe,EACf,SAAiB,EACR,EAAE;IACX,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,UAAU,CAAC,yBAAyB,CAAC,2BAA2B,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,CAAS,CAAC;IAEd,sBAAsB;IACtB,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACZ,CAAC,GAAG,CAAC,CAAC;IACR,CAAC;SAAM,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;QACpB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;SAAM,CAAC;QACN,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,wBAAwB;IAC3C,CAAC;IAED,IAAI,IAAI,GAAG,CAAC,CAAC;IAEb,OAAO,IAAI,GAAG,OAAO,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,gBAAgB;QAExC,oDAAoD;QACpD,IAAI,UAAU,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAE1D,UAAU,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,GAAG,UAAU,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC;QAEjE,CAAC,IAAI,UAAU,CAAC;QAEhB,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,SAAS,EAAE,CAAC;YACrC,OAAO,CAAC,CAAC,CAAC,YAAY;QACxB,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC;IAED,OAAO,GAAG,CAAC,CAAC,mBAAmB;AACjC,CAAC,CAAC"}
@@ -0,0 +1,82 @@
1
+ import { Radians } from '@interstellar-tools/types';
2
+ /**
3
+ * Solves **Kepler's Equation** for the **Eccentric Anomaly** ($E$) using an adaptive approach:
4
+ * - **Newton-Raphson method** for fast convergence.
5
+ * - **Bisection fallback** if Newton’s method fails.
6
+ * - **High-eccentricity solver** for extreme orbits ($e > 0.9$).
7
+ *
8
+ * ---
9
+ *
10
+ * **Mathematical Explanation:**
11
+ *
12
+ * Kepler's equation relates the **mean anomaly** ($M$), the **eccentric anomaly** ($E$),
13
+ * and the **orbital eccentricity** ($e$) as:
14
+ * $$
15
+ * M = E - e \sin(E)
16
+ * $$
17
+ * Since this equation **cannot be solved algebraically**, numerical methods are required.
18
+ *
19
+ * ---
20
+ *
21
+ * **Solving Strategy:**
22
+ * 1. **Handle Special Cases:**
23
+ * - If the orbit is **circular** ($e = 0$), then $E = M$ directly.
24
+ * - If the orbit is **parabolic** ($e = 1$), an exception is thrown.
25
+ * - If **eccentricity is out of range** ($e < 0$ or $e \geq 1$), a `RangeError` is thrown.
26
+ *
27
+ * 2. **Select the Best Solver:**
28
+ * - **For high eccentricities ($e > 0.9$)** → Uses `solveKeplerHighEccentricity()`.
29
+ * - **For moderate eccentricities ($e \leq 0.9$)** → Uses `solveKeplerNewtonRaphson()`.
30
+ * - **If Newton-Raphson fails**, falls back to `solveKeplerBisection()`.
31
+ *
32
+ * 3. **Final Wrapping:**
33
+ * - Ensures the solution is correctly wrapped using `wrapAngle()`.
34
+ *
35
+ * ---
36
+ *
37
+ * **Performance Considerations:**
38
+ * - **Newton-Raphson typically converges in 4-5 iterations.**
39
+ * - **Bisection fallback ensures robustness for extreme cases.**
40
+ * - **High-eccentricity solver prevents instability for $e \approx 1$.**
41
+ *
42
+ * ---
43
+ *
44
+ * @param {Radians} M - Mean anomaly ($M$) in **radians**.
45
+ * @param {number} e - Orbital eccentricity ($0 \leq e < 1$).
46
+ * @param {number} [maxIter=50] - Maximum number of **iterations** before fallback.
47
+ * @param {number} [tolerance=1e-9] - Convergence criterion for stopping the iteration.
48
+ * @returns {Radians} The **eccentric anomaly** ($E$) in **radians** (wrapped to $[0, 2\pi]$).
49
+ *
50
+ * @throws {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} If the **eccentricity ($e$) is invalid** ($e < 0$ or $e \geq 1$).
51
+ *
52
+ * ---
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * import { solveKepler } from './solve-kepler';
57
+ *
58
+ * // Example 1: Moderate eccentricity
59
+ * const M = Math.PI / 4; // 45 degrees in radians
60
+ * const e = 0.1; // Orbital eccentricity
61
+ * const result = solveKepler(M, e);
62
+ * console.log(result); // Output: Eccentric anomaly in radians
63
+ * ```
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * // Example 2: High-eccentricity orbit (e > 0.9)
68
+ * const M_high = 1.5; // Mean anomaly in radians
69
+ * const e_high = 0.95; // High eccentricity
70
+ * console.log(solveKepler(M_high, e_high)); // Uses high-eccentricity solver
71
+ * ```
72
+ *
73
+ * ---
74
+ *
75
+ * @see [Kepler's Equation (Wikipedia)](https://en.wikipedia.org/wiki/Kepler%27s_equation)
76
+ * @see [Newton-Raphson Method (Wikipedia)](https://en.wikipedia.org/wiki/Newton%27s_method)
77
+ * @see [Eccentric Anomaly (Wikipedia)](https://en.wikipedia.org/wiki/Mean_anomaly#Eccentric_anomaly)
78
+ * @see [RangeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError)
79
+ * @category Solve for Kepler
80
+ */
81
+ export declare const solveKepler: (M: Radians, e: number, maxIter?: number, tolerance?: number) => Radians;
82
+ //# sourceMappingURL=solve-kepler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solve-kepler.d.ts","sourceRoot":"","sources":["../src/solve-kepler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAOpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AACH,eAAO,MAAM,WAAW,GACtB,GAAG,OAAO,EACV,GAAG,MAAM,EACT,gBAAY,EACZ,kBAAgB,KACf,OAkBF,CAAC"}
@@ -0,0 +1,99 @@
1
+ import { solveKeplerBisection } from './solve-kepler-bisection';
2
+ import { solveKeplerHighEccentricity } from './solve-kepler-high-eccentricity';
3
+ import { solveKeplerNewtonRaphson } from './solve-kepler-newton-raphson';
4
+ import { wrapAngle } from './wrap-angle';
5
+ /**
6
+ * Solves **Kepler's Equation** for the **Eccentric Anomaly** ($E$) using an adaptive approach:
7
+ * - **Newton-Raphson method** for fast convergence.
8
+ * - **Bisection fallback** if Newton’s method fails.
9
+ * - **High-eccentricity solver** for extreme orbits ($e > 0.9$).
10
+ *
11
+ * ---
12
+ *
13
+ * **Mathematical Explanation:**
14
+ *
15
+ * Kepler's equation relates the **mean anomaly** ($M$), the **eccentric anomaly** ($E$),
16
+ * and the **orbital eccentricity** ($e$) as:
17
+ * $$
18
+ * M = E - e \sin(E)
19
+ * $$
20
+ * Since this equation **cannot be solved algebraically**, numerical methods are required.
21
+ *
22
+ * ---
23
+ *
24
+ * **Solving Strategy:**
25
+ * 1. **Handle Special Cases:**
26
+ * - If the orbit is **circular** ($e = 0$), then $E = M$ directly.
27
+ * - If the orbit is **parabolic** ($e = 1$), an exception is thrown.
28
+ * - If **eccentricity is out of range** ($e < 0$ or $e \geq 1$), a `RangeError` is thrown.
29
+ *
30
+ * 2. **Select the Best Solver:**
31
+ * - **For high eccentricities ($e > 0.9$)** → Uses `solveKeplerHighEccentricity()`.
32
+ * - **For moderate eccentricities ($e \leq 0.9$)** → Uses `solveKeplerNewtonRaphson()`.
33
+ * - **If Newton-Raphson fails**, falls back to `solveKeplerBisection()`.
34
+ *
35
+ * 3. **Final Wrapping:**
36
+ * - Ensures the solution is correctly wrapped using `wrapAngle()`.
37
+ *
38
+ * ---
39
+ *
40
+ * **Performance Considerations:**
41
+ * - **Newton-Raphson typically converges in 4-5 iterations.**
42
+ * - **Bisection fallback ensures robustness for extreme cases.**
43
+ * - **High-eccentricity solver prevents instability for $e \approx 1$.**
44
+ *
45
+ * ---
46
+ *
47
+ * @param {Radians} M - Mean anomaly ($M$) in **radians**.
48
+ * @param {number} e - Orbital eccentricity ($0 \leq e < 1$).
49
+ * @param {number} [maxIter=50] - Maximum number of **iterations** before fallback.
50
+ * @param {number} [tolerance=1e-9] - Convergence criterion for stopping the iteration.
51
+ * @returns {Radians} The **eccentric anomaly** ($E$) in **radians** (wrapped to $[0, 2\pi]$).
52
+ *
53
+ * @throws {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} If the **eccentricity ($e$) is invalid** ($e < 0$ or $e \geq 1$).
54
+ *
55
+ * ---
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * import { solveKepler } from './solve-kepler';
60
+ *
61
+ * // Example 1: Moderate eccentricity
62
+ * const M = Math.PI / 4; // 45 degrees in radians
63
+ * const e = 0.1; // Orbital eccentricity
64
+ * const result = solveKepler(M, e);
65
+ * console.log(result); // Output: Eccentric anomaly in radians
66
+ * ```
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * // Example 2: High-eccentricity orbit (e > 0.9)
71
+ * const M_high = 1.5; // Mean anomaly in radians
72
+ * const e_high = 0.95; // High eccentricity
73
+ * console.log(solveKepler(M_high, e_high)); // Uses high-eccentricity solver
74
+ * ```
75
+ *
76
+ * ---
77
+ *
78
+ * @see [Kepler's Equation (Wikipedia)](https://en.wikipedia.org/wiki/Kepler%27s_equation)
79
+ * @see [Newton-Raphson Method (Wikipedia)](https://en.wikipedia.org/wiki/Newton%27s_method)
80
+ * @see [Eccentric Anomaly (Wikipedia)](https://en.wikipedia.org/wiki/Mean_anomaly#Eccentric_anomaly)
81
+ * @see [RangeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError)
82
+ * @category Solve for Kepler
83
+ */
84
+ export const solveKepler = (M, e, maxIter = 50, tolerance = 1e-9) => {
85
+ if (e < 0 || e >= 1) {
86
+ throw new RangeError(`Invalid eccentricity: ${e}. Must be in range [0,1).`);
87
+ }
88
+ // **Use different solvers for high-eccentricity cases**
89
+ if (e > 0.9) {
90
+ return solveKeplerHighEccentricity(M, e, maxIter, tolerance);
91
+ }
92
+ // Use Newton-Raphson first; if it fails, fallback to bisection
93
+ let E = solveKeplerNewtonRaphson(M, e, maxIter, tolerance);
94
+ if (isNaN(E)) {
95
+ E = solveKeplerBisection(M, e, maxIter, tolerance);
96
+ }
97
+ return wrapAngle(E);
98
+ };
99
+ //# sourceMappingURL=solve-kepler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solve-kepler.js","sourceRoot":"","sources":["../src/solve-kepler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,CAAU,EACV,CAAS,EACT,OAAO,GAAG,EAAE,EACZ,SAAS,GAAG,IAAI,EACP,EAAE;IACX,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,UAAU,CAAC,yBAAyB,CAAC,2BAA2B,CAAC,CAAC;IAC9E,CAAC;IAED,wDAAwD;IACxD,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACZ,OAAO,2BAA2B,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IAED,+DAA+D;IAC/D,IAAI,CAAC,GAAG,wBAAwB,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAE3D,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACb,CAAC,GAAG,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Converts **true anomaly** ($\nu$) to **mean anomaly** ($M$) using Kepler's equation.
3
+ *
4
+ * ---
5
+ *
6
+ * **Mathematical Explanation:**
7
+ *
8
+ * In orbital mechanics, the **true anomaly** ($\nu$), the **eccentric anomaly** ($E$),
9
+ * and the **mean anomaly** ($M$) are related through Kepler's equation.
10
+ *
11
+ * **Step 1: Convert True Anomaly ($\nu$) to Eccentric Anomaly ($E$)**
12
+ * $$
13
+ * E = 2 \tan^{-1} \left( \sqrt{\frac{1 - e}{1 + e}} \tan\left(\frac{\nu}{2}\right) \right)
14
+ * $$
15
+ *
16
+ * This transformation ensures that $E$ is computed correctly **across all quadrants**,
17
+ * using `atan2(y, x)` instead of `atan(x)` to avoid ambiguity in angle computation.
18
+ *
19
+ * **Step 2: Convert Eccentric Anomaly ($E$) to Mean Anomaly ($M$)**
20
+ *
21
+ * Kepler’s equation states:
22
+ * $$
23
+ * M = E - e \sin(E)
24
+ * $$
25
+ *
26
+ * Since anomalies are periodic over **one full orbit** ($0 \leq M < 2\pi$),
27
+ * we apply `wrapAngle(M)` to ensure that the computed **mean anomaly remains within this range**.
28
+ *
29
+ * ---
30
+ *
31
+ * **Why Use `wrapAngle`?**
32
+ * - Ensures that the mean anomaly **is always wrapped within** $[0, 2\pi]$.
33
+ * - Corrects floating-point precision issues that may cause values slightly greater than $2\pi$.
34
+ * - Prevents negative anomalies by shifting them into the valid range.
35
+ *
36
+ * ---
37
+ *
38
+ * @param {number} V - **True anomaly** ($\nu$) in radians.
39
+ * @param {number} e - **Eccentricity** of the orbit ($0 \leq e < 1$).
40
+ *
41
+ * @returns {number} The **mean anomaly** ($M$) in radians, wrapped to the range $[0, 2\pi]$.
42
+ *
43
+ * @throws {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} If the **eccentricity** ($e$) is outside the valid range $0 \leq e < 1$.
44
+ *
45
+ * ---
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import { trueAnomalyToMeanAnomaly } from './true-anomaly-to-mean-anomaly';
50
+ *
51
+ * // Example 1: Standard elliptical orbit
52
+ * const V = Math.PI / 3; // 60 degrees in radians
53
+ * const e = 0.1; // Eccentricity
54
+ * console.log(trueAnomalyToMeanAnomaly(V, e)); // Output: Mean anomaly in radians
55
+ * ```
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * // Example 2: Retrograde motion handling
60
+ * const V_retrograde = -Math.PI / 2; // -90 degrees
61
+ * const e_retrograde = 0.2;
62
+ * console.log(trueAnomalyToMeanAnomaly(V_retrograde, e_retrograde));
63
+ * ```
64
+ *
65
+ * ---
66
+ *
67
+ * @see [Kepler's Equation (Wikipedia)](https://en.wikipedia.org/wiki/Kepler%27s_equation)
68
+ * @see [True Anomaly (Wikipedia)](https://en.wikipedia.org/wiki/True_anomaly)
69
+ * @see [Mean Anomaly (Wikipedia)](https://en.wikipedia.org/wiki/Mean_anomaly)
70
+ * @see [Orbital Eccentricity (Wikipedia)](https://en.wikipedia.org/wiki/Orbital_eccentricity)
71
+ * @category Anomaly
72
+ */
73
+ export declare const trueAnomalyToMeanAnomaly: (V: number, e: number) => number;
74
+ //# sourceMappingURL=true-anomaly-to-mean-anomaly.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"true-anomaly-to-mean-anomaly.d.ts","sourceRoot":"","sources":["../src/true-anomaly-to-mean-anomaly.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,eAAO,MAAM,wBAAwB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAuB/D,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { wrapAngle } from './wrap-angle';
2
+ /**
3
+ * Converts **true anomaly** ($\nu$) to **mean anomaly** ($M$) using Kepler's equation.
4
+ *
5
+ * ---
6
+ *
7
+ * **Mathematical Explanation:**
8
+ *
9
+ * In orbital mechanics, the **true anomaly** ($\nu$), the **eccentric anomaly** ($E$),
10
+ * and the **mean anomaly** ($M$) are related through Kepler's equation.
11
+ *
12
+ * **Step 1: Convert True Anomaly ($\nu$) to Eccentric Anomaly ($E$)**
13
+ * $$
14
+ * E = 2 \tan^{-1} \left( \sqrt{\frac{1 - e}{1 + e}} \tan\left(\frac{\nu}{2}\right) \right)
15
+ * $$
16
+ *
17
+ * This transformation ensures that $E$ is computed correctly **across all quadrants**,
18
+ * using `atan2(y, x)` instead of `atan(x)` to avoid ambiguity in angle computation.
19
+ *
20
+ * **Step 2: Convert Eccentric Anomaly ($E$) to Mean Anomaly ($M$)**
21
+ *
22
+ * Kepler’s equation states:
23
+ * $$
24
+ * M = E - e \sin(E)
25
+ * $$
26
+ *
27
+ * Since anomalies are periodic over **one full orbit** ($0 \leq M < 2\pi$),
28
+ * we apply `wrapAngle(M)` to ensure that the computed **mean anomaly remains within this range**.
29
+ *
30
+ * ---
31
+ *
32
+ * **Why Use `wrapAngle`?**
33
+ * - Ensures that the mean anomaly **is always wrapped within** $[0, 2\pi]$.
34
+ * - Corrects floating-point precision issues that may cause values slightly greater than $2\pi$.
35
+ * - Prevents negative anomalies by shifting them into the valid range.
36
+ *
37
+ * ---
38
+ *
39
+ * @param {number} V - **True anomaly** ($\nu$) in radians.
40
+ * @param {number} e - **Eccentricity** of the orbit ($0 \leq e < 1$).
41
+ *
42
+ * @returns {number} The **mean anomaly** ($M$) in radians, wrapped to the range $[0, 2\pi]$.
43
+ *
44
+ * @throws {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError | RangeError} If the **eccentricity** ($e$) is outside the valid range $0 \leq e < 1$.
45
+ *
46
+ * ---
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { trueAnomalyToMeanAnomaly } from './true-anomaly-to-mean-anomaly';
51
+ *
52
+ * // Example 1: Standard elliptical orbit
53
+ * const V = Math.PI / 3; // 60 degrees in radians
54
+ * const e = 0.1; // Eccentricity
55
+ * console.log(trueAnomalyToMeanAnomaly(V, e)); // Output: Mean anomaly in radians
56
+ * ```
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * // Example 2: Retrograde motion handling
61
+ * const V_retrograde = -Math.PI / 2; // -90 degrees
62
+ * const e_retrograde = 0.2;
63
+ * console.log(trueAnomalyToMeanAnomaly(V_retrograde, e_retrograde));
64
+ * ```
65
+ *
66
+ * ---
67
+ *
68
+ * @see [Kepler's Equation (Wikipedia)](https://en.wikipedia.org/wiki/Kepler%27s_equation)
69
+ * @see [True Anomaly (Wikipedia)](https://en.wikipedia.org/wiki/True_anomaly)
70
+ * @see [Mean Anomaly (Wikipedia)](https://en.wikipedia.org/wiki/Mean_anomaly)
71
+ * @see [Orbital Eccentricity (Wikipedia)](https://en.wikipedia.org/wiki/Orbital_eccentricity)
72
+ * @category Anomaly
73
+ */
74
+ export const trueAnomalyToMeanAnomaly = (V, e) => {
75
+ if (e < 0 || e >= 1) {
76
+ throw new RangeError('Eccentricity (e) must be in the range 0 ≤ e < 1 for elliptical orbits.');
77
+ }
78
+ // Compute Eccentric Anomaly (E) properly using atan2 for quadrant correctness
79
+ const tanHalfV = Math.tan(V / 2);
80
+ const factor = Math.sqrt((1 - e) / (1 + e));
81
+ let E = 2 * Math.atan2(tanHalfV * factor, 1);
82
+ // Ensure correct quadrant handling for retrograde motion
83
+ if (V < -Math.PI || V > Math.PI) {
84
+ E = wrapAngle(E + Math.PI) - Math.PI;
85
+ }
86
+ // Convert eccentric anomaly (E) to mean anomaly (M)
87
+ const M = E - e * Math.sin(E);
88
+ // Ensure M is always in the range [0, 2π]
89
+ return wrapAngle(M);
90
+ };
91
+ //# sourceMappingURL=true-anomaly-to-mean-anomaly.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"true-anomaly-to-mean-anomaly.js","sourceRoot":"","sources":["../src/true-anomaly-to-mean-anomaly.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE;IACvE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,UAAU,CAClB,wEAAwE,CACzE,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAE5C,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;IAE7C,yDAAyD;IACzD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QAChC,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;IACvC,CAAC;IAED,oDAAoD;IACpD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAE9B,0CAA0C;IAC1C,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Wrap an angle (in **radians**) to a **single-turn range** and snap values
3
+ * extremely close to **±τ** (±`2π`) back to **0** to curb floating-point drift.
4
+ *
5
+ * - Uses the JavaScript remainder operator to reduce the angle:
6
+ *
7
+ * $$
8
+ * r \;=\; \theta \bmod \tau,\quad \tau = 2\pi
9
+ * $$
10
+ *
11
+ * - Because JS remainders keep the **sign of the dividend**, after the reduction:
12
+ *
13
+ * $$
14
+ * r \in (-\tau,\;\tau)
15
+ * $$
16
+ *
17
+ * - If the reduced result is numerically indistinguishable from **±τ** within small
18
+ * tolerances, it returns **0**:
19
+ *
20
+ * $$
21
+ * \text{wrap}(\theta) =
22
+ * \begin{cases}
23
+ * 0, & |r - \tau| < \varepsilon \;\lor\; |r + \tau| < \varepsilon \\
24
+ * r, & \text{otherwise}
25
+ * \end{cases}
26
+ * $$
27
+ *
28
+ * where \( r = \theta \bmod \tau \) and \( \varepsilon \in \{\texttt{EPSILON}, \texttt{LARGE\_EPSILON}\} \).
29
+ *
30
+ * @param angle Input angle in **radians** (any real number).
31
+ * @returns Wrapped angle in **radians**, guaranteed to lie in **(-τ, τ)**,
32
+ * with values near **±τ** snapped to **0**.
33
+ *
34
+ * ::: info
35
+ *
36
+ *
37
+ * - This function **does not** force the common principal ranges **[0, τ)** or **(-π, π]**.
38
+ * It merely ensures the magnitude is **< τ** while preserving sign.
39
+ * If you need a principal value in **[0, τ)**, post-process via:
40
+ *
41
+ * ```ts
42
+ * const wrapToZeroTau = (θ: number) => {
43
+ * const r = wrapAngle(θ);
44
+ * return r < 0 ? r + TWO_PI : r;
45
+ * };
46
+ * ```
47
+ *
48
+ * For **(-π, π]**:
49
+ *
50
+ * ```ts
51
+ * const wrapToMinusPiPi = (θ: number) => {
52
+ * const r = wrapAngle(θ);
53
+ * return r > Math.PI ? r - TWO_PI : r;
54
+ * };
55
+ * ```
56
+ *
57
+ * - Very small values near **0** are **not** snapped to zero by this helper;
58
+ * only values near **±τ** are. If you also want to zero-out tiny magnitudes,
59
+ * apply your own deadband, e.g. `Math.abs(r) < 1e-12 ? 0 : r`.
60
+ *
61
+ * :::
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * // Basic reductions
66
+ * wrapAngle(3 * Math.PI); // → Math.PI
67
+ * wrapAngle(-3 * Math.PI); // → -Math.PI
68
+ *
69
+ * // Exact multiples of 2π snap to 0 (within tolerance)
70
+ * wrapAngle(2 * Math.PI); // → 0
71
+ * wrapAngle(-2 * Math.PI); // → 0
72
+ *
73
+ * // Preserve positive values under 2π
74
+ * wrapAngle(1.5 * Math.PI); // → 1.5π
75
+ *
76
+ * // Preserve negative values under 2π
77
+ * wrapAngle(-0.1); // → -0.1
78
+ * ```
79
+ * @category Angle
80
+ */
81
+ export declare const wrapAngle: (angle: number) => number;
82
+ //# sourceMappingURL=wrap-angle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-angle.d.ts","sourceRoot":"","sources":["../src/wrap-angle.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,WAgBtC,CAAC"}
@@ -0,0 +1,97 @@
1
+ import { TWO_PI } from '@interstellar-tools/constants';
2
+ const EPSILON = 1e-10; // Small threshold for floating-point drift
3
+ const LARGE_EPSILON = 1e-8; // Higher tolerance for large angles
4
+ /**
5
+ * Wrap an angle (in **radians**) to a **single-turn range** and snap values
6
+ * extremely close to **±τ** (±`2π`) back to **0** to curb floating-point drift.
7
+ *
8
+ * - Uses the JavaScript remainder operator to reduce the angle:
9
+ *
10
+ * $$
11
+ * r \;=\; \theta \bmod \tau,\quad \tau = 2\pi
12
+ * $$
13
+ *
14
+ * - Because JS remainders keep the **sign of the dividend**, after the reduction:
15
+ *
16
+ * $$
17
+ * r \in (-\tau,\;\tau)
18
+ * $$
19
+ *
20
+ * - If the reduced result is numerically indistinguishable from **±τ** within small
21
+ * tolerances, it returns **0**:
22
+ *
23
+ * $$
24
+ * \text{wrap}(\theta) =
25
+ * \begin{cases}
26
+ * 0, & |r - \tau| < \varepsilon \;\lor\; |r + \tau| < \varepsilon \\
27
+ * r, & \text{otherwise}
28
+ * \end{cases}
29
+ * $$
30
+ *
31
+ * where \( r = \theta \bmod \tau \) and \( \varepsilon \in \{\texttt{EPSILON}, \texttt{LARGE\_EPSILON}\} \).
32
+ *
33
+ * @param angle Input angle in **radians** (any real number).
34
+ * @returns Wrapped angle in **radians**, guaranteed to lie in **(-τ, τ)**,
35
+ * with values near **±τ** snapped to **0**.
36
+ *
37
+ * ::: info
38
+ *
39
+ *
40
+ * - This function **does not** force the common principal ranges **[0, τ)** or **(-π, π]**.
41
+ * It merely ensures the magnitude is **< τ** while preserving sign.
42
+ * If you need a principal value in **[0, τ)**, post-process via:
43
+ *
44
+ * ```ts
45
+ * const wrapToZeroTau = (θ: number) => {
46
+ * const r = wrapAngle(θ);
47
+ * return r < 0 ? r + TWO_PI : r;
48
+ * };
49
+ * ```
50
+ *
51
+ * For **(-π, π]**:
52
+ *
53
+ * ```ts
54
+ * const wrapToMinusPiPi = (θ: number) => {
55
+ * const r = wrapAngle(θ);
56
+ * return r > Math.PI ? r - TWO_PI : r;
57
+ * };
58
+ * ```
59
+ *
60
+ * - Very small values near **0** are **not** snapped to zero by this helper;
61
+ * only values near **±τ** are. If you also want to zero-out tiny magnitudes,
62
+ * apply your own deadband, e.g. `Math.abs(r) < 1e-12 ? 0 : r`.
63
+ *
64
+ * :::
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * // Basic reductions
69
+ * wrapAngle(3 * Math.PI); // → Math.PI
70
+ * wrapAngle(-3 * Math.PI); // → -Math.PI
71
+ *
72
+ * // Exact multiples of 2π snap to 0 (within tolerance)
73
+ * wrapAngle(2 * Math.PI); // → 0
74
+ * wrapAngle(-2 * Math.PI); // → 0
75
+ *
76
+ * // Preserve positive values under 2π
77
+ * wrapAngle(1.5 * Math.PI); // → 1.5π
78
+ *
79
+ * // Preserve negative values under 2π
80
+ * wrapAngle(-0.1); // → -0.1
81
+ * ```
82
+ * @category Angle
83
+ */
84
+ export const wrapAngle = (angle) => {
85
+ // Reduce angle while preserving sign
86
+ angle = angle % TWO_PI;
87
+ // Handle floating-point precision at ±2π
88
+ if (Math.abs(angle - TWO_PI) < EPSILON)
89
+ return 0;
90
+ if (Math.abs(angle + TWO_PI) < EPSILON)
91
+ return 0;
92
+ if (Math.abs(angle - TWO_PI) < LARGE_EPSILON ||
93
+ Math.abs(angle + TWO_PI) < LARGE_EPSILON)
94
+ return 0;
95
+ return angle;
96
+ };
97
+ //# sourceMappingURL=wrap-angle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-angle.js","sourceRoot":"","sources":["../src/wrap-angle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAEvD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,2CAA2C;AAClE,MAAM,aAAa,GAAG,IAAI,CAAC,CAAC,oCAAoC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE;IACzC,qCAAqC;IACrC,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAEvB,yCAAyC;IACzC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,OAAO;QAAE,OAAO,CAAC,CAAC;IAEjD,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,OAAO;QAAE,OAAO,CAAC,CAAC;IAEjD,IACE,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,aAAa;QACxC,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,aAAa;QAExC,OAAO,CAAC,CAAC;IAEX,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}