@johnmorrisdotca/uchusen-rockets 0.19.0 → 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 +19 -0
- package/LICENSES/Orbiter-MIT.txt +21 -0
- package/NOTICE.md +37 -1
- package/README.md +14 -7
- 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/probe.d.ts +15 -0
- package/dist/element/probe.js +46 -0
- package/dist/element/scene.d.ts +7 -0
- package/dist/element/scene.js +38 -10
- package/dist/element.d.ts +7 -0
- package/dist/element.js +74 -20
- 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,155 @@
|
|
|
1
|
+
// Planning a transfer: the speed a burn needs to reach a new orbit size, a change of plane, the bi-elliptic transfer, where two orbits
|
|
2
|
+
// in one plane cross, and where a craft's orbit crosses another plane (its nodes), with when it gets there. Pure.
|
|
3
|
+
// Ported from Orbiter (https://github.com/orbitersim/orbiter): the speed change that keeps a chosen semi-major axis and the crossing of
|
|
4
|
+
// two orbits from Src/Orbiter/MfdTransfer.cpp (Instrument_Transfer::CalcElements and UpdateDraw), and the relative inclination, the
|
|
5
|
+
// nodes, the time to each and the speed there from Src/Orbiter/MfdAlign.cpp (Instrument_OPlaneAlign::UpdateDraw). Copyright (c)
|
|
6
|
+
// 2000-2026 Martin Schweiger, MIT licence (LICENSES/Orbiter-MIT.txt). Changed in the port: functions of elements in place of the
|
|
7
|
+
// displays; a right-handed frame, so Orbiter's node line crossp(nm1, nm2) is nm2 x nm1 here; both crossings of two orbits are given
|
|
8
|
+
// (Orbiter's display picks one); angles by atan2. Written here: the bi-elliptic transfer and the plane change by the law of cosines
|
|
9
|
+
// (Orbiter's display estimates a plane change as the speed times the angle, for a push kept normal to the plane).
|
|
10
|
+
import { stateAtTrueAnomaly, timeToTrueAnomaly } from "./elements.js";
|
|
11
|
+
import { cross, dot, length, scale } from "./vector.js";
|
|
12
|
+
const TAU = 2 * Math.PI;
|
|
13
|
+
const posAngle = (angle) => ((angle % TAU) + TAU) % TAU;
|
|
14
|
+
/**
|
|
15
|
+
* 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).
|
|
16
|
+
* @param gm The body's gravitational parameter, m^3/s^2.
|
|
17
|
+
* @param r The distance of the burn from the body's centre, metres.
|
|
18
|
+
* @param aNow The semi-major axis before, metres (negative for an open path).
|
|
19
|
+
* @param aNew The semi-major axis wanted, metres.
|
|
20
|
+
* @returns The change of speed, metres a second: positive to speed up (prograde), negative to slow down.
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { speedChangeFor } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
24
|
+
*
|
|
25
|
+
* console.log(speedChangeFor(3.986004418e14, 6_778_000, 6_778_000, (6_778_000 + 42_164_000) / 2).toFixed(1), "m/s");
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export const speedChangeFor = (gm, r, aNow, aNew) => Math.sqrt(gm * (2 / r - 1 / aNew)) - Math.sqrt(gm * (2 / r - 1 / aNow));
|
|
29
|
+
/**
|
|
30
|
+
* 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.
|
|
31
|
+
* @param speed The speed before, metres a second.
|
|
32
|
+
* @param angle The angle to turn through, radians.
|
|
33
|
+
* @param newSpeed The speed after; the same as before when left out.
|
|
34
|
+
* @returns The change of speed, metres a second.
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { planeChange } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
38
|
+
*
|
|
39
|
+
* console.log(planeChange(7_669, (10 * Math.PI) / 180).toFixed(0), "m/s for 10 degrees in low orbit");
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function planeChange(speed, angle, newSpeed = speed) {
|
|
43
|
+
return Math.sqrt(Math.max(0, speed * speed + newSpeed * newSpeed - 2 * speed * newSpeed * Math.cos(angle)));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 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).
|
|
47
|
+
* @param gm The body's gravitational parameter, m^3/s^2.
|
|
48
|
+
* @param r1 The starting radius, metres.
|
|
49
|
+
* @param r2 The final radius, metres.
|
|
50
|
+
* @param rb The far point, metres (at least the larger of `r1` and `r2`).
|
|
51
|
+
* @returns The three speed changes (metres a second, each positive), their sum, and the flight time (seconds).
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* import { biElliptic } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
55
|
+
*
|
|
56
|
+
* const far = biElliptic(3.986004418e14, 6_778_000, 384_400_000, 1_000_000_000);
|
|
57
|
+
* console.log(far.total.toFixed(0), "m/s,", (far.seconds / 86_400).toFixed(1), "days");
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function biElliptic(gm, r1, r2, rb) {
|
|
61
|
+
const a1 = (r1 + rb) / 2;
|
|
62
|
+
const a2 = (r2 + rb) / 2;
|
|
63
|
+
const visViva = (r, a) => Math.sqrt(gm * (2 / r - 1 / a));
|
|
64
|
+
const dv1 = Math.abs(visViva(r1, a1) - Math.sqrt(gm / r1));
|
|
65
|
+
const dv2 = Math.abs(visViva(rb, a2) - visViva(rb, a1));
|
|
66
|
+
const dv3 = Math.abs(visViva(r2, a2) - Math.sqrt(gm / r2));
|
|
67
|
+
return { dv1, dv2, dv3, total: dv1 + dv2 + dv3, seconds: Math.PI * (Math.sqrt(a1 ** 3 / gm) + Math.sqrt(a2 ** 3 / gm)) };
|
|
68
|
+
}
|
|
69
|
+
/** The unit normal of an orbit's plane, along its angular momentum. */
|
|
70
|
+
const normalOf = (el) => [Math.sin(el.i) * Math.sin(el.node), -Math.sin(el.i) * Math.cos(el.node), Math.cos(el.i)];
|
|
71
|
+
/**
|
|
72
|
+
* The angle between two orbits' planes.
|
|
73
|
+
* @param a One orbit's elements.
|
|
74
|
+
* @param b The other's.
|
|
75
|
+
* @returns The angle, radians, 0 to pi.
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* import { elementsOf, relativeInclination } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
79
|
+
*
|
|
80
|
+
* const gm = 3.986004418e14;
|
|
81
|
+
* const iss = elementsOf(gm, [6_778_000, 0, 0], [0, 4_766, 6_008]);
|
|
82
|
+
* const equator = elementsOf(gm, [6_778_000, 0, 0], [0, 7_669, 0]);
|
|
83
|
+
* console.log(((relativeInclination(iss, equator) * 180) / Math.PI).toFixed(1), "degrees");
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export function relativeInclination(a, b) {
|
|
87
|
+
const na = normalOf(a);
|
|
88
|
+
const nb = normalOf(b);
|
|
89
|
+
return Math.atan2(length(cross(na, nb)), dot(na, nb));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 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.
|
|
93
|
+
* @param ship The craft's elements.
|
|
94
|
+
* @param target The elements of the orbit whose plane is wanted (another craft, a moon, or one made up for the plane).
|
|
95
|
+
* @returns The angle between the planes and the two nodes, or null when the planes are the same (no nodes).
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* import { elementsOf, nodes } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
99
|
+
*
|
|
100
|
+
* const gm = 3.986004418e14;
|
|
101
|
+
* const tilted = elementsOf(gm, [6_778_000, 0, 0], [0, 4_766, 6_008]);
|
|
102
|
+
* const equator = elementsOf(gm, [6_778_000, 0, 0], [0, 7_669, 0]);
|
|
103
|
+
* const n = nodes(tilted, equator);
|
|
104
|
+
* console.log(n?.descending.seconds.toFixed(0), "s to the descending node,", n?.descending.dv.toFixed(0), "m/s there");
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export function nodes(ship, target) {
|
|
108
|
+
const n1 = normalOf(ship);
|
|
109
|
+
const n2 = normalOf(target);
|
|
110
|
+
const line = cross(n2, n1);
|
|
111
|
+
const l = length(line);
|
|
112
|
+
if (l < 1e-12)
|
|
113
|
+
return null;
|
|
114
|
+
const nd = scale(line, 1 / l);
|
|
115
|
+
const reli = Math.atan2(l, dot(n1, n2));
|
|
116
|
+
const here = stateAtTrueAnomaly(ship, ship.trueAnomaly).position;
|
|
117
|
+
const ahead = Math.atan2(dot(cross(here, nd), n1), dot(here, nd));
|
|
118
|
+
const at = (trueAnomaly) => {
|
|
119
|
+
const speed = length(stateAtTrueAnomaly(ship, trueAnomaly).velocity);
|
|
120
|
+
return { trueAnomaly, seconds: timeToTrueAnomaly(ship, trueAnomaly), speed, dv: planeChange(speed, reli) };
|
|
121
|
+
};
|
|
122
|
+
const ascending = posAngle(ship.trueAnomaly + posAngle(ahead));
|
|
123
|
+
return { relativeInclination: reli, ascending: at(ascending), descending: at(posAngle(ascending + Math.PI)) };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* 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.
|
|
127
|
+
* @param path The orbit flown (a transfer orbit).
|
|
128
|
+
* @param target The orbit to reach.
|
|
129
|
+
* @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).
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* import { crossings, elementsOf } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
133
|
+
*
|
|
134
|
+
* const gm = 3.986004418e14;
|
|
135
|
+
* const transfer = elementsOf(gm, [6_778_000, 0, 0], [0, 9_000, 0]);
|
|
136
|
+
* const higher = elementsOf(gm, [10_000_000, 0, 0], [0, Math.sqrt(gm / 10_000_000), 0]);
|
|
137
|
+
* console.log(crossings(transfer, higher).map((nu) => ((nu * 180) / Math.PI).toFixed(1)));
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export function crossings(path, target) {
|
|
141
|
+
const domega = target.longitudePeriapsis - path.longitudePeriapsis;
|
|
142
|
+
const p1 = path.semiLatus;
|
|
143
|
+
const p2 = target.semiLatus;
|
|
144
|
+
const a = path.e / p1 - (target.e / p2) * Math.cos(domega);
|
|
145
|
+
const b = (-target.e / p2) * Math.sin(domega);
|
|
146
|
+
const c = 1 / p1 - 1 / p2;
|
|
147
|
+
const r = Math.hypot(a, b);
|
|
148
|
+
if (r === 0 || Math.abs(c) > r)
|
|
149
|
+
return [];
|
|
150
|
+
const centre = Math.atan2(b, a);
|
|
151
|
+
const half = Math.acos(Math.max(-1, Math.min(1, -c / r)));
|
|
152
|
+
const found = half === 0 ? [centre] : [centre - half, centre + half];
|
|
153
|
+
const reached = (nu) => 1 + path.e * Math.cos(nu) > 0 && 1 + target.e * Math.cos(nu - domega) > 0;
|
|
154
|
+
return found.map(posAngle).filter(reached).sort((x, y) => x - y);
|
|
155
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A vector in three dimensions: `[x, y, z]`, right-handed. The flight physics works in metres, metres a second and metres a second squared, in whatever frame the caller's bodies are given in (for example the ecliptic of J2000 from the solar system's barycentre, or the Earth's equator from its centre).
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import type { Vec3 } from "@johnmorrisdotca/uchusen-rockets/physics";
|
|
7
|
+
*
|
|
8
|
+
* const issHeight: Vec3 = [6_778_000, 0, 0];
|
|
9
|
+
* console.log(issHeight[0]);
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export type Vec3 = readonly [number, number, number];
|
|
13
|
+
export declare const add: (a: Vec3, b: Vec3) => Vec3;
|
|
14
|
+
export declare const sub: (a: Vec3, b: Vec3) => Vec3;
|
|
15
|
+
export declare const scale: (a: Vec3, k: number) => Vec3;
|
|
16
|
+
/** `a + b k`, the step every integrator takes. */
|
|
17
|
+
export declare const addScaled: (a: Vec3, b: Vec3, k: number) => Vec3;
|
|
18
|
+
export declare const dot: (a: Vec3, b: Vec3) => number;
|
|
19
|
+
export declare const cross: (a: Vec3, b: Vec3) => Vec3;
|
|
20
|
+
export declare const length: (a: Vec3) => number;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Three numbers for a place, a speed or an acceleration, and the few sums the flight physics needs. Pure.
|
|
2
|
+
export const add = (a, b) => [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
|
|
3
|
+
export const sub = (a, b) => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
4
|
+
export const scale = (a, k) => [a[0] * k, a[1] * k, a[2] * k];
|
|
5
|
+
/** `a + b k`, the step every integrator takes. */
|
|
6
|
+
export const addScaled = (a, b, k) => [a[0] + b[0] * k, a[1] + b[1] * k, a[2] + b[2] * k];
|
|
7
|
+
export const dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
8
|
+
export const cross = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
9
|
+
export const length = (a) => Math.hypot(a[0], a[1], a[2]);
|
package/dist/react.d.ts
CHANGED
|
@@ -90,6 +90,7 @@ export declare function UchusenRocket({ build, ...rest }: UchusenRocketProps): i
|
|
|
90
90
|
accessKey?: string | undefined | undefined;
|
|
91
91
|
"aria-selected"?: (boolean | "true" | "false") | undefined;
|
|
92
92
|
hidden?: boolean | undefined | undefined;
|
|
93
|
+
lang?: string | undefined | undefined;
|
|
93
94
|
defaultChecked?: boolean | undefined | undefined;
|
|
94
95
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
95
96
|
suppressContentEditableWarning?: boolean | undefined | undefined;
|
|
@@ -101,7 +102,6 @@ export declare function UchusenRocket({ build, ...rest }: UchusenRocketProps): i
|
|
|
101
102
|
contextMenu?: string | undefined | undefined;
|
|
102
103
|
draggable?: (boolean | "true" | "false") | undefined;
|
|
103
104
|
enterKeyHint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
|
|
104
|
-
lang?: string | undefined | undefined;
|
|
105
105
|
nonce?: string | undefined | undefined;
|
|
106
106
|
spellCheck?: (boolean | "true" | "false") | undefined;
|
|
107
107
|
tabIndex?: number | undefined | undefined;
|
package/dist/rockets.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type MakerId } from "./data/makers.ts";
|
|
2
|
+
import { type CountryCode } from "./data/countries.ts";
|
|
2
3
|
import type { Figure, Variant } from "./data/types.ts";
|
|
3
4
|
import type { SourceId } from "./data/sources.ts";
|
|
4
5
|
/**
|
|
@@ -34,6 +35,8 @@ export interface RocketEntry {
|
|
|
34
35
|
maker: MakerId;
|
|
35
36
|
/** Whose it is and who built it, as its source says, or a blank. */
|
|
36
37
|
madeBy: Figure<string>;
|
|
38
|
+
/** Its country as an ISO 3166-1 alpha-2 code, as its source says, or a blank: none for a craft of several countries or an international body, or a ship of the SPX fleet. */
|
|
39
|
+
country: Figure<CountryCode>;
|
|
37
40
|
}
|
|
38
41
|
/**
|
|
39
42
|
* A rocket on the list with no mesh yet: its name and the sourced facts to build it from.
|
|
@@ -54,6 +57,8 @@ export interface PlannedRocket {
|
|
|
54
57
|
diameter: Figure;
|
|
55
58
|
firstFlight: Figure<string>;
|
|
56
59
|
source: SourceId;
|
|
60
|
+
/** Its country as an ISO 3166-1 alpha-2 code, as its source says, or a blank. */
|
|
61
|
+
country: Figure<CountryCode>;
|
|
57
62
|
}
|
|
58
63
|
/**
|
|
59
64
|
* Whether a craft flies in space: the same ones that may be seen from straight above or below, including the fleet. A rocket or a place on the ground does not. On the compare page one of these stands on a marked plinth, so it is not read as a rocket on a pad.
|
package/dist/rockets.js
CHANGED
|
@@ -21,6 +21,7 @@ import { JUPITER_C_VARIANTS } from "./data/jupiterc.js";
|
|
|
21
21
|
import { ISS_VARIANTS } from "./data/iss.js";
|
|
22
22
|
import { HUBBLE_VARIANTS } from "./data/hubble.js";
|
|
23
23
|
import { TIANGONG_VARIANTS } from "./data/tiangong.js";
|
|
24
|
+
import { ROADSTER_VARIANTS } from "./data/roadster.js";
|
|
24
25
|
import { STARSHIP_VARIANTS } from "./data/starship.js";
|
|
25
26
|
import { FLEET_KIT_ROCKETS, FLEET_SLOT_NAMES } from "./data/fleet.js";
|
|
26
27
|
import { CONCEPT_SLOT_NAMES, KAMINARI_VARIANTS } from "./data/kaminari-concepts.js";
|
|
@@ -29,8 +30,9 @@ import { KYOTORI_SLOT_NAMES, KYOTORI_VARIANTS } from "./data/ship-kyotori.js";
|
|
|
29
30
|
import { DRONE_VARIANTS } from "./data/drone.js";
|
|
30
31
|
import { ARIAKE_VARIANTS, SHIP_03_INSET_ROCKET, SHIP_03_SLOT_NAMES, SHIP_03_VARIANTS } from "./data/ship-03.js";
|
|
31
32
|
import { MADE_BY } from "./data/makers.js";
|
|
33
|
+
import { countryOf } from "./data/countries.js";
|
|
32
34
|
/** Craft that fly in space: seen from any side, from straight above or below. Everything else stands on the ground or the sea, and keeps the ground in view. */
|
|
33
|
-
const IN_SPACE = new Set(["dragon", "lunar-module", "apollo-soyuz", "gemini", "mercury", "iss", "hubble", "tiangong"]);
|
|
35
|
+
const IN_SPACE = new Set(["dragon", "lunar-module", "apollo-soyuz", "gemini", "mercury", "iss", "hubble", "tiangong", "roadster"]);
|
|
34
36
|
/**
|
|
35
37
|
* Whether a craft flies in space: the same ones that may be seen from straight above or below, including the fleet. A rocket or a place on the ground does not. On the compare page one of these stands on a marked plinth, so it is not read as a rocket on a pad.
|
|
36
38
|
*
|
|
@@ -40,11 +42,11 @@ const IN_SPACE = new Set(["dragon", "lunar-module", "apollo-soyuz", "gemini", "m
|
|
|
40
42
|
export function fliesInSpace(id) {
|
|
41
43
|
return IN_SPACE.has(id) || id in FLEET_KIT_ROCKETS || id.startsWith("fleet-");
|
|
42
44
|
}
|
|
43
|
-
/** Gives each variant its `view.tiltMax`: 90 degrees for a craft in space and the fleet, 45 for the rest. */
|
|
45
|
+
/** Gives each variant its `view.tiltMax`: 90 degrees for a craft in space and the fleet, 45 for the rest. And each rocket its country. */
|
|
44
46
|
function withTilt(rockets) {
|
|
45
47
|
return Object.fromEntries(Object.entries(rockets).map(([id, rocket]) => {
|
|
46
48
|
const tiltMax = fliesInSpace(id) ? 90 : 45;
|
|
47
|
-
return [id, { ...rocket, variants: rocket.variants.map((variant) => ({ ...variant, view: { tiltMax } })) }];
|
|
49
|
+
return [id, { ...rocket, country: countryOf(id), variants: rocket.variants.map((variant) => ({ ...variant, view: { tiltMax } })) }];
|
|
48
50
|
}));
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
@@ -78,6 +80,7 @@ export const ROCKETS = withTilt({
|
|
|
78
80
|
"iss": { id: "iss", name: "International Space Station", status: "built", ...MADE_BY["iss"], variants: ISS_VARIANTS, defaultVariant: "iss" },
|
|
79
81
|
"hubble": { id: "hubble", name: "Hubble Space Telescope", status: "built", ...MADE_BY["hubble"], variants: HUBBLE_VARIANTS, defaultVariant: "hubble" },
|
|
80
82
|
tiangong: { id: "tiangong", name: "Tiangong 天宮", status: "built", ...MADE_BY["tiangong"], variants: TIANGONG_VARIANTS, defaultVariant: "tiangong" },
|
|
83
|
+
roadster: { id: "roadster", name: "Roadster", status: "built", ...MADE_BY["roadster"], variants: ROADSTER_VARIANTS, defaultVariant: "first-generation" },
|
|
81
84
|
droneship: { id: "droneship", name: "Drone ships", status: "built", ...MADE_BY["droneship"], variants: DRONESHIP_VARIANTS, defaultVariant: "ocisly" },
|
|
82
85
|
"landing-zone": { id: "landing-zone", name: "Landing zones", status: "built", ...MADE_BY["landing-zone"], variants: LANDING_ZONE_VARIANTS, defaultVariant: "lz-1" },
|
|
83
86
|
"launch-tower": { id: "launch-tower", name: "Launch tower", status: "built", ...MADE_BY["launch-tower"], variants: TOWER_VARIANTS, defaultVariant: "stack" },
|
|
@@ -110,7 +113,7 @@ const fig = (value, source) => ({ value, source });
|
|
|
110
113
|
export const PLANNED_ROCKETS = [
|
|
111
114
|
{ id: "vulcan-centaur", name: "Vulcan Centaur", status: "planned", height: fig(61.6, "wikipedia-vulcan"), diameter: fig(5.4, "wikipedia-vulcan"), firstFlight: { value: "2024-01-08", source: "wikipedia-vulcan" }, source: "wikipedia-vulcan" },
|
|
112
115
|
{ id: "ariane-6", name: "Ariane 6", status: "planned", height: fig(63, "wikipedia-ariane-6"), diameter: fig(5.4, "wikipedia-ariane-6"), firstFlight: { value: "2024-07-09", source: "wikipedia-ariane-6" }, source: "wikipedia-ariane-6" },
|
|
113
|
-
];
|
|
116
|
+
].map((rocket) => ({ ...rocket, country: countryOf(rocket.id) }));
|
|
114
117
|
/**
|
|
115
118
|
* Finds a rocket's variant, with its sourced sizes.
|
|
116
119
|
*
|
|
@@ -235,6 +238,8 @@ export const SLOT_NAMES = {
|
|
|
235
238
|
"arrays-p6": "Solar arrays on P6",
|
|
236
239
|
"radiators-starboard": "Radiators, starboard",
|
|
237
240
|
"radiators-port": "Radiators, port",
|
|
241
|
+
car: "The Roadster",
|
|
242
|
+
starman: "Starman",
|
|
238
243
|
ground: "The ground and the road",
|
|
239
244
|
pads: "The pads",
|
|
240
245
|
"tank-farm": "The tank farm",
|
package/dist/sun.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the `sun` attribute: the direction towards the Sun in the craft's own frame (Y up, +Z its nose or windward side), as three numbers. Anything else is no Sun, and the view keeps its showroom light.
|
|
3
|
+
*
|
|
4
|
+
* @param text The attribute's text, such as `"1, 0.2, -0.5"`.
|
|
5
|
+
* @returns The direction, one metre long, or null for a missing, malformed or zero value.
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { parseSun } from "@johnmorrisdotca/uchusen-rockets";
|
|
9
|
+
*
|
|
10
|
+
* console.log(parseSun("2, 0, 0"), parseSun("east"), parseSun("0,0,0"));
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseSun(text: string | null | undefined): readonly [number, number, number] | null;
|
package/dist/sun.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Where the Sun is, for a craft drawn in space: one direction, read from text. Pure: no three.js and no DOM.
|
|
2
|
+
/**
|
|
3
|
+
* Reads the `sun` attribute: the direction towards the Sun in the craft's own frame (Y up, +Z its nose or windward side), as three numbers. Anything else is no Sun, and the view keeps its showroom light.
|
|
4
|
+
*
|
|
5
|
+
* @param text The attribute's text, such as `"1, 0.2, -0.5"`.
|
|
6
|
+
* @returns The direction, one metre long, or null for a missing, malformed or zero value.
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { parseSun } from "@johnmorrisdotca/uchusen-rockets";
|
|
10
|
+
*
|
|
11
|
+
* console.log(parseSun("2, 0, 0"), parseSun("east"), parseSun("0,0,0"));
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export function parseSun(text) {
|
|
15
|
+
if (typeof text !== "string" || text.length > 80)
|
|
16
|
+
return null;
|
|
17
|
+
const parts = text.split(",").map((one) => one.trim());
|
|
18
|
+
if (parts.length !== 3 || parts.some((one) => !/^-?(\d+\.?\d*|\.\d+)(e-?\d+)?$/i.test(one)))
|
|
19
|
+
return null;
|
|
20
|
+
const [x, y, z] = parts.map(Number);
|
|
21
|
+
const length = Math.hypot(x, y, z);
|
|
22
|
+
if (!Number.isFinite(length) || length < 1e-9)
|
|
23
|
+
return null;
|
|
24
|
+
return [x / length, y / length, z / length];
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/uchusen-rockets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Uchusen Rockets 宇宙船: line drawings and 3D views of rockets, as a web component. Every variant with its own sourced sizes, a typed way to assemble a rocket from parts, stack and separate. No logos. three.js is a peer dependency.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rocket",
|
|
@@ -74,6 +74,11 @@
|
|
|
74
74
|
"import": "./dist/journey/index.js",
|
|
75
75
|
"default": "./dist/journey/index.js"
|
|
76
76
|
},
|
|
77
|
+
"./physics": {
|
|
78
|
+
"types": "./dist/physics/index.d.ts",
|
|
79
|
+
"import": "./dist/physics/index.js",
|
|
80
|
+
"default": "./dist/physics/index.js"
|
|
81
|
+
},
|
|
77
82
|
"./element": {
|
|
78
83
|
"types": "./dist/element.d.ts",
|
|
79
84
|
"import": "./dist/element.js",
|
|
@@ -135,10 +140,14 @@
|
|
|
135
140
|
"size": "node scripts/docs-site.mjs size"
|
|
136
141
|
},
|
|
137
142
|
"peerDependencies": {
|
|
143
|
+
"@johnmorrisdotca/hata": ">=1.8.0 <2",
|
|
138
144
|
"react": ">=18",
|
|
139
145
|
"three": ">=0.170.0"
|
|
140
146
|
},
|
|
141
147
|
"peerDependenciesMeta": {
|
|
148
|
+
"@johnmorrisdotca/hata": {
|
|
149
|
+
"optional": true
|
|
150
|
+
},
|
|
142
151
|
"react": {
|
|
143
152
|
"optional": true
|
|
144
153
|
},
|
|
@@ -156,6 +165,7 @@
|
|
|
156
165
|
"@gltf-transform/extensions": "4.5.1",
|
|
157
166
|
"@gltf-transform/functions": "4.5.1",
|
|
158
167
|
"@johnmorrisdotca/chikyu-earth": "0.10.0",
|
|
168
|
+
"@johnmorrisdotca/hata": "1.8.0",
|
|
159
169
|
"@johnmorrisdotca/kazoku-ui": "^0.32.0",
|
|
160
170
|
"@johnmorrisdotca/wakusei-planets": "0.17.1",
|
|
161
171
|
"@playwright/test": "1.64.0",
|