@johnmorrisdotca/uchusen-rockets 0.19.1 → 0.20.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.
- package/CHANGELOG.md +12 -0
- package/LICENSES/Orbiter-MIT.txt +21 -0
- package/NOTICE.md +37 -1
- package/README.md +13 -6
- package/dist/assets/falcon-heavy-test-flight-apart.painted.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-apart.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-apart.thick.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-car.glb +0 -0
- package/dist/assets/falcon-heavy-test-flight-car.painted.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-car.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-car.thick.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-centre.glb +0 -0
- package/dist/assets/falcon-heavy-test-flight-centre.painted.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-centre.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-centre.thick.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-side-left.glb +0 -0
- package/dist/assets/falcon-heavy-test-flight-side-left.painted.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-side-left.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-side-left.thick.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-side-right.glb +0 -0
- package/dist/assets/falcon-heavy-test-flight-side-right.painted.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-side-right.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-side-right.thick.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-starman.glb +0 -0
- package/dist/assets/falcon-heavy-test-flight-starman.painted.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-starman.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight-starman.thick.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight.glb +0 -0
- package/dist/assets/falcon-heavy-test-flight.painted.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight.svg +1 -0
- package/dist/assets/falcon-heavy-test-flight.thick.svg +1 -0
- package/dist/assets/models/roadster-first-generation-car.glb +0 -0
- package/dist/assets/models/roadster-second-generation-2-car.glb +0 -0
- package/dist/assets/models/roadster-second-generation-car.glb +0 -0
- package/dist/assets/roadster-first-generation-apart.painted.svg +1 -0
- package/dist/assets/roadster-first-generation-apart.svg +1 -0
- package/dist/assets/roadster-first-generation-apart.thick.svg +1 -0
- package/dist/assets/roadster-first-generation-car.glb +0 -0
- package/dist/assets/roadster-first-generation-car.painted.svg +1 -0
- package/dist/assets/roadster-first-generation-car.svg +1 -0
- package/dist/assets/roadster-first-generation-car.thick.svg +1 -0
- package/dist/assets/roadster-first-generation-starman.glb +0 -0
- package/dist/assets/roadster-first-generation-starman.painted.svg +1 -0
- package/dist/assets/roadster-first-generation-starman.svg +1 -0
- package/dist/assets/roadster-first-generation-starman.thick.svg +1 -0
- package/dist/assets/roadster-first-generation.glb +0 -0
- package/dist/assets/roadster-first-generation.painted.svg +1 -0
- package/dist/assets/roadster-first-generation.svg +1 -0
- package/dist/assets/roadster-first-generation.thick.svg +1 -0
- package/dist/assets/roadster-second-generation-2-apart.painted.svg +1 -0
- package/dist/assets/roadster-second-generation-2-apart.svg +1 -0
- package/dist/assets/roadster-second-generation-2-apart.thick.svg +1 -0
- package/dist/assets/roadster-second-generation-2-car.glb +0 -0
- package/dist/assets/roadster-second-generation-2-car.painted.svg +1 -0
- package/dist/assets/roadster-second-generation-2-car.svg +1 -0
- package/dist/assets/roadster-second-generation-2-car.thick.svg +1 -0
- package/dist/assets/roadster-second-generation-2-starman.glb +0 -0
- package/dist/assets/roadster-second-generation-2-starman.painted.svg +1 -0
- package/dist/assets/roadster-second-generation-2-starman.svg +1 -0
- package/dist/assets/roadster-second-generation-2-starman.thick.svg +1 -0
- package/dist/assets/roadster-second-generation-2.glb +0 -0
- package/dist/assets/roadster-second-generation-2.painted.svg +1 -0
- package/dist/assets/roadster-second-generation-2.svg +1 -0
- package/dist/assets/roadster-second-generation-2.thick.svg +1 -0
- package/dist/assets/roadster-second-generation-apart.painted.svg +1 -0
- package/dist/assets/roadster-second-generation-apart.svg +1 -0
- package/dist/assets/roadster-second-generation-apart.thick.svg +1 -0
- package/dist/assets/roadster-second-generation-car.glb +0 -0
- package/dist/assets/roadster-second-generation-car.painted.svg +1 -0
- package/dist/assets/roadster-second-generation-car.svg +1 -0
- package/dist/assets/roadster-second-generation-car.thick.svg +1 -0
- package/dist/assets/roadster-second-generation-starman.glb +0 -0
- package/dist/assets/roadster-second-generation-starman.painted.svg +1 -0
- package/dist/assets/roadster-second-generation-starman.svg +1 -0
- package/dist/assets/roadster-second-generation-starman.thick.svg +1 -0
- package/dist/assets/roadster-second-generation.glb +0 -0
- package/dist/assets/roadster-second-generation.painted.svg +1 -0
- package/dist/assets/roadster-second-generation.svg +1 -0
- package/dist/assets/roadster-second-generation.thick.svg +1 -0
- package/dist/data/countries.d.ts +51 -0
- package/dist/data/countries.js +91 -0
- package/dist/data/credits.d.ts +36 -0
- package/dist/data/credits.js +36 -0
- package/dist/data/falcon.js +26 -14
- package/dist/data/makers.js +1 -0
- package/dist/data/roadster.d.ts +13 -0
- package/dist/data/roadster.js +73 -0
- package/dist/data/sources.d.ts +56 -0
- package/dist/data/sources.js +7 -0
- package/dist/element/flag.d.ts +30 -0
- package/dist/element/flag.js +23 -0
- package/dist/element/scene.d.ts +7 -0
- package/dist/element/scene.js +35 -1
- package/dist/element.d.ts +5 -0
- package/dist/element.js +58 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/inspace.js +1 -0
- package/dist/model/registry.js +6 -4
- package/dist/model/roadster.d.ts +31 -0
- package/dist/model/roadster.js +112 -0
- package/dist/parts.d.ts +1 -1
- package/dist/physics/atmosphere.d.ts +182 -0
- package/dist/physics/atmosphere.js +246 -0
- package/dist/physics/attitude.d.ts +342 -0
- package/dist/physics/attitude.js +351 -0
- package/dist/physics/burns.d.ts +194 -0
- package/dist/physics/burns.js +157 -0
- package/dist/physics/elements.d.ts +133 -0
- package/dist/physics/elements.js +239 -0
- package/dist/physics/gravity.d.ts +53 -0
- package/dist/physics/gravity.js +78 -0
- package/dist/physics/index.d.ts +17 -0
- package/dist/physics/index.js +8 -0
- package/dist/physics/propagate.d.ts +110 -0
- package/dist/physics/propagate.js +122 -0
- package/dist/physics/rocket.d.ts +105 -0
- package/dist/physics/rocket.js +102 -0
- package/dist/physics/transfers.d.ts +128 -0
- package/dist/physics/transfers.js +155 -0
- package/dist/physics/vector.d.ts +20 -0
- package/dist/physics/vector.js +9 -0
- package/dist/react.d.ts +1 -1
- package/dist/rockets.d.ts +5 -0
- package/dist/rockets.js +9 -4
- package/dist/sun.d.ts +13 -0
- package/dist/sun.js +25 -0
- package/package.json +11 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type { Vec3 } from "./vector.ts";
|
|
2
|
+
export { eccentricAnomaly, elementsOf, stateAtTrueAnomaly, stateOf, timeToTrueAnomaly } from "./elements.ts";
|
|
3
|
+
export type { Elements, StateVector } from "./elements.ts";
|
|
4
|
+
export { gravityAt } from "./gravity.ts";
|
|
5
|
+
export type { GravityBody, Zonal } from "./gravity.ts";
|
|
6
|
+
export { path, propagate, step } from "./propagate.ts";
|
|
7
|
+
export type { Acceleration, Method, PropagateOptions, State } from "./propagate.ts";
|
|
8
|
+
export { burnSeconds, deltaV, exhaustSpeedOf, massAfter, massFlow, thrustAt } from "./rocket.ts";
|
|
9
|
+
export type { Engine } from "./rocket.ts";
|
|
10
|
+
export { burnStart, directionOf, flyBurn, flyPlan, impulse } from "./burns.ts";
|
|
11
|
+
export type { Burn, BurnResult, Centre, Direction, FlyOptions, PlannedBurn } from "./burns.ts";
|
|
12
|
+
export { biElliptic, crossings, nodes, planeChange, relativeInclination, speedChangeFor } from "./transfers.ts";
|
|
13
|
+
export type { Node } from "./transfers.ts";
|
|
14
|
+
export { angularAcceleration, fireFor, gravityGradientTorque, holdDirection, killRotation, quatFromAxisAngle, rotateVector, spinFor, stepCraft, stepSpin, thrusterPush, torqueLimits, turnBy, unrotateVector } from "./attitude.ts";
|
|
15
|
+
export type { Craft, CraftForces, Quat, Spin, Thruster, Torque, TorqueLimits } from "./attitude.ts";
|
|
16
|
+
export { airVelocity, atmosphereAt, dragAcceleration, dynamicPressure, EARTH_ATMOSPHERE, MARS_ATMOSPHERE, machNumber, standardAtmosphere, VENUS_ATMOSPHERE } from "./atmosphere.ts";
|
|
17
|
+
export type { Air, AtmosphereLayer, AtmosphereModel } from "./atmosphere.ts";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { eccentricAnomaly, elementsOf, stateAtTrueAnomaly, stateOf, timeToTrueAnomaly } from "./elements.js";
|
|
2
|
+
export { gravityAt } from "./gravity.js";
|
|
3
|
+
export { path, propagate, step } from "./propagate.js";
|
|
4
|
+
export { burnSeconds, deltaV, exhaustSpeedOf, massAfter, massFlow, thrustAt } from "./rocket.js";
|
|
5
|
+
export { burnStart, directionOf, flyBurn, flyPlan, impulse } from "./burns.js";
|
|
6
|
+
export { biElliptic, crossings, nodes, planeChange, relativeInclination, speedChangeFor } from "./transfers.js";
|
|
7
|
+
export { angularAcceleration, fireFor, gravityGradientTorque, holdDirection, killRotation, quatFromAxisAngle, rotateVector, spinFor, stepCraft, stepSpin, thrusterPush, torqueLimits, turnBy, unrotateVector } from "./attitude.js";
|
|
8
|
+
export { airVelocity, atmosphereAt, dragAcceleration, dynamicPressure, EARTH_ATMOSPHERE, MARS_ATMOSPHERE, machNumber, standardAtmosphere, VENUS_ATMOSPHERE } from "./atmosphere.js";
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { type Vec3 } from "./vector.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Where a craft is and how fast it goes at a time: seconds from any start the caller picks, metres and metres a second.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import type { State } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
8
|
+
*
|
|
9
|
+
* const start: State = { t: 0, position: [6_778_000, 0, 0], velocity: [0, 7_669, 0] };
|
|
10
|
+
* console.log(start.t);
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export interface State {
|
|
14
|
+
t: number;
|
|
15
|
+
position: Vec3;
|
|
16
|
+
velocity: Vec3;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* What pulls or pushes the craft: its acceleration (metres a second squared) at a time, place and speed. Gravity from the scene's bodies is `gravityAt(position, bodiesAt(t))`; an engine adds its thrust over the craft's mass.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { gravityAt, type Acceleration } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
24
|
+
*
|
|
25
|
+
* const earthOnly: Acceleration = (_t, position) => gravityAt(position, [{ gm: 3.986004418e14, position: [0, 0, 0] }]);
|
|
26
|
+
* console.log(earthOnly(0, [7_000_000, 0, 0], [0, 0, 0])[0].toFixed(3));
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export type Acceleration = (t: number, position: Vec3, velocity: Vec3) => Vec3;
|
|
30
|
+
/**
|
|
31
|
+
* How a step is taken. `rk4` is the classic fourth-order Runge-Kutta, right for forces that depend on the speed (drag). `sy2`, `sy4`, `sy6` and `sy8` are symplectic (leapfrog and Yoshida's fourth, sixth and eighth orders): for gravity they keep the energy of an orbit from drifting over many turns.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import type { Method } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
36
|
+
*
|
|
37
|
+
* const longCoast: Method = "sy4";
|
|
38
|
+
* console.log(longCoast);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export type Method = "rk4" | "sy2" | "sy4" | "sy6" | "sy8";
|
|
42
|
+
/**
|
|
43
|
+
* One step of `h` seconds.
|
|
44
|
+
* @param state Where the craft is now.
|
|
45
|
+
* @param h The step, seconds (negative to go back in time).
|
|
46
|
+
* @param acceleration What pulls or pushes the craft.
|
|
47
|
+
* @param method How the step is taken; `sy4` when left out.
|
|
48
|
+
* @returns Where the craft is `h` seconds later.
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import { gravityAt, step } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
52
|
+
*
|
|
53
|
+
* const earth = [{ gm: 3.986004418e14, position: [0, 0, 0] as const }];
|
|
54
|
+
* const next = step({ t: 0, position: [6_778_000, 0, 0], velocity: [0, 7_669, 0] }, 10, (_t, p) => gravityAt(p, earth));
|
|
55
|
+
* console.log(next.t, (next.position[1] / 1000).toFixed(2), "km");
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function step(state: State, h: number, acceleration: Acceleration, method?: Method): State;
|
|
59
|
+
/**
|
|
60
|
+
* How to propagate: the step, what pulls, and the method.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { gravityAt, type PropagateOptions } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
65
|
+
*
|
|
66
|
+
* const options: PropagateOptions = { step: 30, method: "sy4", acceleration: (_t, p) => gravityAt(p, [{ gm: 3.986004418e14, position: [0, 0, 0] }]) };
|
|
67
|
+
* console.log(options.step);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export interface PropagateOptions {
|
|
71
|
+
/** The longest step, seconds (positive). The last step is shortened to land on the time asked. */
|
|
72
|
+
step: number;
|
|
73
|
+
acceleration: Acceleration;
|
|
74
|
+
/** `sy4` when left out. */
|
|
75
|
+
method?: Method;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Moves a craft forward (or back) by a span of time, in steps no longer than `options.step`.
|
|
79
|
+
* @param start Where the craft is at the start.
|
|
80
|
+
* @param seconds How long, seconds (negative to go back).
|
|
81
|
+
* @param options The step, what pulls and the method.
|
|
82
|
+
* @returns Where the craft is at `start.t + seconds`.
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* import { gravityAt, propagate } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
86
|
+
*
|
|
87
|
+
* const earth = [{ gm: 3.986004418e14, position: [0, 0, 0] as const }];
|
|
88
|
+
* const start = { t: 0, position: [7_000_000, 0, 0] as const, velocity: [0, 7_546.05, 0] as const };
|
|
89
|
+
* const end = propagate(start, 5_828.5, { step: 10, acceleration: (_t, p) => gravityAt(p, earth) });
|
|
90
|
+
* console.log((end.position[0] / 1000).toFixed(1), "km, once round");
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare function propagate(start: State, seconds: number, options: PropagateOptions): State;
|
|
94
|
+
/**
|
|
95
|
+
* The path a craft takes: its state at `points + 1` evenly spaced times from the start to `start.t + seconds`, for drawing an orbit or a trajectory.
|
|
96
|
+
* @param start Where the craft is at the start.
|
|
97
|
+
* @param seconds How long, seconds.
|
|
98
|
+
* @param points How many stretches the path is cut into (1 or more).
|
|
99
|
+
* @param options The step, what pulls and the method.
|
|
100
|
+
* @returns The states, the first being `start`.
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { gravityAt, path } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
104
|
+
*
|
|
105
|
+
* const earth = [{ gm: 3.986004418e14, position: [0, 0, 0] as const }];
|
|
106
|
+
* const line = path({ t: 0, position: [7_000_000, 0, 0], velocity: [0, 7_546, 0] }, 5_828, 8, { step: 10, acceleration: (_t, p) => gravityAt(p, earth) });
|
|
107
|
+
* console.log(line.length);
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export declare function path(start: State, seconds: number, points: number, options: PropagateOptions): State[];
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Moving a craft forward in time under any acceleration (gravity from the scene's bodies, an engine, or both), in fixed steps. Pure: the caller says how long, and nothing reads a clock.
|
|
2
|
+
// Ported from Orbiter (https://github.com/orbitersim/orbiter), Src/Orbiter/BodyIntegrator.cpp: the linear parts of RK4_LinAng and of the
|
|
3
|
+
// symplectic SY2_LinAng, SY4_LinAng, SY6_LinAng and SY8_LinAng (Yoshida's coefficients, as Orbiter has them). Copyright (c) 2000-2026
|
|
4
|
+
// Martin Schweiger, MIT licence (LICENSES/Orbiter-MIT.txt). Changed in the port: the turning of the craft is left to a later step; the
|
|
5
|
+
// four symplectic methods share one loop built from their weights; each step starts from a fresh acceleration where Orbiter reuses the
|
|
6
|
+
// last step's; the time of each evaluation is absolute where Orbiter gives a fraction of its frame.
|
|
7
|
+
import { addScaled } from "./vector.js";
|
|
8
|
+
/** Yoshida's weights from the middle out, after the centre one, as Orbiter's SY4, SY6 and SY8 hold them. */
|
|
9
|
+
const CBRT2 = 1.25992104989487319066654436028;
|
|
10
|
+
const WEIGHTS = {
|
|
11
|
+
sy2: [],
|
|
12
|
+
sy4: [1 / (2 - CBRT2)],
|
|
13
|
+
sy6: [-0.117767998417887e1, 0.235573213359357e0, 0.784513610477560e0],
|
|
14
|
+
sy8: [0.311790812418427e0, -0.155946803821447e1, -0.167896928259640e1, 0.166335809963315e1, -0.106458714789183e1, 0.136934946416871e1, 0.629030650210433e0],
|
|
15
|
+
};
|
|
16
|
+
/** The kicks `d` and the drifts `c` of a symmetric symplectic method: `d` is the weights mirrored round the centre one, each drift the mean of the kicks beside it. */
|
|
17
|
+
function kicksAndDrifts(weights) {
|
|
18
|
+
const centre = 1 - 2 * weights.reduce((sum, w) => sum + w, 0);
|
|
19
|
+
const d = [...[...weights].reverse(), centre, ...weights];
|
|
20
|
+
const c = [d[0] / 2, ...d.slice(1).map((w, i) => (d[i] + w) / 2), d[d.length - 1] / 2];
|
|
21
|
+
return { d, c };
|
|
22
|
+
}
|
|
23
|
+
const SYMPLECTIC = Object.fromEntries(Object.entries(WEIGHTS).map(([name, weights]) => [name, kicksAndDrifts(weights)]));
|
|
24
|
+
function rk4(state, h, acceleration) {
|
|
25
|
+
const { t, position: p, velocity: v } = state;
|
|
26
|
+
const h2 = h / 2;
|
|
27
|
+
const a0 = acceleration(t, p, v);
|
|
28
|
+
const va = addScaled(v, a0, h2);
|
|
29
|
+
const a1 = acceleration(t + h2, addScaled(p, v, h2), va);
|
|
30
|
+
const vb = addScaled(v, a1, h2);
|
|
31
|
+
const a2 = acceleration(t + h2, addScaled(p, va, h2), vb);
|
|
32
|
+
const vc = addScaled(v, a2, h);
|
|
33
|
+
const a3 = acceleration(t + h, addScaled(p, vb, h), vc);
|
|
34
|
+
const h6 = h / 6;
|
|
35
|
+
const sum = (x0, x1, x2, x3, k) => x0[k] + 2 * (x1[k] + x2[k]) + x3[k];
|
|
36
|
+
return {
|
|
37
|
+
t: t + h,
|
|
38
|
+
position: [p[0] + sum(v, va, vb, vc, 0) * h6, p[1] + sum(v, va, vb, vc, 1) * h6, p[2] + sum(v, va, vb, vc, 2) * h6],
|
|
39
|
+
velocity: [v[0] + sum(a0, a1, a2, a3, 0) * h6, v[1] + sum(a0, a1, a2, a3, 1) * h6, v[2] + sum(a0, a1, a2, a3, 2) * h6],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function symplectic(state, h, acceleration, method) {
|
|
43
|
+
const { c, d } = SYMPLECTIC[method];
|
|
44
|
+
let position = state.position;
|
|
45
|
+
let velocity = state.velocity;
|
|
46
|
+
let section = 0;
|
|
47
|
+
for (let i = 0; i < c.length; i++) {
|
|
48
|
+
position = addScaled(position, velocity, h * c[i]);
|
|
49
|
+
section += c[i];
|
|
50
|
+
if (i < d.length)
|
|
51
|
+
velocity = addScaled(velocity, acceleration(state.t + section * h, position, velocity), h * d[i]);
|
|
52
|
+
}
|
|
53
|
+
return { t: state.t + h, position, velocity };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* One step of `h` seconds.
|
|
57
|
+
* @param state Where the craft is now.
|
|
58
|
+
* @param h The step, seconds (negative to go back in time).
|
|
59
|
+
* @param acceleration What pulls or pushes the craft.
|
|
60
|
+
* @param method How the step is taken; `sy4` when left out.
|
|
61
|
+
* @returns Where the craft is `h` seconds later.
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { gravityAt, step } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
65
|
+
*
|
|
66
|
+
* const earth = [{ gm: 3.986004418e14, position: [0, 0, 0] as const }];
|
|
67
|
+
* const next = step({ t: 0, position: [6_778_000, 0, 0], velocity: [0, 7_669, 0] }, 10, (_t, p) => gravityAt(p, earth));
|
|
68
|
+
* console.log(next.t, (next.position[1] / 1000).toFixed(2), "km");
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function step(state, h, acceleration, method = "sy4") {
|
|
72
|
+
return method === "rk4" ? rk4(state, h, acceleration) : symplectic(state, h, acceleration, method);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Moves a craft forward (or back) by a span of time, in steps no longer than `options.step`.
|
|
76
|
+
* @param start Where the craft is at the start.
|
|
77
|
+
* @param seconds How long, seconds (negative to go back).
|
|
78
|
+
* @param options The step, what pulls and the method.
|
|
79
|
+
* @returns Where the craft is at `start.t + seconds`.
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* import { gravityAt, propagate } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
83
|
+
*
|
|
84
|
+
* const earth = [{ gm: 3.986004418e14, position: [0, 0, 0] as const }];
|
|
85
|
+
* const start = { t: 0, position: [7_000_000, 0, 0] as const, velocity: [0, 7_546.05, 0] as const };
|
|
86
|
+
* const end = propagate(start, 5_828.5, { step: 10, acceleration: (_t, p) => gravityAt(p, earth) });
|
|
87
|
+
* console.log((end.position[0] / 1000).toFixed(1), "km, once round");
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export function propagate(start, seconds, options) {
|
|
91
|
+
if (!(options.step > 0))
|
|
92
|
+
throw new RangeError("step must be a positive number of seconds");
|
|
93
|
+
const count = Math.max(1, Math.ceil(Math.abs(seconds) / options.step - 1e-9));
|
|
94
|
+
const h = seconds / count;
|
|
95
|
+
let state = start;
|
|
96
|
+
for (let i = 0; i < count; i++)
|
|
97
|
+
state = step(state, h, options.acceleration, options.method);
|
|
98
|
+
return { ...state, t: start.t + seconds };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The path a craft takes: its state at `points + 1` evenly spaced times from the start to `start.t + seconds`, for drawing an orbit or a trajectory.
|
|
102
|
+
* @param start Where the craft is at the start.
|
|
103
|
+
* @param seconds How long, seconds.
|
|
104
|
+
* @param points How many stretches the path is cut into (1 or more).
|
|
105
|
+
* @param options The step, what pulls and the method.
|
|
106
|
+
* @returns The states, the first being `start`.
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* import { gravityAt, path } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
110
|
+
*
|
|
111
|
+
* const earth = [{ gm: 3.986004418e14, position: [0, 0, 0] as const }];
|
|
112
|
+
* const line = path({ t: 0, position: [7_000_000, 0, 0], velocity: [0, 7_546, 0] }, 5_828, 8, { step: 10, acceleration: (_t, p) => gravityAt(p, earth) });
|
|
113
|
+
* console.log(line.length);
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export function path(start, seconds, points, options) {
|
|
117
|
+
const parts = Math.max(1, Math.floor(points));
|
|
118
|
+
const states = [start];
|
|
119
|
+
for (let i = 1; i <= parts; i++)
|
|
120
|
+
states.push(propagate(states[i - 1], seconds / parts, options));
|
|
121
|
+
return states;
|
|
122
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A rocket engine as Orbiter describes a thruster: its thrust in vacuum, its exhaust speed in vacuum and, if it loses thrust in air, the exhaust speed at a reference pressure.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { exhaustSpeedOf, type Engine } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
7
|
+
*
|
|
8
|
+
* const sps: Engine = { thrust: 91_189, exhaustSpeed: exhaustSpeedOf(314) };
|
|
9
|
+
* console.log(sps.exhaustSpeed.toFixed(0), "m/s");
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export interface Engine {
|
|
13
|
+
/** Thrust in vacuum at full throttle, newtons. */
|
|
14
|
+
thrust: number;
|
|
15
|
+
/** Exhaust speed in vacuum, metres a second (specific impulse times standard gravity). */
|
|
16
|
+
exhaustSpeed: number;
|
|
17
|
+
/** The exhaust speed (metres a second) at a pressure (pascals), such as at sea level, for an engine that loses thrust in air. Left out, the thrust is the same at every pressure. */
|
|
18
|
+
reference?: {
|
|
19
|
+
exhaustSpeed: number;
|
|
20
|
+
pressure: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* An exhaust speed from a specific impulse: `isp g0`.
|
|
25
|
+
* @param ispSeconds The specific impulse, seconds.
|
|
26
|
+
* @returns The exhaust speed, metres a second.
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { exhaustSpeedOf } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
30
|
+
*
|
|
31
|
+
* console.log(exhaustSpeedOf(311).toFixed(1));
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare const exhaustSpeedOf: (ispSeconds: number) => number;
|
|
35
|
+
/**
|
|
36
|
+
* The propellant an engine burns, kilograms a second: its vacuum thrust over its vacuum exhaust speed, times the throttle. In air the flow stays the same and the thrust falls (see {@link thrustAt}), as in Orbiter.
|
|
37
|
+
* @param engine The engine.
|
|
38
|
+
* @param throttle 0 to 1; 1 when left out.
|
|
39
|
+
* @returns The mass flow, kg/s.
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { exhaustSpeedOf, massFlow } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
43
|
+
*
|
|
44
|
+
* console.log(massFlow({ thrust: 91_189, exhaustSpeed: exhaustSpeedOf(314) }).toFixed(2), "kg/s");
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare const massFlow: (engine: Engine, throttle?: number) => number;
|
|
48
|
+
/**
|
|
49
|
+
* An engine's thrust at an outside pressure: the vacuum thrust times `max(0, 1 - p (v0 - vref) / (pref v0))`, Orbiter's straight-line model through the vacuum and the reference exhaust speeds.
|
|
50
|
+
* @param engine The engine.
|
|
51
|
+
* @param pressure The outside pressure, pascals (0 in space).
|
|
52
|
+
* @param throttle 0 to 1; 1 when left out.
|
|
53
|
+
* @returns The thrust, newtons.
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { exhaustSpeedOf, thrustAt } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
57
|
+
*
|
|
58
|
+
* const engine = { thrust: 1_000_000, exhaustSpeed: exhaustSpeedOf(330), reference: { exhaustSpeed: exhaustSpeedOf(300), pressure: 101_325 } };
|
|
59
|
+
* console.log(thrustAt(engine, 0), thrustAt(engine, 101_325).toFixed(0));
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function thrustAt(engine: Engine, pressure: number, throttle?: number): number;
|
|
63
|
+
/**
|
|
64
|
+
* The rocket equation (Tsiolkovsky's): the speed a burn gives, `v ln(m0 / m1)`.
|
|
65
|
+
* @param exhaustSpeed The exhaust speed, metres a second.
|
|
66
|
+
* @param startMass The mass before the burn, kilograms.
|
|
67
|
+
* @param endMass The mass after it, kilograms (more than 0, at most `startMass`).
|
|
68
|
+
* @returns The change of speed, metres a second.
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* import { deltaV, exhaustSpeedOf } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
72
|
+
*
|
|
73
|
+
* console.log(deltaV(exhaustSpeedOf(314), 30_000, 20_000).toFixed(0), "m/s");
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare const deltaV: (exhaustSpeed: number, startMass: number, endMass: number) => number;
|
|
77
|
+
/**
|
|
78
|
+
* The rocket equation turned round: the mass left after a change of speed, `m0 exp(-dv / v)`.
|
|
79
|
+
* @param exhaustSpeed The exhaust speed, metres a second.
|
|
80
|
+
* @param startMass The mass before the burn, kilograms.
|
|
81
|
+
* @param dv The change of speed, metres a second.
|
|
82
|
+
* @returns The mass after the burn, kilograms; `startMass - massAfter(...)` is the propellant burned.
|
|
83
|
+
* @example
|
|
84
|
+
* ```ts
|
|
85
|
+
* import { exhaustSpeedOf, massAfter } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
86
|
+
*
|
|
87
|
+
* console.log((30_000 - massAfter(exhaustSpeedOf(314), 30_000, 1_000)).toFixed(0), "kg burned");
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare const massAfter: (exhaustSpeed: number, startMass: number, dv: number) => number;
|
|
91
|
+
/**
|
|
92
|
+
* How long an engine must burn, at a steady throttle in vacuum, to change a craft's speed by `dv`: the propellant the rocket equation asks for over the engine's mass flow.
|
|
93
|
+
* @param engine The engine.
|
|
94
|
+
* @param startMass The mass before the burn, kilograms.
|
|
95
|
+
* @param dv The change of speed, metres a second.
|
|
96
|
+
* @param throttle 0 to 1; 1 when left out.
|
|
97
|
+
* @returns The burn's length, seconds (Infinity at zero throttle).
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* import { burnSeconds, exhaustSpeedOf } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
101
|
+
*
|
|
102
|
+
* console.log(burnSeconds({ thrust: 91_189, exhaustSpeed: exhaustSpeedOf(314) }, 30_000, 1_000).toFixed(1), "s");
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function burnSeconds(engine: Engine, startMass: number, dv: number, throttle?: number): number;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// An engine's thrust and the propellant it burns, and the rocket equation: what a burn changes the speed by, the mass left and how long it takes. Pure.
|
|
2
|
+
// Ported from Orbiter (https://github.com/orbitersim/orbiter): the propellant flow `thrust / isp0` of Vessel::UpdateThrustForces and the
|
|
3
|
+
// thrust's scaling in air of ThrusterAtmScale (Src/Orbiter/Vessel.cpp and Vessel.h, with the pfac of Vessel::CreateThruster), and the
|
|
4
|
+
// rocket equation `isp * log(m0 / (m0 - m))` of the DeltaGlider's fuel display (Src/Vessel/DeltaGlider/FuelMfd.cpp).
|
|
5
|
+
// Copyright (c) 2000-2026 Martin Schweiger, MIT licence (LICENSES/Orbiter-MIT.txt). Orbiter's "Isp" is an exhaust speed in metres a second,
|
|
6
|
+
// as `exhaustSpeed` is here; `exhaustSpeedOf` turns a specific impulse in seconds into one. Changed in the port: functions of plain
|
|
7
|
+
// numbers in place of a vessel's thrusters and tanks; a tank's efficiency factor is left out.
|
|
8
|
+
import { G0 } from "../journey/constants.js";
|
|
9
|
+
const clampThrottle = (throttle) => Math.max(0, Math.min(1, throttle));
|
|
10
|
+
/**
|
|
11
|
+
* An exhaust speed from a specific impulse: `isp g0`.
|
|
12
|
+
* @param ispSeconds The specific impulse, seconds.
|
|
13
|
+
* @returns The exhaust speed, metres a second.
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { exhaustSpeedOf } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
17
|
+
*
|
|
18
|
+
* console.log(exhaustSpeedOf(311).toFixed(1));
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export const exhaustSpeedOf = (ispSeconds) => ispSeconds * G0;
|
|
22
|
+
/**
|
|
23
|
+
* The propellant an engine burns, kilograms a second: its vacuum thrust over its vacuum exhaust speed, times the throttle. In air the flow stays the same and the thrust falls (see {@link thrustAt}), as in Orbiter.
|
|
24
|
+
* @param engine The engine.
|
|
25
|
+
* @param throttle 0 to 1; 1 when left out.
|
|
26
|
+
* @returns The mass flow, kg/s.
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { exhaustSpeedOf, massFlow } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
30
|
+
*
|
|
31
|
+
* console.log(massFlow({ thrust: 91_189, exhaustSpeed: exhaustSpeedOf(314) }).toFixed(2), "kg/s");
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export const massFlow = (engine, throttle = 1) => (engine.thrust * clampThrottle(throttle)) / engine.exhaustSpeed;
|
|
35
|
+
/**
|
|
36
|
+
* An engine's thrust at an outside pressure: the vacuum thrust times `max(0, 1 - p (v0 - vref) / (pref v0))`, Orbiter's straight-line model through the vacuum and the reference exhaust speeds.
|
|
37
|
+
* @param engine The engine.
|
|
38
|
+
* @param pressure The outside pressure, pascals (0 in space).
|
|
39
|
+
* @param throttle 0 to 1; 1 when left out.
|
|
40
|
+
* @returns The thrust, newtons.
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { exhaustSpeedOf, thrustAt } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
44
|
+
*
|
|
45
|
+
* const engine = { thrust: 1_000_000, exhaustSpeed: exhaustSpeedOf(330), reference: { exhaustSpeed: exhaustSpeedOf(300), pressure: 101_325 } };
|
|
46
|
+
* console.log(thrustAt(engine, 0), thrustAt(engine, 101_325).toFixed(0));
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function thrustAt(engine, pressure, throttle = 1) {
|
|
50
|
+
const vacuum = engine.thrust * clampThrottle(throttle);
|
|
51
|
+
const ref = engine.reference;
|
|
52
|
+
if (!ref || !(ref.exhaustSpeed > 0) || !(ref.pressure > 0))
|
|
53
|
+
return vacuum;
|
|
54
|
+
const pfac = (engine.exhaustSpeed - ref.exhaustSpeed) / (ref.pressure * engine.exhaustSpeed);
|
|
55
|
+
return vacuum * Math.max(0, 1 - pressure * pfac);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The rocket equation (Tsiolkovsky's): the speed a burn gives, `v ln(m0 / m1)`.
|
|
59
|
+
* @param exhaustSpeed The exhaust speed, metres a second.
|
|
60
|
+
* @param startMass The mass before the burn, kilograms.
|
|
61
|
+
* @param endMass The mass after it, kilograms (more than 0, at most `startMass`).
|
|
62
|
+
* @returns The change of speed, metres a second.
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* import { deltaV, exhaustSpeedOf } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
66
|
+
*
|
|
67
|
+
* console.log(deltaV(exhaustSpeedOf(314), 30_000, 20_000).toFixed(0), "m/s");
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export const deltaV = (exhaustSpeed, startMass, endMass) => exhaustSpeed * Math.log(startMass / endMass);
|
|
71
|
+
/**
|
|
72
|
+
* The rocket equation turned round: the mass left after a change of speed, `m0 exp(-dv / v)`.
|
|
73
|
+
* @param exhaustSpeed The exhaust speed, metres a second.
|
|
74
|
+
* @param startMass The mass before the burn, kilograms.
|
|
75
|
+
* @param dv The change of speed, metres a second.
|
|
76
|
+
* @returns The mass after the burn, kilograms; `startMass - massAfter(...)` is the propellant burned.
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { exhaustSpeedOf, massAfter } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
80
|
+
*
|
|
81
|
+
* console.log((30_000 - massAfter(exhaustSpeedOf(314), 30_000, 1_000)).toFixed(0), "kg burned");
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export const massAfter = (exhaustSpeed, startMass, dv) => startMass * Math.exp(-dv / exhaustSpeed);
|
|
85
|
+
/**
|
|
86
|
+
* How long an engine must burn, at a steady throttle in vacuum, to change a craft's speed by `dv`: the propellant the rocket equation asks for over the engine's mass flow.
|
|
87
|
+
* @param engine The engine.
|
|
88
|
+
* @param startMass The mass before the burn, kilograms.
|
|
89
|
+
* @param dv The change of speed, metres a second.
|
|
90
|
+
* @param throttle 0 to 1; 1 when left out.
|
|
91
|
+
* @returns The burn's length, seconds (Infinity at zero throttle).
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* import { burnSeconds, exhaustSpeedOf } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
95
|
+
*
|
|
96
|
+
* console.log(burnSeconds({ thrust: 91_189, exhaustSpeed: exhaustSpeedOf(314) }, 30_000, 1_000).toFixed(1), "s");
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export function burnSeconds(engine, startMass, dv, throttle = 1) {
|
|
100
|
+
const flow = massFlow(engine, throttle);
|
|
101
|
+
return flow > 0 ? (startMass - massAfter(engine.exhaustSpeed, startMass, dv)) / flow : Infinity;
|
|
102
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { type Elements } from "./elements.ts";
|
|
2
|
+
/**
|
|
3
|
+
* The speed change at distance `r` that turns an orbit of semi-major axis `aNow` into one of `aNew`, burning along the speed (the vis-viva equation, as Orbiter's transfer display rescales a burn to keep a chosen orbit).
|
|
4
|
+
* @param gm The body's gravitational parameter, m^3/s^2.
|
|
5
|
+
* @param r The distance of the burn from the body's centre, metres.
|
|
6
|
+
* @param aNow The semi-major axis before, metres (negative for an open path).
|
|
7
|
+
* @param aNew The semi-major axis wanted, metres.
|
|
8
|
+
* @returns The change of speed, metres a second: positive to speed up (prograde), negative to slow down.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { speedChangeFor } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
12
|
+
*
|
|
13
|
+
* console.log(speedChangeFor(3.986004418e14, 6_778_000, 6_778_000, (6_778_000 + 42_164_000) / 2).toFixed(1), "m/s");
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare const speedChangeFor: (gm: number, r: number, aNow: number, aNew: number) => number;
|
|
17
|
+
/**
|
|
18
|
+
* The change of speed that turns a speed through an angle, and to a new size if given: `sqrt(v1^2 + v2^2 - 2 v1 v2 cos angle)`, which is `2 v sin(angle / 2)` for a pure change of plane. Orbiter's plane-alignment display estimates `v angle` instead, the cost of keeping the push normal to the plane all through the burn.
|
|
19
|
+
* @param speed The speed before, metres a second.
|
|
20
|
+
* @param angle The angle to turn through, radians.
|
|
21
|
+
* @param newSpeed The speed after; the same as before when left out.
|
|
22
|
+
* @returns The change of speed, metres a second.
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { planeChange } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
26
|
+
*
|
|
27
|
+
* console.log(planeChange(7_669, (10 * Math.PI) / 180).toFixed(0), "m/s for 10 degrees in low orbit");
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function planeChange(speed: number, angle: number, newSpeed?: number): number;
|
|
31
|
+
/**
|
|
32
|
+
* The bi-elliptic transfer between two circular orbits about one body: out on one half-ellipse to a far point `rb`, a burn there, and back on a second half-ellipse to the final orbit. With `rb` equal to the final radius its speed changes are the Hohmann transfer's (and its time adds the half turn of the final circle that the second leg then is).
|
|
33
|
+
* @param gm The body's gravitational parameter, m^3/s^2.
|
|
34
|
+
* @param r1 The starting radius, metres.
|
|
35
|
+
* @param r2 The final radius, metres.
|
|
36
|
+
* @param rb The far point, metres (at least the larger of `r1` and `r2`).
|
|
37
|
+
* @returns The three speed changes (metres a second, each positive), their sum, and the flight time (seconds).
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { biElliptic } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
41
|
+
*
|
|
42
|
+
* const far = biElliptic(3.986004418e14, 6_778_000, 384_400_000, 1_000_000_000);
|
|
43
|
+
* console.log(far.total.toFixed(0), "m/s,", (far.seconds / 86_400).toFixed(1), "days");
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function biElliptic(gm: number, r1: number, r2: number, rb: number): {
|
|
47
|
+
dv1: number;
|
|
48
|
+
dv2: number;
|
|
49
|
+
dv3: number;
|
|
50
|
+
total: number;
|
|
51
|
+
seconds: number;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* The angle between two orbits' planes.
|
|
55
|
+
* @param a One orbit's elements.
|
|
56
|
+
* @param b The other's.
|
|
57
|
+
* @returns The angle, radians, 0 to pi.
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* import { elementsOf, relativeInclination } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
61
|
+
*
|
|
62
|
+
* const gm = 3.986004418e14;
|
|
63
|
+
* const iss = elementsOf(gm, [6_778_000, 0, 0], [0, 4_766, 6_008]);
|
|
64
|
+
* const equator = elementsOf(gm, [6_778_000, 0, 0], [0, 7_669, 0]);
|
|
65
|
+
* console.log(((relativeInclination(iss, equator) * 180) / Math.PI).toFixed(1), "degrees");
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function relativeInclination(a: Elements, b: Elements): number;
|
|
69
|
+
/**
|
|
70
|
+
* One crossing of a craft's orbit with another plane: where on its orbit, how long until it is there, its speed there and the change of speed that turns it into the other plane.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* import { elementsOf, nodes, type Node } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
75
|
+
*
|
|
76
|
+
* const gm = 3.986004418e14;
|
|
77
|
+
* const crossing = nodes(elementsOf(gm, [6_778_000, 0, 0], [0, 4_766, 6_008]), elementsOf(gm, [0, 6_778_000, 0], [-7_669, 0, 0]));
|
|
78
|
+
* const next: Node | undefined = crossing?.ascending;
|
|
79
|
+
* console.log(next?.seconds.toFixed(0));
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export interface Node {
|
|
83
|
+
/** The craft's true anomaly there, radians. */
|
|
84
|
+
trueAnomaly: number;
|
|
85
|
+
/** Seconds from when the craft's elements were taken until it is there (the next time). */
|
|
86
|
+
seconds: number;
|
|
87
|
+
/** Its speed there, metres a second. */
|
|
88
|
+
speed: number;
|
|
89
|
+
/** An impulsive change of plane there, `2 v sin(angle / 2)`, metres a second. */
|
|
90
|
+
dv: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Where a craft's orbit crosses another orbit's plane, and when it gets there (Orbiter's plane-alignment display): the ascending node, where it passes to the north of the other plane, and the descending node.
|
|
94
|
+
* @param ship The craft's elements.
|
|
95
|
+
* @param target The elements of the orbit whose plane is wanted (another craft, a moon, or one made up for the plane).
|
|
96
|
+
* @returns The angle between the planes and the two nodes, or null when the planes are the same (no nodes).
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* import { elementsOf, nodes } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
100
|
+
*
|
|
101
|
+
* const gm = 3.986004418e14;
|
|
102
|
+
* const tilted = elementsOf(gm, [6_778_000, 0, 0], [0, 4_766, 6_008]);
|
|
103
|
+
* const equator = elementsOf(gm, [6_778_000, 0, 0], [0, 7_669, 0]);
|
|
104
|
+
* const n = nodes(tilted, equator);
|
|
105
|
+
* console.log(n?.descending.seconds.toFixed(0), "s to the descending node,", n?.descending.dv.toFixed(0), "m/s there");
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare function nodes(ship: Elements, target: Elements): {
|
|
109
|
+
relativeInclination: number;
|
|
110
|
+
ascending: Node;
|
|
111
|
+
descending: Node;
|
|
112
|
+
} | null;
|
|
113
|
+
/**
|
|
114
|
+
* Where two orbits about one body, in one plane, cross: the points that are on both (Orbiter's transfer display, which finds where a transfer orbit meets its target's). Both orbits must share their plane; for orbits in different planes, use the {@link nodes} first.
|
|
115
|
+
* @param path The orbit flown (a transfer orbit).
|
|
116
|
+
* @param target The orbit to reach.
|
|
117
|
+
* @returns The true anomalies on `path` of the crossings, radians, 0 to 2 pi in increasing order: none, one (touching) or two (on an open path, only points it reaches).
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* import { crossings, elementsOf } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
121
|
+
*
|
|
122
|
+
* const gm = 3.986004418e14;
|
|
123
|
+
* const transfer = elementsOf(gm, [6_778_000, 0, 0], [0, 9_000, 0]);
|
|
124
|
+
* const higher = elementsOf(gm, [10_000_000, 0, 0], [0, Math.sqrt(gm / 10_000_000), 0]);
|
|
125
|
+
* console.log(crossings(transfer, higher).map((nu) => ((nu * 180) / Math.PI).toFixed(1)));
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export declare function crossings(path: Elements, target: Elements): number[];
|