Simplified interpolation
This commit is contained in:
parent
dd63c64443
commit
b3366eba01
@ -1,5 +1,5 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en-US">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/png" href="/satellite.png" />
|
<link rel="icon" type="image/png" href="/satellite.png" />
|
||||||
|
|||||||
@ -133,6 +133,20 @@ export function addVector(vectorOne: number[][], vectorTwo: number[][]): number[
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addVectors(vectors: number[][][]) {
|
||||||
|
let resultVector = [
|
||||||
|
[0],
|
||||||
|
[0],
|
||||||
|
[0]
|
||||||
|
];
|
||||||
|
|
||||||
|
vectors.forEach(vector => {
|
||||||
|
resultVector = addVector(resultVector, vector);
|
||||||
|
});
|
||||||
|
|
||||||
|
return resultVector;
|
||||||
|
}
|
||||||
|
|
||||||
export function addMatrix(matrixOne: number[][], matrixTwo: number[][]): number[][] {
|
export function addMatrix(matrixOne: number[][], matrixTwo: number[][]): number[][] {
|
||||||
if (!checkIfValidMatrix(matrixOne) || !checkIfValidMatrix(matrixTwo)) {
|
if (!checkIfValidMatrix(matrixOne) || !checkIfValidMatrix(matrixTwo)) {
|
||||||
throw new TypeError("Two valid matrices are required");
|
throw new TypeError("Two valid matrices are required");
|
||||||
@ -227,3 +241,32 @@ export function multiplyMatrixWithScalar(scalar: number, matrix: number[][]): nu
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function invertTwoByTwoMatrix(matrix: number[][]): number[][] {
|
||||||
|
if (!checkIfValidMatrix(matrix)) {
|
||||||
|
throw new TypeError("A valid matrix is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matrix.length != 2) {
|
||||||
|
throw new TypeError("Can only invert 2x2 matrices");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matrix[0].length != 2) {
|
||||||
|
throw new TypeError("Can only invert 2x2 matrices");
|
||||||
|
}
|
||||||
|
|
||||||
|
let divisor = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
|
||||||
|
|
||||||
|
let multiplier = 1 / divisor;
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
matrix[1][1] * multiplier,
|
||||||
|
-matrix[0][1] * multiplier
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-matrix[1][0] * multiplier,
|
||||||
|
matrix[0][0] * multiplier
|
||||||
|
]
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import type { InterpolationParameters } from "../gui/interpolate";
|
import type { InterpolationParameters } from "../gui/interpolate";
|
||||||
import type { Body } from "./constants";
|
import type { Body } from "./constants";
|
||||||
import { addMatrix, addVector, getVectorMagnitude, matrixMultiply, multiplyMatrixWithScalar, normalizeVector, subtractVector, vectorCrossProduct, vectorDotProduct } from "./mathematics";
|
import { addMatrix, addVector, getVectorMagnitude, invertTwoByTwoMatrix, matrixMultiply, multiplyMatrixWithScalar, normalizeVector, subtractVector, vectorCrossProduct, vectorDotProduct } from "./mathematics";
|
||||||
|
|
||||||
export interface Orbit {
|
export interface Orbit {
|
||||||
semiLatusRectum: number,
|
semiLatusRectum: number,
|
||||||
@ -362,7 +362,14 @@ export function getEccentricAndTrueAnomalyFromMeanAnomaly(meanAnomaly: number, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getOrbitalCoordinates(timeToPeriapsis: number, orbit: Orbit, planet: Body): OrbitalCoordinates {
|
export function getOrbitalCoordinates(timeToPeriapsis: number, orbit: Orbit, planet: Body): OrbitalCoordinates {
|
||||||
const meanAngularMotion = Math.sqrt(planet.gravitationalParameter * Math.abs(1 - orbit.eccentricity**2)**3 / orbit.semiLatusRectum**3);
|
let meanAngularMotion;
|
||||||
|
|
||||||
|
if (Math.abs(orbit.eccentricity - 1) < 0.0001) {
|
||||||
|
meanAngularMotion = Math.sqrt(8 * planet.gravitationalParameter / orbit.semiLatusRectum**3);
|
||||||
|
} else {
|
||||||
|
meanAngularMotion = Math.sqrt(planet.gravitationalParameter * Math.abs(1 - orbit.eccentricity**2)**3 / orbit.semiLatusRectum**3);
|
||||||
|
}
|
||||||
|
|
||||||
const meanAnomaly = meanAngularMotion * -timeToPeriapsis;
|
const meanAnomaly = meanAngularMotion * -timeToPeriapsis;
|
||||||
|
|
||||||
|
|
||||||
@ -412,9 +419,11 @@ export function getOrbitalCoordinatesFromAltitude(altitude: number, headingInwar
|
|||||||
|
|
||||||
let eccentricAnomaly;
|
let eccentricAnomaly;
|
||||||
let meanAnomaly;
|
let meanAnomaly;
|
||||||
|
let meanAngularMotion: number | null = null;
|
||||||
if (Math.abs(orbit.eccentricity - 1) < 0.0001) {
|
if (Math.abs(orbit.eccentricity - 1) < 0.0001) {
|
||||||
eccentricAnomaly = trueAnomaly;
|
eccentricAnomaly = trueAnomaly;
|
||||||
meanAnomaly = eccentricAnomaly;
|
meanAnomaly = Math.sqrt(2) * (Math.tan(trueAnomaly / 2) + Math.tan(trueAnomaly / 2)**3 / 3);
|
||||||
|
meanAngularMotion = Math.sqrt(8 * planet.gravitationalParameter / orbit.semiLatusRectum**3);
|
||||||
} else if (orbit.eccentricity < 1) {
|
} else if (orbit.eccentricity < 1) {
|
||||||
eccentricAnomaly = Math.atan2(Math.sqrt(1 - orbit.eccentricity**2)*Math.sin(trueAnomaly), orbit.eccentricity + Math.cos(trueAnomaly));
|
eccentricAnomaly = Math.atan2(Math.sqrt(1 - orbit.eccentricity**2)*Math.sin(trueAnomaly), orbit.eccentricity + Math.cos(trueAnomaly));
|
||||||
meanAnomaly = eccentricAnomaly - orbit.eccentricity * Math.sin(eccentricAnomaly);
|
meanAnomaly = eccentricAnomaly - orbit.eccentricity * Math.sin(eccentricAnomaly);
|
||||||
@ -423,7 +432,9 @@ export function getOrbitalCoordinatesFromAltitude(altitude: number, headingInwar
|
|||||||
meanAnomaly = orbit.eccentricity * Math.sinh(eccentricAnomaly) - eccentricAnomaly;
|
meanAnomaly = orbit.eccentricity * Math.sinh(eccentricAnomaly) - eccentricAnomaly;
|
||||||
}
|
}
|
||||||
|
|
||||||
const meanAngularMotion = Math.sqrt(planet.gravitationalParameter * Math.abs(1 - orbit.eccentricity**2)**3 / orbit.semiLatusRectum**3);
|
if (meanAngularMotion == null) {
|
||||||
|
meanAngularMotion = Math.sqrt(planet.gravitationalParameter * Math.abs(1 - orbit.eccentricity**2)**3 / orbit.semiLatusRectum**3);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
orbit: orbit,
|
orbit: orbit,
|
||||||
@ -977,6 +988,10 @@ export function findCheapestIntercept(startingSituation: OrbitalCoordinates, tar
|
|||||||
let startOrbitMeanAnomaly = startingSituation.meanAnomaly + startTime * startingSituation.meanAngularMotion;
|
let startOrbitMeanAnomaly = startingSituation.meanAnomaly + startTime * startingSituation.meanAngularMotion;
|
||||||
let endOrbitMeanAnomaly = targetSituation.meanAnomaly + endTime * targetSituation.meanAngularMotion;
|
let endOrbitMeanAnomaly = targetSituation.meanAnomaly + endTime * targetSituation.meanAngularMotion;
|
||||||
|
|
||||||
|
if (Math.abs(startingSituation.orbit.eccentricity - 1) < 0.0001) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
let extraStartOrbits = Math.floor(startOrbitMeanAnomaly / (2 * Math.PI));
|
let extraStartOrbits = Math.floor(startOrbitMeanAnomaly / (2 * Math.PI));
|
||||||
let extraEndOrbits = Math.floor(endOrbitMeanAnomaly / (2 * Math.PI));
|
let extraEndOrbits = Math.floor(endOrbitMeanAnomaly / (2 * Math.PI));
|
||||||
|
|
||||||
@ -1141,7 +1156,7 @@ export function findCheapestLanding(startingCoordinates: OrbitalCoordinates, sta
|
|||||||
let position = startingPosition;
|
let position = startingPosition;
|
||||||
|
|
||||||
let mass = ship.mass;
|
let mass = ship.mass;
|
||||||
let massUse = ship.thrust / ship.specificImpulse;
|
let massUse = ship.thrust / (ship.specificImpulse * 9.81);
|
||||||
|
|
||||||
let timeSteps = 0;
|
let timeSteps = 0;
|
||||||
let lengthOfStep = 0.01;
|
let lengthOfStep = 0.01;
|
||||||
@ -1369,261 +1384,326 @@ export function findOrbitThroughInterpolation(ownCoordinates: OrbitalCoordinates
|
|||||||
return trueAnomaly;
|
return trueAnomaly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ownFirstTrueAnomaly = getTrueAnomalyFromAltitude(interpolationParameters.firstOwnAltitude, ownCoordinates.orbit.semiLatusRectum, ownCoordinates.orbit.eccentricity, ownShipHeadedInwards);
|
||||||
|
const ownSecondTrueAnomaly = getTrueAnomalyFromAltitude(interpolationParameters.secondOwnAltitude, ownCoordinates.orbit.semiLatusRectum, ownCoordinates.orbit.eccentricity, ownShipHeadedInwards);
|
||||||
|
|
||||||
const getPossibleTargetVectors = (ownOrbit: Orbit, ownAltitude: number, targetAltitude: number, distanceToTarget: number): [number[][], number[][], number[][], number, number] => {
|
const targetFirstTrueAnomaly = getTrueAnomalyFromAltitude(interpolationParameters.firstTargetAltitude, targetSemiLatusRectum, targetEccentricity, targetHeadedInwards);
|
||||||
let ownTrueAnomaly = getTrueAnomalyFromAltitude(ownAltitude, ownOrbit.semiLatusRectum, ownOrbit.eccentricity, ownShipHeadedInwards);
|
const targetSecondTrueAnomaly = getTrueAnomalyFromAltitude(interpolationParameters.secondTargetAltitude, targetSemiLatusRectum, targetEccentricity, targetHeadedInwards);
|
||||||
|
|
||||||
let ownLocalX = ownAltitude * Math.cos(ownTrueAnomaly);
|
const getVectors = (trueAnomaly: number, orbit: Orbit) => {
|
||||||
let ownLocalY = ownAltitude * Math.sin(ownTrueAnomaly);
|
const radius = orbit.semiLatusRectum / (1 + orbit.eccentricity * Math.cos(trueAnomaly));
|
||||||
|
const localX = radius * Math.cos(trueAnomaly);
|
||||||
|
const localY = radius * Math.sin(trueAnomaly);
|
||||||
|
|
||||||
let ownDirection = normalizeVector(
|
const vectorPointingTowardsShip = normalizeVector(
|
||||||
addVector(
|
addVector(
|
||||||
multiplyMatrixWithScalar(ownLocalX, ownOrbit.coordinateAxes[0]),
|
multiplyMatrixWithScalar(localX, orbit.coordinateAxes[0]),
|
||||||
multiplyMatrixWithScalar(ownLocalY, ownOrbit.coordinateAxes[1])
|
multiplyMatrixWithScalar(localY, orbit.coordinateAxes[1])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
let perpendicularInPlane = normalizeVector(vectorCrossProduct(ownOrbit.coordinateAxes[2], ownDirection));
|
const perpendicularVectorInPlane = normalizeVector(
|
||||||
let perpendicularOutOfPlane = normalizeVector(vectorCrossProduct(ownDirection, perpendicularInPlane));
|
vectorCrossProduct(orbit.coordinateAxes[2], vectorPointingTowardsShip)
|
||||||
|
|
||||||
// Find phase angle to target
|
|
||||||
let phaseAngle = Math.acos((ownAltitude**2 + targetAltitude**2 - distanceToTarget**2) / (2 * ownAltitude * targetAltitude));
|
|
||||||
|
|
||||||
let distanceAlongDirection = targetAltitude * Math.cos(phaseAngle);
|
|
||||||
let distanceAlongNormal = targetAltitude * Math.sin(phaseAngle);
|
|
||||||
|
|
||||||
let root = multiplyMatrixWithScalar(distanceAlongDirection, ownDirection);
|
|
||||||
let vectorOne = multiplyMatrixWithScalar(distanceAlongNormal, perpendicularInPlane);
|
|
||||||
let vectorTwo = multiplyMatrixWithScalar(distanceAlongNormal, perpendicularOutOfPlane);
|
|
||||||
|
|
||||||
return [root, vectorOne, vectorTwo, distanceAlongDirection, distanceAlongNormal];
|
|
||||||
}
|
|
||||||
|
|
||||||
let firstPositionPossibleVectors = getPossibleTargetVectors(ownCoordinates.orbit, interpolationParameters.firstOwnAltitude, interpolationParameters.firstTargetAltitude, interpolationParameters.firstDistance);
|
|
||||||
let secondPositionPossibleVectors = getPossibleTargetVectors(ownCoordinates.orbit, interpolationParameters.secondOwnAltitude, interpolationParameters.secondTargetAltitude, interpolationParameters.secondDistance);
|
|
||||||
|
|
||||||
let targetFirstTrueAnomaly = getTrueAnomalyFromAltitude(interpolationParameters.firstTargetAltitude, targetSemiLatusRectum, targetEccentricity, targetHeadedInwards);
|
|
||||||
let targetSecondTrueAnomaly = getTrueAnomalyFromAltitude(interpolationParameters.secondTargetAltitude, targetSemiLatusRectum, targetEccentricity, targetHeadedInwards);
|
|
||||||
|
|
||||||
let c1 = firstPositionPossibleVectors[0];
|
|
||||||
let p11 = firstPositionPossibleVectors[1];
|
|
||||||
let p12 = firstPositionPossibleVectors[2];
|
|
||||||
|
|
||||||
let c2 = secondPositionPossibleVectors[0];
|
|
||||||
let p21 = secondPositionPossibleVectors[1];
|
|
||||||
let p22 = secondPositionPossibleVectors[2];
|
|
||||||
|
|
||||||
// Scale everything to avoid numerical explosions
|
|
||||||
let scaleFactor = 1 / getVectorMagnitude(c2);
|
|
||||||
|
|
||||||
c1 = multiplyMatrixWithScalar(scaleFactor, c1);
|
|
||||||
p11 = multiplyMatrixWithScalar(scaleFactor, p11);
|
|
||||||
p12 = multiplyMatrixWithScalar(scaleFactor, p12);
|
|
||||||
c2 = multiplyMatrixWithScalar(scaleFactor, c2);
|
|
||||||
p21 = multiplyMatrixWithScalar(scaleFactor, p21);
|
|
||||||
p22 = multiplyMatrixWithScalar(scaleFactor, p22);
|
|
||||||
|
|
||||||
let scaledAltitudeOne = interpolationParameters.firstTargetAltitude * scaleFactor;
|
|
||||||
let scaledAltitudeTwo = interpolationParameters.secondTargetAltitude * scaleFactor;
|
|
||||||
|
|
||||||
const constantPart = scaledAltitudeOne * scaledAltitudeTwo * Math.cos(targetSecondTrueAnomaly - targetFirstTrueAnomaly);
|
|
||||||
|
|
||||||
const functionToMinimize = (angleOne: number, angleTwo: number) => {
|
|
||||||
let d1 = addVector(c1, addVector(
|
|
||||||
multiplyMatrixWithScalar(Math.cos(angleOne), p11),
|
|
||||||
multiplyMatrixWithScalar(Math.sin(angleOne), p12)
|
|
||||||
));
|
|
||||||
|
|
||||||
let d2 = addVector(c2, addVector(
|
|
||||||
multiplyMatrixWithScalar(Math.cos(angleTwo), p21),
|
|
||||||
multiplyMatrixWithScalar(Math.sin(angleTwo), p22)
|
|
||||||
));
|
|
||||||
|
|
||||||
return vectorDotProduct(d1, d2) - constantPart;
|
|
||||||
}
|
|
||||||
|
|
||||||
const partialDerivativeAngleOne = (angleOne: number, angleTwo: number) => {
|
|
||||||
let d2 = addVector(c2, addVector(
|
|
||||||
multiplyMatrixWithScalar(Math.cos(angleTwo), p21),
|
|
||||||
multiplyMatrixWithScalar(Math.sin(angleTwo), p22)
|
|
||||||
));
|
|
||||||
|
|
||||||
let d1Dx = addVector(
|
|
||||||
multiplyMatrixWithScalar(-Math.sin(angleOne), p11),
|
|
||||||
multiplyMatrixWithScalar(Math.cos(angleOne), p12)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return vectorDotProduct(d1Dx, d2);
|
const perpendicularVectorOutOfPlane = orbit.coordinateAxes[2];
|
||||||
|
|
||||||
|
return [vectorPointingTowardsShip, perpendicularVectorInPlane, perpendicularVectorOutOfPlane];
|
||||||
}
|
}
|
||||||
|
|
||||||
const partialDerivativeAngleTwo = (angleOne: number, angleTwo: number) => {
|
const firstVectors = getVectors(ownFirstTrueAnomaly, ownCoordinates.orbit);
|
||||||
let d1 = addVector(c1, addVector(
|
const secondVectors = getVectors(ownSecondTrueAnomaly, ownCoordinates.orbit);
|
||||||
multiplyMatrixWithScalar(Math.cos(angleOne), p11),
|
|
||||||
multiplyMatrixWithScalar(Math.sin(angleOne), p12)
|
|
||||||
));
|
|
||||||
|
|
||||||
let d2Dy = addVector(
|
const getDistances = (ownAltitude: number, targetAltitude: number, targetDistance: number) => {
|
||||||
multiplyMatrixWithScalar(-Math.sin(angleTwo), p21),
|
const angleBetweenPlanetAndTarget = Math.acos((ownAltitude**2 + targetAltitude**2 - targetDistance**2) / (2*ownAltitude*targetAltitude));
|
||||||
multiplyMatrixWithScalar(Math.cos(angleTwo), p22)
|
const distanceAlongDirection = Math.cos(angleBetweenPlanetAndTarget) * targetAltitude;
|
||||||
|
const distanceAlongPerpendicular = Math.sin(angleBetweenPlanetAndTarget) * targetAltitude;
|
||||||
|
|
||||||
|
return [distanceAlongDirection, distanceAlongPerpendicular];
|
||||||
|
}
|
||||||
|
|
||||||
|
const [firstDistanceAlongDirection, firstDistancePerpendicularToDirection] = getDistances(interpolationParameters.firstOwnAltitude, interpolationParameters.firstTargetAltitude, interpolationParameters.firstDistance);
|
||||||
|
const [secondDistanceAlongDirection, secondDistancePerpendicularToDirection] = getDistances(interpolationParameters.secondOwnAltitude, interpolationParameters.secondTargetAltitude, interpolationParameters.secondDistance);
|
||||||
|
|
||||||
|
const phaseAngleDifference = (ownSecondTrueAnomaly + interpolationParameters.secondPhaseAngle) - (ownFirstTrueAnomaly + interpolationParameters.firstPhaseAngle);
|
||||||
|
|
||||||
|
// Now, try some Newton's method to estimate the two position's the target has gone through
|
||||||
|
|
||||||
|
// To avoid the maths exploding, we'll scale everything down a bit
|
||||||
|
const scaleFactor = 1;
|
||||||
|
|
||||||
|
const c1 = multiplyMatrixWithScalar(firstDistanceAlongDirection * scaleFactor, firstVectors[0]);
|
||||||
|
const n11 = multiplyMatrixWithScalar(firstDistancePerpendicularToDirection * scaleFactor, firstVectors[1]);
|
||||||
|
const n12 = multiplyMatrixWithScalar(firstDistancePerpendicularToDirection * scaleFactor, firstVectors[2]);
|
||||||
|
|
||||||
|
const c2 = multiplyMatrixWithScalar(secondDistanceAlongDirection * scaleFactor, secondVectors[0]);
|
||||||
|
const n21 = multiplyMatrixWithScalar(secondDistancePerpendicularToDirection * scaleFactor, secondVectors[1]);
|
||||||
|
const n22 = multiplyMatrixWithScalar(secondDistancePerpendicularToDirection * scaleFactor, secondVectors[2]);
|
||||||
|
|
||||||
|
let expectedDistance = Math.sqrt(interpolationParameters.firstTargetAltitude**2 + interpolationParameters.secondTargetAltitude**2 - 2 * interpolationParameters.firstTargetAltitude * interpolationParameters.secondTargetAltitude * Math.cos(targetSecondTrueAnomaly - targetFirstTrueAnomaly));
|
||||||
|
// Scale the expected distance too
|
||||||
|
expectedDistance *= scaleFactor;
|
||||||
|
|
||||||
|
const distanceFunction = (angleOne: number, angleTwo: number) => {
|
||||||
|
let p1 = addVector(
|
||||||
|
c1,
|
||||||
|
addVector(
|
||||||
|
multiplyMatrixWithScalar(Math.cos(angleOne), n11),
|
||||||
|
multiplyMatrixWithScalar(Math.sin(angleOne), n12)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return vectorDotProduct(d1, d2Dy);
|
let p2 = addVector(
|
||||||
|
c2,
|
||||||
|
addVector(
|
||||||
|
multiplyMatrixWithScalar(Math.cos(angleTwo), n21),
|
||||||
|
multiplyMatrixWithScalar(Math.sin(angleTwo), n22)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return getVectorMagnitude(addVector(p2, multiplyMatrixWithScalar(-1, p1))) - expectedDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
let firstOwnTrueAnomaly = getTrueAnomalyFromAltitude(interpolationParameters.firstOwnAltitude, ownCoordinates.orbit.semiLatusRectum, ownCoordinates.orbit.eccentricity, ownShipHeadedInwards);
|
const distancePartialDerivativeAngleOne = (angleOne: number, angleTwo: number) => {
|
||||||
let secondOwnTrueAnomaly = getTrueAnomalyFromAltitude(interpolationParameters.secondOwnAltitude, ownCoordinates.orbit.semiLatusRectum, ownCoordinates.orbit.eccentricity, ownShipHeadedInwards);
|
let distance = distanceFunction(angleOne, angleTwo) + expectedDistance;
|
||||||
|
return (
|
||||||
let horizontalAngleDifference = (secondOwnTrueAnomaly - interpolationParameters.secondPhaseAngle) - (firstOwnTrueAnomaly - interpolationParameters.firstPhaseAngle);
|
Math.sin(angleOne) * vectorDotProduct(n11, c2)
|
||||||
|
+ Math.sin(angleOne) * Math.cos(angleTwo) * vectorDotProduct(n21, n11)
|
||||||
const phaseAngleFunction = (angleOne: number, angleTwo: number): number => {
|
- Math.sin(angleOne) * Math.cos(angleOne) * vectorDotProduct(n11, n11)
|
||||||
let d1 = addVector(c1, multiplyMatrixWithScalar(Math.cos(angleOne), p11));
|
- Math.cos(angleOne) * vectorDotProduct(n12, c2)
|
||||||
let d2 = addVector(c2, multiplyMatrixWithScalar(Math.cos(angleTwo), p21));
|
- Math.cos(angleOne) * Math.sin(angleTwo) * vectorDotProduct(n12, n22)
|
||||||
return vectorDotProduct(d1, d2) - Math.cos(horizontalAngleDifference) * getVectorMagnitude(d1) * getVectorMagnitude(d2);
|
+ Math.sin(angleOne) * Math.sin(angleOne) * vectorDotProduct(n12, n12)
|
||||||
|
) / distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
const phaseAnglePartialDerivativeAngleOne = (angleOne: number, angleTwo: number) => {
|
const distancePartialDerivativeAngleTwo = (angleOne: number, angleTwo: number) => {
|
||||||
let d1 = addVector(c1, multiplyMatrixWithScalar(Math.cos(angleOne), p11));
|
let distance = distanceFunction(angleOne, angleTwo) + expectedDistance;
|
||||||
let d1Dx = multiplyMatrixWithScalar(-Math.sin(angleOne), p11);
|
return (
|
||||||
let d2 = addVector(c2, multiplyMatrixWithScalar(Math.cos(angleTwo), p21));
|
Math.cos(angleTwo) * Math.sin(angleTwo) * vectorDotProduct(n22, n22)
|
||||||
|
- Math.cos(angleTwo) * vectorDotProduct(n22, c1)
|
||||||
return vectorDotProduct(d1Dx, d2) - Math.cos(horizontalAngleDifference) * getVectorMagnitude(d2) * Math.sin(angleOne) * Math.cos(angleOne) * firstPositionPossibleVectors[4]**2 / getVectorMagnitude(d1);
|
- Math.cos(angleTwo) * Math.sin(angleOne) * vectorDotProduct(n22, n12)
|
||||||
|
- Math.sin(angleTwo) * Math.cos(angleTwo) * vectorDotProduct(n21, n21)
|
||||||
|
+ Math.sin(angleTwo) * vectorDotProduct(n21, c1)
|
||||||
|
+ Math.sin(angleTwo) * Math.cos(angleOne) * vectorDotProduct(n21, n11)
|
||||||
|
) / distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const planeAngleFunction = (angleOne: number, angleTwo: number) => {
|
||||||
|
const horizontalOne = addVector(
|
||||||
|
c1,
|
||||||
|
multiplyMatrixWithScalar(Math.cos(angleOne), n11)
|
||||||
|
);
|
||||||
|
|
||||||
const gradientDescent = (startingGuessAngleOne: number, startingGuessAngleTwo: number): [number, number, number] => {
|
const horizontalTwo = addVector(
|
||||||
let angleOne = startingGuessAngleOne;
|
c2,
|
||||||
let angleTwo = startingGuessAngleTwo;
|
multiplyMatrixWithScalar(Math.cos(angleTwo), n21)
|
||||||
|
);
|
||||||
|
|
||||||
let distanceAlongDirection = getVectorMagnitude(firstPositionPossibleVectors[0]);
|
return vectorDotProduct(horizontalOne, horizontalTwo) / (getVectorMagnitude(horizontalOne) * getVectorMagnitude(horizontalTwo)) - Math.cos(phaseAngleDifference);
|
||||||
let distanceAlongPerpendicular = getVectorMagnitude(firstPositionPossibleVectors[1]);
|
}
|
||||||
|
|
||||||
let value = minimizeFunction(angleOne, angleTwo);
|
const planeAnglePartialDerivativeAngleOne = (angleOne: number, angleTwo: number) => {
|
||||||
// Do up to 100 minimizing steps
|
const horizontalOne = addVector(
|
||||||
for (var i = 0; i < 100; i++) {
|
c1,
|
||||||
let dfDx = partialDerivativeAngleOne(angleOne, angleTwo);
|
multiplyMatrixWithScalar(Math.cos(angleOne), n11)
|
||||||
let dfDy = partialDerivativeAngleTwo(angleOne, angleTwo);
|
);
|
||||||
|
|
||||||
let phaseAngleValue = distanceAlongPerpendicular * Math.cos(angleOne) / distanceAlongDirection - Math.tan(interpolationParameters.firstPhaseAngle);
|
const horizontalTwo = addVector(
|
||||||
let phaseAngleDerivative = -distanceAlongPerpendicular * Math.sin(angleOne) / distanceAlongDirection;
|
c2,
|
||||||
|
multiplyMatrixWithScalar(Math.cos(angleTwo), n21)
|
||||||
|
);
|
||||||
|
|
||||||
let changeAngleOne = dfDx * phaseAngleValue / (dfDy * phaseAngleDerivative);
|
return (
|
||||||
let changeAngleTwo = (dfDx * phaseAngleValue - phaseAngleDerivative * value) / (dfDy * phaseAngleDerivative);
|
-Math.sin(angleOne) * vectorDotProduct(n11, c2)
|
||||||
|
-Math.sin(angleOne) * Math.cos(angleTwo) * vectorDotProduct(n11, n21)
|
||||||
|
-Math.cos(angleOne) * Math.sin(angleOne) * vectorDotProduct(n11, n11) * vectorDotProduct(horizontalOne, horizontalTwo) / getVectorMagnitude(horizontalOne)
|
||||||
|
) / (getVectorMagnitude(horizontalOne) * getVectorMagnitude(horizontalTwo));
|
||||||
|
}
|
||||||
|
|
||||||
let trialAngleOne = angleOne;
|
const planeAnglePartialDerivativeAngleTwo = (angleOne: number, angleTwo: number) => {
|
||||||
let trialAngleTwo = angleTwo;
|
const horizontalOne = addVector(
|
||||||
let trialValue = value;
|
c1,
|
||||||
let divisor = 1;
|
multiplyMatrixWithScalar(Math.cos(angleOne), n11)
|
||||||
|
);
|
||||||
|
|
||||||
// We don't want things to blow up
|
const horizontalTwo = addVector(
|
||||||
while (Math.abs(changeAngleOne) / 2**divisor > Math.PI / 1000 || Math.abs(changeAngleTwo) / 2**divisor > Math.PI / 1000) {
|
c2,
|
||||||
divisor +=1;
|
multiplyMatrixWithScalar(Math.cos(angleTwo), n21)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
-Math.sin(angleTwo) * vectorDotProduct(n21, c1)
|
||||||
|
-Math.sin(angleTwo) * Math.cos(angleOne) * vectorDotProduct(n21, n11)
|
||||||
|
-Math.cos(angleTwo) * Math.sin(angleTwo) * vectorDotProduct(n21, n21) * vectorDotProduct(horizontalOne, horizontalTwo) / getVectorMagnitude(horizontalTwo)
|
||||||
|
) / (getVectorMagnitude(horizontalOne) * getVectorMagnitude(horizontalTwo))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to Newton's method up in this bitch
|
||||||
|
const getFunctionVector = (anglesVector: number[][]) => {
|
||||||
|
return [
|
||||||
|
[distanceFunction(anglesVector[0][0], anglesVector[1][0])],
|
||||||
|
[planeAngleFunction(anglesVector[0][0], anglesVector[1][0])]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const getJacobianMatrix = (anglesVector: number[][]) => {
|
||||||
|
let angleOne = anglesVector[0][0];
|
||||||
|
let angleTwo = anglesVector[1][0];
|
||||||
|
return[
|
||||||
|
[distancePartialDerivativeAngleOne(angleOne, angleTwo), distancePartialDerivativeAngleTwo(angleOne, angleTwo)],
|
||||||
|
[planeAnglePartialDerivativeAngleOne(angleOne, angleTwo), planeAnglePartialDerivativeAngleTwo(angleOne, angleTwo)]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const performNewtonMethod = (initialGuess: number[][], iterations: number) => {
|
||||||
|
let anglesVector = [
|
||||||
|
[initialGuess[0][0]],
|
||||||
|
[initialGuess[1][0]]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < iterations; i++) {
|
||||||
|
let functionVector = getFunctionVector(anglesVector);
|
||||||
|
let jacobianMatrix = getJacobianMatrix(anglesVector);
|
||||||
|
|
||||||
|
let update = matrixMultiply(invertTwoByTwoMatrix(jacobianMatrix), functionVector);
|
||||||
|
|
||||||
|
// Don't make updates too big
|
||||||
|
while (getVectorMagnitude(update) > Math.PI / 100) {
|
||||||
|
update = multiplyMatrixWithScalar(0.5, update);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
// Also don't update if it brings us further away from where we want to be
|
||||||
|
let trialFunctionVector = getFunctionVector(addVector(anglesVector, multiplyMatrixWithScalar(-1, update)));
|
||||||
|
let counter = 0;
|
||||||
let deadEnd = false;
|
let deadEnd = false;
|
||||||
|
|
||||||
while (Math.abs(trialValue) >= Math.abs(value)) {
|
while (Math.abs(trialFunctionVector[0][0]) >= Math.abs(functionVector[0][0])) {
|
||||||
trialAngleOne = angleOne - changeAngleOne / (2 ** divisor);
|
counter += 1;
|
||||||
trialAngleTwo = angleTwo - changeAngleTwo / (2 ** divisor);
|
if (counter >= 16) {
|
||||||
trialValue = minimizeFunction(trialAngleOne, trialAngleTwo);
|
|
||||||
divisor += 1;
|
|
||||||
|
|
||||||
if (divisor >= 32) {
|
|
||||||
deadEnd = true;
|
deadEnd = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update = multiplyMatrixWithScalar(0.5, update);
|
||||||
|
trialFunctionVector = getFunctionVector(addVector(anglesVector, multiplyMatrixWithScalar(-1, update)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deadEnd) {
|
if (deadEnd) {
|
||||||
return [angleOne, angleTwo, value];
|
break;
|
||||||
}
|
}*/
|
||||||
|
anglesVector = addVector(anglesVector, multiplyMatrixWithScalar(-1, update));
|
||||||
|
};
|
||||||
|
return anglesVector;
|
||||||
|
}
|
||||||
|
|
||||||
value = trialValue;
|
const getAnglesFromPhaseAngles = (firstPhaseAngle: number, secondPhaseAngle: number) => {
|
||||||
angleOne = trialAngleOne;
|
let angleOne;
|
||||||
angleTwo = trialAngleTwo;
|
let angleTwo;
|
||||||
|
|
||||||
|
if (Math.abs(interpolationParameters.firstPhaseAngle) < Math.PI / 2) {
|
||||||
|
angleOne = Math.acos(Math.tan(firstPhaseAngle) * firstDistanceAlongDirection / firstDistancePerpendicularToDirection);
|
||||||
|
} else {
|
||||||
|
angleOne = Math.acos(Math.tan(Math.PI - firstPhaseAngle) * -firstDistanceAlongDirection / firstDistancePerpendicularToDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [angleOne, angleTwo, value];
|
if (Math.abs(interpolationParameters.secondPhaseAngle) < Math.PI / 2) {
|
||||||
|
angleTwo = Math.acos(Math.tan(secondPhaseAngle) * secondDistanceAlongDirection / secondDistancePerpendicularToDirection);
|
||||||
|
} else {
|
||||||
|
angleTwo = Math.acos(Math.tan(Math.PI - secondPhaseAngle) * -secondDistanceAlongDirection / secondDistancePerpendicularToDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [angleOne, angleTwo];
|
||||||
}
|
}
|
||||||
|
|
||||||
let firstCenterLength = getVectorMagnitude(firstPositionPossibleVectors[0]);
|
let bestAngles = [[0], [0]];
|
||||||
let firstPerpendicularLength = getVectorMagnitude(firstPositionPossibleVectors[1]);
|
let bestDistance: number | null = null;
|
||||||
|
|
||||||
let secondCenterLength = getVectorMagnitude(secondPositionPossibleVectors[0]);
|
for (var i = -100; i < 101; i++) {
|
||||||
let secondPerpendicularLength = getVectorMagnitude(secondPositionPossibleVectors[1]);
|
for (var j = -100; j < 101; j++) {
|
||||||
|
let firstPhaseAngle = interpolationParameters.firstPhaseAngle + i * Math.PI / 18000;
|
||||||
|
let secondPhaseAngle = interpolationParameters.secondPhaseAngle + j * Math.PI / 18000;
|
||||||
|
|
||||||
let angleOneGuess = Math.acos(firstCenterLength * Math.tan(interpolationParameters.firstPhaseAngle) / firstPerpendicularLength);
|
let [angleOne, angleTwo] = getAnglesFromPhaseAngles(firstPhaseAngle, secondPhaseAngle);
|
||||||
let angleTwoGuess = Math.acos(secondCenterLength * Math.tan(interpolationParameters.secondPhaseAngle) / secondPerpendicularLength);
|
let distance = distanceFunction(angleOne, angleTwo);
|
||||||
|
if (bestDistance == null || Math.abs(distance) < Math.abs(bestDistance)) {
|
||||||
let bestAngleOne = 0;
|
bestDistance = distance;
|
||||||
let bestAngleTwo = 0;
|
bestAngles = [[angleOne], [angleTwo]];
|
||||||
let bestValue: number | null = null;
|
|
||||||
|
|
||||||
[angleOneGuess, -angleOneGuess].forEach(angleOne => {
|
|
||||||
[angleTwoGuess, -angleTwoGuess].forEach(angleTwo => {
|
|
||||||
let value = minimizeFunction(angleOne, angleTwo);
|
|
||||||
if (bestValue == null || value < bestValue) {
|
|
||||||
bestValue = value;
|
|
||||||
bestAngleOne = angleOne;
|
|
||||||
bestAngleTwo = angleTwo;
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
[bestAngleOne, bestAngleOne, bestValue] = gradientDescent(bestAngleOne, bestAngleTwo);
|
|
||||||
|
|
||||||
let bestFirstPosition = addVector(
|
|
||||||
firstPositionPossibleVectors[0],
|
|
||||||
addVector(
|
|
||||||
multiplyMatrixWithScalar(Math.cos(bestAngleOne), firstPositionPossibleVectors[1]),
|
|
||||||
multiplyMatrixWithScalar(Math.sin(bestAngleOne), firstPositionPossibleVectors[2])
|
|
||||||
)
|
|
||||||
);
|
|
||||||
let bestSecondPosition = addVector(
|
|
||||||
secondPositionPossibleVectors[0],
|
|
||||||
addVector(
|
|
||||||
multiplyMatrixWithScalar(Math.cos(bestAngleTwo), secondPositionPossibleVectors[1]),
|
|
||||||
multiplyMatrixWithScalar(Math.sin(bestAngleTwo), secondPositionPossibleVectors[2])
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (bestFirstPosition == null || bestSecondPosition == null) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
// We can now find the vector that defines the plane the target is in
|
|
||||||
let normalVector = normalizeVector(vectorCrossProduct(bestFirstPosition, bestSecondPosition));
|
|
||||||
let firstTargetPositionDirection = normalizeVector(bestFirstPosition);
|
|
||||||
|
|
||||||
// Rotate the position vector about the normal vector by the true anomaly to find the vector pointing to the periapsis
|
if (!interpolationParameters.targetAbovePlane) {
|
||||||
let identityMatrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
|
bestAngles = [[-bestAngles[0][0]], [-bestAngles[1][0]]];
|
||||||
let crossProductMatrix = [
|
}
|
||||||
[0, -normalVector[2][0], normalVector[1][0]],
|
|
||||||
[normalVector[2][0], 0, -normalVector[0][0]],
|
|
||||||
[-normalVector[1][0], normalVector[0][0], 0]
|
|
||||||
];
|
|
||||||
let outerProductMatrix = [
|
|
||||||
[normalVector[0][0]**2, normalVector[0][0]*normalVector[1][0], normalVector[0][0]*normalVector[2][0]],
|
|
||||||
[normalVector[0][0]*normalVector[1][0], normalVector[1][0]**2, normalVector[1][0]*normalVector[2][0]],
|
|
||||||
[normalVector[0][0]*normalVector[2][0], normalVector[1][0]*normalVector[2][0], normalVector[2][0]**2]
|
|
||||||
];
|
|
||||||
|
|
||||||
let rotationMatrix = addMatrix(
|
// Do some additional Newtoning on the best angles we've found so far
|
||||||
multiplyMatrixWithScalar(Math.cos(-firstTargetTrueAnomaly), identityMatrix),
|
//bestAngles = performNewtonMethod(bestAngles, 10000);
|
||||||
addMatrix(
|
|
||||||
multiplyMatrixWithScalar(Math.sin(-firstTargetTrueAnomaly), crossProductMatrix),
|
let targetPositionOne = addVector(multiplyMatrixWithScalar(firstDistanceAlongDirection, firstVectors[0]),
|
||||||
multiplyMatrixWithScalar(1 - Math.cos(-firstTargetTrueAnomaly), outerProductMatrix)
|
addVector(
|
||||||
|
multiplyMatrixWithScalar(Math.cos(bestAngles[0][0]) * firstDistancePerpendicularToDirection, firstVectors[1]),
|
||||||
|
multiplyMatrixWithScalar(Math.sin(bestAngles[0][0]) * firstDistancePerpendicularToDirection, firstVectors[2])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
let targetOrbitXVector = matrixMultiply(rotationMatrix, firstTargetPositionDirection);
|
let targetPositionTwo = addVector(multiplyMatrixWithScalar(secondDistanceAlongDirection, secondVectors[0]),
|
||||||
let targetOrbitYVector = vectorCrossProduct(normalVector, targetOrbitXVector);
|
addVector(
|
||||||
|
multiplyMatrixWithScalar(Math.cos(bestAngles[1][0]) * secondDistancePerpendicularToDirection, secondVectors[1]),
|
||||||
|
multiplyMatrixWithScalar(Math.sin(bestAngles[1][0]) * secondDistancePerpendicularToDirection, secondVectors[2])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
let normalVector = normalizeVector(vectorCrossProduct(targetPositionTwo, targetPositionOne));
|
||||||
|
|
||||||
|
// Rotate the position vector about this normal vector to get the direction of the periapsis
|
||||||
|
let ux = normalVector[0][0];
|
||||||
|
let uy = normalVector[1][0];
|
||||||
|
let uz = normalVector[2][0];
|
||||||
|
|
||||||
|
let rotationMatrix = [
|
||||||
|
[
|
||||||
|
ux*ux*(1 - Math.cos(-targetFirstTrueAnomaly)) + Math.cos(-targetFirstTrueAnomaly),
|
||||||
|
ux*uy*(1 - Math.cos(-targetFirstTrueAnomaly)) - uz * Math.sin(-targetFirstTrueAnomaly),
|
||||||
|
ux*uz*(1 - Math.cos(-targetFirstTrueAnomaly)) + uy * Math.sin(-targetFirstTrueAnomaly)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
ux*ux*(1 - Math.cos(-targetFirstTrueAnomaly)) + uz * Math.sin(-targetFirstTrueAnomaly),
|
||||||
|
uy*uy*(1 - Math.cos(-targetFirstTrueAnomaly)) + Math.cos(-targetFirstTrueAnomaly),
|
||||||
|
uy*uz*(1 - Math.cos(-targetFirstTrueAnomaly)) - ux * Math.sin(-targetFirstTrueAnomaly)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
ux*uz*(1 - Math.cos(-targetFirstTrueAnomaly)) - uy * Math.sin(-targetFirstTrueAnomaly),
|
||||||
|
uy*uz*(1 - Math.cos(-targetFirstTrueAnomaly)) + ux * Math.sin(-targetFirstTrueAnomaly),
|
||||||
|
uz*uz*(1 - Math.cos(-targetFirstTrueAnomaly)) + Math.cos(-targetFirstTrueAnomaly)
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
let periapsisVector = normalizeVector(matrixMultiply(rotationMatrix, targetPositionOne));
|
||||||
let targetOrbit: Orbit = {
|
let targetOrbit: Orbit = {
|
||||||
semiLatusRectum: targetSemiLatusRectum,
|
semiLatusRectum: targetSemiLatusRectum,
|
||||||
eccentricity: targetEccentricity,
|
eccentricity: targetEccentricity,
|
||||||
coordinateAxes: [targetOrbitXVector, targetOrbitYVector, normalVector]
|
coordinateAxes: [
|
||||||
|
periapsisVector,
|
||||||
|
normalizeVector(vectorCrossProduct(normalVector, periapsisVector)),
|
||||||
|
normalVector
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
let timePassed = getTimeBetweenTrueAnomalies(ownCoordinates.trueAnomaly, getTrueAnomalyFromAltitude(interpolationParameters.secondOwnAltitude, ownCoordinates.orbit.semiLatusRectum, ownCoordinates.orbit.eccentricity, ownShipHeadedInwards), ownCoordinates.orbit, body);
|
let targetCoordinates: OrbitalCoordinates = getOrbitalCoordinatesFromAltitude(
|
||||||
|
interpolationParameters.secondTargetAltitude,
|
||||||
|
targetHeadedInwards,
|
||||||
|
targetOrbit,
|
||||||
|
body
|
||||||
|
);
|
||||||
|
|
||||||
return [getOrbitalCoordinatesFromAltitude(interpolationParameters.secondTargetAltitude, targetHeadedInwards, targetOrbit, body), timePassed];
|
let epochTrueAnomaly = ownCoordinates.trueAnomaly;
|
||||||
|
while (epochTrueAnomaly + 2 * Math.PI < ownFirstTrueAnomaly) {
|
||||||
|
epochTrueAnomaly += 2 * Math.PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeElapsed = getTimeBetweenTrueAnomalies(epochTrueAnomaly, ownSecondTrueAnomaly, ownCoordinates.orbit, body);
|
||||||
|
return [
|
||||||
|
targetCoordinates,
|
||||||
|
timeElapsed
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@ export interface InterpolationParameters {
|
|||||||
targetApoapsis: number,
|
targetApoapsis: number,
|
||||||
targetSpeed: number,
|
targetSpeed: number,
|
||||||
targetAltitude: number,
|
targetAltitude: number,
|
||||||
|
targetAbovePlane: boolean,
|
||||||
firstOwnAltitude: number,
|
firstOwnAltitude: number,
|
||||||
firstTargetAltitude: number,
|
firstTargetAltitude: number,
|
||||||
firstDistance: number,
|
firstDistance: number,
|
||||||
@ -23,6 +24,7 @@ export const DefaultInterpolationParameters: InterpolationParameters = {
|
|||||||
targetApoapsis: 200000,
|
targetApoapsis: 200000,
|
||||||
targetSpeed: 0,
|
targetSpeed: 0,
|
||||||
targetAltitude: 0,
|
targetAltitude: 0,
|
||||||
|
targetAbovePlane: true,
|
||||||
firstOwnAltitude: 0,
|
firstOwnAltitude: 0,
|
||||||
firstTargetAltitude: 0,
|
firstTargetAltitude: 0,
|
||||||
firstDistance: 0,
|
firstDistance: 0,
|
||||||
@ -78,6 +80,13 @@ export class InterpolateOrbitGui {
|
|||||||
let speedInput = createInputWithLabel("Target speed:", 0);
|
let speedInput = createInputWithLabel("Target speed:", 0);
|
||||||
let altitudeInput = createInputWithLabel("Target altitude:", 0);
|
let altitudeInput = createInputWithLabel("Target altitude:", 0);
|
||||||
|
|
||||||
|
let abovePlaneId = crypto.randomUUID();
|
||||||
|
let abovePlaneButton = document.createElement("input");
|
||||||
|
abovePlaneButton.setAttribute("type", "checkbox");
|
||||||
|
abovePlaneButton.setAttribute("id", abovePlaneId);
|
||||||
|
let abovePlaneLabel = createLabel(abovePlaneId, "Target is currently above orbital plane");
|
||||||
|
addToParent([abovePlaneButton, abovePlaneLabel]);
|
||||||
|
|
||||||
let instantOneHeader = document.createElement("h4");
|
let instantOneHeader = document.createElement("h4");
|
||||||
instantOneHeader.appendChild(document.createTextNode("Measurement one:"));
|
instantOneHeader.appendChild(document.createTextNode("Measurement one:"));
|
||||||
this.parentDiv.appendChild(instantOneHeader);
|
this.parentDiv.appendChild(instantOneHeader);
|
||||||
@ -102,6 +111,7 @@ export class InterpolateOrbitGui {
|
|||||||
let apoapsis = parseFloat(apoapsisInput.value);
|
let apoapsis = parseFloat(apoapsisInput.value);
|
||||||
let speed = parseFloat(speedInput.value);
|
let speed = parseFloat(speedInput.value);
|
||||||
let altitude = parseFloat(altitudeInput.value);
|
let altitude = parseFloat(altitudeInput.value);
|
||||||
|
let abovePlane = abovePlaneButton.checked;
|
||||||
let firstTargetAltitude = parseFloat(firstTargetAltitudeInput.value);
|
let firstTargetAltitude = parseFloat(firstTargetAltitudeInput.value);
|
||||||
let firstOwnAltitude = parseFloat(firstOwnAltitudeInput.value);
|
let firstOwnAltitude = parseFloat(firstOwnAltitudeInput.value);
|
||||||
let firstDistance = parseFloat(firstDistanceInput.value);
|
let firstDistance = parseFloat(firstDistanceInput.value);
|
||||||
@ -122,6 +132,7 @@ export class InterpolateOrbitGui {
|
|||||||
targetApoapsis: apoapsis,
|
targetApoapsis: apoapsis,
|
||||||
targetSpeed: speed,
|
targetSpeed: speed,
|
||||||
targetAltitude: altitude,
|
targetAltitude: altitude,
|
||||||
|
targetAbovePlane: abovePlane,
|
||||||
firstTargetAltitude: firstTargetAltitude,
|
firstTargetAltitude: firstTargetAltitude,
|
||||||
firstOwnAltitude: firstOwnAltitude,
|
firstOwnAltitude: firstOwnAltitude,
|
||||||
firstDistance: firstDistance,
|
firstDistance: firstDistance,
|
||||||
@ -140,6 +151,7 @@ export class InterpolateOrbitGui {
|
|||||||
apoapsisInput,
|
apoapsisInput,
|
||||||
speedInput,
|
speedInput,
|
||||||
altitudeInput,
|
altitudeInput,
|
||||||
|
abovePlaneButton,
|
||||||
firstOwnAltitudeInput,
|
firstOwnAltitudeInput,
|
||||||
firstTargetAltitudeInput,
|
firstTargetAltitudeInput,
|
||||||
firstDistanceInput,
|
firstDistanceInput,
|
||||||
@ -171,6 +183,11 @@ export class InterpolateOrbitGui {
|
|||||||
apoapsisInput.value = value.targetApoapsis.toString();
|
apoapsisInput.value = value.targetApoapsis.toString();
|
||||||
speedInput.value = value.targetSpeed.toString();
|
speedInput.value = value.targetSpeed.toString();
|
||||||
altitudeInput.value = value.targetAltitude.toString();
|
altitudeInput.value = value.targetAltitude.toString();
|
||||||
|
if (value.targetAbovePlane) {
|
||||||
|
abovePlaneButton.setAttribute("checked", "");
|
||||||
|
} else {
|
||||||
|
abovePlaneButton.removeAttribute("checked");
|
||||||
|
}
|
||||||
firstOwnAltitudeInput.value = value.firstOwnAltitude.toString();
|
firstOwnAltitudeInput.value = value.firstOwnAltitude.toString();
|
||||||
firstTargetAltitudeInput.value = value.firstTargetAltitude.toString();
|
firstTargetAltitudeInput.value = value.firstTargetAltitude.toString();
|
||||||
firstDistanceInput.value = value.firstDistance.toString();
|
firstDistanceInput.value = value.firstDistance.toString();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user