Change to set reading times for orbits separately

This commit is contained in:
Martin Asprusten 2026-03-30 15:10:50 +02:00
parent 2b4fb65d4f
commit c8708cebad
No known key found for this signature in database
7 changed files with 159 additions and 70 deletions

View File

@ -228,7 +228,7 @@ export class LambertSolutions {
} }
} }
const ZeroManoeuvre: Manoeuvre = { export const ZeroManoeuvre: Manoeuvre = {
time: 0, time: 0,
progradeDeltaV: 0, progradeDeltaV: 0,
radialDeltaV: 0, radialDeltaV: 0,

View File

@ -13,7 +13,9 @@ export interface OrbitalParameters {
positionChoice: "timeToPeriapsis" | "altitude"; positionChoice: "timeToPeriapsis" | "altitude";
timeToPeriapsis: number, timeToPeriapsis: number,
altitude: number, altitude: number,
headingInwards: boolean headingInwards: boolean,
currentTimeAtReading: number
} }
export const DefaultOrbitalParameters: OrbitalParameters = { export const DefaultOrbitalParameters: OrbitalParameters = {
@ -27,7 +29,8 @@ export const DefaultOrbitalParameters: OrbitalParameters = {
positionChoice: "timeToPeriapsis", positionChoice: "timeToPeriapsis",
timeToPeriapsis: 0, timeToPeriapsis: 0,
altitude: 100000, altitude: 100000,
headingInwards: true headingInwards: true,
currentTimeAtReading: 0
} }
export function encodeOrbitalParameters(orbitalParameters: OrbitalParameters): string { export function encodeOrbitalParameters(orbitalParameters: OrbitalParameters): string {

View File

@ -4,6 +4,7 @@ import { type Body } from "../calculations/constants";
import type { FindBestInterceptMessage, ProgressMessage } from "./worker"; import type { FindBestInterceptMessage, ProgressMessage } from "./worker";
import type { ChangingStorageValue } from "../storage"; import type { ChangingStorageValue } from "../storage";
import { ManoeuvresGui } from "./manoeuvres"; import { ManoeuvresGui } from "./manoeuvres";
import { extrapolateTrajectory, type OrbitalCoordinates } from "../calculations/orbit-calculations";
export class InterceptTargetGui { export class InterceptTargetGui {
currentTime: ChangingStorageValue<number>; currentTime: ChangingStorageValue<number>;
@ -72,38 +73,60 @@ export class InterceptTargetGui {
let startingOrbitalParameters = this.startingOrbitalParameters.getCurrentValue(); let startingOrbitalParameters = this.startingOrbitalParameters.getCurrentValue();
let targetOrbitalParameters = this.targetOrbitalParameters.getCurrentValue(); let targetOrbitalParameters = this.targetOrbitalParameters.getCurrentValue();
let startingCoordinates = getCoordinatesFromParameters(startingOrbitalParameters, body); let startingCoordinates: OrbitalCoordinates | null = getCoordinatesFromParameters(startingOrbitalParameters, body);
let targetCoordinates = getCoordinatesFromParameters(targetOrbitalParameters, body); let targetCoordinates: OrbitalCoordinates | null = getCoordinatesFromParameters(targetOrbitalParameters, body);
let startTime = Math.max(currentTime, startingOrbitalParameters.currentTimeAtReading, targetOrbitalParameters.currentTimeAtReading);
if (startTime > startingOrbitalParameters.currentTimeAtReading) {
let addedTime = startTime - startingOrbitalParameters.currentTimeAtReading;
startingCoordinates = extrapolateTrajectory(addedTime, startingCoordinates, body);
}
if (startTime > targetOrbitalParameters.currentTimeAtReading) {
let addedTime = startTime - targetOrbitalParameters.currentTimeAtReading;
targetCoordinates = extrapolateTrajectory(addedTime, targetCoordinates, body);
}
let additionalTrueAnomaly = this.additionalTrueAnomaly.getCurrentValue(); let additionalTrueAnomaly = this.additionalTrueAnomaly.getCurrentValue();
this.worker = new Worker(new URL('./worker.ts', import.meta.url), {type: 'module'}); if (startingCoordinates && targetCoordinates) {
this.worker.addEventListener("message", event => { this.worker = new Worker(new URL('./worker.ts', import.meta.url), {type: 'module'});
let transferResponse = event.data as ProgressMessage; this.worker.addEventListener("message", event => {
if (transferResponse) { let transferResponse = event.data as ProgressMessage;
if (transferResponse.finished) { if (transferResponse) {
searchButton.innerHTML = "Search for cheapest intercept"; if (transferResponse.finished) {
this.worker = null; searchButton.innerHTML = "Search for cheapest intercept";
this.worker = null;
}
if (transferResponse.bestTransfer) {
transferResponse.bestTransfer.firstManoeuvre.time += currentTime;
transferResponse.bestTransfer.secondManoeuvre.time += currentTime;
}
this.manoeuvresGui.displayProgress(transferResponse);
} }
});
if (transferResponse.bestTransfer) { let workerMessage: FindBestInterceptMessage = {
transferResponse.bestTransfer.firstManoeuvre.time += currentTime; type: "FindBestIntercept",
transferResponse.bestTransfer.secondManoeuvre.time += currentTime; startingSituation: startingCoordinates,
} targetSituation: targetCoordinates,
body: body,
additionalTrueAnomaly: additionalTrueAnomaly
};
this.manoeuvresGui.displayProgress(transferResponse); this.worker.postMessage(workerMessage);
} } else {
}); this.manoeuvresGui.displayProgress({
type: "ProgressMessage",
let workerMessage: FindBestInterceptMessage = { finished: true,
type: "FindBestIntercept", percentDone: 100,
startingSituation: startingCoordinates, bestDeltaV: null,
targetSituation: targetCoordinates, bestTransfer: null
body: body, });
additionalTrueAnomaly: additionalTrueAnomaly }
};
this.worker.postMessage(workerMessage);
} }
}); });

View File

@ -9,8 +9,10 @@ export class OrbitalParametersGui {
parentDiv: HTMLDivElement; parentDiv: HTMLDivElement;
orbitalParameters: ChangingStorageValue<OrbitalParameters>; orbitalParameters: ChangingStorageValue<OrbitalParameters>;
currentTime: ChangingStorageValue<number>;
currentTimeGui: TimeGui;
timeToPeriapsis: ChangingStorageValue<number>; timeToPeriapsis: ChangingStorageValue<number>;
timeGui: TimeGui; timeToPeriapsisGui: TimeGui;
altitudeData: ChangingStorageValue<AltitudeData>; altitudeData: ChangingStorageValue<AltitudeData>;
altitudeGui: AltitudeGui; altitudeGui: AltitudeGui;
@ -21,7 +23,10 @@ export class OrbitalParametersGui {
this.orbitalParameters = orbitalParameters; this.orbitalParameters = orbitalParameters;
this.timeToPeriapsis = new ChangingStorageValue(orbitalParameters.getCurrentValue().timeToPeriapsis); this.timeToPeriapsis = new ChangingStorageValue(orbitalParameters.getCurrentValue().timeToPeriapsis);
this.timeGui = new TimeGui(this.timeToPeriapsis, false); this.timeToPeriapsisGui = new TimeGui(this.timeToPeriapsis, false);
this.currentTime = new ChangingStorageValue(orbitalParameters.getCurrentValue().currentTimeAtReading);
this.currentTimeGui = new TimeGui(this.currentTime, true);
this.altitudeData = new ChangingStorageValue({altitude: orbitalParameters.getCurrentValue().altitude, headingInwards: orbitalParameters.getCurrentValue().headingInwards}); this.altitudeData = new ChangingStorageValue({altitude: orbitalParameters.getCurrentValue().altitude, headingInwards: orbitalParameters.getCurrentValue().headingInwards});
this.altitudeGui = new AltitudeGui(this.altitudeData); this.altitudeGui = new AltitudeGui(this.altitudeData);
@ -88,6 +93,17 @@ export class OrbitalParametersGui {
addToParent([createLabel(aopId, "Argument of periapsis:"), aopInput], this.parentDiv); addToParent([createLabel(aopId, "Argument of periapsis:"), aopInput], this.parentDiv);
} }
let currentTimeHeader = document.createElement("h5");
currentTimeHeader.appendChild(document.createTextNode("Time of reading:"));
if (guiType == "orbitWithPosition") {
addToParent(currentTimeHeader, this.parentDiv);
this.parentDiv.appendChild(this.currentTimeGui.parentDiv);
}
let positionHeader = document.createElement("h5");
positionHeader.appendChild(document.createTextNode("Position in orbit:"));
let positionChoiceId = crypto.randomUUID(); let positionChoiceId = crypto.randomUUID();
let timeToPeriapsisChoiceId = crypto.randomUUID(); let timeToPeriapsisChoiceId = crypto.randomUUID();
let altitudeChoiceId = crypto.randomUUID(); let altitudeChoiceId = crypto.randomUUID();
@ -95,7 +111,7 @@ export class OrbitalParametersGui {
let timeToPeriapsisButton = createRadioButton(positionChoiceId, timeToPeriapsisChoiceId); let timeToPeriapsisButton = createRadioButton(positionChoiceId, timeToPeriapsisChoiceId);
let altitudeButton = createRadioButton(positionChoiceId, altitudeChoiceId); let altitudeButton = createRadioButton(positionChoiceId, altitudeChoiceId);
if (guiType == "orbitWithPosition") { if (guiType == "orbitWithPosition") {
addToParent([timeToPeriapsisButton, createLabel(timeToPeriapsisChoiceId, "Use time to periapsis"), altitudeButton, createLabel(altitudeChoiceId, "Use altitude")], this.parentDiv); addToParent([positionHeader, timeToPeriapsisButton, createLabel(timeToPeriapsisChoiceId, "Use time to periapsis"), altitudeButton, createLabel(altitudeChoiceId, "Use altitude")], this.parentDiv);
} }
let positionDiv = document.createElement("div"); let positionDiv = document.createElement("div");
@ -118,7 +134,7 @@ export class OrbitalParametersGui {
positionDiv.innerHTML = ""; positionDiv.innerHTML = "";
if (value.positionChoice == "timeToPeriapsis") { if (value.positionChoice == "timeToPeriapsis") {
timeToPeriapsisButton.setAttribute("checked", ""); timeToPeriapsisButton.setAttribute("checked", "");
positionDiv.appendChild(this.timeGui.parentDiv); positionDiv.appendChild(this.timeToPeriapsisGui.parentDiv);
} else { } else {
altitudeButton.setAttribute("checked", ""); altitudeButton.setAttribute("checked", "");
positionDiv.appendChild(this.altitudeGui.parentDiv); positionDiv.appendChild(this.altitudeGui.parentDiv);
@ -139,6 +155,7 @@ export class OrbitalParametersGui {
altitude: value.altitude, altitude: value.altitude,
headingInwards: value.headingInwards headingInwards: value.headingInwards
}, this.sourceId); }, this.sourceId);
this.currentTime.set(value.currentTimeAtReading, this.sourceId);
}); });
const onChange = () => { const onChange = () => {
@ -161,7 +178,8 @@ export class OrbitalParametersGui {
positionChoice: timeToPeriapsisButton.checked ? "timeToPeriapsis" : "altitude", positionChoice: timeToPeriapsisButton.checked ? "timeToPeriapsis" : "altitude",
timeToPeriapsis: this.timeToPeriapsis.getCurrentValue(), timeToPeriapsis: this.timeToPeriapsis.getCurrentValue(),
altitude: this.altitudeData.getCurrentValue().altitude, altitude: this.altitudeData.getCurrentValue().altitude,
headingInwards: this.altitudeData.getCurrentValue().headingInwards headingInwards: this.altitudeData.getCurrentValue().headingInwards,
currentTimeAtReading: this.currentTime.getCurrentValue()
}; };
this.orbitalParameters.set(newOrbitalParameters, this.sourceId); this.orbitalParameters.set(newOrbitalParameters, this.sourceId);
@ -180,8 +198,14 @@ export class OrbitalParametersGui {
altitudeButton altitudeButton
].forEach(input => input.addEventListener("change", onChange)); ].forEach(input => input.addEventListener("change", onChange));
this.currentTime.listenToValue((sourceId, _) => {
if (sourceId == this.currentTimeGui.sourceId) {
onChange();
}
});
this.timeToPeriapsis.listenToValue((sourceId, _) => { this.timeToPeriapsis.listenToValue((sourceId, _) => {
if (sourceId == this.timeGui.sourceId) { if (sourceId == this.timeToPeriapsisGui.sourceId) {
onChange(); onChange();
} }
}); });
@ -190,6 +214,6 @@ export class OrbitalParametersGui {
if (sourceId == this.altitudeGui.sourceId) { if (sourceId == this.altitudeGui.sourceId) {
onChange(); onChange();
} }
}) });
} }
} }

