public override ManeuverParameters MakeNodeImpl(Orbit o, double UT, MechJebModuleTargetController target) { if (!target.NormalTargetExists) { throw new Exception("must select a target for the Hohmann transfer."); } else if (o.referenceBody != target.TargetOrbit.referenceBody) { throw new Exception("target for Hohmann transfer must be in the same sphere of influence."); } else if (o.eccentricity > 1) { throw new Exception("starting orbit for Hohmann transfer must not be hyperbolic."); } else if (target.TargetOrbit.eccentricity > 1) { throw new Exception("target orbit for Hohmann transfer must not be hyperbolic."); } else if (o.RelativeInclination(target.TargetOrbit) > 30 && o.RelativeInclination(target.TargetOrbit) < 150) { errorMessage = "Warning: target's orbital plane is at a " + o.RelativeInclination(target.TargetOrbit).ToString("F0") + "º angle to starting orbit's plane (recommend at most 30º). Planned transfer may not intercept target properly."; } else if (o.eccentricity > 0.2) { errorMessage = "Warning: Recommend starting Hohmann transfers from a near-circular orbit (eccentricity < 0.2). Planned transfer is starting from an orbit with eccentricity " + o.eccentricity.ToString("F2") + " and so may not intercept target properly."; } Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(o, target.TargetOrbit, UT, out UT); return(new ManeuverParameters(dV, UT)); }
override public void activateAction(int actionIndex) { base.activateAction(actionIndex); double UT; Vessel vessel = FlightGlobals.ActiveVessel; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(this.scriptModule.orbit, core.target.TargetOrbit, this.scriptModule.vesselState.time, out UT); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(this.scriptModule.orbit, dV, UT); this.endAction(); }
public override void Drive(FlightCtrlState s) { if (!core.target.NormalTargetExists) { users.Clear(); return; } core.node.autowarp = core.target.Distance > 1000; //don't warp when close to target, because warping introduces small perturbations //If we get within the target distance and then next maneuver node is still //far in the future, delete it and we will create a new one to match velocities immediately. //This can often happen because the target vessel's orbit shifts slightly when it is unpacked. if (core.target.Distance < desiredDistance && vessel.patchedConicSolver.maneuverNodes.Count > 0 && vessel.patchedConicSolver.maneuverNodes[0].UT > vesselState.time + 1) { vessel.RemoveAllManeuverNodes(); } if (vessel.patchedConicSolver.maneuverNodes.Count > 0) { //If we have plotted a maneuver, execute it. if (!core.node.enabled) { core.node.ExecuteAllNodes(this); } } else if (core.target.Distance < desiredDistance * 1.05 + 2 && core.target.RelativeVelocity.magnitude < 1) { //finished users.Clear(); core.thrust.ThrustOff(); status = "Successful rendezvous"; } else if (core.target.Distance < desiredDistance * 1.05 + 2) { //We are within the target distance: match velocities double UT = vesselState.time; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Within " + desiredDistance.ToString() + "m: matching velocities."; } else if (core.target.Distance < vesselState.radius / 25) { if (orbit.NextClosestApproachDistance(core.target.Orbit, vesselState.time) < desiredDistance && orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time) < vesselState.time + 150) { //We're close to the target, and on a course that will take us closer. Kill relvel at closest approach double UT = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); //adjust burn time so as to come to rest at the desired distance from the target: double approachDistance = orbit.Separation(core.target.Orbit, UT); double approachSpeed = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.Orbit.SwappedOrbitalVelocityAtUT(UT)).magnitude; if (approachDistance < desiredDistance) { UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed; } //if coming in hot, stop early to avoid crashing: if (approachSpeed > 10) { UT -= 1; } vessel.PlaceManeuverNode(orbit, dV, UT); status = "Planning to match velocities at closest approach."; } else { //We're not far from the target. Close the distance double closingSpeed = core.target.Distance / 100; if (closingSpeed > 100) { closingSpeed = 100; } double closingTime = core.target.Distance / closingSpeed; double UT = vesselState.time + 15; double interceptUT = UT + closingTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.Orbit, interceptUT, 0); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Close to target: plotting intercept"; } } else if (orbit.NextClosestApproachDistance(core.target.Orbit, vesselState.time) < core.target.Orbit.semiMajorAxis / 25) { //We're not close to the target, but we're on an approximate intercept course. //Kill relative velocities at closest approach double UT = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); //adjust burn time so as to come to rest at the desired distance from the target: double approachDistance = (orbit.SwappedAbsolutePositionAtUT(UT) - core.target.Orbit.SwappedAbsolutePositionAtUT(UT)).magnitude; double approachSpeed = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.Orbit.SwappedOrbitalVelocityAtUT(UT)).magnitude; if (approachDistance < desiredDistance) { UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed; } //if coming in hot, stop early to avoid crashing: if (approachSpeed > 10) { UT -= 1; } vessel.PlaceManeuverNode(orbit, dV, UT); status = "On intercept course. Planning to match velocities at closest approach."; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05 && orbit.eccentricity < 0.05 && orbit.SynodicPeriod(core.target.Orbit) < 5 * orbit.period) { //We're not on an intercept course, but we have a circular orbit in the right plane. //Also we are phasing quickly enough that it won't be too long until an intercept window //Plot a Hohmann transfer intercept. double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.Orbit, vesselState.time, out UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Planning Hohmann transfer for intercept."; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05 && orbit.eccentricity < 0.05) { //We are in a circular orbit in the right plane, but we aren't phasing quickly enough. Move to a better phasing orbit double lowPhasingRadius = core.target.Orbit.semiMajorAxis / 1.16; double highPhasingRadius = core.target.Orbit.semiMajorAxis * 1.16; bool useLowPhasingRadius = (lowPhasingRadius > mainBody.RealMaxAtmosphereAltitude() + 3000 && orbit.semiMajorAxis < core.target.orbit.semiMajorAxis); double phasingOrbitRadius = (useLowPhasingRadius ? lowPhasingRadius : highPhasingRadius); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } status = "Increasing phasing rate by establishing new phasing orbit at " + MuUtils.ToSI(phasingOrbitRadius - mainBody.Radius, 0) + "m"; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05) { //We're not on an intercept course. We're in the right plane, but our orbit isn't circular. Circularize. bool circularizeAtPe; if (orbit.eccentricity > 1) { circularizeAtPe = true; } else { circularizeAtPe = Math.Abs(orbit.PeR - core.target.Orbit.semiMajorAxis) < Math.Abs(orbit.ApR - core.target.Orbit.semiMajorAxis); } double UT; if (circularizeAtPe) { UT = Math.Max(vesselState.time, orbit.NextPeriapsisTime(vesselState.time)); } else { UT = orbit.NextApoapsisTime(vesselState.time); } Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Circularizing."; } else { //We're not on an intercept course, and we're not in the right plane. Match planes bool ascending; if (orbit.eccentricity < 1) { if (orbit.TimeOfAscendingNode(core.target.Orbit, vesselState.time) < orbit.TimeOfDescendingNode(core.target.Orbit, vesselState.time)) { ascending = true; } else { ascending = false; } } else { if (orbit.AscendingNodeExists(core.target.Orbit)) { ascending = true; } else { ascending = false; } } double UT; Vector3d dV; if (ascending) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.Orbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.Orbit, vesselState.time, out UT); } vessel.PlaceManeuverNode(orbit, dV, UT); status = "Matching planes."; } }
protected override void WindowGUI(int windowID) { if (!core.target.NormalTargetExists) { GUILayout.Label("Select a target to rendezvous with."); base.WindowGUI(windowID); return; } if (core.target.Orbit.referenceBody != orbit.referenceBody) { GUILayout.Label("Rendezvous target must be in the same sphere of influence."); base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); //Information readouts: GuiUtils.SimpleLabel("Rendezvous target", core.target.Name); double leadTime = 30; GuiUtils.SimpleLabel("Target orbit", MuUtils.ToSI(core.target.Orbit.PeA, 3) + "m x " + MuUtils.ToSI(core.target.Orbit.ApA, 3) + "m"); GuiUtils.SimpleLabel("Current orbit", MuUtils.ToSI(orbit.PeA, 3) + "m x " + MuUtils.ToSI(orbit.ApA, 3) + "m"); GuiUtils.SimpleLabel("Relative inclination", orbit.RelativeInclination(core.target.Orbit).ToString("F2") + "º"); double closestApproachTime = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); GuiUtils.SimpleLabel("Time until closest approach", GuiUtils.TimeToDHMS(closestApproachTime - vesselState.time)); GuiUtils.SimpleLabel("Separation at closest approach", MuUtils.ToSI(orbit.Separation(core.target.Orbit, closestApproachTime), 0) + "m"); //Maneuver planning buttons: if (GUILayout.Button("Align Planes")) { double UT; Vector3d dV; if (orbit.AscendingNodeExists(core.target.Orbit)) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.Orbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.Orbit, vesselState.time, out UT); } vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } GUILayout.BeginHorizontal(); if (GUILayout.Button("Establish new orbit at")) { double phasingOrbitRadius = phasingOrbitAltitude + mainBody.Radius; vessel.RemoveAllManeuverNodes(); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } } phasingOrbitAltitude.text = GUILayout.TextField(phasingOrbitAltitude.text, GUILayout.Width(70)); GUILayout.Label("km", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Intercept with Hohmann transfer")) { double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.Orbit, vesselState.time, out UT); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (GUILayout.Button("Match velocities at closest approach")) { double UT = closestApproachTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (GUILayout.Button("Get closer")) { double UT = vesselState.time; double interceptUT = UT + 100; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.Orbit, interceptUT, 10); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
public override ManeuverParameters MakeNodeImpl(Orbit o, double universalTime, MechJebModuleTargetController target) { double UT = 0; if (!target.NormalTargetExists) { throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception1"));//must select a target for the bi-impulsive transfer. } else if (o.referenceBody != target.TargetOrbit.referenceBody) { throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception2"));//target for bi-impulsive transfer must be in the same sphere of influence. } Vector3d dV; Orbit targetOrbit = target.TargetOrbit; if (periodOffset != 0) { targetOrbit = target.TargetOrbit.Clone(); targetOrbit.MutatedOrbit(periodOffset: periodOffset); } if (simpleTransfer) { dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(o, targetOrbit, universalTime, out UT); } else { if (timeSelector.timeReference == TimeReference.COMPUTED) { dV = OrbitalManeuverCalculator.DeltaVAndTimeForBiImpulsiveAnnealed(o, targetOrbit, universalTime, out UT, intercept_only: intercept_only); } else { var anExists = o.AscendingNodeExists(target.TargetOrbit); var dnExists = o.DescendingNodeExists(target.TargetOrbit); double anTime = o.TimeOfAscendingNode(target.TargetOrbit, universalTime); double dnTime = o.TimeOfDescendingNode(target.TargetOrbit, universalTime); if (timeSelector.timeReference == TimeReference.REL_ASCENDING) { if (!anExists) { throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception3"));//ascending node with target doesn't exist. } UT = anTime; } else if (timeSelector.timeReference == TimeReference.REL_DESCENDING) { if (!dnExists) { throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception4"));//descending node with target doesn't exist. } UT = dnTime; } else if (timeSelector.timeReference == TimeReference.REL_NEAREST_AD) { if (!anExists && !dnExists) { throw new OperationException(Localizer.Format("#MechJeb_Hohm_Exception5"));//neither ascending nor descending node with target exists. } if (!dnExists || anTime <= dnTime) { UT = anTime; } else { UT = dnTime; } } UT = timeSelector.ComputeManeuverTime(o, universalTime, target); dV = OrbitalManeuverCalculator.DeltaVAndTimeForBiImpulsiveAnnealed(o, targetOrbit, UT, out UT, intercept_only: intercept_only, fixed_ut: true); } } return(new ManeuverParameters(dV, UT)); }
protected override void WindowGUI(int windowID) { if (btNormal == null) { btNormal = new GUIStyle(GUI.skin.button); btNormal.normal.textColor = btNormal.focused.textColor = Color.white; btNormal.hover.textColor = btNormal.active.textColor = Color.yellow; btNormal.onNormal.textColor = btNormal.onFocused.textColor = btNormal.onHover.textColor = btNormal.onActive.textColor = Color.green; btNormal.padding = new RectOffset(8, 8, 8, 8); btActive = new GUIStyle(btNormal); btActive.active = btActive.onActive; btActive.normal = btActive.onNormal; btActive.onFocused = btActive.focused; btActive.hover = btActive.onHover; } GUILayout.BeginVertical(); if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button1")))//Disengage autopilot { autopilot.users.Remove(this); } } else { if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button2")))//Engage autopilot { autopilot.users.Add(this); } } if (ascentPathIdx == ascentType.PVG) { if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button3")))//Reset Guidance (DO NOT PRESS) { core.guidance.Reset(); } GUILayout.BeginHorizontal(); // EditorStyles.toolbar); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button4"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //"TARG" { autopilot.showTargeting = !autopilot.showTargeting; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button5"), autopilot.showGuidanceSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //GUID { autopilot.showGuidanceSettings = !autopilot.showGuidanceSettings; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button6"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //OPTS { autopilot.showSettings = !autopilot.showSettings; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button7"), autopilot.showStatus ? btActive : btNormal, GUILayout.ExpandWidth(true))) //STATUS { autopilot.showStatus = !autopilot.showStatus; } GUILayout.EndHorizontal(); } else if (ascentPathIdx == ascentType.GRAVITYTURN) { GUILayout.BeginHorizontal(); // EditorStyles.toolbar); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button8"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //TARG { autopilot.showTargeting = !autopilot.showTargeting; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button9"), autopilot.showGuidanceSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //GUID { autopilot.showGuidanceSettings = !autopilot.showGuidanceSettings; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button10"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //OPTS { autopilot.showSettings = !autopilot.showSettings; } GUILayout.EndHorizontal(); } else if (ascentPathIdx == ascentType.BREATHING_GT) { GUILayout.BeginHorizontal(); // EditorStyles.toolbar); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button8"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //TARG { autopilot.showTargeting = !autopilot.showTargeting; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button9"), autopilot.showGuidanceSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))//GUID { autopilot.showGuidanceSettings = !autopilot.showGuidanceSettings; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button10"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true)))//OPTS { autopilot.showSettings = !autopilot.showSettings; } GUILayout.EndHorizontal(); } else if (ascentPathIdx == ascentType.CLASSIC) { GUILayout.BeginHorizontal(); // EditorStyles.toolbar); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button11"), autopilot.showTargeting ? btActive : btNormal, GUILayout.ExpandWidth(true))) //TARG { autopilot.showTargeting = !autopilot.showTargeting; } if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button12"), autopilot.showSettings ? btActive : btNormal, GUILayout.ExpandWidth(true))) //OPTS { autopilot.showSettings = !autopilot.showSettings; } GUILayout.EndHorizontal(); } if (autopilot.showTargeting) { if (ascentPathIdx == ascentType.PVG) { GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label1"), autopilot.desiredOrbitAltitude, "km"); //Target Periapsis GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label2"), pvgascent.desiredApoapsis, "km"); //Target Apoapsis: if (pvgascent.desiredApoapsis >= 0 && pvgascent.desiredApoapsis < autopilot.desiredOrbitAltitude) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label3"), s);//Ap < Pe: circularizing orbit } if (pvgascent.desiredApoapsis < 0) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = XKCDColors.Orange; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label4"), s);//Hyperbolic target orbit (neg Ap) } } else { GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label5"), autopilot.desiredOrbitAltitude, "km");//Orbit altitude } GUIStyle si = new GUIStyle(GUI.skin.label); if (Math.Abs(desiredInclination) < Math.Abs(vesselState.latitude) - 2.001) { si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Orange; } GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label6"), si, GUILayout.ExpandWidth(true));//Orbit inc. desiredInclination.text = GUILayout.TextField(desiredInclination.text, GUILayout.ExpandWidth(true), GUILayout.Width(100)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button13")))//Current { desiredInclination.val = vesselState.latitude; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (Math.Abs(desiredInclination) < Math.Abs(vesselState.latitude) - 2.001) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label7", Math.Abs(vesselState.latitude) - Math.Abs(desiredInclination)), si);//inc {0:F1}º below current latitude } GUILayout.EndHorizontal(); autopilot.desiredInclination = desiredInclination; } if (autopilot.showGuidanceSettings) { if (ascentPathIdx == ascentType.GRAVITYTURN) { GUILayout.BeginVertical(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label8"), gtascent.turnStartAltitude, "km"); //Turn start altitude: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label9"), gtascent.turnStartVelocity, "m/s"); //Turn start velocity: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label10"), gtascent.turnStartPitch, "deg"); //Turn start pitch: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label11"), gtascent.intermediateAltitude, "km"); //Intermediate altitude: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label12"), gtascent.holdAPTime, "s"); //Hold AP Time: GUILayout.EndVertical(); } else if (ascentPathIdx == ascentType.BREATHING_GT) { GUILayout.BeginVertical(); //GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label8"), bgtascent.turnStartAltitude, "km");//Turn start altitude: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label9"), bgtascent.turnStartVelocity, "m/s"); //Turn start velocity: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label10"), bgtascent.turnStartPitch, "deg"); //Turn start pitch: GuiUtils.SimpleTextBox(Localizer.Format("speed for breathing mode:"), bgtascent.startBreathingSpeed, "m/s"); //speed for breathing mode: GuiUtils.SimpleTextBox(Localizer.Format("TWR to throttle other:"), bgtascent.minTWRthrottle, "s"); //TWR to throttle other: GUILayout.EndVertical(); } else if (ascentPathIdx == ascentType.PVG) { GUILayout.BeginVertical(); GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label13"), pvgascent.pitchStartVelocity, "m/s"); //Booster Pitch start: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label14"), pvgascent.pitchRate, "°/s"); //Booster Pitch rate: GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label15"), core.guidance.pvgInterval, "s"); //Guidance Interval: if (core.guidance.pvgInterval < 1 || core.guidance.pvgInterval > 30) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label16"), s); //Guidance intervals are limited to between 1s and 30s } GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label17"), autopilot.limitQa, "Pa-rad"); //Qα limit if (autopilot.limitQa < 100 || autopilot.limitQa > 4000) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; if (autopilot.limitQa < 100) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label18"), s);//Qα limit cannot be set to lower than 100 Pa-rad } else if (autopilot.limitQa > 10000) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label19"), s);//Qα limit cannot be set to higher than 10000 Pa-rad } else { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label20"), s);//Qα limit is recommended to be 1000 to 4000 Pa-rad } } pvgascent.omitCoast = GUILayout.Toggle(pvgascent.omitCoast, Localizer.Format("#MechJeb_Ascent_checkbox1"));//Omit Coast GUILayout.EndVertical(); } } autopilot.limitQaEnabled = (ascentPathIdx == ascentType.PVG); // this is mandatory for PVG if (autopilot.showSettings) { ToggleAscentNavballGuidanceInfoItem(); if (ascentPathIdx != ascentType.PVG) { core.thrust.LimitToPreventOverheatsInfoItem(); //core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitToMaxDynamicPressureInfoItem(); core.thrust.LimitAccelerationInfoItem(); core.thrust.LimitThrottleInfoItem(); core.thrust.LimiterMinThrottleInfoItem(); core.thrust.LimitElectricInfoItem(); } else { core.thrust.LimitToPreventOverheatsInfoItem(); //core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitToMaxDynamicPressureInfoItem(); //core.thrust.LimitAccelerationInfoItem(); //core.thrust.LimitThrottleInfoItem(); core.thrust.LimiterMinThrottleInfoItem(); //core.thrust.LimitElectricInfoItem(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label21")); //FIXME: g-limiter is down for maintenance core.thrust.limitAcceleration = false; core.thrust.limitThrottle = false; core.thrust.limitToTerminalVelocity = false; core.thrust.electricThrottle = false; } GUILayout.BeginHorizontal(); autopilot.forceRoll = GUILayout.Toggle(autopilot.forceRoll, Localizer.Format("#MechJeb_Ascent_checkbox2"));//Force Roll if (autopilot.forceRoll) { GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label22"), autopilot.verticalRoll, "º", 30f); //climb GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label23"), autopilot.turnRoll, "º", 30f); //turn } GUILayout.EndHorizontal(); if (ascentPathIdx != ascentType.PVG) { GUILayout.BeginHorizontal(); GUIStyle s = new GUIStyle(GUI.skin.toggle); if (autopilot.limitingAoA) { s.onHover.textColor = s.onNormal.textColor = Color.green; } autopilot.limitAoA = GUILayout.Toggle(autopilot.limitAoA, Localizer.Format("#MechJeb_Ascent_checkbox3"), s, GUILayout.ExpandWidth(true));//Limit AoA to autopilot.maxAoA.text = GUILayout.TextField(autopilot.maxAoA.text, GUILayout.Width(30)); GUILayout.Label("º (" + autopilot.currentMaxAoA.ToString("F1") + "°)", GUILayout.ExpandWidth(true)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Space(25); if (autopilot.limitAoA) { GUIStyle sl = new GUIStyle(GUI.skin.label); if (autopilot.limitingAoA && vesselState.dynamicPressure < autopilot.aoALimitFadeoutPressure) { sl.normal.textColor = sl.hover.textColor = Color.green; } GuiUtils.SimpleTextBox(Localizer.Format("#MechJeb_Ascent_label24"), autopilot.aoALimitFadeoutPressure, "Pa", 50, sl);//Dynamic Pressure Fadeout } GUILayout.EndHorizontal(); autopilot.limitQaEnabled = false; // this is only for PVG } if (ascentPathIdx == ascentType.CLASSIC) { // corrective steering only applies to Classic GUILayout.BeginHorizontal(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, Localizer.Format("#MechJeb_Ascent_checkbox4"), GUILayout.ExpandWidth(false));//Corrective steering if (autopilot.correctiveSteering) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label25"), GUILayout.ExpandWidth(false));//Gain autopilot.correctiveSteeringGain.text = GUILayout.TextField(autopilot.correctiveSteeringGain.text, GUILayout.Width(40)); } GUILayout.EndHorizontal(); } autopilot.autostage = GUILayout.Toggle(autopilot.autostage, Localizer.Format("#MechJeb_Ascent_checkbox5"));//Autostage if (autopilot.autostage) { core.staging.AutostageSettingsInfoItem(); } autopilot.autodeploySolarPanels = GUILayout.Toggle(autopilot.autodeploySolarPanels, Localizer.Format("#MechJeb_Ascent_checkbox6"));//Auto-deploy solar panels autopilot.autoDeployAntennas = GUILayout.Toggle(autopilot.autoDeployAntennas, Localizer.Format("#MechJeb_Ascent_checkbox7"));//Auto-deploy antennas GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, Localizer.Format("#MechJeb_Ascent_checkbox8"));//Auto-warp if (ascentPathIdx != ascentType.PVG) { autopilot.skipCircularization = GUILayout.Toggle(autopilot.skipCircularization, Localizer.Format("#MechJeb_Ascent_checkbox9"));//Skip Circularization } else { // skipCircularization is always true for Optimizer autopilot.skipCircularization = true; } GUILayout.EndHorizontal(); } if (autopilot.showStatus) { if (ascentPathIdx == ascentType.PVG) { if (core.guidance.solution != null) { for (int i = core.guidance.solution.num_segments; i > 0; i--) { GUILayout.Label(String.Format("{0}: {1}", i, core.guidance.solution.ArcString(vesselState.time, i - 1))); } } GUILayout.BeginHorizontal(); GUILayout.Label(String.Format("vgo: {0:F1}", core.guidance.vgo), GUILayout.Width(100)); GUILayout.Label(String.Format("heading: {0:F1}", core.guidance.heading), GUILayout.Width(100)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(String.Format("tgo: {0:F3}", core.guidance.tgo), GUILayout.Width(100)); GUILayout.Label(String.Format("pitch: {0:F1}", core.guidance.pitch), GUILayout.Width(100)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUIStyle si = new GUIStyle(GUI.skin.label); if (core.guidance.isStable()) { si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Green; } else if (core.guidance.isInitializing() || core.guidance.status == PVGStatus.FINISHED) { si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Orange; } else { si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Red; } GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label26") + core.guidance.status, si);//Guidance Status: GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label27") + core.guidance.successful_converges, GUILayout.Width(100)); //converges: GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label28") + core.guidance.last_lm_status, GUILayout.Width(100)); //status: GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("n: " + core.guidance.last_lm_iteration_count + "(" + core.guidance.max_lm_iteration_count + ")", GUILayout.Width(100)); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label29") + GuiUtils.TimeToDHMS(core.guidance.staleness));//staleness: GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label(String.Format("znorm: {0:G5}", core.guidance.last_znorm)); GUILayout.EndHorizontal(); if (core.guidance.last_failure_cause != null) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.red; GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label30") + core.guidance.last_failure_cause, s);//LAST FAILURE: GUILayout.EndHorizontal(); } if (vessel.situation != Vessel.Situations.LANDED && vessel.situation != Vessel.Situations.PRELAUNCH && vessel.situation != Vessel.Situations.SPLASHED) { double m0 = atmoStats[vessel.currentStage].startMass; double thrust = atmoStats[vessel.currentStage].startThrust; if (Math.Abs(vesselState.mass - m0) / m0 > 0.01) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.BeginHorizontal(); GUILayout.Label(String.Format(Localizer.Format("#MechJeb_Ascent_label31") + "{0:F1}%", (vesselState.mass - m0) / m0 * 100.0), s);//MASS IS OFF BY GUILayout.EndHorizontal(); } if (Math.Abs(vesselState.thrustCurrent - thrust) / thrust > 0.01) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.yellow; GUILayout.BeginHorizontal(); GUILayout.Label(String.Format(Localizer.Format("#MechJeb_Ascent_label32") + "{0:F1}%", (vesselState.thrustCurrent - thrust) / thrust * 100.0), s);//THRUST IS OFF BY GUILayout.EndHorizontal(); } } } } if (vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (core.node.autowarp) { GUILayout.BeginHorizontal(); GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label33"), GUILayout.ExpandWidth(true)); //Launch countdown: autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60)); GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary) { // disable plane/rendezvous/interplanetary for now if (ascentPathIdx != ascentType.PVG) { GUILayout.BeginHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button14"), GUILayout.ExpandWidth(false))) //Launch to rendezvous: { launchingToRendezvous = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit)); } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.BeginHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button15"), GUILayout.ExpandWidth(false))) //Launch into plane of target { launchingToPlane = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPlane(autopilot.launchLANDifference, mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit)); } autopilot.launchLANDifference.text = GUILayout.TextField( autopilot.launchLANDifference.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody) { if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button16"))) //Launch at interplanetary window { launchingToInterplanetary = true; //compute the desired launch date OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT); double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt( Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter); //launch just before the window, but don't try to launch in the past interplanetaryWindowUT -= 3 * desiredOrbitPeriod; interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT); autopilot.StartCountdown(interplanetaryWindowUT); } } } } else { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label34")); //Select a target for a timed launch. } if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous) { string message = ""; if (launchingToInterplanetary) { message = Localizer.Format("#MechJeb_Ascent_msg1"); //Launching at interplanetary window } else if (launchingToPlane) { desiredInclination = MuUtils.Clamp(core.target.TargetOrbit.inclination, Math.Abs(vesselState.latitude), 180 - Math.Abs(vesselState.latitude)); desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); message = Localizer.Format("#MechJeb_Ascent_msg2"); //Launching to target plane } else if (launchingToRendezvous) { message = "#MechJeb_Ascent_msg3"; //Launching to rendezvous } if (autopilot.tMinus > 3 * vesselState.deltaT) { message += ": T-" + GuiUtils.TimeToDHMS(autopilot.tMinus, 1); } GUILayout.Label(message); if (GUILayout.Button(Localizer.Format("#MechJeb_Ascent_button17")))//Abort { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = autopilot.timedLaunch = false; } } } if (autopilot.enabled) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label35") + autopilot.status);//Autopilot status: } if (core.DeactivateControl) { GUIStyle s = new GUIStyle(GUI.skin.label); s.normal.textColor = Color.red; GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label36"), s);//CONTROL DISABLED (AVIONICS) } } if (!vessel.patchedConicsUnlocked() && ascentPathIdx != ascentType.PVG) { GUILayout.Label(Localizer.Format("#MechJeb_Ascent_label37"));//"Warning: MechJeb is unable to circularize without an upgraded Tracking Station." } GUILayout.BeginHorizontal(); autopilot.ascentPathIdxPublic = (ascentType)GuiUtils.ComboBox.Box((int)autopilot.ascentPathIdxPublic, autopilot.ascentPathList, this); GUILayout.EndHorizontal(); if (autopilot.ascentMenu != null) { autopilot.ascentMenu.enabled = GUILayout.Toggle(autopilot.ascentMenu.enabled, Localizer.Format("#MechJeb_Ascent_checkbox10")); //Edit ascent path } GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME); if (showingGuidance) { GUILayout.Label("The purple circle on the navball points along the ascent path."); if (GUILayout.Button("Stop showing navball guidance")) { core.target.Unset(); } } else if (GUILayout.Button("Show navball ascent path guidance")) { core.target.SetDirectionTarget(TARGET_NAME); } if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot")) { autopilot.users.Remove(this); } } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } ascentPath = autopilot.ascentPath; GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km"); autopilot.desiredInclination = desiredInclination; } GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º"); core.thrust.LimitToPreventOverheatsInfoItem(); core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitAccelerationInfoItem(); core.thrust.LimitThrottleInfoItem(); GUILayout.BeginHorizontal(); autopilot.forceRoll = GUILayout.Toggle(autopilot.forceRoll, "Force Roll"); if (autopilot.forceRoll) { GuiUtils.SimpleTextBox("climb", autopilot.verticalRoll, "º", 30f); GuiUtils.SimpleTextBox("turn", autopilot.turnRoll, "º", 30f); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUIStyle s = new GUIStyle(GUI.skin.toggle); if (autopilot.limitingAoA) { s.onHover.textColor = s.onNormal.textColor = Color.green; } autopilot.limitAoA = GUILayout.Toggle(autopilot.limitAoA, "Limit AoA to", s, GUILayout.ExpandWidth(true)); autopilot.maxAoA.text = GUILayout.TextField(autopilot.maxAoA.text, GUILayout.Width(30)); GUILayout.Label("º (" + autopilot.currentMaxAoA.ToString("F1") + "°)", GUILayout.ExpandWidth(true)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Space(25); if (autopilot.limitAoA) { GUIStyle sl = new GUIStyle(GUI.skin.label); if (autopilot.limitingAoA && vesselState.dynamicPressure < autopilot.aoALimitFadeoutPressure) { sl.normal.textColor = sl.hover.textColor = Color.green; } GuiUtils.SimpleTextBox("Dynamic Pressure Fadeout", autopilot.aoALimitFadeoutPressure, "pa", 50, sl); } GUILayout.EndHorizontal(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering"); autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage"); if (autopilot.autostage) { core.staging.AutostageSettingsInfoItem(); } autopilot.autodeploySolarPanels = GUILayout.Toggle(autopilot.autodeploySolarPanels, "Auto-deploy solar panels"); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp"); if (autopilot != null && vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (core.node.autowarp) { GUILayout.BeginHorizontal(); GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true)); autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60)); GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary) { GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false))) { launchingToRendezvous = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit)); } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Launch into plane of target")) { launchingToPlane = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit)); } if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody) { if (GUILayout.Button("Launch at interplanetary window")) { launchingToInterplanetary = true; //compute the desired launch date OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT); double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter); //launch just before the window, but don't try to launch in the past interplanetaryWindowUT -= 3 * desiredOrbitPeriod; interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT); autopilot.StartCountdown(interplanetaryWindowUT); } } } } else { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; GUILayout.Label("Select a target for a timed launch."); } if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous) { string message = ""; if (launchingToInterplanetary) { message = "Launching at interplanetary window"; } else if (launchingToPlane) { desiredInclination = core.target.TargetOrbit.inclination; desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); message = "Launching to target plane"; } else if (launchingToRendezvous) { message = "Launching to rendezvous"; } if (autopilot.tMinus > 3 * vesselState.deltaT) { message += ": T-" + GuiUtils.TimeToDHMS(autopilot.tMinus, 1); } GUILayout.Label(message); if (GUILayout.Button("Abort")) { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = autopilot.timedLaunch = false; } } } if (autopilot != null && autopilot.enabled) { GUILayout.Label("Autopilot status: " + autopilot.status); } if (!vessel.patchedConicsUnlocked()) { GUILayout.Label("Warning: MechJeb is unable to circularize without an upgraded Tracking Station."); } MechJebModuleAscentPathEditor editor = core.GetComputerModule <MechJebModuleAscentPathEditor>(); if (editor != null) { editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path"); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); bool showingGuidance = (core.target.Target != null && core.target.Name == TARGET_NAME); if (showingGuidance) { GUILayout.Label("The purple circle on the navball points along the ascent path."); if (GUILayout.Button("Stop showing navball guidance")) { core.target.Unset(); } } else if (GUILayout.Button("Show navball ascent path guidance")) { core.target.SetDirectionTarget(TARGET_NAME); } if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot")) { autopilot.users.Remove(this); } } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } ascentPath = autopilot.ascentPath; GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km"); autopilot.desiredInclination = desiredInclination; } GuiUtils.SimpleTextBox("Orbit inclination", desiredInclination, "º"); core.thrust.LimitToPreventOverheatsInfoItem(); core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitAccelerationInfoItem(); core.thrust.LimitThrottleInfoItem(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering"); autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage"); if (autopilot.autostage) { core.staging.AutostageSettingsInfoItem(); } core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp"); if (autopilot != null && vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (core.node.autowarp) { GUILayout.BeginHorizontal(); GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true)); autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60)); GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary) { GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false))) { launchingToRendezvous = true; lastTMinus = 999; } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button("Launch into plane of target")) { launchingToPlane = true; lastTMinus = 999; } if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody) { if (GUILayout.Button("Launch at interplanetary window")) { launchingToInterplanetary = true; lastTMinus = 999; //compute the desired launch date OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT); double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter); //launch just before the window, but don't try to launch in the past interplanetaryWindowUT -= 3 * desiredOrbitPeriod; interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT); } } } } else { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; GUILayout.Label("Select a target for a timed launch."); } if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous) { double tMinus = 0; string message = ""; if (launchingToInterplanetary) { tMinus = interplanetaryWindowUT - vesselState.time; message = "Launching at interplanetary window"; } else if (launchingToPlane) { tMinus = LaunchTiming.TimeToPlane(mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit); desiredInclination = core.target.TargetOrbit.inclination; desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); message = "Launching to target plane"; } else if (launchingToRendezvous) { tMinus = LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit); message = "Launching to rendezvous"; } double launchTime = vesselState.time + tMinus; if (tMinus < 3 * vesselState.deltaT || (tMinus > 10.0 && lastTMinus < 1.0)) { if (autopilot.enabled) { Staging.ActivateNextStage(); } launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; } else { message += ": T-" + MuUtils.ToSI(tMinus, 0) + "s"; if (autopilot.enabled && core.node.autowarp) { core.warp.WarpToUT(launchTime - autopilot.warpCountDown); } } GUILayout.Label(message); lastTMinus = tMinus; if (GUILayout.Button("Abort")) { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; } } } if (autopilot != null && autopilot.enabled) { GUILayout.Label("Autopilot status: " + autopilot.status); } MechJebModuleAscentPathEditor editor = core.GetComputerModule <MechJebModuleAscentPathEditor>(); if (editor != null) { editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path"); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { if (!core.target.NormalTargetExists) { GUILayout.Label("Select a target to rendezvous with."); base.WindowGUI(windowID); return; } if (core.target.Orbit.referenceBody != orbit.referenceBody) { GUILayout.Label("Rendezvous target must be in the same sphere of influence."); base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); step = (Step)GuiUtils.ArrowSelector((int)step, numSteps, stepStrings[(int)step]); double leadTime = 30; switch (step) { case Step.AlignPlanes: GUILayout.Label("First, bring your relative inclination to zero by aligning your orbital plane with the target's orbital plane:"); GUILayout.Label("Relative inclination: " + orbit.RelativeInclination(core.target.Orbit).ToString("F2") + "º"); if (GUILayout.Button("Align Planes")) { double UT; Vector3d dV; if (orbit.AscendingNodeExists(core.target.Orbit)) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.Orbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.Orbit, vesselState.time, out UT); } vessel.PlaceManeuverNode(orbit, dV, UT); } break; case Step.PhasingOrbit: double phasingOrbitRadius = 0.9 * core.target.Orbit.PeR; if (phasingOrbitRadius < orbit.referenceBody.Radius + orbit.referenceBody.RealMaxAtmosphereAltitude()) { phasingOrbitRadius = 1.1 * core.target.Orbit.ApR; } double phasingOrbitAltitude = phasingOrbitRadius - mainBody.Radius; GUILayout.Label("Next, establish a circular phasing orbit close to the target orbit."); GUILayout.Label("Target orbit: " + MuUtils.ToSI(core.target.Orbit.PeA, 3) + "m x " + MuUtils.ToSI(core.target.Orbit.ApA, 3) + "m"); GUILayout.Label("Suggested phasing orbit: " + MuUtils.ToSI(phasingOrbitAltitude, 3) + "m x " + MuUtils.ToSI(phasingOrbitAltitude, 3) + "m"); GUILayout.Label("Current orbit: " + MuUtils.ToSI(orbit.PeA, 3) + "m x " + MuUtils.ToSI(orbit.ApA, 3) + "m"); if (GUILayout.Button("Establish Phasing Orbit")) { if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } } break; case Step.Transfer: GUILayout.Label("Once in the phasing orbit, transfer to the target orbit at just the right time to intercept the target:"); if (GUILayout.Button("Intercept with Hohmann transfer")) { double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.Orbit, vesselState.time, out UT); vessel.PlaceManeuverNode(orbit, dV, UT); } double closestApproachTime = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); GUILayout.Label("Once on a transfer trajectory, match velocities at closest approach:"); GUILayout.Label("Time until closest approach: " + GuiUtils.TimeToDHMS(closestApproachTime - vesselState.time)); GUILayout.Label("Separation at closest approach: " + MuUtils.ToSI(orbit.Separation(core.target.Orbit, closestApproachTime), 0) + "m"); if (GUILayout.Button("Match velocities at closest approach")) { double UT = closestApproachTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); } break; case Step.GetCloser: GUILayout.Label("If you aren't close enough after matching velocities, thrust gently toward the target:"); if (GUILayout.Button("Get closer")) { double UT = vesselState.time; double interceptUT = UT + 100; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.Orbit, interceptUT, 10); vessel.PlaceManeuverNode(orbit, dV, UT); } GUILayout.Label("Then match velocities again at closest approach"); break; } GUILayout.EndVertical(); MechJebModuleRendezvousAutopilot autopilot = core.GetComputerModule <MechJebModuleRendezvousAutopilot>(); if (autopilot != null) { bool active = GUILayout.Toggle(autopilot.enabled, "Autopilot enable"); if (autopilot.enabled != active) { if (active) { autopilot.users.Add(this); } else { autopilot.users.Remove(this); } } if (autopilot.enabled) { GUILayout.Label("Status: " + autopilot.status); } } base.WindowGUI(windowID); }
protected override void WindowGUI(int windowID) { if (!core.target.NormalTargetExists) { GUILayout.Label(Localizer.Format("#MechJeb_RZplan_label1"));//"Select a target to rendezvous with." base.WindowGUI(windowID); return; } if (core.target.TargetOrbit.referenceBody != orbit.referenceBody) { GUILayout.Label(Localizer.Format("#MechJeb_RZplan_label2"));//"Rendezvous target must be in the same sphere of influence." base.WindowGUI(windowID); return; } GUILayout.BeginVertical(); //Information readouts: GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label3"), core.target.Name);//"Rendezvous target" const double leadTime = 30; GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label4"), MuUtils.ToSI(core.target.TargetOrbit.PeA, 3) + "m x " + MuUtils.ToSI(core.target.TargetOrbit.ApA, 3) + "m"); //"Target orbit" GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label5"), MuUtils.ToSI(orbit.PeA, 3) + "m x " + MuUtils.ToSI(orbit.ApA, 3) + "m"); //"Current orbit" GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label6"), orbit.RelativeInclination(core.target.TargetOrbit).ToString("F2") + "º"); //"Relative inclination" double closestApproachTime = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time); GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label7"), GuiUtils.TimeToDHMS(closestApproachTime - vesselState.time)); //"Time until closest approach" GuiUtils.SimpleLabel(Localizer.Format("#MechJeb_RZplan_label8"), MuUtils.ToSI(orbit.Separation(core.target.TargetOrbit, closestApproachTime), 0) + "m"); //"Separation at closest approach" //Maneuver planning buttons: if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button1")))//"Align Planes" { double UT; Vector3d dV; if (orbit.AscendingNodeExists(core.target.TargetOrbit)) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } GUILayout.BeginHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button2")))//"Establish new orbit at" { double phasingOrbitRadius = phasingOrbitAltitude + mainBody.Radius; vessel.RemoveAllManeuverNodes(); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } } phasingOrbitAltitude.text = GUILayout.TextField(phasingOrbitAltitude.text, GUILayout.Width(70)); GUILayout.Label("km", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button3")))//"Intercept with Hohmann transfer" { double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.TargetOrbit, vesselState.time, out UT); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button4")))//"Match velocities at closest approach" { double UT = closestApproachTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button5")))//"Get closer" { double UT = vesselState.time; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.TargetOrbit, 100, 10); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } if (core.node != null) { if (vessel.patchedConicSolver.maneuverNodes.Any() && !core.node.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button6")))//"Execute next node" { core.node.ExecuteOneNode(this); } if (vessel.patchedConicSolver.maneuverNodes.Count > 1) { if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button7")))//"Execute all nodes" { core.node.ExecuteAllNodes(this); } } } else if (core.node.enabled) { if (GUILayout.Button(Localizer.Format("#MechJeb_RZplan_button8")))//"Abort node execution" { core.node.Abort(); } } GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, Localizer.Format("#MechJeb_RZplan_checkbox"), GUILayout.ExpandWidth(true)); //"Auto-warp" GUILayout.Label(Localizer.Format("#MechJeb_RZplan_label9"), GUILayout.ExpandWidth(false)); //"Tolerance:" core.node.tolerance.text = GUILayout.TextField(core.node.tolerance.text, GUILayout.Width(35), GUILayout.ExpandWidth(false)); if (GUILayout.Button("+", GUILayout.ExpandWidth(false))) { core.node.tolerance.val += 0.1; } if (GUILayout.Button("-", GUILayout.ExpandWidth(false))) { core.node.tolerance.val -= core.node.tolerance.val > 0.1 ? 0.1 : 0.0; } if (GUILayout.Button("R", GUILayout.ExpandWidth(false))) { core.node.tolerance.val = 0.1; } GUILayout.Label("m/s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); base.WindowGUI(windowID); }
void MakeNodeForOperation(Orbit o, double UT) { Vector3d dV = Vector3d.zero; double bodyRadius = o.referenceBody.Radius; switch (operation) { case Operation.CIRCULARIZE: dV = OrbitalManeuverCalculator.DeltaVToCircularize(o, UT); break; case Operation.ELLIPTICIZE: dV = OrbitalManeuverCalculator.DeltaVToEllipticize(o, UT, newPeA + bodyRadius, newApA + bodyRadius); break; case Operation.PERIAPSIS: dV = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(o, UT, newPeA + bodyRadius); break; case Operation.APOAPSIS: dV = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(o, UT, newApA + bodyRadius); break; case Operation.INCLINATION: dV = OrbitalManeuverCalculator.DeltaVToChangeInclination(o, UT, newInc); break; case Operation.PLANE: if (timeReference == TimeReference.REL_ASCENDING) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, core.target.Orbit, UT, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, core.target.Orbit, UT, out UT); } break; case Operation.TRANSFER: dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(o, core.target.Orbit, UT, out UT); break; case Operation.MOON_RETURN: dV = OrbitalManeuverCalculator.DeltaVAndTimeForMoonReturnEjection(o, UT, o.referenceBody.referenceBody.Radius + moonReturnAltitude, out UT); break; case Operation.COURSE_CORRECTION: CelestialBody targetBody = core.target.Target as CelestialBody; if (targetBody != null) { dV = OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, core.target.Orbit, targetBody, targetBody.Radius + courseCorrectFinalPeA, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, core.target.Orbit, out UT); } break; case Operation.INTERPLANETARY_TRANSFER: dV = OrbitalManeuverCalculator.DeltaVAndTimeForInterplanetaryTransferEjection(o, UT, core.target.Orbit, true, out UT); break; case Operation.LAMBERT: dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(o, UT, core.target.Orbit, UT + interceptInterval); break; case Operation.KILL_RELVEL: dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(o, UT, core.target.Orbit); break; } vessel.PlaceManeuverNode(o, dV, UT); }
void MakeNodeForOperation(Orbit o, double UT, Operation op, double newPeA, double newApA, double newInc, double courseCorrectFinalPeA, double moonReturnAltitude, double interceptInterval) { Vector3d dV = Vector3d.zero; double bodyRadius = o.referenceBody.Radius; // print(newPeA + " - " + this.newPeA + "\n" + // newApA + " - " + this.newApA + "\n" + // newInc + " - " + this.newInc + "\n" + // courseCorrectFinalPeA + " - " + this.courseCorrectFinalPeA + "\n" + // moonReturnAltitude + " - " + this.moonReturnAltitude + "\n" + // interceptInterval + " - " + this.interceptInterval); switch (op) { case Operation.CIRCULARIZE: dV = OrbitalManeuverCalculator.DeltaVToCircularize(o, UT); break; case Operation.ELLIPTICIZE: dV = OrbitalManeuverCalculator.DeltaVToEllipticize(o, UT, newPeA + bodyRadius, newApA + bodyRadius); break; case Operation.PERIAPSIS: dV = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(o, UT, newPeA + bodyRadius); break; case Operation.APOAPSIS: dV = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(o, UT, newApA + bodyRadius); break; case Operation.INCLINATION: dV = OrbitalManeuverCalculator.DeltaVToChangeInclination(o, UT, newInc); break; case Operation.PLANE: if (timeReference == TimeReference.REL_ASCENDING) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(o, core.target.TargetOrbit, UT, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(o, core.target.TargetOrbit, UT, out UT); } break; case Operation.TRANSFER: dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(o, core.target.TargetOrbit, UT, out UT); break; case Operation.MOON_RETURN: dV = OrbitalManeuverCalculator.DeltaVAndTimeForMoonReturnEjection(o, UT, o.referenceBody.referenceBody.Radius + moonReturnAltitude, out UT); break; case Operation.COURSE_CORRECTION: CelestialBody targetBody = core.target.Target as CelestialBody; if (targetBody != null) { dV = OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, core.target.TargetOrbit, targetBody, targetBody.Radius + courseCorrectFinalPeA, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeForCheapestCourseCorrection(o, UT, core.target.TargetOrbit, interceptDistance, out UT); } break; case Operation.INTERPLANETARY_TRANSFER: dV = OrbitalManeuverCalculator.DeltaVAndTimeForInterplanetaryTransferEjection(o, UT, core.target.TargetOrbit, true, out UT); break; case Operation.LAMBERT: dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(o, UT, core.target.TargetOrbit, UT + interceptInterval); break; case Operation.KILL_RELVEL: dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(o, UT, core.target.TargetOrbit); break; case Operation.RESONANT_ORBIT: dV = OrbitalManeuverCalculator.DeltaVToResonantOrbit(o, UT, (double)resonanceNumerator.val / resonanceDenominator.val); break; case Operation.SEMI_MAJOR: dV = OrbitalManeuverCalculator.DeltaVForSemiMajorAxis(o, UT, newSMA); break; case Operation.LAN: dV = OrbitalManeuverCalculator.DeltaVToShiftLAN(o, UT, core.target.targetLongitude); break; } vessel.PlaceManeuverNode(o, dV, UT); }
public override void Drive(FlightCtrlState s) { if (!core.target.NormalTargetExists) { users.Clear(); return; } core.node.autowarp = core.target.Distance > 1000; //don't warp when close to target, because warping introduces small perturbations if (vessel.patchedConicSolver.maneuverNodes.Count > 0) { if (!core.node.enabled) { core.node.ExecuteAllNodes(this); } } else if (core.target.Distance < 100 && core.target.RelativeVelocity.magnitude < 1) { //finished users.Clear(); core.thrust.ThrustOff(); status = "Successful rendezvous"; } else if (core.target.Distance < 100) { double UT = vesselState.time; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Within 100m: matching velocities."; } else if (core.target.Distance < vesselState.radius / 50) { if (orbit.NextClosestApproachDistance(core.target.Orbit, vesselState.time) < 100 && orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time) < vesselState.time + 150) { //We're close to the target, and on a course that will take us closer. Kill relvel at closest approach double UT = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Planning to match velocities at closest approach."; } else { //We're not far from the target. Close the distance double closingSpeed = core.target.Distance / 100; if (closingSpeed > 100) { closingSpeed = 100; } double closingTime = core.target.Distance / closingSpeed; double UT = vesselState.time + 15; double interceptUT = UT + closingTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.Orbit, interceptUT, 10); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Close to target: plotting intercept over " + closingTime.ToString("F0") + "s"; } } else if (orbit.NextClosestApproachDistance(core.target.Orbit, vesselState.time) < core.target.Orbit.semiMajorAxis / 50) { //We're not close to the target, but we're on an approximate intercept course. //Kill relative velocities at closest approach double UT = orbit.NextClosestApproachTime(core.target.Orbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.Orbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = "On intercept course. Planning to match velocities at closest approach."; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05 && orbit.eccentricity < 0.05 && orbit.SynodicPeriod(core.target.Orbit) < 5 * orbit.period) { //We're not on an intercept course, but we have a circular orbit in the right plane. //Also we are phasing quickly enough that it won't be too long until an intercept window //Plot a Hohmann transfer intercept. double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.Orbit, vesselState.time, out UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Planning Hohmann transfer for intercept."; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05 && orbit.eccentricity < 0.05) { //We are in a circular orbit in the right plane, but we aren't phasing quickly enough. Move to a better phasing orbit double lowPhasingRadius = core.target.Orbit.semiMajorAxis / 1.16; double highPhasingRadius = core.target.Orbit.semiMajorAxis * 1.16; bool useLowPhasingRadius = (lowPhasingRadius > mainBody.RealMaxAtmosphereAltitude() + 3000 && orbit.semiMajorAxis < core.target.orbit.semiMajorAxis); double phasingOrbitRadius = (useLowPhasingRadius ? lowPhasingRadius : highPhasingRadius); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } status = "Increasing phasing rate by establishing new phasing orbit at " + MuUtils.ToSI(phasingOrbitRadius - mainBody.Radius, 0) + "m"; } else if (orbit.RelativeInclination(core.target.Orbit) < 0.05) { //We're not on an intercept course. We're in the right plane, but our orbit isn't circular. Circularize. bool circularizeAtPe; if (orbit.eccentricity > 1) { circularizeAtPe = true; } else { circularizeAtPe = Math.Abs(orbit.PeR - core.target.Orbit.semiMajorAxis) < Math.Abs(orbit.ApR - core.target.Orbit.semiMajorAxis); } double UT; if (circularizeAtPe) { UT = Math.Max(vesselState.time, orbit.NextPeriapsisTime(vesselState.time)); } else { UT = orbit.NextApoapsisTime(vesselState.time); } Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = "Circularizing."; } else { //We're not on an intercept course, and we're not in the right plane. Match planes bool ascending; if (orbit.eccentricity < 1) { if (orbit.TimeOfAscendingNode(core.target.Orbit, vesselState.time) < orbit.TimeOfDescendingNode(core.target.Orbit, vesselState.time)) { ascending = true; } else { ascending = false; } } else { if (orbit.AscendingNodeExists(core.target.Orbit)) { ascending = true; } else { ascending = false; } } double UT; Vector3d dV; if (ascending) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.Orbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.Orbit, vesselState.time, out UT); } vessel.PlaceManeuverNode(orbit, dV, UT); status = "Matching planes."; } }
public override void Drive(FlightCtrlState s) { if (!core.target.NormalTargetExists) { users.Clear(); return; } core.node.autowarp = core.node.autowarp && core.target.Distance > 1000; //If we get within the target distance and then next maneuver node is still //far in the future, delete it and we will create a new one to match velocities immediately. //This can often happen because the target vessel's orbit shifts slightly when it is unpacked. if (core.target.Distance < desiredDistance && vessel.patchedConicSolver.maneuverNodes.Count > 0 && vessel.patchedConicSolver.maneuverNodes[0].UT > vesselState.time + 1) { vessel.RemoveAllManeuverNodes(); } if (vessel.patchedConicSolver.maneuverNodes.Count > 0) { //If we have plotted a maneuver, execute it. if (!core.node.enabled) { core.node.ExecuteAllNodes(this); } } else if (core.target.Distance < desiredDistance * 1.05 + 2 && core.target.RelativeVelocity.magnitude < 1) { //finished users.Clear(); core.thrust.ThrustOff(); status = Localizer.Format("#MechJeb_RZauto_statu1");//"Successful rendezvous" } else if (core.target.Distance < desiredDistance * 1.05 + 2) { //We are within the target distance: match velocities double UT = vesselState.time; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu2", desiredDistance.ToString());//"Within " + + "m: matching velocities." } else if (core.target.Distance < vesselState.radius / 25) { if (orbit.NextClosestApproachDistance(core.target.TargetOrbit, vesselState.time) < desiredDistance && orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time) < vesselState.time + 150) { //We're close to the target, and on a course that will take us closer. Kill relvel at closest approach double UT = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); //adjust burn time so as to come to rest at the desired distance from the target: double approachDistance = orbit.Separation(core.target.TargetOrbit, UT); double approachSpeed = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.TargetOrbit.SwappedOrbitalVelocityAtUT(UT)).magnitude; if (approachDistance < desiredDistance) { UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed; } //if coming in hot, stop early to avoid crashing: if (approachSpeed > 10) { UT -= 1; } vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu3");//"Planning to match velocities at closest approach." } else { //We're not far from the target. Close the distance double closingSpeed = core.target.Distance / 100; if (closingSpeed > 100) { closingSpeed = 100; } double closingTime = core.target.Distance / closingSpeed; double UT = vesselState.time + 15; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.TargetOrbit, closingTime); vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu4");//"Close to target: plotting intercept" } } else if (orbit.NextClosestApproachDistance(core.target.TargetOrbit, vesselState.time) < core.target.TargetOrbit.semiMajorAxis / 25) { //We're not close to the target, but we're on an approximate intercept course. //Kill relative velocities at closest approach double UT = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time); Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); //adjust burn time so as to come to rest at the desired distance from the target: double approachDistance = (orbit.SwappedAbsolutePositionAtUT(UT) - core.target.TargetOrbit.SwappedAbsolutePositionAtUT(UT)).magnitude; double approachSpeed = (orbit.SwappedOrbitalVelocityAtUT(UT) - core.target.TargetOrbit.SwappedOrbitalVelocityAtUT(UT)).magnitude; if (approachDistance < desiredDistance) { UT -= Math.Sqrt(Math.Abs(desiredDistance * desiredDistance - approachDistance * approachDistance)) / approachSpeed; } //if coming in hot, stop early to avoid crashing: if (approachSpeed > 10) { UT -= 1; } vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu5");//"On intercept course. Planning to match velocities at closest approach." } else if (orbit.RelativeInclination(core.target.TargetOrbit) < 0.05 && orbit.eccentricity < 0.05) { //We're not on an intercept course, but we have a circular orbit in the right plane. double hohmannUT; Vector3d hohmannDV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.TargetOrbit, vesselState.time, out hohmannUT); double numPhasingOrbits = (hohmannUT - vesselState.time) / orbit.period; double actualMaxPhasingOrbits = Math.Max(maxPhasingOrbits, 5); // ignore input values that are unreasonably small if (numPhasingOrbits < actualMaxPhasingOrbits) { //It won't be too long until the intercept window. Plot a Hohmann transfer intercept. vessel.PlaceManeuverNode(orbit, hohmannDV, hohmannUT); status = Localizer.Format("#MechJeb_RZauto_statu6", numPhasingOrbits.ToString("F2"));//"Planning Hohmann transfer for intercept after " + + " phasing orbits." } else { //We are in a circular orbit in the right plane, but we aren't phasing quickly enough. Move to a better phasing orbit double axisRatio = Math.Pow(1 + 1.25 / actualMaxPhasingOrbits, 2.0 / 3.0); double lowPhasingRadius = core.target.TargetOrbit.semiMajorAxis / axisRatio; double highPhasingRadius = core.target.TargetOrbit.semiMajorAxis * axisRatio; bool useLowPhasingRadius = (lowPhasingRadius > mainBody.Radius + mainBody.RealMaxAtmosphereAltitude() + 3000) && (orbit.semiMajorAxis < core.target.TargetOrbit.semiMajorAxis); double phasingOrbitRadius = (useLowPhasingRadius ? lowPhasingRadius : highPhasingRadius); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + 15; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } status = Localizer.Format("#MechJeb_RZauto_statu7", numPhasingOrbits.ToString("F1"), maxPhasingOrbits.text, MuUtils.ToSI(phasingOrbitRadius - mainBody.Radius, 0));//"Next intercept window would be <<1>> orbits away, which is more than the maximum of <<2>> phasing orbits. Increasing phasing rate by establishing new phasing orbit at <<3>>m } } else if (orbit.RelativeInclination(core.target.TargetOrbit) < 0.05) { //We're not on an intercept course. We're in the right plane, but our orbit isn't circular. Circularize. bool circularizeAtPe; if (orbit.eccentricity > 1) { circularizeAtPe = true; } else { circularizeAtPe = Math.Abs(orbit.PeR - core.target.TargetOrbit.semiMajorAxis) < Math.Abs(orbit.ApR - core.target.TargetOrbit.semiMajorAxis); } double UT; if (circularizeAtPe) { UT = Math.Max(vesselState.time, orbit.NextPeriapsisTime(vesselState.time)); } else { UT = orbit.NextApoapsisTime(vesselState.time); } Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu8");//"Circularizing." } else { //We're not on an intercept course, and we're not in the right plane. Match planes bool ascending; if (orbit.eccentricity < 1) { if (orbit.TimeOfAscendingNode(core.target.TargetOrbit, vesselState.time) < orbit.TimeOfDescendingNode(core.target.TargetOrbit, vesselState.time)) { ascending = true; } else { ascending = false; } } else { if (orbit.AscendingNodeExists(core.target.TargetOrbit)) { ascending = true; } else { ascending = false; } } double UT; Vector3d dV; if (ascending) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } vessel.PlaceManeuverNode(orbit, dV, UT); status = Localizer.Format("#MechJeb_RZauto_statu9");//"Matching planes." } }
override public void activateAction() { base.activateAction(); Vessel vessel = this.scriptModule.vessel; VesselState vesselState = this.scriptModule.vesselState; Orbit orbit = this.scriptModule.orbit; CelestialBody mainBody = this.scriptModule.mainBody; const double leadTime = 30; double closestApproachTime = orbit.NextClosestApproachTime(core.target.TargetOrbit, vesselState.time); if (actionType == 0) //Align planes { double UT; Vector3d dV; if (orbit.AscendingNodeExists(core.target.TargetOrbit)) { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesAscending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } else { dV = OrbitalManeuverCalculator.DeltaVAndTimeToMatchPlanesDescending(orbit, core.target.TargetOrbit, vesselState.time, out UT); } vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(this.scriptModule.orbit, dV, UT); } else if (actionType == 1) //Establish new orbit { double phasingOrbitRadius = phasingOrbitAltitude + mainBody.Radius; vessel.RemoveAllManeuverNodes(); if (orbit.ApR < phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextApoapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else if (orbit.PeR > phasingOrbitRadius) { double UT1 = vesselState.time + leadTime; Vector3d dV1 = OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, UT1, phasingOrbitRadius); vessel.PlaceManeuverNode(orbit, dV1, UT1); Orbit transferOrbit = vessel.patchedConicSolver.maneuverNodes[0].nextPatch; double UT2 = transferOrbit.NextPeriapsisTime(UT1); Vector3d dV2 = OrbitalManeuverCalculator.DeltaVToCircularize(transferOrbit, UT2); vessel.PlaceManeuverNode(transferOrbit, dV2, UT2); } else { double UT = orbit.NextTimeOfRadius(vesselState.time, phasingOrbitRadius); Vector3d dV = OrbitalManeuverCalculator.DeltaVToCircularize(orbit, UT); vessel.PlaceManeuverNode(orbit, dV, UT); } } else if (actionType == 2) //Intercept with Hohmann transfer { double UT; Vector3d dV = OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(orbit, core.target.TargetOrbit, vesselState.time, out UT); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } else if (actionType == 3) //Match velocities at closest approach { double UT = closestApproachTime; Vector3d dV = OrbitalManeuverCalculator.DeltaVToMatchVelocities(orbit, UT, core.target.TargetOrbit); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } else if (actionType == 4) //Get closer { double UT = vesselState.time; double interceptUT = UT + 100; Vector3d dV = OrbitalManeuverCalculator.DeltaVToInterceptAtTime(orbit, UT, core.target.TargetOrbit, interceptUT, 10); vessel.RemoveAllManeuverNodes(); vessel.PlaceManeuverNode(orbit, dV, UT); } this.endAction(); }
protected override void WindowGUI(int windowID) { GUILayout.BeginVertical(); GUILayout.Label("When guidance is enabled, the purple circle on the navball points along the ascent path."); ToggleAscentNavballGuidanceInfoItem(); if (autopilot != null) { if (autopilot.enabled) { if (GUILayout.Button("Disengage autopilot")) { autopilot.users.Remove(this); } } else { if (GUILayout.Button("Engage autopilot")) { autopilot.users.Add(this); } } GuiUtils.SimpleTextBox("Orbit altitude", autopilot.desiredOrbitAltitude, "km"); autopilot.desiredInclination = desiredInclination; GUIStyle si = new GUIStyle(GUI.skin.label); if (!autopilot.enabled && Math.Abs(desiredInclination) < Math.Abs(vesselState.latitude)) { si.onHover.textColor = si.onNormal.textColor = si.normal.textColor = XKCDColors.Orange; } GUILayout.BeginHorizontal(); GUILayout.Label("Orbit inc.", si, GUILayout.ExpandWidth(true)); desiredInclination.text = GUILayout.TextField(desiredInclination.text, GUILayout.ExpandWidth(true), GUILayout.Width(100)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); if (GUILayout.Button("Current")) { desiredInclination.val = vesselState.latitude; } GUILayout.EndHorizontal(); core.thrust.LimitToPreventOverheatsInfoItem(); //core.thrust.LimitToTerminalVelocityInfoItem(); core.thrust.LimitToMaxDynamicPressureInfoItem(); core.thrust.LimitAccelerationInfoItem(); core.thrust.LimitThrottleInfoItem(); core.thrust.LimiterMinThrottleInfoItem(); core.thrust.LimitElectricInfoItem(); GUILayout.BeginHorizontal(); autopilot.forceRoll = GUILayout.Toggle(autopilot.forceRoll, "Force Roll"); if (autopilot.forceRoll) { GuiUtils.SimpleTextBox("climb", autopilot.verticalRoll, "º", 30f); GuiUtils.SimpleTextBox("turn", autopilot.turnRoll, "º", 30f); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUIStyle s = new GUIStyle(GUI.skin.toggle); if (autopilot.limitingAoA) { s.onHover.textColor = s.onNormal.textColor = Color.green; } autopilot.limitAoA = GUILayout.Toggle(autopilot.limitAoA, "Limit AoA to", s, GUILayout.ExpandWidth(true)); autopilot.maxAoA.text = GUILayout.TextField(autopilot.maxAoA.text, GUILayout.Width(30)); GUILayout.Label("º (" + autopilot.currentMaxAoA.ToString("F1") + "°)", GUILayout.ExpandWidth(true)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Space(25); if (autopilot.limitAoA) { GUIStyle sl = new GUIStyle(GUI.skin.label); if (autopilot.limitingAoA && vesselState.dynamicPressure < autopilot.aoALimitFadeoutPressure) { sl.normal.textColor = sl.hover.textColor = Color.green; } GuiUtils.SimpleTextBox("Dynamic Pressure Fadeout", autopilot.aoALimitFadeoutPressure, "pa", 50, sl); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); autopilot.correctiveSteering = GUILayout.Toggle(autopilot.correctiveSteering, "Corrective steering", GUILayout.ExpandWidth(false)); if (autopilot.correctiveSteering) { GUILayout.Label("Gain", GUILayout.ExpandWidth(false)); autopilot.correctiveSteeringGain.text = GUILayout.TextField(autopilot.correctiveSteeringGain.text, GUILayout.Width(40)); } GUILayout.EndHorizontal(); autopilot.autostage = GUILayout.Toggle(autopilot.autostage, "Autostage"); if (autopilot.autostage) { core.staging.AutostageSettingsInfoItem(); } autopilot.autodeploySolarPanels = GUILayout.Toggle(autopilot.autodeploySolarPanels, "Auto-deploy solar panels"); autopilot.autoDeployAntennas = GUILayout.Toggle(autopilot.autoDeployAntennas, "Auto-deploy antennas"); GUILayout.BeginHorizontal(); core.node.autowarp = GUILayout.Toggle(core.node.autowarp, "Auto-warp"); autopilot.skipCircularization = GUILayout.Toggle(autopilot.skipCircularization, "Skip Circularization"); GUILayout.EndHorizontal(); if (vessel.LandedOrSplashed) { if (core.target.NormalTargetExists) { if (core.node.autowarp) { GUILayout.BeginHorizontal(); GUILayout.Label("Launch countdown:", GUILayout.ExpandWidth(true)); autopilot.warpCountDown.text = GUILayout.TextField(autopilot.warpCountDown.text, GUILayout.Width(60)); GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } if (!launchingToPlane && !launchingToRendezvous && !launchingToInterplanetary) { GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch to rendezvous:", GUILayout.ExpandWidth(false))) { launchingToRendezvous = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPhaseAngle(autopilot.launchPhaseAngle, mainBody, vesselState.longitude, core.target.TargetOrbit)); } autopilot.launchPhaseAngle.text = GUILayout.TextField(autopilot.launchPhaseAngle.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Launch into plane of target", GUILayout.ExpandWidth(false))) { launchingToPlane = true; autopilot.StartCountdown(vesselState.time + LaunchTiming.TimeToPlane(autopilot.launchLANDifference, mainBody, vesselState.latitude, vesselState.longitude, core.target.TargetOrbit)); } autopilot.launchLANDifference.text = GUILayout.TextField( autopilot.launchLANDifference.text, GUILayout.Width(60)); GUILayout.Label("º", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); if (core.target.TargetOrbit.referenceBody == orbit.referenceBody.referenceBody) { if (GUILayout.Button("Launch at interplanetary window")) { launchingToInterplanetary = true; //compute the desired launch date OrbitalManeuverCalculator.DeltaVAndTimeForHohmannTransfer(mainBody.orbit, core.target.TargetOrbit, vesselState.time, out interplanetaryWindowUT); double desiredOrbitPeriod = 2 * Math.PI * Math.Sqrt( Math.Pow(mainBody.Radius + autopilot.desiredOrbitAltitude, 3) / mainBody.gravParameter); //launch just before the window, but don't try to launch in the past interplanetaryWindowUT -= 3 * desiredOrbitPeriod; interplanetaryWindowUT = Math.Max(vesselState.time + autopilot.warpCountDown, interplanetaryWindowUT); autopilot.StartCountdown(interplanetaryWindowUT); } } } } else { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = false; GUILayout.Label("Select a target for a timed launch."); } if (launchingToInterplanetary || launchingToPlane || launchingToRendezvous) { string message = ""; if (launchingToInterplanetary) { message = "Launching at interplanetary window"; } else if (launchingToPlane) { // FIXME: When plane matching azimuth autopilot is available, this clamping can be removed desiredInclination = MuUtils.Clamp(core.target.TargetOrbit.inclination, Math.Abs(vesselState.latitude), 180 - Math.Abs(vesselState.latitude)); desiredInclination *= Math.Sign(Vector3d.Dot(core.target.TargetOrbit.SwappedOrbitNormal(), Vector3d.Cross(vesselState.CoM - mainBody.position, mainBody.transform.up))); message = "Launching to target plane"; } else if (launchingToRendezvous) { message = "Launching to rendezvous"; } if (autopilot.tMinus > 3 * vesselState.deltaT) { message += ": T-" + GuiUtils.TimeToDHMS(autopilot.tMinus, 1); } GUILayout.Label(message); if (GUILayout.Button("Abort")) { launchingToInterplanetary = launchingToPlane = launchingToRendezvous = autopilot.timedLaunch = false; } } } if (autopilot.enabled) { GUILayout.Label("Autopilot status: " + autopilot.status); } } if (!vessel.patchedConicsUnlocked()) { GUILayout.Label("Warning: MechJeb is unable to circularize without an upgraded Tracking Station."); } int last_idx = ascentPathIdx; GUILayout.BeginHorizontal(); ascentPathIdx = GuiUtils.ComboBox.Box(ascentPathIdx, ascentPathList, this); GUILayout.EndHorizontal(); if (last_idx != ascentPathIdx) { bool last_enabled = editor.enabled; enable_path_module(ascentPathIdx); editor.enabled = last_enabled; } if (editor != null) { editor.enabled = GUILayout.Toggle(editor.enabled, "Edit ascent path"); } GUILayout.EndVertical(); base.WindowGUI(windowID); }