Added ejection angle display

- Added velocity vector calculation in `Orbit` class
- Added item for ejection maneuver to display ejection angle
This commit is contained in:
Krafpy
2022-10-08 14:35:32 +02:00
parent 30157380d2
commit b95a4da37d
9 changed files with 125 additions and 7 deletions

View File

@@ -151,6 +151,7 @@ export async function initEditorWithSystem(systems, systemIndex) {
progradeDVSpan: getSpan("prograde-delta-v"),
normalDVSpan: getSpan("normal-delta-v"),
radialDVSpan: getSpan("radial-delta-v"),
ejAngleSpan: getSpan("ejection-angle"),
depDateSpan: getSpan("result-departure-date"),
arrDateSpan: getSpan("result-arrival-date"),
totalDVSpan: getSpan("result-total-delta-v"),
@@ -160,10 +161,10 @@ export async function initEditorWithSystem(systems, systemIndex) {
endDateSpan: getSpan("flyby-end-date"),
periAltitudeSpan: getSpan("flyby-periapsis-altitude"),
inclinationSpan: getSpan("flyby-inclination"),
maneuverDiv: getDiv("maneuvre-details"),
flybyDiv: getDiv("flyby-details"),
detailsSelector: detailsSelector,
stepSlider: stepSlider,
maneuverDiv: getDiv("maneuvre-details"),
flybyDiv: getDiv("flyby-details")
};
const resetFoundTrajectory = () => {
systemTime.input(updateSystemTime);
@@ -243,6 +244,7 @@ export async function initEditorWithSystem(systems, systemIndex) {
resultItems.dateSpan.innerHTML = "--";
resultItems.normalDVSpan.innerHTML = "--";
resultItems.radialDVSpan.innerHTML = "--";
resultItems.ejAngleSpan.innerHTML = "--";
resultItems.depDateSpan.innerHTML = "--";
resultItems.arrDateSpan.innerHTML = "--";
resultItems.totalDVSpan.innerHTML = "--";

View File

@@ -80,6 +80,31 @@ export class Orbit {
pos.multiplyScalar(this.radius(trueAnomaly));
return pos;
}
velocityFromTrueAnomaly(trueAnomaly) {
const e = this.eccentricity;
const mu = this.attractor.stdGravParam;
const nu = trueAnomaly;
const a = this.semiMajorAxis;
const r = this.radius(nu);
const vel = new THREE.Vector3();
if (e < 1) {
const v = Math.sqrt(mu * a) / r;
const E = 2 * Math.atan(Math.tan(nu * 0.5) * Math.sqrt((1 - e) / (1 + e)));
vel.set(-v * Math.sin(E), 0, -v * Math.sqrt(1 - e * e) * Math.cos(E));
}
else {
const v = Math.sqrt(-mu * a) / r;
const H = 2 * Math.atanh(Math.tan(nu * 0.5) * Math.sqrt((e - 1) / (e + 1)));
vel.set(-v * Math.sinh(H), 0, -v * Math.sqrt(e * e - 1) * Math.cosh(H));
}
const right = new THREE.Vector3(1, 0, 0), up = new THREE.Vector3(0, 1, 0);
const ascNodeDir = right.clone();
ascNodeDir.applyAxisAngle(up, this.ascNodeLongitude);
vel.applyAxisAngle(up, this.ascNodeLongitude);
vel.applyAxisAngle(up, this.argOfPeriapsis);
vel.applyAxisAngle(ascNodeDir, this.inclination);
return vel;
}
radius(trueAnomaly) {
return this.orbitalParam / (1 + this.eccentricity * Math.cos(trueAnomaly));
}

View File

@@ -138,12 +138,27 @@ export class Trajectory {
const radialDir = progradeDir.clone();
radialDir.cross(normalDir);
const deltaV = new THREE.Vector3(maneuvre.deltaVToPrevStep.x, maneuvre.deltaVToPrevStep.y, maneuvre.deltaVToPrevStep.z);
let ejectAngle = undefined;
if (maneuvre.context.type == "ejection") {
const nodePos = maneuvre.position;
const body = this.system.bodyFromId(step.attractorId);
const bodyNu = body.trueAnomalyAtDate(departureDate);
const bodyVel = body.orbit.velocityFromTrueAnomaly(bodyNu);
const u = new THREE.Vector2(nodePos.x, nodePos.z);
const v = new THREE.Vector2(bodyVel.x, bodyVel.z);
u.normalize();
v.normalize();
const cosA = Math.min(Math.max(u.dot(v), -1), 1);
ejectAngle = Math.acos(cosA) * 180 / Math.PI;
ejectAngle *= Math.sign(u.x * v.y - u.y * v.x);
}
const details = {
stepIndex: i,
dateMET: step.dateOfStart - departureDate,
progradeDV: progradeDir.dot(deltaV),
normalDV: normalDir.dot(deltaV),
radialDV: radialDir.dot(deltaV),
ejectAngle: ejectAngle
};
this._maneuvres.push(details);
}
@@ -243,6 +258,14 @@ export class Trajectory {
resultItems.normalDVSpan.innerHTML = details.normalDV.toFixed(1);
resultItems.radialDVSpan.innerHTML = details.radialDV.toFixed(1);
resultItems.maneuvreNumber.innerHTML = (option.origin + 1).toString();
const ejAngleLI = resultItems.ejAngleSpan.parentElement;
if (details.ejectAngle !== undefined) {
ejAngleLI.hidden = false;
resultItems.ejAngleSpan.innerHTML = details.ejectAngle.toFixed(1);
}
else {
ejAngleLI.hidden = true;
}
const date = depDate.dateSeconds + dateEMT.dateSeconds;
resultItems.dateSpan.onclick = onDateClick(date);
resultItems.flybyDiv.hidden = true;

View File

@@ -280,6 +280,7 @@
<li><strong>Prograde ΔV:</strong> <span id="prograde-delta-v">--</span> m/s</li>
<li><strong>Normal ΔV:</strong> <span id="normal-delta-v">--</span> m/s</li>
<li><strong>Radial ΔV:</strong> <span id="radial-delta-v">--</span> m/s</li>
<li hidden><strong>Ejection angle:</strong> <span id="ejection-angle">--</span>° (counter clockwise)</li>
</ul>
</div>

View File

@@ -203,14 +203,15 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd
detailsSelector.disable();
stepSlider.disable();
const getSpan = (id: string) => document.getElementById(id) as HTMLSpanElement;
const getDiv = (id: string) => document.getElementById(id) as HTMLDivElement;
const getSpan = (id: string) => document.getElementById(id) as HTMLSpanElement;
const getDiv = (id: string) => document.getElementById(id) as HTMLDivElement;
const resultItems: ResultPannelItems = {
dateSpan: getSpan("maneuvre-date"),
progradeDVSpan: getSpan("prograde-delta-v"),
normalDVSpan: getSpan("normal-delta-v"),
radialDVSpan: getSpan("radial-delta-v"),
ejAngleSpan: getSpan("ejection-angle"),
depDateSpan: getSpan("result-departure-date"),
arrDateSpan: getSpan("result-arrival-date"),
totalDVSpan: getSpan("result-total-delta-v"),
@@ -220,10 +221,10 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd
endDateSpan: getSpan("flyby-end-date"),
periAltitudeSpan: getSpan("flyby-periapsis-altitude"),
inclinationSpan: getSpan("flyby-inclination"),
maneuverDiv: getDiv("maneuvre-details"),
flybyDiv: getDiv("flyby-details"),
detailsSelector: detailsSelector,
stepSlider: stepSlider,
maneuverDiv: getDiv("maneuvre-details"),
flybyDiv: getDiv("flyby-details")
};
const resetFoundTrajectory = () => {
@@ -322,6 +323,7 @@ export async function initEditorWithSystem(systems: SolarSystemData[], systemInd
resultItems.dateSpan.innerHTML = "--";
resultItems.normalDVSpan.innerHTML = "--";
resultItems.radialDVSpan.innerHTML = "--";
resultItems.ejAngleSpan.innerHTML = "--";
resultItems.depDateSpan.innerHTML = "--";
resultItems.arrDateSpan.innerHTML = "--";
resultItems.totalDVSpan.innerHTML = "--";

View File

@@ -128,6 +128,36 @@ export class Orbit implements IOrbit {
return pos;
}
public velocityFromTrueAnomaly(trueAnomaly: number){
const e = this.eccentricity;
const mu = this.attractor.stdGravParam;
const nu = trueAnomaly;
const a = this.semiMajorAxis;
const r = this.radius(nu);
const vel = new THREE.Vector3();
if(e < 1) { // Elliptical orbit
const v = Math.sqrt(mu * a) / r;
const E = 2 * Math.atan( Math.tan(nu*0.5) * Math.sqrt((1-e)/(1+e)) );
vel.set(-v * Math.sin(E), 0, -v * Math.sqrt(1 - e*e) * Math.cos(E));
} else { // Hyperbolic orbit (the case e = 1, parabolic orbit, will never be reached)
const v = Math.sqrt(-mu * a) / r;
const H = 2 * Math.atanh( Math.tan(nu*0.5) * Math.sqrt((e-1)/(e+1)) );
vel.set(-v * Math.sinh(H), 0, -v * Math.sqrt(e*e - 1) * Math.cosh(H));
}
const right = new THREE.Vector3(1, 0, 0), up = new THREE.Vector3(0, 1, 0);
const ascNodeDir = right.clone();
ascNodeDir.applyAxisAngle(up, this.ascNodeLongitude);
vel.applyAxisAngle(up, this.ascNodeLongitude);
vel.applyAxisAngle(up, this.argOfPeriapsis);
vel.applyAxisAngle(ascNodeDir, this.inclination);
return vel;
}
/**
* @param trueAnomaly The true anomaly
* @returns The real radius of the orbit for the specified anomaly.

View File

@@ -5,6 +5,7 @@ import { SolarSystem } from "../objects/system.js";
import { KSPTime } from "../utilities/time.js";
import { CameraController } from "../objects/camera.js";
import { SpriteManager } from "../utilities/sprites.js";
import { OrbitingBody } from "../objects/body.js";
export class Trajectory {
private _orbitObjects: THREE.Object3D[] = [];
@@ -186,7 +187,8 @@ export class Trajectory {
const {maneuvre} = step;
if(maneuvre){
const orbit = this.orbits[i];
// compute the maneuver delta-V vectors
const progradeDir = new THREE.Vector3(
maneuvre.progradeDir.x,
maneuvre.progradeDir.y,
@@ -202,12 +204,34 @@ export class Trajectory {
maneuvre.deltaVToPrevStep.z,
);
// compute the ejection angle if it's the ejection maneuver
let ejectAngle: (undefined | number) = undefined;
if(maneuvre.context.type == "ejection"){
const nodePos = maneuvre.position;
const body = this.system.bodyFromId(step.attractorId) as OrbitingBody;
const bodyNu = body.trueAnomalyAtDate(departureDate);
const bodyVel = body.orbit.velocityFromTrueAnomaly(bodyNu);
// the parking orbit is always in the xz plane
const u = new THREE.Vector2(nodePos.x, nodePos.z);
const v = new THREE.Vector2(bodyVel.x, bodyVel.z); // project planet velocity in xz plane
u.normalize();
v.normalize();
const cosA = Math.min(Math.max(u.dot(v), -1), 1);
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),
ejectAngle: ejectAngle
};
this._maneuvres.push(details);
}
@@ -343,6 +367,14 @@ export class Trajectory {
resultItems.radialDVSpan.innerHTML = details.radialDV.toFixed(1);
resultItems.maneuvreNumber.innerHTML = (option.origin + 1).toString();
const ejAngleLI = resultItems.ejAngleSpan.parentElement as HTMLLIElement;
if(details.ejectAngle !== undefined){
ejAngleLI.hidden = false;
resultItems.ejAngleSpan.innerHTML = details.ejectAngle.toFixed(1);
} else {
ejAngleLI.hidden = true;
}
const date = depDate.dateSeconds + dateEMT.dateSeconds;
resultItems.dateSpan.onclick = onDateClick(date);

2
src/types.d.ts vendored
View File

@@ -286,6 +286,7 @@ type ManeuvreDetails = {
progradeDV: number,
normalDV: number,
radialDV: number,
ejectAngle?: number
};
type FlybyDetails = {
@@ -309,6 +310,7 @@ type ResultPannelItems = {
progradeDVSpan: HTMLSpanElement,
normalDVSpan: HTMLSpanElement,
radialDVSpan: HTMLSpanElement,
ejAngleSpan: HTMLSpanElement,
depDateSpan: HTMLSpanElement,
arrDateSpan: HTMLSpanElement,
totalDVSpan: HTMLSpanElement,

View File

@@ -382,6 +382,7 @@ input[type="range"]
#result-sub-panels
{
height: 127px;
display: flex;
flex-direction: row;
}