Added flyby details display in maneuvers selector.

This commit is contained in:
Krafpy
2022-07-10 02:06:52 +02:00
parent 591a94b37c
commit 44beeeb1b5
9 changed files with 441 additions and 179 deletions

View File

@@ -270,13 +270,21 @@ class TrajectoryCalculator {
const periapsisState = { pos: periPos, vel: periVel };
const flybyOrbit = Physics3D.stateToOrbitElements(periapsisState, body);
const tof = Physics3D.tofBetweenAnomalies(flybyOrbit, body, angles.begin, angles.end);
const flybyDetails = {
bodyId: body.id,
soiEnterDate: this._lastStepEndDate,
soiExitDate: this._lastStepEndDate + tof,
periRadius: periRadius,
inclination: flybyOrbit.inclination
};
this.steps.push({
orbitElts: flybyOrbit,
attractorId: body.id,
angles: angles,
drawAngles: drawAngles,
duration: tof,
dateOfStart: this._lastStepEndDate
dateOfStart: this._lastStepEndDate,
flyby: flybyDetails
});
const exitState = Physics3D.orbitElementsToState(flybyOrbit, body, exitAngle);
this._vesselState = exitState;

View File

@@ -100,23 +100,33 @@ export function initEditor(controls, system, config, canvas) {
const solver = new TrajectorySolver(system, config, deltaVPlot);
const paramsErr = new ErrorMessage("search-params-error");
let trajectory;
const maneuvreSelector = new Selector("maneuvre-selector");
const detailsSelector = new Selector("details-selector");
const stepSlider = new DiscreteRange("displayed-steps-slider");
maneuvreSelector.disable();
detailsSelector.disable();
stepSlider.disable();
const resultSpans = {
dateSpan: document.getElementById("maneuvre-date"),
progradeDVSpan: document.getElementById("prograde-delta-v"),
normalDVSpan: document.getElementById("normal-delta-v"),
radialDVSpan: document.getElementById("radial-delta-v"),
depDateSpan: document.getElementById("result-departure-date"),
totalDVSpan: document.getElementById("result-total-delta-v"),
maneuvreNumber: document.getElementById("maneuvre-number"),
const getSpan = (id) => document.getElementById(id);
const resultItems = {
dateSpan: getSpan("maneuvre-date"),
progradeDVSpan: getSpan("prograde-delta-v"),
normalDVSpan: getSpan("normal-delta-v"),
radialDVSpan: getSpan("radial-delta-v"),
depDateSpan: getSpan("result-departure-date"),
totalDVSpan: getSpan("result-total-delta-v"),
maneuvreNumber: getSpan("maneuvre-number"),
flybyNumberSpan: getSpan("flyby-number"),
startDateSpan: getSpan("flyby-start-date"),
endDateSpan: getSpan("flyby-end-date"),
periAltitudeSpan: getSpan("flyby-periapsis-altitude"),
inclinationSpan: getSpan("flyby-inclination"),
detailsSelector: detailsSelector,
stepSlider: stepSlider,
maneuverDiv: document.getElementById("maneuvre-details"),
flybyDiv: document.getElementById("flyby-details")
};
const resetFoundTrajectory = () => {
deltaVPlot.reveal();
maneuvreSelector.clear();
maneuvreSelector.disable();
detailsSelector.clear();
detailsSelector.disable();
stepSlider.disable();
if (trajectory) {
trajectory.remove();
@@ -125,9 +135,9 @@ export function initEditor(controls, system, config, canvas) {
const displayFoundTrajectory = () => {
trajectory = new Trajectory(solver.bestTrajectorySteps, system, config);
trajectory.draw(canvas);
trajectory.fillResultControls(maneuvreSelector, resultSpans, stepSlider, systemTime, controls);
maneuvreSelector.select(0);
maneuvreSelector.enable();
trajectory.fillResultControls(resultItems, systemTime, controls);
detailsSelector.select(0);
detailsSelector.enable();
stepSlider.enable();
console.log(solver.bestDeltaV);
};

View File

@@ -9,6 +9,7 @@ export class Trajectory {
this.orbits = [];
this._objects = [];
this._maneuvres = [];
this._flybys = [];
for (const { orbitElts, attractorId } of this.steps) {
const attractor = this.system.bodyFromId(attractorId);
const orbit = Orbit.fromOrbitalElements(orbitElts, attractor, config.orbit);
@@ -28,6 +29,7 @@ export class Trajectory {
this._createTrajectoryArcs(resolution);
this._createManeuvreSprites();
this._calculateManeuvresDetails();
this._calculateFlybyDetails();
}
_createTrajectoryArcs(resolution) {
const { lineWidth } = this.config.orbit;
@@ -63,6 +65,7 @@ export class Trajectory {
}
}
_calculateManeuvresDetails() {
const departureDate = this.steps[0].dateOfStart;
for (let i = 0; i < this.steps.length; i++) {
const step = this.steps[i];
const { maneuvre } = step;
@@ -75,70 +78,127 @@ export class Trajectory {
const deltaV = new THREE.Vector3(maneuvre.deltaVToPrevStep.x, maneuvre.deltaVToPrevStep.y, maneuvre.deltaVToPrevStep.z);
const details = {
stepIndex: i,
dateMET: step.dateOfStart - this.steps[0].dateOfStart,
dateMET: step.dateOfStart - departureDate,
progradeDV: progradeDir.dot(deltaV),
normalDV: normalDir.dot(deltaV),
radialDV: radialDir.dot(deltaV)
radialDV: radialDir.dot(deltaV),
};
this._maneuvres.push(details);
}
}
}
fillResultControls(maneuvreSelector, resultSpans, stepSlider, systemTime, controls) {
_calculateFlybyDetails() {
const departureDate = this.steps[0].dateOfStart;
for (const { flyby } of this.steps) {
if (flyby) {
const body = this.system.bodyFromId(flyby.bodyId);
let inc = flyby.inclination * 57.2957795131;
inc = inc > 90 ? 180 - inc : inc;
const details = {
bodyId: flyby.bodyId,
soiEnterDateMET: flyby.soiEnterDate - departureDate,
soiExitDateMET: flyby.soiExitDate - departureDate,
periAltitude: (flyby.periRadius - body.radius) / 1000,
inclinationDeg: inc
};
this._flybys.push(details);
}
}
}
fillResultControls(resultItems, systemTime, controls) {
const depDate = new KSPTime(this.steps[0].dateOfStart, this.config.time);
resultSpans.totalDVSpan.innerHTML = this._totalDeltaV.toFixed(1);
resultSpans.depDateSpan.innerHTML = depDate.stringYDHMS("hms", "ut");
resultSpans.depDateSpan.onclick = () => {
this.system.date = depDate.dateSeconds;
resultItems.totalDVSpan.innerHTML = this._totalDeltaV.toFixed(1);
resultItems.depDateSpan.innerHTML = depDate.stringYDHMS("hms", "ut");
const onDateClick = (date) => () => {
this.system.date = date;
controls.centerOnTarget();
systemTime.time.dateSeconds = depDate.dateSeconds;
systemTime.time.dateSeconds = date;
systemTime.update();
};
resultItems.depDateSpan.onclick = onDateClick(depDate.dateSeconds);
const { stepSlider } = resultItems;
stepSlider.setMinMax(0, this.steps.length - 1);
stepSlider.input((index) => this._displayStepsUpTo(index));
stepSlider.value = this.steps.length - 1;
const selectorOptions = [];
for (let i = 0; i < this._maneuvres.length; i++) {
const details = this._maneuvres[i];
const step = this.steps[details.stepIndex];
const context = step.maneuvre.context;
if (context.type == "ejection") {
const startBodyName = this.system.bodyFromId(step.attractorId).name;
const optionName = `${i + 1}: ${startBodyName} escape`;
selectorOptions.push(optionName);
let maneuvreIdx = 0, flybyIdx = 0;
let optionNumber = 0;
for (let i = 0; i < this.steps.length; i++) {
const { maneuvre, flyby } = this.steps[i];
if (maneuvre) {
const details = this._maneuvres[maneuvreIdx];
const step = this.steps[details.stepIndex];
const context = step.maneuvre.context;
let optionName;
if (context.type == "ejection") {
const startBodyName = this.system.bodyFromId(step.attractorId).name;
optionName = `${++optionNumber}: ${startBodyName} escape`;
}
else if (context.type == "dsm") {
const originName = this.system.bodyFromId(context.originId).name;
const targetName = this.system.bodyFromId(context.targetId).name;
optionName = `${++optionNumber}: ${originName}-${targetName} DSM`;
}
else {
const arrivalBodyName = this.system.bodyFromId(step.attractorId).name;
optionName = `${++optionNumber}: ${arrivalBodyName} circularization`;
}
const option = {
text: optionName,
index: i,
type: "maneuver",
origin: maneuvreIdx++
};
selectorOptions.push(option);
}
else if (context.type == "dsm") {
const originName = this.system.bodyFromId(context.originId).name;
const targetName = this.system.bodyFromId(context.targetId).name;
const optionName = `${i + 1}: ${originName}-${targetName} DSM`;
selectorOptions.push(optionName);
}
else {
const arrivalBodyName = this.system.bodyFromId(step.attractorId).name;
const optionName = `${i + 1}: ${arrivalBodyName} circularization`;
selectorOptions.push(optionName);
else if (flyby) {
const details = this._flybys[flybyIdx];
const bodyName = this.system.bodyFromId(details.bodyId).name;
const optionName = `${++optionNumber}: ${bodyName} flyby`;
const option = {
text: optionName,
index: i,
type: "flyby",
origin: flybyIdx++
};
selectorOptions.push(option);
}
}
maneuvreSelector.fill(selectorOptions);
maneuvreSelector.change((_, index) => {
const details = this._maneuvres[index];
const dateEMT = new KSPTime(details.dateMET, this.config.time);
resultSpans.dateSpan.innerHTML = dateEMT.stringYDHMS("hm", "emt");
resultSpans.progradeDVSpan.innerHTML = details.progradeDV.toFixed(1);
resultSpans.normalDVSpan.innerHTML = details.normalDV.toFixed(1);
resultSpans.radialDVSpan.innerHTML = details.radialDV.toFixed(1);
resultSpans.maneuvreNumber.innerHTML = (index + 1).toString();
resultSpans.dateSpan.onclick = () => {
const optionNames = selectorOptions.map(opt => opt.text);
const { detailsSelector } = resultItems;
detailsSelector.fill(optionNames);
detailsSelector.change((_, index) => {
const option = selectorOptions[index];
if (option.type == "maneuver") {
const details = this._maneuvres[option.origin];
const dateEMT = new KSPTime(details.dateMET, this.config.time);
resultItems.dateSpan.innerHTML = dateEMT.stringYDHMS("hm", "emt");
resultItems.progradeDVSpan.innerHTML = details.progradeDV.toFixed(1);
resultItems.normalDVSpan.innerHTML = details.normalDV.toFixed(1);
resultItems.radialDVSpan.innerHTML = details.radialDV.toFixed(1);
resultItems.maneuvreNumber.innerHTML = (option.origin + 1).toString();
const date = depDate.dateSeconds + dateEMT.dateSeconds;
this.system.date = date;
controls.centerOnTarget();
systemTime.time.dateSeconds = date;
systemTime.update();
};
resultItems.dateSpan.onclick = onDateClick(date);
resultItems.flybyDiv.hidden = true;
resultItems.maneuverDiv.hidden = false;
}
else if (option.type == "flyby") {
const details = this._flybys[option.origin];
const startDateEMT = new KSPTime(details.soiEnterDateMET, this.config.time);
const endDateEMT = new KSPTime(details.soiExitDateMET, this.config.time);
resultItems.startDateSpan.innerHTML = startDateEMT.stringYDHMS("hm", "emt");
resultItems.endDateSpan.innerHTML = endDateEMT.stringYDHMS("hm", "emt");
resultItems.periAltitudeSpan.innerHTML = details.periAltitude.toFixed(0);
resultItems.inclinationSpan.innerHTML = details.inclinationDeg.toFixed(0);
resultItems.flybyNumberSpan.innerHTML = (option.origin + 1).toString();
let enterDate = depDate.dateSeconds + startDateEMT.dateSeconds;
resultItems.startDateSpan.onclick = onDateClick(enterDate);
let exitDate = depDate.dateSeconds + endDateEMT.dateSeconds;
resultItems.endDateSpan.onclick = onDateClick(exitDate);
resultItems.flybyDiv.hidden = false;
resultItems.maneuverDiv.hidden = true;
}
});
for (const step of this.steps) {
console.log(step);
}
}
_displayStepsUpTo(index) {
for (let i = 0; i < this.steps.length; i++) {

View File

@@ -222,13 +222,21 @@
<!-- End of the 3D display panel -->
<div id="result-panel">
<h2 class="calculation-panel-title">Calculated trajectory</h2>
<div id="result-panel-header">
<h2 class="calculation-panel-title">Calculated trajectory</h2>
<div id="steps-slider-control-group" class="control-group">
<label class="control-label" for="displayed-steps-slider">Displayed steps:</label>
<div id="steps-slider-controls" class="controls">
<input name="displayed-steps-slider" id="displayed-steps-slider" type="range" min="0" max="1" value="1" disabled>
</div>
</div>
</div>
<div id="result-sub-panels">
<div id="result-controls">
<div class="control-group">
<label class="control-label">Departure date:</label>
<p><strong><span id="result-departure-date">--</span> UT</strong></p>
<p><strong><span id="result-departure-date" class="clickable-date">--</span> UT</strong></p>
</div>
<div class="control-group">
@@ -237,32 +245,37 @@
</div>
<div class="control-group">
<label class="control-label" for="displayed-steps-slider">Displayed steps:</label>
<label class="control-label" for="details-selector">Maneuvers:</label>
<div class="controls">
<input name="displayed-steps-slider" id="displayed-steps-slider" type="range" min="0" max="1" value="1" disabled>
</div>
</div>
<div class="control-group">
<label class="control-label" for="maneuvre-selector">Maneuvres:</label>
<div class="controls">
<select id="maneuvre-selector" name="maneuvre-selector" disabled>
<select id="details-selector" name="details-selector" disabled>
<!-- filled by js -->
</select>
</div>
</div>
</div>
<!-- End of result controls -->
<div id="maneuvre-details">
<h3>Maneuver <span id="maneuvre-number"></span> details:</h3>
<ul>
<li><strong>Date:</strong> <span id="maneuvre-date">--</span> MET</li>
<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>
</ul>
<div>
<div id="maneuvre-details" class="result-details">
<h3>Maneuver <span id="maneuvre-number"></span> details:</h3>
<ul>
<li><strong>Date:</strong> <span id="maneuvre-date" class="clickable-date">--</span> MET</li>
<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>
</ul>
</div>
<div id="flyby-details" class="result-details" hidden>
<h3>Flyby <span id="flyby-number"></span> details:</h3>
<ul>
<li><strong>SOI enter date:</strong> <span id="flyby-start-date" class="clickable-date">--</span> MET</li>
<li><strong>SOI exit date:</strong> <span id="flyby-end-date" class="clickable-date">--</span> MET</li>
<li><strong>Periapsis altitude:</strong> <span id="flyby-periapsis-altitude">--</span> km</li>
<li><strong>Inclination:</strong> <span id="flyby-inclination">--</span>°</li>
</ul>
</div>
</div>
<!-- End of maneuvre details -->
</div>
@@ -366,7 +379,7 @@
</p>
<p>
The resulting trajectory will be displayed in the interactive 3D window, alongside with
the details of each maneuver (ejection from the departure body and DSMs).
the details of each maneuver (ejection from the departure body and DSMs) and flybys' information.
</p>
<figure id="example-image-container">

View File

@@ -15,9 +15,9 @@ class TrajectoryCalculator {
private _bodiesOrbits!: OrbitalElements3D[];
private _legs: LegInfo[] = [];
private _flybys: FlybyInfo[] = [];
private _departureInfos!: DepartureInfo;
private _legs: AgentLegInfo[] = [];
private _flybys: AgentFlybyInfo[] = [];
private _departureInfos!: AgentDepartureInfo;
private _secondArcsData: SecondArcData[] = [];
@@ -167,7 +167,7 @@ class TrajectoryCalculator {
* parameters
* @param infos The leg infos to complete
*/
private _computeLegDuration(infos: LegInfo){
private _computeLegDuration(infos: AgentLegInfo){
const exitedBody = this.system[infos.exitedBodyId];
const {durationParam} = infos;
const attr = this._mainAttractor;
@@ -381,7 +381,7 @@ class TrajectoryCalculator {
* Computes the flyby orbit with the provided parameters.
* @param flybyInfo The flyby parameters
*/
private _computeFlyby(flybyInfo: FlybyInfo){
private _computeFlyby(flybyInfo: AgentFlybyInfo){
const body = this.system[flybyInfo.flybyBodyId];
// Compute the relative velocity to the body when entering its SOI
@@ -442,13 +442,22 @@ class TrajectoryCalculator {
const tof = Physics3D.tofBetweenAnomalies(flybyOrbit, body, angles.begin, angles.end);
// Append the flyby orbit
const flybyDetails: FlybyInfo = {
bodyId: body.id,
soiEnterDate: this._lastStepEndDate,
soiExitDate: this._lastStepEndDate + tof,
periRadius: periRadius,
inclination: flybyOrbit.inclination
};
this.steps.push({
orbitElts: flybyOrbit,
attractorId: body.id,
angles: angles,
drawAngles: drawAngles,
duration: tof,
dateOfStart: this._lastStepEndDate
dateOfStart: this._lastStepEndDate,
flyby: flybyDetails
});
// Compute the vessel state relative to the body when exiting its SOI
@@ -471,7 +480,7 @@ class TrajectoryCalculator {
* supposing a null radius SOI.
* @param legInfo The leg parameters
*/
private _computeLegSecondArcSimple(legInfo: LegInfo){
private _computeLegSecondArcSimple(legInfo: AgentLegInfo){
const attr = this._mainAttractor;
const lastStep = this._lastStep;
const preDSMState = this._vesselState;
@@ -540,7 +549,7 @@ class TrajectoryCalculator {
* Computes the next leg first arc with the provided parameters.
* @param legInfo The parameters of the leg
*/
private _computeFirstLegArc(legInfo: LegInfo){
private _computeFirstLegArc(legInfo: AgentLegInfo){
// Compute the state of the vessel relatived to the exited body after exiting its SOI
/*const lastStep = this._lastStep;
const exitedBody = this.system[lastStep.attractorId];

View File

@@ -139,25 +139,40 @@ export function initEditor(controls: CameraController, system: SolarSystem, conf
let trajectory: Trajectory | undefined;
// Result panel
const maneuvreSelector = new Selector("maneuvre-selector");
const detailsSelector = new Selector("details-selector");
const stepSlider = new DiscreteRange("displayed-steps-slider");
maneuvreSelector.disable();
detailsSelector.disable();
stepSlider.disable();
const resultSpans = {
dateSpan: document.getElementById("maneuvre-date") as HTMLSpanElement,
progradeDVSpan: document.getElementById("prograde-delta-v") as HTMLSpanElement,
normalDVSpan: document.getElementById("normal-delta-v") as HTMLSpanElement,
radialDVSpan: document.getElementById("radial-delta-v") as HTMLSpanElement,
depDateSpan: document.getElementById("result-departure-date") as HTMLSpanElement,
totalDVSpan: document.getElementById("result-total-delta-v") as HTMLSpanElement,
maneuvreNumber: document.getElementById("maneuvre-number") as HTMLSpanElement,
const getSpan = (id: string) => document.getElementById(id) as HTMLSpanElement;
const resultItems = {
dateSpan: getSpan("maneuvre-date"),
progradeDVSpan: getSpan("prograde-delta-v"),
normalDVSpan: getSpan("normal-delta-v"),
radialDVSpan: getSpan("radial-delta-v"),
depDateSpan: getSpan("result-departure-date") ,
totalDVSpan: getSpan("result-total-delta-v"),
maneuvreNumber: getSpan("maneuvre-number"),
flybyNumberSpan: getSpan("flyby-number"),
startDateSpan: getSpan("flyby-start-date"),
endDateSpan: getSpan("flyby-end-date"),
periAltitudeSpan: getSpan("flyby-periapsis-altitude"),
inclinationSpan: getSpan("flyby-inclination"),
detailsSelector: detailsSelector,
stepSlider: stepSlider,
maneuverDiv: document.getElementById("maneuvre-details") as HTMLDivElement,
flybyDiv: document.getElementById("flyby-details") as HTMLDivElement
};
const resetFoundTrajectory = () => {
deltaVPlot.reveal();
maneuvreSelector.clear();
maneuvreSelector.disable();
detailsSelector.clear();
detailsSelector.disable();
stepSlider.disable();
if(trajectory){
trajectory.remove();
@@ -167,10 +182,10 @@ export function initEditor(controls: CameraController, system: SolarSystem, conf
const displayFoundTrajectory = () => {
trajectory = new Trajectory(solver.bestTrajectorySteps, system, config);
trajectory.draw(canvas);
trajectory.fillResultControls(maneuvreSelector, resultSpans, stepSlider, systemTime, controls);
trajectory.fillResultControls(resultItems, systemTime, controls);
maneuvreSelector.select(0);
maneuvreSelector.enable();
detailsSelector.select(0);
detailsSelector.enable();
stepSlider.enable();
console.log(solver.bestDeltaV);

View File

@@ -10,8 +10,9 @@ import { CameraController } from "../objects/camera.js";
export class Trajectory {
public readonly orbits: Orbit[] = [];
private readonly _objects: THREE.Object3D[] = [];
private readonly _objects: THREE.Object3D[] = [];
private readonly _maneuvres: ManeuvreDetails[] = [];
private readonly _flybys: FlybyDetails[] = [];
static arrowMaterial: THREE.SpriteMaterial;
@@ -37,6 +38,7 @@ export class Trajectory {
this._createTrajectoryArcs(resolution);
this._createManeuvreSprites();
this._calculateManeuvresDetails();
this._calculateFlybyDetails();
}
private _createTrajectoryArcs(resolution: {width: number, height: number}){
@@ -76,6 +78,8 @@ export class Trajectory {
}
private _calculateManeuvresDetails(){
const departureDate = this.steps[0].dateOfStart;
for(let i = 0; i < this.steps.length; i++){
const step = this.steps[i];
const {maneuvre} = step;
@@ -97,80 +101,154 @@ export class Trajectory {
maneuvre.deltaVToPrevStep.z,
);
const details: ManeuvreDetails = {
stepIndex: i,
dateMET: step.dateOfStart - this.steps[0].dateOfStart,
progradeDV: progradeDir.dot(deltaV),
normalDV: normalDir.dot(deltaV),
radialDV: radialDir.dot(deltaV)
const details = {
stepIndex: i,
dateMET: step.dateOfStart - departureDate,
progradeDV: progradeDir.dot(deltaV),
normalDV: normalDir.dot(deltaV),
radialDV: radialDir.dot(deltaV),
};
this._maneuvres.push(details);
}
}
}
private _calculateFlybyDetails(){
const departureDate = this.steps[0].dateOfStart;
for(const {flyby} of this.steps){
if(flyby){
const body = this.system.bodyFromId(flyby.bodyId);
// non oriented inclination compared to x-z plane
let inc = flyby.inclination * 57.2957795131 // in degrees
inc = inc > 90 ? 180 - inc : inc;
const details: FlybyDetails = {
bodyId: flyby.bodyId,
soiEnterDateMET: flyby.soiEnterDate - departureDate,
soiExitDateMET: flyby.soiExitDate - departureDate,
periAltitude: (flyby.periRadius - body.radius) / 1000, // in km
inclinationDeg: inc
}
this._flybys.push(details);
}
}
}
public fillResultControls(maneuvreSelector: Selector, resultSpans: ResultPanelSpans, stepSlider: DiscreteRange, systemTime: TimeSelector, controls: CameraController){
public fillResultControls(resultItems: ResultPannelItems, systemTime: TimeSelector, controls: CameraController){
const depDate = new KSPTime(this.steps[0].dateOfStart, this.config.time);
resultSpans.totalDVSpan.innerHTML = this._totalDeltaV.toFixed(1);
resultSpans.depDateSpan.innerHTML = depDate.stringYDHMS("hms", "ut");
resultItems.totalDVSpan.innerHTML = this._totalDeltaV.toFixed(1);
resultItems.depDateSpan.innerHTML = depDate.stringYDHMS("hms", "ut");
resultSpans.depDateSpan.onclick = () => {
this.system.date = depDate.dateSeconds;
const onDateClick = (date: number) => () => {
this.system.date = date;
controls.centerOnTarget();
systemTime.time.dateSeconds = depDate.dateSeconds;
systemTime.time.dateSeconds = date;
systemTime.update();
};
resultItems.depDateSpan.onclick = onDateClick(depDate.dateSeconds);
const {stepSlider} = resultItems;
stepSlider.setMinMax(0, this.steps.length - 1);
stepSlider.input((index: number) => this._displayStepsUpTo(index));
stepSlider.value = this.steps.length - 1;
const selectorOptions: string[] = [];
for(let i = 0; i < this._maneuvres.length; i++){
const details = this._maneuvres[i];
const step = this.steps[details.stepIndex];
const context = (<ManeuvreInfo>step.maneuvre).context;
if(context.type == "ejection") {
const startBodyName = this.system.bodyFromId(step.attractorId).name;
const optionName = `${i+1}: ${startBodyName} escape`;
selectorOptions.push(optionName);
} else if(context.type == "dsm") {
const originName = this.system.bodyFromId(context.originId).name;
const targetName = this.system.bodyFromId(context.targetId).name;
const optionName = `${i+1}: ${originName}-${targetName} DSM`;
selectorOptions.push(optionName);
} else {
const arrivalBodyName = this.system.bodyFromId(step.attractorId).name;
const optionName = `${i+1}: ${arrivalBodyName} circularization`;
selectorOptions.push(optionName);
const selectorOptions: DetailsSelectorOption[] = [];
let maneuvreIdx = 0, flybyIdx = 0;
let optionNumber = 0;
for(let i = 0; i < this.steps.length; i++){
const {maneuvre, flyby} = this.steps[i];
if(maneuvre){
const details = this._maneuvres[maneuvreIdx];
const step = this.steps[details.stepIndex];
const context = (<ManeuvreInfo>step.maneuvre).context;
let optionName: string;
if(context.type == "ejection") {
const startBodyName = this.system.bodyFromId(step.attractorId).name;
optionName = `${++optionNumber}: ${startBodyName} escape`;
} else if(context.type == "dsm") {
const originName = this.system.bodyFromId(context.originId).name;
const targetName = this.system.bodyFromId(context.targetId).name;
optionName = `${++optionNumber}: ${originName}-${targetName} DSM`;
} else {
const arrivalBodyName = this.system.bodyFromId(step.attractorId).name;
optionName = `${++optionNumber}: ${arrivalBodyName} circularization`;
}
const option: DetailsSelectorOption = {
text: optionName,
index: i,
type: "maneuver",
origin: maneuvreIdx++
};
selectorOptions.push(option);
} else if(flyby){
const details = this._flybys[flybyIdx];
const bodyName = this.system.bodyFromId(details.bodyId).name;
const optionName = `${++optionNumber}: ${bodyName} flyby`;
const option: DetailsSelectorOption = {
text: optionName,
index: i,
type: "flyby",
origin: flybyIdx++
};
selectorOptions.push(option);
}
}
maneuvreSelector.fill(selectorOptions);
maneuvreSelector.change((_: string, index: number) => {
const details = this._maneuvres[index];
const dateEMT = new KSPTime(details.dateMET, this.config.time);
const optionNames = selectorOptions.map(opt => opt.text);
const {detailsSelector} = resultItems;
detailsSelector.fill(optionNames);
detailsSelector.change((_: string, index: number) => {
const option = selectorOptions[index];
resultSpans.dateSpan.innerHTML = dateEMT.stringYDHMS("hm", "emt");
resultSpans.progradeDVSpan.innerHTML = details.progradeDV.toFixed(1);
resultSpans.normalDVSpan.innerHTML = details.normalDV.toFixed(1);
resultSpans.radialDVSpan.innerHTML = details.radialDV.toFixed(1);
resultSpans.maneuvreNumber.innerHTML = (index + 1).toString();
if(option.type == "maneuver"){
const details = this._maneuvres[option.origin];
const dateEMT = new KSPTime(details.dateMET, this.config.time);
resultItems.dateSpan.innerHTML = dateEMT.stringYDHMS("hm", "emt");
resultItems.progradeDVSpan.innerHTML = details.progradeDV.toFixed(1);
resultItems.normalDVSpan.innerHTML = details.normalDV.toFixed(1);
resultItems.radialDVSpan.innerHTML = details.radialDV.toFixed(1);
resultItems.maneuvreNumber.innerHTML = (option.origin + 1).toString();
resultSpans.dateSpan.onclick = () => {
const date = depDate.dateSeconds + dateEMT.dateSeconds;
this.system.date = date;
controls.centerOnTarget();
systemTime.time.dateSeconds = date;
systemTime.update();
};
});
resultItems.dateSpan.onclick = onDateClick(date);
for(const step of this.steps){
resultItems.flybyDiv.hidden = true;
resultItems.maneuverDiv.hidden = false;
} else if(option.type == "flyby"){
const details = this._flybys[option.origin];
const startDateEMT = new KSPTime(details.soiEnterDateMET, this.config.time);
const endDateEMT = new KSPTime(details.soiExitDateMET, this.config.time);
resultItems.startDateSpan.innerHTML = startDateEMT.stringYDHMS("hm", "emt");
resultItems.endDateSpan.innerHTML = endDateEMT.stringYDHMS("hm", "emt");
resultItems.periAltitudeSpan.innerHTML = details.periAltitude.toFixed(0);
resultItems.inclinationSpan.innerHTML = details.inclinationDeg.toFixed(0);
resultItems.flybyNumberSpan.innerHTML = (option.origin + 1).toString();
let enterDate = depDate.dateSeconds + startDateEMT.dateSeconds;
resultItems.startDateSpan.onclick = onDateClick(enterDate);
let exitDate = depDate.dateSeconds + endDateEMT.dateSeconds;
resultItems.endDateSpan.onclick = onDateClick(exitDate);
resultItems.flybyDiv.hidden = false;
resultItems.maneuverDiv.hidden = true;
}
});
/*for(const step of this.steps){
console.log(step);
}
}*/
}
private _displayStepsUpTo(index: number){

73
src/types.d.ts vendored
View File

@@ -200,7 +200,8 @@ type TrajectoryStep = {
drawAngles: ArcEndsAngles,
dateOfStart: number,
duration: number,
maneuvre?: ManeuvreInfo
maneuvre?: ManeuvreInfo,
flyby?: FlybyInfo
};
type ManeuvreInfo = {
@@ -210,19 +211,28 @@ type ManeuvreInfo = {
context: ManeuvreContext
};
type FlybyInfo = {
bodyId: number,
soiEnterDate: number,
soiExitDate: number,
periRadius: number,
inclination: number
};
type ManeuvreContext =
| {type: "ejection"}
| {type: "dsm", originId: number, targetId: number}
| {type: "circularization"}
;
type DepartureInfo = {
type AgentDepartureInfo = {
phaseParam: number,
ejVelParam: number,
dateParam: number,
};
type LegInfo = {
type AgentLegInfo = {
exitedBodyId: number,
targetBodyId: number,
durationParam: number,
@@ -230,7 +240,7 @@ type LegInfo = {
dsmParam: number,
}
type FlybyInfo = {
type AgentFlybyInfo = {
flybyBodyId: number,
normAngleParam: number,
periRadiParam: number
@@ -252,19 +262,46 @@ type GenerationResult = {
}
type ManeuvreDetails = {
stepIndex: number,
dateMET: number,
progradeDV: number,
normalDV: number,
radialDV: number
stepIndex: number,
dateMET: number,
progradeDV: number,
normalDV: number,
radialDV: number,
};
type ResultPanelSpans = {
dateSpan: HTMLSpanElement,
progradeDVSpan: HTMLSpanElement,
normalDVSpan: HTMLSpanElement,
radialDVSpan: HTMLSpanElement,
depDateSpan: HTMLSpanElement,
totalDVSpan: HTMLSpanElement;
maneuvreNumber: HTMLSpanElement
}
type FlybyDetails = {
bodyId: number,
soiEnterDateMET: number,
soiExitDateMET: number,
periAltitude: number,
inclinationDeg: number
};
type ResultPannelItems = {
dateSpan: HTMLSpanElement,
progradeDVSpan: HTMLSpanElement,
normalDVSpan: HTMLSpanElement,
radialDVSpan: HTMLSpanElement,
depDateSpan: HTMLSpanElement,
totalDVSpan: HTMLSpanElement,
maneuvreNumber: HTMLSpanElement,
flybyNumberSpan: HTMLSpanElement,
startDateSpan: HTMLSpanElement,
endDateSpan: HTMLSpanElement,
periAltitudeSpan: HTMLSpanElement,
inclinationSpan: HTMLSpanElement
detailsSelector: Selector,
stepSlider: DiscreteRange,
maneuverDiv: HTMLDivElement,
flybyDiv: HTMLDivElement
};
type DetailsSelectorOption = {
text: string,
index: number,
type: "maneuver" | "flyby",
origin: number
};

View File

@@ -387,39 +387,71 @@ input[type="range"]
flex-direction: row;
}
#maneuvre-details
.result-details
{
margin-left: 0;
}
#maneuvre-details ul
.result-details ul
{
margin-top: 0px;
margin-bottom: 0px;
padding-left: 20px;
}
#maneuvre-details h3
.result-details h3
{
margin-top: 0;
}
#maneuvre-details li strong
.result-details li strong
{
display: inline-block;
width: 100px;
width: 127px;
}
#result-departure-date, #maneuvre-date
.clickable-date
{
color: rgb(86, 169, 224);
}
#result-departure-date:hover, #maneuvre-date:hover
.clickable-date:hover
{
cursor: pointer;
}
#result-panel-header
{
display: flex;
justify-content: space-between;
}
#steps-slider-control-group
{
margin-bottom: 0;
}
#steps-slider-controls
{
width: auto;
}
#displayed-steps-slider
{
margin-bottom: 0;
margin-top: 5px;
}
#result-controls .controls
{
width: auto;
}
#result-controls
{
width: 413px;
}
/* Paragraphs */
p