View File

@ -3,7 +3,7 @@ import { type Body } from "../calculations/constants";
import type { ChangingStorageValue } from "../storage"; import type { ChangingStorageValue } from "../storage";
import { OrbitalParametersGui } from "./orbit"; import { OrbitalParametersGui } from "./orbit";
import { ManoeuvresGui } from "./manoeuvres"; import { ManoeuvresGui } from "./manoeuvres";
import { calculateSimplePlaneChange, type Transfer } from "../calculations/orbit-calculations"; import { calculateSimplePlaneChange, extrapolateTrajectory, ZeroManoeuvre, type OrbitalCoordinates, type SimplePlaneChange, type Transfer } from "../calculations/orbit-calculations";
import { type ProgressMessage } from "./worker"; import { type ProgressMessage } from "./worker";
export class SimplePlaneChangeGui { export class SimplePlaneChangeGui {
@ -52,17 +52,32 @@ export class SimplePlaneChangeGui {
let targetOrbitalParameters = this.targetOrbitalParameters.getCurrentValue(); let targetOrbitalParameters = this.targetOrbitalParameters.getCurrentValue();
let circularizeOrbit = this.circularizeOrbit.getCurrentValue(); let circularizeOrbit = this.circularizeOrbit.getCurrentValue();
let coordinates = getCoordinatesFromParameters(startingOrbitalParameters, body); let coordinates: OrbitalCoordinates | null = getCoordinatesFromParameters(startingOrbitalParameters, body);
let planeChange = calculateSimplePlaneChange(
coordinates,
body,
targetOrbitalParameters.inclination,
targetOrbitalParameters.longitudeOfAscendingNode,
circularizeOrbit
);
planeChange.firstManoeuvre.time += currentTime; // If we need to extrapolate the orbit, do that
planeChange.secondManoeuvre.time += currentTime; let startingTime = Math.max(currentTime, startingOrbitalParameters.currentTimeAtReading);
if (startingTime > startingOrbitalParameters.currentTimeAtReading) {
let addedTime = startingTime - startingOrbitalParameters.currentTimeAtReading;
coordinates = extrapolateTrajectory(addedTime, coordinates, body);
}
let planeChange: SimplePlaneChange = {
firstManoeuvre: ZeroManoeuvre,
secondManoeuvre: ZeroManoeuvre
}
if (coordinates) {
planeChange = calculateSimplePlaneChange(
coordinates,
body,
targetOrbitalParameters.inclination,
targetOrbitalParameters.longitudeOfAscendingNode,
circularizeOrbit
);
}
planeChange.firstManoeuvre.time += startingTime;
planeChange.secondManoeuvre.time += startingTime;
let bestDeltaV = Math.min(planeChange.firstManoeuvre.totalDeltaV, planeChange.secondManoeuvre.totalDeltaV); let bestDeltaV = Math.min(planeChange.firstManoeuvre.totalDeltaV, planeChange.secondManoeuvre.totalDeltaV);
let bestTransfer: Transfer = { let bestTransfer: Transfer = {

View File

@ -1,4 +1,5 @@
import type { Body } from "../calculations/constants"; import type { Body } from "../calculations/constants";
import { extrapolateTrajectory, type OrbitalCoordinates } from "../calculations/orbit-calculations";
import type { ChangingStorageValue } from "../storage"; import type { ChangingStorageValue } from "../storage";
import { getCoordinatesFromParameters, getOrbitFromParameters, type OrbitalParameters } from "./common"; import { getCoordinatesFromParameters, getOrbitFromParameters, type OrbitalParameters } from "./common";
import { ManoeuvresGui } from "./manoeuvres"; import { ManoeuvresGui } from "./manoeuvres";
@ -58,35 +59,53 @@ export class TargetOrbitGui {
let targetOrbitalParameters = this.targetOrbitalParameters.getCurrentValue(); let targetOrbitalParameters = this.targetOrbitalParameters.getCurrentValue();
let body = this.body.getCurrentValue(); let body = this.body.getCurrentValue();
let startingCoordinates = getCoordinatesFromParameters(startingOrbitalParameters, body); let startingCoordinates: OrbitalCoordinates | null = getCoordinatesFromParameters(startingOrbitalParameters, body);
let targetOrbit = getOrbitFromParameters(targetOrbitalParameters, body.radius); let targetOrbit = getOrbitFromParameters(targetOrbitalParameters, body.radius);
this.worker = new Worker(new URL('./worker.ts', import.meta.url), {type: 'module'}); let startingTime = Math.max(currentTime, startingOrbitalParameters.currentTimeAtReading);
this.worker.addEventListener("message", event => { if (startingTime > startingOrbitalParameters.currentTimeAtReading) {
let transferResponse = event.data as ProgressMessage; let addedTime = startingTime - startingOrbitalParameters.currentTimeAtReading;
if (transferResponse) { startingCoordinates = extrapolateTrajectory(addedTime, startingCoordinates, body);
if (transferResponse.finished) { }
searchButton.innerHTML = "Search for cheapest transfer";
this.worker = null; if (startingCoordinates) {
this.worker = new Worker(new URL('./worker.ts', import.meta.url), {type: 'module'});
this.worker.addEventListener("message", event => {
let transferResponse = event.data as ProgressMessage;
if (transferResponse) {
if (transferResponse.finished) {
searchButton.innerHTML = "Search for cheapest transfer";
this.worker = null;
}
if (transferResponse.bestTransfer) {
transferResponse.bestTransfer.firstManoeuvre.time += currentTime;
transferResponse.bestTransfer.secondManoeuvre.time += currentTime;
}
this.manoeuvresGui.displayProgress(transferResponse);
} }
});
if (transferResponse.bestTransfer) { let workerMessage: FindBestTransferMessage = {
transferResponse.bestTransfer.firstManoeuvre.time += currentTime; type: "FindBestTransfer",
transferResponse.bestTransfer.secondManoeuvre.time += currentTime; startingSituation: startingCoordinates,
} targetOrbit: targetOrbit,
body: body
};
this.manoeuvresGui.displayProgress(transferResponse); this.worker.postMessage(workerMessage);
} } else {
}); let progressMessage: ProgressMessage = {
type: "ProgressMessage",
percentDone: 100,
finished: true,
bestDeltaV: null,
bestTransfer: null
};
let workerMessage: FindBestTransferMessage = { this.manoeuvresGui.displayProgress(progressMessage);
type: "FindBestTransfer", }
startingSituation: startingCoordinates,
targetOrbit: targetOrbit,
body: body
};
this.worker.postMessage(workerMessage);
} }
}); });
} }

View File

@ -29,6 +29,11 @@
width: 150px; width: 150px;
} }
.orbitalParameter h5 {
margin: 0px;
padding: 0px;
}
#calculationChoice label { #calculationChoice label {
margin-right: 30px; margin-right: 30px;
} }