mirror of
https://github.com/Krafpy/KSP-MGA-Planner.git
synced 2025-12-12 07:40:41 -08:00
Added trajectory to text conversion.
This commit is contained in:
8
dist/main/editor/editor.js
vendored
8
dist/main/editor/editor.js
vendored
@@ -15,6 +15,7 @@ import { Trajectory } from "../solvers/trajectory.js";
|
||||
import { Selector } from "./selector.js";
|
||||
import { DiscreteRange } from "./range.js";
|
||||
import { loadBodiesData, loadConfig } from "../utilities/data.js";
|
||||
import { trajectoryToText } from "../utilities/trajectory-text.js";
|
||||
export async function initEditorWithSystem(systems, systemIndex) {
|
||||
const canvas = document.getElementById("three-canvas");
|
||||
const width = canvas.clientWidth;
|
||||
@@ -179,8 +180,8 @@ export async function initEditorWithSystem(systems, systemIndex) {
|
||||
if (trajectory)
|
||||
trajectory.remove();
|
||||
};
|
||||
const displayFoundTrajectory = () => {
|
||||
trajectory = new Trajectory(solver.bestSteps, system, config);
|
||||
const displayFoundTrajectory = (sequence) => {
|
||||
trajectory = new Trajectory(solver, system, config);
|
||||
trajectory.draw(canvas);
|
||||
trajectory.fillResultControls(resultItems, systemTime, controls);
|
||||
systemTime.input(() => {
|
||||
@@ -192,6 +193,7 @@ export async function initEditorWithSystem(systems, systemIndex) {
|
||||
stepSlider.enable();
|
||||
trajectory.updatePodPosition(systemTime);
|
||||
console.log(solver.bestDeltaV);
|
||||
console.log(trajectoryToText(trajectory, sequence));
|
||||
};
|
||||
const findTrajectory = async () => {
|
||||
paramsErr.hide();
|
||||
@@ -225,7 +227,7 @@ export async function initEditorWithSystem(systems, systemIndex) {
|
||||
const perfStart = performance.now();
|
||||
await solver.searchOptimalTrajectory(sequence, userSettings);
|
||||
console.log(`Search time: ${performance.now() - perfStart} ms`);
|
||||
displayFoundTrajectory();
|
||||
displayFoundTrajectory(sequence);
|
||||
}
|
||||
catch (err) {
|
||||
if (err instanceof Error && err.message != "TRAJECTORY FINDER CANCELLED")
|
||||
|
||||
13
dist/main/solvers/sequence.js
vendored
13
dist/main/solvers/sequence.js
vendored
@@ -1,3 +1,4 @@
|
||||
import { joinStrings } from "../utilities/array.js";
|
||||
export class FlybySequence {
|
||||
constructor(system, ids) {
|
||||
this.ids = ids;
|
||||
@@ -6,12 +7,12 @@ export class FlybySequence {
|
||||
this.bodies.push(system.bodyFromId(id));
|
||||
}
|
||||
this.length = this.bodies.length;
|
||||
const getSubstr = (i) => this.bodies[i].name.substring(0, 2);
|
||||
let str = getSubstr(0);
|
||||
for (let i = 1; i < this.length; i++) {
|
||||
str += "-" + getSubstr(i);
|
||||
}
|
||||
this.seqString = str;
|
||||
const initials = this.bodies.map((body) => body.name.substring(0, 2));
|
||||
this.seqString = joinStrings(initials, "-");
|
||||
}
|
||||
get seqStringFullNames() {
|
||||
const names = this.bodies.map((body) => body.name);
|
||||
return joinStrings(names, "-");
|
||||
}
|
||||
static fromString(str, system) {
|
||||
str = str.trim();
|
||||
|
||||
31
dist/main/solvers/trajectory.js
vendored
31
dist/main/solvers/trajectory.js
vendored
@@ -3,18 +3,19 @@ import { Orbit } from "../objects/orbit.js";
|
||||
import { KSPTime } from "../time/time.js";
|
||||
import { SpriteManager } from "../utilities/sprites.js";
|
||||
export class Trajectory {
|
||||
constructor(steps, system, config) {
|
||||
this.steps = steps;
|
||||
constructor(solver, system, config) {
|
||||
this.solver = solver;
|
||||
this.system = system;
|
||||
this.config = config;
|
||||
this._orbitObjects = [];
|
||||
this._spriteObjects = [];
|
||||
this._podSpriteIndex = 0;
|
||||
this.orbits = [];
|
||||
this._maneuvres = [];
|
||||
this._flybys = [];
|
||||
this.maneuvres = [];
|
||||
this.flybys = [];
|
||||
this._displayedSteps = [];
|
||||
this._spritesUpdateFunId = -1;
|
||||
this.steps = solver.bestSteps;
|
||||
for (const { orbitElts, attractorId } of this.steps) {
|
||||
const attractor = this.system.bodyFromId(attractorId);
|
||||
const orbit = Orbit.fromOrbitalElements(orbitElts, attractor, config.orbit);
|
||||
@@ -158,15 +159,17 @@ export class Trajectory {
|
||||
progradeDV: progradeDir.dot(deltaV),
|
||||
normalDV: normalDir.dot(deltaV),
|
||||
radialDV: radialDir.dot(deltaV),
|
||||
totalDV: deltaV.length(),
|
||||
ejectAngle: ejectAngle
|
||||
};
|
||||
this._maneuvres.push(details);
|
||||
this.maneuvres.push(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
_calculateFlybyDetails() {
|
||||
const departureDate = this.steps[0].dateOfStart;
|
||||
for (const { flyby } of this.steps) {
|
||||
for (let i = 0; i < this.steps.length; i++) {
|
||||
const { flyby } = this.steps[i];
|
||||
if (flyby) {
|
||||
const body = this.system.bodyFromId(flyby.bodyId);
|
||||
let inc = flyby.inclination * 57.2957795131;
|
||||
@@ -178,14 +181,14 @@ export class Trajectory {
|
||||
periAltitude: (flyby.periRadius - body.radius) / 1000,
|
||||
inclinationDeg: inc
|
||||
};
|
||||
this._flybys.push(details);
|
||||
this.flybys.push(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
fillResultControls(resultItems, systemTime, controls) {
|
||||
const depDate = KSPTime(this.steps[0].dateOfStart, this.config.time);
|
||||
const arrDate = KSPTime(this.steps[this.steps.length - 1].dateOfStart, this.config.time);
|
||||
resultItems.totalDVSpan.innerHTML = this._totalDeltaV.toFixed(1);
|
||||
resultItems.totalDVSpan.innerHTML = this.totalDeltaV.toFixed(1);
|
||||
resultItems.depDateSpan.innerHTML = depDate.stringYDHMS("hms", "ut");
|
||||
resultItems.arrDateSpan.innerHTML = arrDate.stringYDHMS("hms", "ut");
|
||||
const onDateClick = (date) => () => {
|
||||
@@ -207,7 +210,7 @@ export class Trajectory {
|
||||
for (let i = 0; i < this.steps.length; i++) {
|
||||
const { maneuvre, flyby } = this.steps[i];
|
||||
if (maneuvre) {
|
||||
const details = this._maneuvres[maneuvreIdx];
|
||||
const details = this.maneuvres[maneuvreIdx];
|
||||
const step = this.steps[details.stepIndex];
|
||||
const context = step.maneuvre.context;
|
||||
let optionName;
|
||||
@@ -233,7 +236,7 @@ export class Trajectory {
|
||||
selectorOptions.push(option);
|
||||
}
|
||||
else if (flyby) {
|
||||
const details = this._flybys[flybyIdx];
|
||||
const details = this.flybys[flybyIdx];
|
||||
const bodyName = this.system.bodyFromId(details.bodyId).name;
|
||||
const optionName = `${++optionNumber}: ${bodyName} flyby`;
|
||||
const option = {
|
||||
@@ -251,7 +254,7 @@ export class Trajectory {
|
||||
detailsSelector.change((_, index) => {
|
||||
const option = selectorOptions[index];
|
||||
if (option.type == "maneuver") {
|
||||
const details = this._maneuvres[option.origin];
|
||||
const details = this.maneuvres[option.origin];
|
||||
const dateEMT = KSPTime(details.dateMET, this.config.time);
|
||||
resultItems.dateSpan.innerHTML = dateEMT.stringYDHMS("hm", "emt");
|
||||
resultItems.progradeDVSpan.innerHTML = details.progradeDV.toFixed(1);
|
||||
@@ -272,7 +275,7 @@ export class Trajectory {
|
||||
resultItems.maneuverDiv.hidden = false;
|
||||
}
|
||||
else if (option.type == "flyby") {
|
||||
const details = this._flybys[option.origin];
|
||||
const details = this.flybys[option.origin];
|
||||
const startDateEMT = KSPTime(details.soiEnterDateMET, this.config.time);
|
||||
const endDateEMT = KSPTime(details.soiExitDateMET, this.config.time);
|
||||
resultItems.startDateSpan.innerHTML = startDateEMT.stringYDHMS("hm", "emt");
|
||||
@@ -336,9 +339,9 @@ export class Trajectory {
|
||||
pod.position.set(pos.x, pos.y, pos.z);
|
||||
pod.position.multiplyScalar(scale);
|
||||
}
|
||||
get _totalDeltaV() {
|
||||
get totalDeltaV() {
|
||||
let total = 0;
|
||||
for (const details of this._maneuvres) {
|
||||
for (const details of this.maneuvres) {
|
||||
const x = details.progradeDV;
|
||||
const y = details.normalDV;
|
||||
const z = details.radialDV;
|
||||
|
||||
9
dist/main/utilities/array.js
vendored
9
dist/main/utilities/array.js
vendored
@@ -23,3 +23,12 @@ export function shuffleArray(array) {
|
||||
array[j] = tmp;
|
||||
}
|
||||
}
|
||||
export function joinStrings(arr, sep) {
|
||||
if (arr.length == 0)
|
||||
return "";
|
||||
let str = arr[0];
|
||||
for (let i = 1; i < arr.length; i++) {
|
||||
str += sep + arr[i];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
87
dist/main/utilities/trajectory-text.js
vendored
Normal file
87
dist/main/utilities/trajectory-text.js
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
import { KSPTime } from "../time/time.js";
|
||||
import { joinStrings } from "./array.js";
|
||||
export function trajectoryToText(traj, seq) {
|
||||
const { steps, system, config } = traj;
|
||||
const pairs = [];
|
||||
const add = (label, data, indent) => {
|
||||
pairs.push({ label, data, indent });
|
||||
};
|
||||
const space = () => add("", "", 0);
|
||||
add("Sequence", seq.seqStringFullNames, 0);
|
||||
const depDate = KSPTime(steps[0].dateOfStart, config.time);
|
||||
const arrDate = KSPTime(steps[steps.length - 1].dateOfStart, config.time);
|
||||
add("Departure", depDate.stringYDHMS("hms", "ut"), 0);
|
||||
add("Arrival", arrDate.stringYDHMS("hms", "ut"), 0);
|
||||
add("Total ΔV", `${traj.totalDeltaV.toFixed(1)} m/s`, 0);
|
||||
space();
|
||||
add("Steps", "", 0);
|
||||
let maneuvreIdx = 0, flybyIdx = 0;
|
||||
for (let i = 0; i < steps.length; i++) {
|
||||
const { maneuvre, flyby } = steps[i];
|
||||
if (maneuvre) {
|
||||
space();
|
||||
const step = steps[i];
|
||||
const details = traj.maneuvres[maneuvreIdx];
|
||||
const context = step.maneuvre.context;
|
||||
const { progradeDV, normalDV, radialDV, totalDV } = details;
|
||||
let label;
|
||||
if (context.type == "ejection") {
|
||||
const startBodyName = system.bodyFromId(step.attractorId).name;
|
||||
label = `${startBodyName} escape`;
|
||||
}
|
||||
else if (context.type == "dsm") {
|
||||
const originName = system.bodyFromId(context.originId).name;
|
||||
const targetName = system.bodyFromId(context.targetId).name;
|
||||
label = `${originName}-${targetName} DSM`;
|
||||
}
|
||||
else {
|
||||
const arrivalBodyName = system.bodyFromId(step.attractorId).name;
|
||||
label = `${arrivalBodyName} circularization`;
|
||||
}
|
||||
add(label, "", 1);
|
||||
add("Date", KSPTime(details.dateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2);
|
||||
if (details.ejectAngle !== undefined) {
|
||||
add("Ejection angle", `${details.ejectAngle.toFixed(1)}°`, 2);
|
||||
}
|
||||
add("ΔV", `${totalDV.toFixed(1)} m/s`, 2);
|
||||
add("Prograde", `${progradeDV.toFixed(1)}`, 3);
|
||||
add("Normal", `${normalDV.toFixed(1)}`, 3);
|
||||
add("Radial", `${radialDV.toFixed(1)}`, 3);
|
||||
maneuvreIdx++;
|
||||
}
|
||||
else if (flyby) {
|
||||
space();
|
||||
const details = traj.flybys[flybyIdx];
|
||||
const bodyName = system.bodyFromId(details.bodyId).name;
|
||||
add(`Flyby around ${bodyName}`, "", 1);
|
||||
add("SOI enter date", KSPTime(details.soiEnterDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2);
|
||||
add("SOI exit date", KSPTime(details.soiExitDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2);
|
||||
add("Periapsis altitude", `${details.periAltitude.toFixed(0)} km`, 2);
|
||||
add("Inclination", `${details.inclinationDeg.toFixed(0)}°`, 2);
|
||||
flybyIdx++;
|
||||
}
|
||||
}
|
||||
return pairsToString(pairs);
|
||||
}
|
||||
function pairsToString(pairs) {
|
||||
const lines = [];
|
||||
for (const pair of pairs) {
|
||||
if (pair.label == "") {
|
||||
lines.push("");
|
||||
continue;
|
||||
}
|
||||
let indent = " ".repeat(pair.indent * 2);
|
||||
lines.push(`${indent}${pair.label}:`);
|
||||
}
|
||||
let maxLen = 0;
|
||||
for (const line of lines) {
|
||||
maxLen = Math.max(maxLen, line.length);
|
||||
}
|
||||
for (let i = 0; i < pairs.length; i++) {
|
||||
if (pairs[i].label == "" || pairs[i].data == "")
|
||||
continue;
|
||||
const spaces = " ".repeat(maxLen - lines[i].length + 1);
|
||||
lines[i] += spaces + pairs[i].data;
|
||||
}
|
||||
return joinStrings(lines, "\n");
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import { Selector } from "./selector.js";
|
||||
import { DiscreteRange } from "./range.js";
|
||||
import { OrbitingBody } from "../objects/body.js";
|
||||
import { loadBodiesData, loadConfig } from "../utilities/data.js";
|
||||
import { trajectoryToText } from "../utilities/trajectory-text.js";
|
||||
|
||||
|
||||
export async function initEditorWithSystem(systems: SolarSystemData[], systemIndex: number){
|
||||
@@ -240,8 +241,8 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd
|
||||
if(trajectory) trajectory.remove();
|
||||
}
|
||||
|
||||
const displayFoundTrajectory = () => {
|
||||
trajectory = new Trajectory(solver.bestSteps, system, config);
|
||||
const displayFoundTrajectory = (sequence: FlybySequence) => {
|
||||
trajectory = new Trajectory(solver, system, config);
|
||||
trajectory.draw(canvas);
|
||||
trajectory.fillResultControls(resultItems, systemTime, controls);
|
||||
|
||||
@@ -256,6 +257,8 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd
|
||||
trajectory.updatePodPosition(systemTime);
|
||||
|
||||
console.log(solver.bestDeltaV);
|
||||
|
||||
console.log(trajectoryToText(trajectory, sequence));
|
||||
};
|
||||
|
||||
const findTrajectory = async () => {
|
||||
@@ -298,7 +301,7 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd
|
||||
await solver.searchOptimalTrajectory(sequence, userSettings);
|
||||
console.log(`Search time: ${performance.now() - perfStart} ms`);
|
||||
|
||||
displayFoundTrajectory();
|
||||
displayFoundTrajectory(sequence);
|
||||
|
||||
} catch(err) {
|
||||
if(err instanceof Error && err.message != "TRAJECTORY FINDER CANCELLED")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { OrbitingBody } from "../objects/body";
|
||||
import { SolarSystem } from "../objects/system";
|
||||
import { OrbitingBody } from "../objects/body.js";
|
||||
import { SolarSystem } from "../objects/system.js";
|
||||
import { joinStrings } from "../utilities/array.js";
|
||||
|
||||
export class FlybySequence {
|
||||
public readonly bodies!: OrbitingBody[];
|
||||
@@ -13,12 +14,13 @@ export class FlybySequence {
|
||||
}
|
||||
this.length = this.bodies.length;
|
||||
|
||||
const getSubstr = (i: number) => this.bodies[i].name.substring(0, 2);
|
||||
let str = getSubstr(0);
|
||||
for(let i = 1; i < this.length; i++){
|
||||
str += "-" + getSubstr(i);
|
||||
}
|
||||
this.seqString = str;
|
||||
const initials = this.bodies.map((body: OrbitingBody) => body.name.substring(0, 2));
|
||||
this.seqString = joinStrings(initials, "-");
|
||||
}
|
||||
|
||||
get seqStringFullNames(){
|
||||
const names = this.bodies.map((body: OrbitingBody) => body.name);
|
||||
return joinStrings(names, "-");
|
||||
}
|
||||
|
||||
static fromString(str: string, system: SolarSystem){
|
||||
|
||||
@@ -6,21 +6,24 @@ import { KSPTime } from "../time/time.js";
|
||||
import { CameraController } from "../objects/camera.js";
|
||||
import { SpriteManager } from "../utilities/sprites.js";
|
||||
import { OrbitingBody } from "../objects/body.js";
|
||||
import { TrajectorySolver } from "./trajectory-solver.js";
|
||||
|
||||
export class Trajectory {
|
||||
private _orbitObjects: THREE.Object3D[] = [];
|
||||
private _spriteObjects: THREE.Sprite[][] = [];
|
||||
private _podSpriteIndex: number = 0;
|
||||
|
||||
public readonly steps: TrajectoryStep[];
|
||||
public readonly orbits: Orbit[] = [];
|
||||
|
||||
private readonly _maneuvres: ManeuvreDetails[] = [];
|
||||
private readonly _flybys: FlybyDetails[] = [];
|
||||
public readonly maneuvres: ManeuvreDetails[] = [];
|
||||
public readonly flybys: FlybyDetails[] = [];
|
||||
|
||||
private _displayedSteps: boolean[] = [];
|
||||
private _spritesUpdateFunId: number = -1;
|
||||
|
||||
constructor(public readonly steps: TrajectoryStep[], public readonly system: SolarSystem, public readonly config: Config) {
|
||||
constructor(public readonly solver: TrajectorySolver, public readonly system: SolarSystem, public readonly config: Config) {
|
||||
this.steps = solver.bestSteps;
|
||||
for(const {orbitElts, attractorId} of this.steps) {
|
||||
const attractor = this.system.bodyFromId(attractorId);
|
||||
const orbit = Orbit.fromOrbitalElements(orbitElts, attractor, config.orbit);
|
||||
@@ -224,16 +227,17 @@ export class Trajectory {
|
||||
ejectAngle = Math.acos(cosA) * 180 / Math.PI;
|
||||
ejectAngle *= Math.sign(u.x*v.y - u.y*v.x); // counter clockwise direction of the angle
|
||||
}
|
||||
|
||||
|
||||
const details = {
|
||||
stepIndex: i,
|
||||
dateMET: step.dateOfStart - departureDate,
|
||||
progradeDV: progradeDir.dot(deltaV),
|
||||
normalDV: normalDir.dot(deltaV),
|
||||
radialDV: radialDir.dot(deltaV),
|
||||
totalDV: deltaV.length(),
|
||||
ejectAngle: ejectAngle
|
||||
};
|
||||
this._maneuvres.push(details);
|
||||
this.maneuvres.push(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +247,8 @@ export class Trajectory {
|
||||
*/
|
||||
private _calculateFlybyDetails(){
|
||||
const departureDate = this.steps[0].dateOfStart;
|
||||
for(const {flyby} of this.steps){
|
||||
for(let i = 0; i < this.steps.length; i++){
|
||||
const {flyby} = this.steps[i];
|
||||
if(flyby){
|
||||
const body = this.system.bodyFromId(flyby.bodyId);
|
||||
// non oriented inclination compared to x-z plane
|
||||
@@ -256,7 +261,7 @@ export class Trajectory {
|
||||
periAltitude: (flyby.periRadius - body.radius) / 1000, // in km
|
||||
inclinationDeg: inc
|
||||
}
|
||||
this._flybys.push(details);
|
||||
this.flybys.push(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,7 +277,7 @@ export class Trajectory {
|
||||
const arrDate = KSPTime(this.steps[this.steps.length-1].dateOfStart, this.config.time);
|
||||
|
||||
// total delta-V
|
||||
resultItems.totalDVSpan.innerHTML = this._totalDeltaV.toFixed(1);
|
||||
resultItems.totalDVSpan.innerHTML = this.totalDeltaV.toFixed(1);
|
||||
// departure date
|
||||
resultItems.depDateSpan.innerHTML = depDate.stringYDHMS("hms", "ut");
|
||||
// arrival date
|
||||
@@ -305,7 +310,7 @@ export class Trajectory {
|
||||
for(let i = 0; i < this.steps.length; i++){
|
||||
const {maneuvre, flyby} = this.steps[i];
|
||||
if(maneuvre){
|
||||
const details = this._maneuvres[maneuvreIdx];
|
||||
const details = this.maneuvres[maneuvreIdx];
|
||||
const step = this.steps[details.stepIndex];
|
||||
const context = (<ManeuvreInfo>step.maneuvre).context;
|
||||
|
||||
@@ -333,7 +338,7 @@ export class Trajectory {
|
||||
|
||||
} else if(flyby){
|
||||
// details the options in the selector, if it's a flyby
|
||||
const details = this._flybys[flybyIdx];
|
||||
const details = this.flybys[flybyIdx];
|
||||
const bodyName = this.system.bodyFromId(details.bodyId).name;
|
||||
const optionName = `${++optionNumber}: ${bodyName} flyby`;
|
||||
|
||||
@@ -358,7 +363,7 @@ export class Trajectory {
|
||||
const option = selectorOptions[index];
|
||||
|
||||
if(option.type == "maneuver"){
|
||||
const details = this._maneuvres[option.origin];
|
||||
const details = this.maneuvres[option.origin];
|
||||
const dateEMT = KSPTime(details.dateMET, this.config.time);
|
||||
|
||||
resultItems.dateSpan.innerHTML = dateEMT.stringYDHMS("hm", "emt");
|
||||
@@ -382,7 +387,7 @@ export class Trajectory {
|
||||
resultItems.maneuverDiv.hidden = false;
|
||||
|
||||
} else if(option.type == "flyby"){
|
||||
const details = this._flybys[option.origin];
|
||||
const details = this.flybys[option.origin];
|
||||
const startDateEMT = KSPTime(details.soiEnterDateMET, this.config.time);
|
||||
const endDateEMT = KSPTime(details.soiExitDateMET, this.config.time);
|
||||
|
||||
@@ -478,9 +483,9 @@ export class Trajectory {
|
||||
/**
|
||||
* Computes and returns the total delta-V of the trajectory
|
||||
*/
|
||||
private get _totalDeltaV(){
|
||||
public get totalDeltaV(){
|
||||
let total = 0;
|
||||
for(const details of this._maneuvres){
|
||||
for(const details of this.maneuvres){
|
||||
const x = details.progradeDV;
|
||||
const y = details.normalDV;
|
||||
const z = details.radialDV;
|
||||
|
||||
@@ -24,4 +24,14 @@ export function shuffleArray<T>(array: T[]){
|
||||
array[i] = array[j];
|
||||
array[j] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
export function joinStrings(arr: string[], sep: string){
|
||||
if(arr.length == 0)
|
||||
return "";
|
||||
let str = arr[0];
|
||||
for(let i = 1; i < arr.length; i++){
|
||||
str += sep + arr[i];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
102
src/main/utilities/trajectory-text.ts
Normal file
102
src/main/utilities/trajectory-text.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { FlybySequence } from "../solvers/sequence.js";
|
||||
import { Trajectory } from "../solvers/trajectory.js";
|
||||
import { KSPTime } from "../time/time.js";
|
||||
import { joinStrings } from "./array.js";
|
||||
|
||||
type pair = {label: string, data: string, indent: number};
|
||||
|
||||
export function trajectoryToText(traj: Trajectory, seq: FlybySequence) {
|
||||
const {steps, system, config} = traj;
|
||||
|
||||
const pairs: pair[] = [];
|
||||
const add = (label: string, data: string, indent: number) => {
|
||||
pairs.push({label, data, indent} as pair);
|
||||
};
|
||||
const space = () => add("", "", 0);
|
||||
|
||||
|
||||
add("Sequence", seq.seqStringFullNames, 0);
|
||||
|
||||
const depDate = KSPTime(steps[0].dateOfStart, config.time);
|
||||
const arrDate = KSPTime(steps[steps.length-1].dateOfStart, config.time);
|
||||
add("Departure", depDate.stringYDHMS("hms", "ut"), 0);
|
||||
add("Arrival", arrDate.stringYDHMS("hms", "ut"), 0);
|
||||
add("Total ΔV", `${traj.totalDeltaV.toFixed(1)} m/s`, 0);
|
||||
space();
|
||||
add("Steps", "", 0);
|
||||
|
||||
let maneuvreIdx = 0, flybyIdx = 0;
|
||||
|
||||
for(let i = 0; i < steps.length; i++){
|
||||
const {maneuvre, flyby} = steps[i];
|
||||
if(maneuvre){
|
||||
space();
|
||||
const step = steps[i];
|
||||
const details = traj.maneuvres[maneuvreIdx];
|
||||
const context = (<ManeuvreInfo>step.maneuvre).context;
|
||||
const {progradeDV, normalDV, radialDV, totalDV} = details;
|
||||
|
||||
let label: string;
|
||||
if(context.type == "ejection") {
|
||||
const startBodyName = system.bodyFromId(step.attractorId).name;
|
||||
label = `${startBodyName} escape`;
|
||||
} else if(context.type == "dsm") {
|
||||
const originName = system.bodyFromId(context.originId).name;
|
||||
const targetName = system.bodyFromId(context.targetId).name;
|
||||
label = `${originName}-${targetName} DSM`;
|
||||
} else {
|
||||
const arrivalBodyName = system.bodyFromId(step.attractorId).name;
|
||||
label = `${arrivalBodyName} circularization`;
|
||||
}
|
||||
add(label, "", 1);
|
||||
add("Date", KSPTime(details.dateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2);
|
||||
if(details.ejectAngle !== undefined){
|
||||
add("Ejection angle", `${details.ejectAngle.toFixed(1)}°`, 2);
|
||||
}
|
||||
add("ΔV", `${totalDV.toFixed(1)} m/s`, 2);
|
||||
add("Prograde", `${progradeDV.toFixed(1)}`, 3);
|
||||
add("Normal", `${normalDV.toFixed(1)}`, 3);
|
||||
add("Radial", `${radialDV.toFixed(1)}`, 3);
|
||||
|
||||
maneuvreIdx++;
|
||||
|
||||
} else if(flyby){
|
||||
space();
|
||||
const details = traj.flybys[flybyIdx];
|
||||
const bodyName = system.bodyFromId(details.bodyId).name;
|
||||
add(`Flyby around ${bodyName}`, "", 1);
|
||||
add("SOI enter date", KSPTime(details.soiEnterDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2);
|
||||
add("SOI exit date", KSPTime(details.soiExitDateMET, config.time).stringYDHMS("hms", "emt") + " MET", 2);
|
||||
add("Periapsis altitude", `${details.periAltitude.toFixed(0)} km`, 2);
|
||||
add("Inclination", `${details.inclinationDeg.toFixed(0)}°`, 2);
|
||||
|
||||
flybyIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
return pairsToString(pairs);
|
||||
}
|
||||
|
||||
|
||||
function pairsToString(pairs: pair[]){
|
||||
const lines: string[] = [];
|
||||
for(const pair of pairs){
|
||||
if(pair.label == "") {
|
||||
lines.push("");
|
||||
continue;
|
||||
}
|
||||
let indent = " ".repeat(pair.indent*2);
|
||||
lines.push(`${indent}${pair.label}:`);
|
||||
}
|
||||
let maxLen = 0;
|
||||
for(const line of lines){
|
||||
maxLen = Math.max(maxLen, line.length);
|
||||
}
|
||||
for(let i = 0; i < pairs.length; i++){
|
||||
if(pairs[i].label == "" || pairs[i].data == "")
|
||||
continue;
|
||||
const spaces = " ".repeat(maxLen - lines[i].length + 1);
|
||||
lines[i] += spaces + pairs[i].data;
|
||||
}
|
||||
return joinStrings(lines, "\n");
|
||||
}
|
||||
1
src/types.d.ts
vendored
1
src/types.d.ts
vendored
@@ -299,6 +299,7 @@ type ManeuvreDetails = {
|
||||
progradeDV: number,
|
||||
normalDV: number,
|
||||
radialDV: number,
|
||||
totalDV: number,
|
||||
ejectAngle?: number
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user