From c8708cebad243a5f2cf14750e76a6c990c37efae Mon Sep 17 00:00:00 2001 From: Martin Asprusten Date: Mon, 30 Mar 2026 15:10:50 +0200 Subject: [PATCH] Change to set reading times for orbits separately --- src/calculations/orbit-calculations.ts | 2 +- src/gui/common.ts | 7 ++- src/gui/intercept.ts | 75 +++++++++++++++++--------- src/gui/orbit.ts | 38 ++++++++++--- src/gui/simpleplanechange.ts | 37 +++++++++---- src/gui/targetorbit.ts | 65 ++++++++++++++-------- src/style.css | 5 ++ 7 files changed, 159 insertions(+), 70 deletions(-) diff --git a/src/calculations/orbit-calculations.ts b/src/calculations/orbit-calculations.ts index 9bde6f6..be69f55 100644 --- a/src/calculations/orbit-calculations.ts +++ b/src/calculations/orbit-calculations.ts @@ -228,7 +228,7 @@ export class LambertSolutions { } } -const ZeroManoeuvre: Manoeuvre = { +export const ZeroManoeuvre: Manoeuvre = { time: 0, progradeDeltaV: 0, radialDeltaV: 0, diff --git a/src/gui/common.ts b/src/gui/common.ts index 0d64a47..d59021c 100644 --- a/src/gui/common.ts +++ b/src/gui/common.ts @@ -13,7 +13,9 @@ export interface OrbitalParameters { positionChoice: "timeToPeriapsis" | "altitude"; timeToPeriapsis: number, altitude: number, - headingInwards: boolean + headingInwards: boolean, + + currentTimeAtReading: number } export const DefaultOrbitalParameters: OrbitalParameters = { @@ -27,7 +29,8 @@ export const DefaultOrbitalParameters: OrbitalParameters = { positionChoice: "timeToPeriapsis", timeToPeriapsis: 0, altitude: 100000, - headingInwards: true + headingInwards: true, + currentTimeAtReading: 0 } export function encodeOrbitalParameters(orbitalParameters: OrbitalParameters): string { diff --git a/src/gui/intercept.ts b/src/gui/intercept.ts index 3f74dde..30bd7a9 100644 --- a/src/gui/intercept.ts +++ b/src/gui/intercept.ts @@ -4,6 +4,7 @@ import { type Body } from "../calculations/constants"; import type { FindBestInterceptMessage, ProgressMessage } from "./worker"; import type { ChangingStorageValue } from "../storage"; import { ManoeuvresGui } from "./manoeuvres"; +import { extrapolateTrajectory, type OrbitalCoordinates } from "../calculations/orbit-calculations"; export class InterceptTargetGui { currentTime: ChangingStorageValue; @@ -72,38 +73,60 @@ export class InterceptTargetGui { let startingOrbitalParameters = this.startingOrbitalParameters.getCurrentValue(); let targetOrbitalParameters = this.targetOrbitalParameters.getCurrentValue(); - let startingCoordinates = getCoordinatesFromParameters(startingOrbitalParameters, body); - let targetCoordinates = getCoordinatesFromParameters(targetOrbitalParameters, body); + let startingCoordinates: OrbitalCoordinates | null = getCoordinatesFromParameters(startingOrbitalParameters, 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(); - 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 intercept"; - this.worker = null; + if (startingCoordinates && targetCoordinates) { + 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 intercept"; + this.worker = null; + } + + if (transferResponse.bestTransfer) { + transferResponse.bestTransfer.firstManoeuvre.time += currentTime; + transferResponse.bestTransfer.secondManoeuvre.time += currentTime; + } + + this.manoeuvresGui.displayProgress(transferResponse); } + }); - if (transferResponse.bestTransfer) { - transferResponse.bestTransfer.firstManoeuvre.time += currentTime; - transferResponse.bestTransfer.secondManoeuvre.time += currentTime; - } + let workerMessage: FindBestInterceptMessage = { + type: "FindBestIntercept", + startingSituation: startingCoordinates, + targetSituation: targetCoordinates, + body: body, + additionalTrueAnomaly: additionalTrueAnomaly + }; - this.manoeuvresGui.displayProgress(transferResponse); - } - }); - - let workerMessage: FindBestInterceptMessage = { - type: "FindBestIntercept", - startingSituation: startingCoordinates, - targetSituation: targetCoordinates, - body: body, - additionalTrueAnomaly: additionalTrueAnomaly - }; - - this.worker.postMessage(workerMessage); + this.worker.postMessage(workerMessage); + } else { + this.manoeuvresGui.displayProgress({ + type: "ProgressMessage", + finished: true, + percentDone: 100, + bestDeltaV: null, + bestTransfer: null + }); + } } }); diff --git a/src/gui/orbit.ts b/src/gui/orbit.ts index 50b34c8..12ca6fd 100644 --- a/src/gui/orbit.ts +++ b/src/gui/orbit.ts @@ -9,8 +9,10 @@ export class OrbitalParametersGui { parentDiv: HTMLDivElement; orbitalParameters: ChangingStorageValue; + currentTime: ChangingStorageValue; + currentTimeGui: TimeGui; timeToPeriapsis: ChangingStorageValue; - timeGui: TimeGui; + timeToPeriapsisGui: TimeGui; altitudeData: ChangingStorageValue; altitudeGui: AltitudeGui; @@ -21,7 +23,10 @@ export class OrbitalParametersGui { this.orbitalParameters = orbitalParameters; 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.altitudeGui = new AltitudeGui(this.altitudeData); @@ -88,6 +93,17 @@ export class OrbitalParametersGui { 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 timeToPeriapsisChoiceId = crypto.randomUUID(); let altitudeChoiceId = crypto.randomUUID(); @@ -95,7 +111,7 @@ export class OrbitalParametersGui { let timeToPeriapsisButton = createRadioButton(positionChoiceId, timeToPeriapsisChoiceId); let altitudeButton = createRadioButton(positionChoiceId, altitudeChoiceId); 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"); @@ -118,7 +134,7 @@ export class OrbitalParametersGui { positionDiv.innerHTML = ""; if (value.positionChoice == "timeToPeriapsis") { timeToPeriapsisButton.setAttribute("checked", ""); - positionDiv.appendChild(this.timeGui.parentDiv); + positionDiv.appendChild(this.timeToPeriapsisGui.parentDiv); } else { altitudeButton.setAttribute("checked", ""); positionDiv.appendChild(this.altitudeGui.parentDiv); @@ -139,6 +155,7 @@ export class OrbitalParametersGui { altitude: value.altitude, headingInwards: value.headingInwards }, this.sourceId); + this.currentTime.set(value.currentTimeAtReading, this.sourceId); }); const onChange = () => { @@ -161,7 +178,8 @@ export class OrbitalParametersGui { positionChoice: timeToPeriapsisButton.checked ? "timeToPeriapsis" : "altitude", timeToPeriapsis: this.timeToPeriapsis.getCurrentValue(), 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); @@ -180,8 +198,14 @@ export class OrbitalParametersGui { altitudeButton ].forEach(input => input.addEventListener("change", onChange)); + this.currentTime.listenToValue((sourceId, _) => { + if (sourceId == this.currentTimeGui.sourceId) { + onChange(); + } + }); + this.timeToPeriapsis.listenToValue((sourceId, _) => { - if (sourceId == this.timeGui.sourceId) { + if (sourceId == this.timeToPeriapsisGui.sourceId) { onChange(); } }); @@ -190,6 +214,6 @@ export class OrbitalParametersGui { if (sourceId == this.altitudeGui.sourceId) { onChange(); } - }) + }); } } \ No newline at end of file diff --git a/src/gui/simpleplanechange.ts b/src/gui/simpleplanechange.ts index bf1251a..4ff83e8 100644 --- a/src/gui/simpleplanechange.ts +++ b/src/gui/simpleplanechange.ts @@ -3,7 +3,7 @@ import { type Body } from "../calculations/constants"; import type { ChangingStorageValue } from "../storage"; import { OrbitalParametersGui } from "./orbit"; 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"; export class SimplePlaneChangeGui { @@ -52,17 +52,32 @@ export class SimplePlaneChangeGui { let targetOrbitalParameters = this.targetOrbitalParameters.getCurrentValue(); let circularizeOrbit = this.circularizeOrbit.getCurrentValue(); - let coordinates = getCoordinatesFromParameters(startingOrbitalParameters, body); - let planeChange = calculateSimplePlaneChange( - coordinates, - body, - targetOrbitalParameters.inclination, - targetOrbitalParameters.longitudeOfAscendingNode, - circularizeOrbit - ); + let coordinates: OrbitalCoordinates | null = getCoordinatesFromParameters(startingOrbitalParameters, body); - planeChange.firstManoeuvre.time += currentTime; - planeChange.secondManoeuvre.time += currentTime; + // If we need to extrapolate the orbit, do that + 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 bestTransfer: Transfer = { diff --git a/src/gui/targetorbit.ts b/src/gui/targetorbit.ts index 1b5a76a..22865c7 100644 --- a/src/gui/targetorbit.ts +++ b/src/gui/targetorbit.ts @@ -1,4 +1,5 @@ import type { Body } from "../calculations/constants"; +import { extrapolateTrajectory, type OrbitalCoordinates } from "../calculations/orbit-calculations"; import type { ChangingStorageValue } from "../storage"; import { getCoordinatesFromParameters, getOrbitFromParameters, type OrbitalParameters } from "./common"; import { ManoeuvresGui } from "./manoeuvres"; @@ -58,35 +59,53 @@ export class TargetOrbitGui { let targetOrbitalParameters = this.targetOrbitalParameters.getCurrentValue(); let body = this.body.getCurrentValue(); - let startingCoordinates = getCoordinatesFromParameters(startingOrbitalParameters, body); + let startingCoordinates: OrbitalCoordinates | null = getCoordinatesFromParameters(startingOrbitalParameters, body); let targetOrbit = getOrbitFromParameters(targetOrbitalParameters, body.radius); - 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; + let startingTime = Math.max(currentTime, startingOrbitalParameters.currentTimeAtReading); + if (startingTime > startingOrbitalParameters.currentTimeAtReading) { + let addedTime = startingTime - startingOrbitalParameters.currentTimeAtReading; + startingCoordinates = extrapolateTrajectory(addedTime, startingCoordinates, body); + } + + 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) { - transferResponse.bestTransfer.firstManoeuvre.time += currentTime; - transferResponse.bestTransfer.secondManoeuvre.time += currentTime; - } + let workerMessage: FindBestTransferMessage = { + type: "FindBestTransfer", + 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 = { - type: "FindBestTransfer", - startingSituation: startingCoordinates, - targetOrbit: targetOrbit, - body: body - }; - - this.worker.postMessage(workerMessage); + this.manoeuvresGui.displayProgress(progressMessage); + } } }); } diff --git a/src/style.css b/src/style.css index 101da22..574ccd0 100644 --- a/src/style.css +++ b/src/style.css @@ -29,6 +29,11 @@ width: 150px; } +.orbitalParameter h5 { + margin: 0px; + padding: 0px; +} + #calculationChoice label { margin-right: 30px; }