@interstellar-tools/equations 0.9.0 → 0.10.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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hohmann-transfer.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hohmann-transfer.spec.d.ts","sourceRoot":"","sources":["../../src/__tests__/hohmann-transfer.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,101 @@
1
+ import assert from 'node:assert/strict';
2
+ import test, { describe } from 'node:test';
3
+ import { hohmannSemiMajorAxis, hohmannTransfer, hohmannTransferTime } from '../categories/manoeuvres/hohmann-transfer';
4
+ import { absClose, relClose } from './helpers';
5
+ describe('hohmannTransfer', () => {
6
+ test('semi-major axis: at = (r1 + r2) / 2', () => {
7
+ const r1 = 7000e3;
8
+ const r2 = 42164e3;
9
+ const at = hohmannSemiMajorAxis(r1, r2);
10
+ absClose(at, 0.5 * (r1 + r2));
11
+ });
12
+ test('transfer time: t = π sqrt(at^3 / μ)', () => {
13
+ const mu = 3.986004418e14; // Earth μ (m^3/s^2)
14
+ const r1 = 7000e3;
15
+ const r2 = 42164e3;
16
+ const at = 0.5 * (r1 + r2);
17
+ const expected = Math.PI * Math.sqrt((at * at * at) / mu);
18
+ const t = hohmannTransferTime(r1, r2, mu);
19
+ relClose(t, expected, 1e-12);
20
+ });
21
+ test('raise orbit (r2 > r1): dv1,dv2 magnitudes & directions (prograde, prograde)', () => {
22
+ const mu = 3.986004418e14; // Earth μ
23
+ const r1 = 7000e3;
24
+ const r2 = 12000e3;
25
+ const res = hohmannTransfer(r1, r2, mu);
26
+ // Expected magnitudes from textbook formulas
27
+ const at = 0.5 * (r1 + r2);
28
+ const dv1Exp = Math.sqrt(mu / r1) * (Math.sqrt((2 * r2) / (r1 + r2)) - 1);
29
+ const dv2Exp = Math.sqrt(mu / r2) * (1 - Math.sqrt((2 * r1) / (r1 + r2)));
30
+ assert.ok(res.dv1 >= 0 && res.dv2 >= 0, 'Δv magnitudes must be non-negative');
31
+ relClose(res.at, at);
32
+ relClose(res.dv1, dv1Exp, 1e-12);
33
+ relClose(res.dv2, dv2Exp, 1e-12);
34
+ relClose(res.dvTotal, res.dv1 + res.dv2, 1e-12);
35
+ assert.equal(res.dir1, 'prograde');
36
+ assert.equal(res.dir2, 'prograde');
37
+ // Transfer time check
38
+ const tExp = Math.PI * Math.sqrt((at * at * at) / mu);
39
+ relClose(res.tTransfer, tExp, 1e-12);
40
+ });
41
+ test('lower orbit (r2 < r1): dv1,dv2 magnitudes & directions (retrograde, retrograde)', () => {
42
+ const mu = 3.986004418e14;
43
+ const r1 = 12000e3;
44
+ const r2 = 7000e3;
45
+ const res = hohmannTransfer(r1, r2, mu);
46
+ const at = 0.5 * (r1 + r2);
47
+ const dv1Exp = Math.sqrt(mu / r1) * (Math.sqrt((2 * r2) / (r1 + r2)) - 1);
48
+ const dv2Exp = Math.sqrt(mu / r2) * (1 - Math.sqrt((2 * r1) / (r1 + r2)));
49
+ // Magnitudes compare against absolute values of textbook (which are negative here)
50
+ relClose(res.at, at);
51
+ relClose(res.dv1, Math.abs(dv1Exp), 1e-12);
52
+ relClose(res.dv2, Math.abs(dv2Exp), 1e-12);
53
+ relClose(res.dvTotal, res.dv1 + res.dv2, 1e-12);
54
+ assert.equal(res.dir1, 'retrograde');
55
+ assert.equal(res.dir2, 'retrograde');
56
+ const tExp = Math.PI * Math.sqrt((at * at * at) / mu);
57
+ relClose(res.tTransfer, tExp, 1e-12);
58
+ });
59
+ test('symmetry: total Δv is same for r1→r2 and r2→r1', () => {
60
+ const mu = 3.986004418e14;
61
+ const r1 = 9000e3;
62
+ const r2 = 14000e3;
63
+ const up = hohmannTransfer(r1, r2, mu);
64
+ const down = hohmannTransfer(r2, r1, mu);
65
+ relClose(up.dvTotal, down.dvTotal, 1e-12);
66
+ });
67
+ test('degenerate: r1 == r2 → dv1=dv2=0, t = half circular period', () => {
68
+ const mu = 3.986004418e14;
69
+ const r = 7000e3;
70
+ const res = hohmannTransfer(r, r, mu);
71
+ absClose(res.dv1, 0, 1e-12);
72
+ absClose(res.dv2, 0, 1e-12);
73
+ absClose(res.dvTotal, 0, 1e-12);
74
+ assert.equal(res.dir1, 'none');
75
+ assert.equal(res.dir2, 'none');
76
+ const T_circ = 2 * Math.PI * Math.sqrt((r * r * r) / mu);
77
+ const half = 0.5 * T_circ;
78
+ relClose(res.tTransfer, half, 1e-12);
79
+ });
80
+ test('input validation: type and range errors', () => {
81
+ const mu = 3.986004418e14;
82
+ // TypeError: non-number inputs
83
+ assert.throws(() => hohmannTransfer('x', 7000e3, mu), TypeError);
84
+ assert.throws(() => hohmannTransfer(7000e3, 'y', mu), TypeError);
85
+ assert.throws(() => hohmannTransfer(7000e3, 8000e3, 'z'), TypeError);
86
+ // RangeError: non-finite / non-positive
87
+ assert.throws(() => hohmannTransfer(NaN, 8000e3, mu), RangeError);
88
+ assert.throws(() => hohmannTransfer(7000e3, Infinity, mu), RangeError);
89
+ assert.throws(() => hohmannTransfer(7000e3, 8000e3, 0), RangeError);
90
+ assert.throws(() => hohmannTransfer(-1, 8000e3, mu), RangeError);
91
+ assert.throws(() => hohmannTransfer(7000e3, -1, mu), RangeError);
92
+ // Semi-major axis helper
93
+ assert.throws(() => hohmannSemiMajorAxis('a', 1), TypeError);
94
+ assert.throws(() => hohmannSemiMajorAxis(1, NaN), RangeError);
95
+ assert.throws(() => hohmannSemiMajorAxis(0, 1), RangeError);
96
+ // Transfer time helper
97
+ assert.throws(() => hohmannTransferTime(1, 1, 0), RangeError);
98
+ assert.throws(() => hohmannTransferTime(1, 1, 'mu'), TypeError);
99
+ });
100
+ });
101
+ //# sourceMappingURL=hohmann-transfer.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hohmann-transfer.spec.js","sourceRoot":"","sources":["../../src/__tests__/hohmann-transfer.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ export type HohmannTransferReturnType = {
2
+ at: number;
3
+ dv1: number;
4
+ dv2: number;
5
+ dvTotal: number;
6
+ tTransfer: number;
7
+ dir1: 'prograde' | 'retrograde' | 'none';
8
+ dir2: 'prograde' | 'retrograde' | 'none';
9
+ };
10
+ /**
11
+ * **Hohmann transfer** (coplanar, circular ($ r_1 \to r_2 $)).
12
+ *
13
+ * **Definitions**
14
+ *
15
+ * $$
16
+ * a_t=\frac{r_1+r_2}{2}
17
+ * $$
18
+ * $$
19
+ * \Delta v_1=\sqrt{\frac{\mu}{r_1}}\!\left(\sqrt{\frac{2r_2}{r_1+r_2}}-1\right),\qquad
20
+ * \Delta v_2=\sqrt{\frac{\mu}{r_2}}\!\left(1-\sqrt{\frac{2r_1}{r_1+r_2}}\right)
21
+ * $$
22
+ * $$
23
+ * \Delta v_{\text{total}}=\Delta v_1+\Delta v_2,\qquad
24
+ * t_t=\pi \sqrt{\frac{a_t^3}{\mu}}
25
+ * $$
26
+ *
27
+ * **Conventions**
28
+ * - Inputs in **SI**: ($ r_1,r_2 $) in **meters**, ($ \mu $) in **m³/s²**.
29
+ * - The returned ($ \Delta v_1,\Delta v_2 $) are **magnitudes** (non-negative).
30
+ * Their **signs** (prograde/retrograde) are provided separately for clarity.
31
+ * - Works for ($ r_2>r_1 $) (raise) and ($ r_2<r_1 $) (lower). If ($ r_1=r_2 $): ($ \Delta v $)s are 0 and ($ t_t $) is half the circular period.
32
+ *
33
+ * **Domain**
34
+ * - ($ r_1>0,\ r_2>0,\ \mu>0 $)
35
+ *
36
+ * @param {number} r1 Initial circular-orbit radius (m).
37
+ * @param {number} r2 Target circular-orbit radius (m).
38
+ * @param {number} mu Standard gravitational parameter ($ \mu $) (m³/s²).
39
+ * @returns {HohmannTransferReturnType}
40
+ * Object with transfer semi-major axis `at` (m), burn magnitudes `dv1`, `dv2`, their sum `dvTotal` (m/s), transfer time `tTransfer` (s),
41
+ * and burn directions `dir1`, `dir2`.
42
+ *
43
+ * @throws {TypeError} If an input is not a number.
44
+ * @throws {RangeError} If ($ r_1\le 0 $), ($ r_2\le 0 $), or ($ \mu\le 0 $), or a value is non-finite.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * // No code example here by request; see package docs for usage.
49
+ * ```
50
+ *
51
+ * @group Manoeuvres
52
+ */
53
+ export declare const hohmannTransfer: (r1: number, r2: number, mu: number) => HohmannTransferReturnType;
54
+ /**
55
+ * Convenience: compute only the **semi-major axis** ($ a_t $) (m) of the Hohmann transfer.
56
+ *
57
+ * $$ a_t=\frac{r_1+r_2}{2} $$
58
+ *
59
+ * @param {number} r1 Initial circular-orbit radius (m).
60
+ * @param {number} r2 Target circular-orbit radius (m).
61
+ * @returns {number} ($ a_t $) (m).
62
+ * @throws {TypeError|RangeError} On invalid inputs.
63
+ * @group Manoeuvres
64
+ */
65
+ export declare const hohmannSemiMajorAxis: (r1: number, r2: number) => number;
66
+ /**
67
+ * Convenience: compute only the **transfer time** ($ t_t $) (s).
68
+ *
69
+ * $$ t_t=\pi \sqrt{\frac{a_t^3}{\mu}} $$
70
+ *
71
+ * @param {number} r1 Initial radius (m).
72
+ * @param {number} r2 Target radius (m).
73
+ * @param {number} mu Gravitational parameter (m³/s²).
74
+ * @returns {number} Transfer time ($ t_t $) (s).
75
+ * @throws {TypeError|RangeError} On invalid inputs.
76
+ * @group Manoeuvres
77
+ */
78
+ export declare const hohmannTransferTime: (r1: number, r2: number, mu: number) => number;
79
+ //# sourceMappingURL=hohmann-transfer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hohmann-transfer.d.ts","sourceRoot":"","sources":["../../../src/categories/manoeuvres/hohmann-transfer.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GAAG;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IACzC,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;CAC1C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,eAAO,MAAM,eAAe,GAC1B,IAAI,MAAM,EACV,IAAI,MAAM,EACV,IAAI,MAAM,KACT,yBAkDF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,GAAI,IAAI,MAAM,EAAE,IAAI,MAAM,KAAG,MAU7D,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,GAC9B,IAAI,MAAM,EACV,IAAI,MAAM,EACV,IAAI,MAAM,KACT,MASF,CAAC"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * **Hohmann transfer** (coplanar, circular ($ r_1 \to r_2 $)).
3
+ *
4
+ * **Definitions**
5
+ *
6
+ * $$
7
+ * a_t=\frac{r_1+r_2}{2}
8
+ * $$
9
+ * $$
10
+ * \Delta v_1=\sqrt{\frac{\mu}{r_1}}\!\left(\sqrt{\frac{2r_2}{r_1+r_2}}-1\right),\qquad
11
+ * \Delta v_2=\sqrt{\frac{\mu}{r_2}}\!\left(1-\sqrt{\frac{2r_1}{r_1+r_2}}\right)
12
+ * $$
13
+ * $$
14
+ * \Delta v_{\text{total}}=\Delta v_1+\Delta v_2,\qquad
15
+ * t_t=\pi \sqrt{\frac{a_t^3}{\mu}}
16
+ * $$
17
+ *
18
+ * **Conventions**
19
+ * - Inputs in **SI**: ($ r_1,r_2 $) in **meters**, ($ \mu $) in **m³/s²**.
20
+ * - The returned ($ \Delta v_1,\Delta v_2 $) are **magnitudes** (non-negative).
21
+ * Their **signs** (prograde/retrograde) are provided separately for clarity.
22
+ * - Works for ($ r_2>r_1 $) (raise) and ($ r_2<r_1 $) (lower). If ($ r_1=r_2 $): ($ \Delta v $)s are 0 and ($ t_t $) is half the circular period.
23
+ *
24
+ * **Domain**
25
+ * - ($ r_1>0,\ r_2>0,\ \mu>0 $)
26
+ *
27
+ * @param {number} r1 Initial circular-orbit radius (m).
28
+ * @param {number} r2 Target circular-orbit radius (m).
29
+ * @param {number} mu Standard gravitational parameter ($ \mu $) (m³/s²).
30
+ * @returns {HohmannTransferReturnType}
31
+ * Object with transfer semi-major axis `at` (m), burn magnitudes `dv1`, `dv2`, their sum `dvTotal` (m/s), transfer time `tTransfer` (s),
32
+ * and burn directions `dir1`, `dir2`.
33
+ *
34
+ * @throws {TypeError} If an input is not a number.
35
+ * @throws {RangeError} If ($ r_1\le 0 $), ($ r_2\le 0 $), or ($ \mu\le 0 $), or a value is non-finite.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * // No code example here by request; see package docs for usage.
40
+ * ```
41
+ *
42
+ * @group Manoeuvres
43
+ */
44
+ export const hohmannTransfer = (r1, r2, mu) => {
45
+ // Type & range checks
46
+ if (typeof r1 !== 'number' ||
47
+ typeof r2 !== 'number' ||
48
+ typeof mu !== 'number') {
49
+ throw new TypeError('r1, r2, and mu must be numbers.');
50
+ }
51
+ if (!Number.isFinite(r1) || !Number.isFinite(r2) || !Number.isFinite(mu)) {
52
+ throw new RangeError('r1, r2, and mu must be finite.');
53
+ }
54
+ if (r1 <= 0 || r2 <= 0 || mu <= 0) {
55
+ throw new RangeError('r1 and r2 must be > 0 (m), mu must be > 0 (m^3/s^2).');
56
+ }
57
+ const at = 0.5 * (r1 + r2);
58
+ // Circular speeds at the endpoints
59
+ const v1c = Math.sqrt(mu / r1);
60
+ const v2c = Math.sqrt(mu / r2);
61
+ // Transfer-ellipse speeds at peri/apo
62
+ const vPeriTrans = Math.sqrt(mu * (2 / r1 - 1 / at)); // speed at r1 on transfer
63
+ const vApoTrans = Math.sqrt(mu * (2 / r2 - 1 / at)); // speed at r2 on transfer
64
+ // Signed burns relative to local circular velocity direction.
65
+ // Positive => prograde (speed up), negative => retrograde (slow down).
66
+ const signedDv1 = vPeriTrans - v1c;
67
+ const signedDv2 = v2c - vApoTrans;
68
+ const dv1 = Math.abs(signedDv1);
69
+ const dv2 = Math.abs(signedDv2);
70
+ const dvTotal = dv1 + dv2;
71
+ const dir1 = Math.abs(signedDv1) < 1e-15
72
+ ? 'none'
73
+ : signedDv1 > 0
74
+ ? 'prograde'
75
+ : 'retrograde';
76
+ const dir2 = Math.abs(signedDv2) < 1e-15
77
+ ? 'none'
78
+ : signedDv2 > 0
79
+ ? 'prograde'
80
+ : 'retrograde';
81
+ // Half the period of the transfer ellipse
82
+ const tTransfer = Math.PI * Math.sqrt((at * at * at) / mu);
83
+ return { at, dv1, dv2, dvTotal, tTransfer, dir1, dir2 };
84
+ };
85
+ /**
86
+ * Convenience: compute only the **semi-major axis** ($ a_t $) (m) of the Hohmann transfer.
87
+ *
88
+ * $$ a_t=\frac{r_1+r_2}{2} $$
89
+ *
90
+ * @param {number} r1 Initial circular-orbit radius (m).
91
+ * @param {number} r2 Target circular-orbit radius (m).
92
+ * @returns {number} ($ a_t $) (m).
93
+ * @throws {TypeError|RangeError} On invalid inputs.
94
+ * @group Manoeuvres
95
+ */
96
+ export const hohmannSemiMajorAxis = (r1, r2) => {
97
+ if (typeof r1 !== 'number' || typeof r2 !== 'number')
98
+ throw new TypeError('r1 and r2 must be numbers.');
99
+ if (!Number.isFinite(r1) || !Number.isFinite(r2))
100
+ throw new RangeError('r1 and r2 must be finite.');
101
+ if (r1 <= 0 || r2 <= 0)
102
+ throw new RangeError('r1 and r2 must be > 0 (m).');
103
+ return 0.5 * (r1 + r2);
104
+ };
105
+ /**
106
+ * Convenience: compute only the **transfer time** ($ t_t $) (s).
107
+ *
108
+ * $$ t_t=\pi \sqrt{\frac{a_t^3}{\mu}} $$
109
+ *
110
+ * @param {number} r1 Initial radius (m).
111
+ * @param {number} r2 Target radius (m).
112
+ * @param {number} mu Gravitational parameter (m³/s²).
113
+ * @returns {number} Transfer time ($ t_t $) (s).
114
+ * @throws {TypeError|RangeError} On invalid inputs.
115
+ * @group Manoeuvres
116
+ */
117
+ export const hohmannTransferTime = (r1, r2, mu) => {
118
+ const at = hohmannSemiMajorAxis(r1, r2);
119
+ if (typeof mu !== 'number')
120
+ throw new TypeError('mu must be a number.');
121
+ if (!Number.isFinite(mu) || mu <= 0)
122
+ throw new RangeError('mu must be finite and > 0 (m^3/s^2).');
123
+ return Math.PI * Math.sqrt((at * at * at) / mu);
124
+ };
125
+ //# sourceMappingURL=hohmann-transfer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hohmann-transfer.js","sourceRoot":"","sources":["../../../src/categories/manoeuvres/hohmann-transfer.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -24,4 +24,5 @@ export * from './categories/orbits/specific-angular-momentum';
24
24
  export * from './categories/orbits/specific-angular-momentum-from-elements';
25
25
  export * from './categories/orbits/specific-mechanical-energy';
26
26
  export * from './categories/orbits/flight-path-angle-from-true-anomaly';
27
+ export * from './categories/manoeuvres/hohmann-transfer';
27
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,kCAAkC,CAAC;AAEjD,cAAc,+BAA+B,CAAC;AAG9C,cAAc,kDAAkD,CAAC;AAEjE,cAAc,kDAAkD,CAAC;AAEjE,cAAc,6CAA6C,CAAC;AAG5D,cAAc,kCAAkC,CAAC;AAEjD,cAAc,iDAAiD,CAAC;AAEhE,cAAc,4CAA4C,CAAC;AAE3D,cAAc,oDAAoD,CAAC;AAGnE,cAAc,8CAA8C,CAAC;AAE7D,cAAc,0CAA0C,CAAC;AAEzD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,2CAA2C,CAAC;AAG1D,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,kCAAkC,CAAC;AAEjD,cAAc,mCAAmC,CAAC;AAElD,cAAc,+CAA+C,CAAC;AAE9D,cAAc,6DAA6D,CAAC;AAE5E,cAAc,gDAAgD,CAAC;AAE/D,cAAc,yDAAyD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,kCAAkC,CAAC;AAEjD,cAAc,+BAA+B,CAAC;AAG9C,cAAc,kDAAkD,CAAC;AAEjE,cAAc,kDAAkD,CAAC;AAEjE,cAAc,6CAA6C,CAAC;AAG5D,cAAc,kCAAkC,CAAC;AAEjD,cAAc,iDAAiD,CAAC;AAEhE,cAAc,4CAA4C,CAAC;AAE3D,cAAc,oDAAoD,CAAC;AAGnE,cAAc,8CAA8C,CAAC;AAE7D,cAAc,0CAA0C,CAAC;AAEzD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,2CAA2C,CAAC;AAG1D,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,kCAAkC,CAAC;AAEjD,cAAc,mCAAmC,CAAC;AAElD,cAAc,+CAA+C,CAAC;AAE9D,cAAc,6DAA6D,CAAC;AAE5E,cAAc,gDAAgD,CAAC;AAE/D,cAAc,yDAAyD,CAAC;AAIxE,cAAc,0CAA0C,CAAC"}
package/dist/index.js CHANGED
@@ -29,4 +29,6 @@ export * from './categories/orbits/specific-angular-momentum';
29
29
  export * from './categories/orbits/specific-angular-momentum-from-elements';
30
30
  export * from './categories/orbits/specific-mechanical-energy';
31
31
  export * from './categories/orbits/flight-path-angle-from-true-anomaly';
32
+ // categories/manoeuvres
33
+ export * from './categories/manoeuvres/hohmann-transfer';
32
34
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,mBAAmB;AACnB,cAAc,kCAAkC,CAAC;AAEjD,cAAc,+BAA+B,CAAC;AAE9C,uBAAuB;AACvB,cAAc,kDAAkD,CAAC;AAEjE,cAAc,kDAAkD,CAAC;AAEjE,cAAc,6CAA6C,CAAC;AAE5D,8BAA8B;AAC9B,cAAc,kCAAkC,CAAC;AAEjD,cAAc,iDAAiD,CAAC;AAEhE,cAAc,4CAA4C,CAAC;AAE3D,cAAc,oDAAoD,CAAC;AAEnE,qBAAqB;AACrB,cAAc,8CAA8C,CAAC;AAE7D,cAAc,0CAA0C,CAAC;AAEzD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,2CAA2C,CAAC;AAE1D,oBAAoB;AACpB,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,kCAAkC,CAAC;AAEjD,cAAc,mCAAmC,CAAC;AAElD,cAAc,+CAA+C,CAAC;AAE9D,cAAc,6DAA6D,CAAC;AAE5E,cAAc,gDAAgD,CAAC;AAE/D,cAAc,yDAAyD,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,mBAAmB;AACnB,cAAc,kCAAkC,CAAC;AAEjD,cAAc,+BAA+B,CAAC;AAE9C,uBAAuB;AACvB,cAAc,kDAAkD,CAAC;AAEjE,cAAc,kDAAkD,CAAC;AAEjE,cAAc,6CAA6C,CAAC;AAE5D,8BAA8B;AAC9B,cAAc,kCAAkC,CAAC;AAEjD,cAAc,iDAAiD,CAAC;AAEhE,cAAc,4CAA4C,CAAC;AAE3D,cAAc,oDAAoD,CAAC;AAEnE,qBAAqB;AACrB,cAAc,8CAA8C,CAAC;AAE7D,cAAc,0CAA0C,CAAC;AAEzD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,2CAA2C,CAAC;AAE1D,oBAAoB;AACpB,cAAc,oCAAoC,CAAC;AAEnD,cAAc,oCAAoC,CAAC;AAEnD,cAAc,kCAAkC,CAAC;AAEjD,cAAc,mCAAmC,CAAC;AAElD,cAAc,+CAA+C,CAAC;AAE9D,cAAc,6DAA6D,CAAC;AAE5E,cAAc,gDAAgD,CAAC;AAE/D,cAAc,yDAAyD,CAAC;AAExE,wBAAwB;AAExB,cAAc,0CAA0C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interstellar-tools/equations",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Curated, well-tested orbital mechanics and dynamics formulas (e.g., Newtonian gravity, vis-viva, Kepler's 3rd law, escape/circular speeds, specific energy, specific angular momentum, peri/apoapsis radii).",
5
5
  "keywords": [
6
6
  "interstellar",