// find orbit round with min normalDiff to target, makes only sense if we are in inclined orbit bool minOrbit() { ManeuverNode plannedNode = vessel.patchedConicSolver.maneuverNodes[0]; if (Math.Abs(orbit.inclination) < 5) { return(true); } Debug.Log(String.Format("Current deorbit round at t={0:F0} has normalDiff={1:F1}", plannedNode.UT - Planetarium.GetUniversalTime(), targetInfo.normalDifference)); if (iteration == 0 || Math.Abs(targetInfo.normalDifference) < minDiff) { Debug.Log(String.Format("Found new optimum deorbit round at t={0:F0} for normalDiff={1:F1} ", plannedNode.UT - Planetarium.GetUniversalTime(), targetInfo.normalDifference)); minDiff = Math.Abs(targetInfo.normalDifference); minUT = plannedNode.UT; } iteration++; if (iteration > maxIterations) { plannedNode.RemoveSelf(); vessel.PlaceManeuverNode(vessel.orbit, OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, minUT, mainBody.Radius + core.landing.reentryTargetHeight), minUT); targetInfo.invalidateCalculation(); return(true); } // factor accounts for ground movement during orbit round double nextRound = plannedNode.UT + orbit.period * vessel.mainBody.rotationPeriod / (vessel.mainBody.rotationPeriod - orbit.period); plannedNode.RemoveSelf(); vessel.PlaceManeuverNode(vessel.orbit, OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, nextRound, mainBody.Radius + core.landing.reentryTargetHeight), nextRound); targetInfo.invalidateCalculation(); return(false); }
protected override void Update() { if (!VSL.HasManeuverNode || Node != Solver.maneuverNodes[0] || NodeCB != Node.patch.referenceBody) { Message("Maneuver has been interrupted."); Disable(); return; } if (!VSL.Engines.HaveThrusters && !VSL.Engines.HaveNextStageEngines) { Message("Out of fuel"); Disable(); return; } //update the node NodeDeltaV = (TargetOrbit.GetFrameVelAtUT(NodeUT) - VSL.orbit.GetFrameVelAtUT(NodeUT)).xzy; Executor.ThrustWhenAligned = ThrustWhenAligned; ThrustWhenAligned = true; if (Executor.Execute(NodeDeltaV, MinDeltaV, StartCondition)) { return; } ManeuverStage = Stage.FINISHED; Node.RemoveSelf(); Disable(); }
public void Remove() { if (nodeRef == null) { return; } string careerReason; if (!Career.CanMakeNodes(out careerReason)) { throw new KOSLowTechException("use maneuver nodes", careerReason); } nodeLookup.Remove(nodeRef); if (vesselRef.patchedConicSolver == null) { throw new KOSSituationallyInvalidException( "A KSP limitation makes it impossible to access the manuever nodes of this vessel at this time. " + "(perhaps it's not the active vessel?)"); } nodeRef.RemoveSelf(); nodeRef = null; vesselRef = null; }
internal void DeleteNode() { if (currentNode != null) { currentNode.RemoveSelf(); currentNode = null; UpdateCurrentNode(); } }
internal void deleteNode() { if (_currentNode != null) { _currentNode.RemoveSelf(); _currentNode = null; updateCurrentNode(); } }
bool optimizeDeorbit() { //Debug.Log(String.Format("Autoland: currentImpactRadialVector={0} currentTargetRadialVector={1} differenceTarget={2}", targetInfo.currentImpactRadialVector, targetInfo.currentTargetRadialVector, targetInfo.differenceTarget)); //Debug.Log(String.Format("Autoland: orbitClosestToTarget={0} orbitNormal={1} targetForward={2} ", targetInfo.orbitClosestToTarget, orbit.SwappedOrbitNormal(), targetForward.ToString("F3"))); //Debug.Log(String.Format("Autoland: normalDiff={0:F1}, backwardDiff={1:F1}", targetInfo.normalDifference, targetInfo.backwardDifference)); if (Math.Abs(targetInfo.targetAheadAngle) < 0.5 && Math.Abs(targetInfo.backwardDifference) < deorbitprecision) { return(true); // execute plannedNode } else { //move Node ManeuverNode plannedNode = vessel.patchedConicSolver.maneuverNodes[0]; double deorbitTime = plannedNode.UT; double timedelta; if (Math.Abs(targetInfo.targetAheadAngle) < 0.5) // for small changes use tangential calculation, otherwise angluar { timedelta = targetInfo.backwardDifference / vesselState.speedSurfaceHorizontal; } else { timedelta = targetInfo.targetAheadAngle * orbit.period / 360f; } if (timedelta < 0) // asymetric to avoid jumping between two points without improvement. Observed with inclined trajectory. { deorbitTime -= timedelta; } else { deorbitTime -= 0.5 * timedelta; } if (deorbitTime < vesselState.time) { deorbitTime += orbit.period; } if (deorbitTime > vesselState.time + 1.5 * orbit.period) { deorbitTime -= orbit.period; } status = String.Format("Optimizing deorbit time based on trajectory prediction, shift by {0:F4} degree, {1:F0} m equals {2:F1} seconds", targetInfo.targetAheadAngle, targetInfo.backwardDifference, deorbitTime - plannedNode.UT); Debug.Log("Autoland: " + status); // deltaV needs to rotate plannedNode.RemoveSelf(); vessel.PlaceManeuverNode(vessel.orbit, OrbitalManeuverCalculator.DeltaVToChangePeriapsis(orbit, deorbitTime, mainBody.Radius + core.landing.reentryTargetHeight), deorbitTime); targetInfo.invalidateCalculation(); iteration++; } return(false); }
/// <summary> /// /// </summary> /// <param name="computer">FlightComputer instance of the computer of the vessel.</param> private void AbortManeuver(FlightComputer computer) { RTUtil.ScreenMessage("[Flight Computer]: Maneuver removed"); if (computer.Vessel.patchedConicSolver != null) { Node.RemoveSelf(); } // enqueue kill rot computer.Enqueue(AttitudeCommand.KillRot(), true, true, true); }
void MergeNext(int index) { ManeuverNode cur = vessel.patchedConicSolver.maneuverNodes[index]; ManeuverNode next = vessel.patchedConicSolver.maneuverNodes[index + 1]; double newUT = (cur.UT + next.UT) / 2; cur.UpdateNode(cur.patch.DeltaVToManeuverNodeCoordinates(newUT, cur.WorldDeltaV() + next.WorldDeltaV()), newUT); next.RemoveSelf(); }
public override AutopilotStep OnFixedUpdate() { if (!vessel.patchedConicsUnlocked() || vessel.patchedConicSolver.maneuverNodes.Count == 0) { return(doAfterExecution); } node = vessel.patchedConicSolver.maneuverNodes[0]; double dVLeft = node.GetBurnVector(orbit).magnitude; if (dVLeft < core.node.tolerance && core.attitude.attitudeAngleFromTarget() > 5) { burnTriggered = false; node.RemoveSelf(); return(this); // we are done for this frame, continue in next } double halfBurnTime; double burnTime = core.node.BurnTime(dVLeft, out halfBurnTime); double timeToNode = node.UT - vesselState.time; status = "Moving to node"; if ((!double.IsInfinity(halfBurnTime) && halfBurnTime > 0 && timeToNode < halfBurnTime) || timeToNode < 0) { burnTriggered = true; status = "Executing node"; if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } } //autowarp, but only if we're already aligned with the node if (core.node.autowarp && !burnTriggered) { if ((core.attitude.attitudeAngleFromTarget() < 1 && core.vessel.angularVelocity.magnitude < 0.01) || (core.attitude.attitudeAngleFromTarget() < 10 && !MuUtils.PhysicsRunning())) { core.warp.WarpToUT(node.UT - halfBurnTime - core.node.leadTime); } else if (!MuUtils.PhysicsRunning() && core.attitude.attitudeAngleFromTarget() > 10 && timeToNode < 600) { //realign core.warp.MinimumWarp(); } } return(this); }
private void remove_maneuver_node() { if (Node.solver != null) { Node.RemoveSelf(); } else if (Solver != null && Solver.maneuverNodes.Count > 0 && Math.Abs(Solver.maneuverNodes[0].UT - Node.UT) < 1e-6) { Solver.maneuverNodes[0].RemoveSelf(); } Node = null; }
protected override void Update() { if (!IsActive) { return; } if (!VSL.HasManeuverNode || Node != Solver.maneuverNodes[0]) { reset(); return; } if (Executor.Execute(Node.GetBurnVector(VSL.orbit), MinDeltaV, StartCondition)) { return; } Node.RemoveSelf(); reset(); }
/// <summary> /// /// </summary> /// <param name="computer">FlightComputer instance of the computer of the vessel.</param> private void AbortManeuver(FlightComputer computer) { RTUtil.ScreenMessage("[Flight Computer]: Maneuver removed"); if (computer.Vessel.patchedConicSolver != null) { Node.RemoveSelf(); } // Flight Computer mode after execution based on settings if (RTSettings.Instance.FCOffAfterExecute) { computer.Enqueue(AttitudeCommand.Off(), true, true, true); } if (!RTSettings.Instance.FCOffAfterExecute) { computer.Enqueue(AttitudeCommand.KillRot(), true, true, true); } }
protected override void Update() { if (!IsActive) { return; } if (!VSL.HasManeuverNode || Node != Solver.maneuverNodes[0]) { reset(); return; } NodeDeltaV = Node.GetBurnVector(VSL.orbit); // Log("Node.dV {}", NodeDeltaV);//debug if (Executor.Execute(NodeDeltaV, MinDeltaV, StartCondition)) { within_threshold |= Executor.RemainingDeltaV < ThresholdDeltaV; if (within_threshold) { VSL.Controls.GimbalLimit = 0; var dV = Executor.RemainingDeltaV; if (dV < min_deltaV) { min_deltaV = dV; return; } if (dV - min_deltaV < GLB.THR.MinDeltaV) { return; } } else { return; } } Node.RemoveSelf(); reset(); }
/// <summary> /// Draw the main window. /// </summary> /// <param name="windowId">Window identifier.</param> void OnWindow(int windowId) { if (FlightGlobals.ActiveVessel == null) { return; } PatchedConicSolver solver = FlightGlobals.ActiveVessel.patchedConicSolver; GUILayout.BeginVertical(GUILayout.Width(320.0f)); GUILayout.BeginHorizontal(); if (GUILayout.Button("New") && IsAllowed()) { _maneuver = solver.AddManeuverNode(Planetarium.GetUniversalTime() + (10.0 * 60.0)); _mindex = solver.maneuverNodes.IndexOf(_maneuver); } if (GUILayout.Button("Delete") && _maneuver != null) { _maneuver.RemoveSelf(); } if (GUILayout.Button("Delete All") && _maneuver != null) { DeleteAll(); } if (GUILayout.Button("Store") && solver.maneuverNodes.Count > 0) { StoredManeuver start = null; StoredManeuver prev = null; foreach (ManeuverNode node in solver.maneuverNodes) { StoredManeuver temp = new StoredManeuver(node.DeltaV, node.UT); if (start == null) { start = temp; } if (prev != null) { prev.Next = temp; } prev = temp; } _stored.Add(start); } if (GUILayout.Button("Close")) { ToggleWindow(); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Warp"); if (GUILayout.Button("+10m")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(Planetarium.GetUniversalTime() + 10.0 * Format.ONE_KMIN); } if (GUILayout.Button("+1h")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(Planetarium.GetUniversalTime() + Format.ONE_KHOUR); } if (GUILayout.Button("+1d")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(Planetarium.GetUniversalTime() + Format.ONE_KDAY); } if (GUILayout.Button("+10d")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(Planetarium.GetUniversalTime() + 10.0 * Format.ONE_KDAY); } if (FlightGlobals.ActiveVessel.orbit.patchEndTransition != Orbit.PatchTransitionType.FINAL) { if (GUILayout.Button("Transition")) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(FlightGlobals.ActiveVessel.orbit.EndUT - Format.ONE_KMIN); } } GUILayout.EndHorizontal(); if (solver.maneuverNodes.Count > 0) { if (_maneuver == null || _mvessel != FlightGlobals.ActiveVessel || !solver.maneuverNodes.Contains(_maneuver)) { _maneuver = solver.maneuverNodes [0]; _mvessel = FlightGlobals.ActiveVessel; _mindex = 0; } GUILayout.BeginHorizontal(); GUILayout.Label("Maneuver:" + (_mindex + 1) + " of " + solver.maneuverNodes.Count); if (GUILayout.Button("Prev")) { _mindex--; if (_mindex < 0) { _mindex = solver.maneuverNodes.Count - 1; } _maneuver = solver.maneuverNodes [_mindex]; _mvessel = FlightGlobals.ActiveVessel; } if (GUILayout.Button("Next")) { _mindex++; if (_mindex >= solver.maneuverNodes.Count) { _mindex = 0; } _maneuver = solver.maneuverNodes [_mindex]; _mvessel = FlightGlobals.ActiveVessel; } GUILayout.EndHorizontal(); if (_maneuver != null) { double timeToNode = Planetarium.GetUniversalTime() - _maneuver.UT; if (_mindex == 0) { GUILayout.BeginHorizontal(); GUILayout.Label("Warp To Maneuver"); if (GUILayout.Button("-1m") && -timeToNode > Format.ONE_KMIN) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(_maneuver.UT - Format.ONE_KMIN); } if (GUILayout.Button("-10m") && -timeToNode > 10.0 * Format.ONE_KMIN) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(_maneuver.UT - 10.0 * Format.ONE_KMIN); } if (GUILayout.Button("-1h") && -timeToNode > Format.ONE_KHOUR) { // Cancel any existing warp. TimeWarp.SetRate(0, true); // Warp to the maneuver. TimeWarp.fetch.WarpTo(_maneuver.UT - Format.ONE_KHOUR); } GUILayout.EndHorizontal(); } else { GUILayout.Label("Warp To Maneuver - Switch to first maneuver"); } GUILayout.Label("Time:" + KSPUtil.dateTimeFormatter.PrintDateDeltaCompact(timeToNode, true, true, true)); GUILayout.Label("Δv:" + Format.GetNumberString(_maneuver.DeltaV.magnitude) + "m/s"); GUILayout.BeginHorizontal(); _menuSelection = GUILayout.SelectionGrid(_menuSelection, new string [] { ".01 m/s", ".1 m/s", "1 m/s", "10 m/s", "100 m/s", "1000 m/s" }, 3, GUILayout.MinWidth(300.0f)); if (_menuSelection == 0) { _increment = 0.01d; } else if (_menuSelection == 1) { _increment = 0.1d; } else if (_menuSelection == 2) { _increment = 1.0d; } else if (_menuSelection == 3) { _increment = 10.0d; } else if (_menuSelection == 4) { _increment = 100.0d; } else if (_menuSelection == 5) { _increment = 1000.0d; } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Prograde:" + Format.GetNumberString(_maneuver.DeltaV.z) + "m/s", GUILayout.MinWidth(200.0f)); if (GUILayout.Button("-")) { Vector3d dv = _maneuver.DeltaV; dv.z -= _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("0")) { Vector3d dv = _maneuver.DeltaV; dv.z = 0.0d; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("+")) { Vector3d dv = _maneuver.DeltaV; dv.z += _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Normal :" + Format.GetNumberString(_maneuver.DeltaV.y) + "m/s", GUILayout.MinWidth(200.0f)); if (GUILayout.Button("-")) { Vector3d dv = _maneuver.DeltaV; dv.y -= _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("0")) { Vector3d dv = _maneuver.DeltaV; dv.y = 0.0d; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("+")) { Vector3d dv = _maneuver.DeltaV; dv.y += _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.Label("Radial :" + Format.GetNumberString(_maneuver.DeltaV.x) + "m/s", GUILayout.MinWidth(200.0f)); if (GUILayout.Button("-")) { Vector3d dv = _maneuver.DeltaV; dv.x -= _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("0")) { Vector3d dv = _maneuver.DeltaV; dv.x = 0.0d; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } if (GUILayout.Button("+")) { Vector3d dv = _maneuver.DeltaV; dv.x += _increment; _maneuver.OnGizmoUpdated(dv, _maneuver.UT); } GUILayout.EndHorizontal(); double ut = _maneuver.UT; double utUpdate = _timeControl.TimeGUI(ut, FlightGlobals.ActiveVessel); if (utUpdate != ut) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, utUpdate); } GUILayout.BeginHorizontal(); if (GUILayout.Button("=10min")) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, Planetarium.GetUniversalTime() + (10.0 * 60.0)); } double period = _maneuver.patch.period; if (GUILayout.Button("-10 Orbit") && period > 0 && -timeToNode > 10.0 * period) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, _maneuver.UT - (10.0 * period)); } if (GUILayout.Button("-1 Orbit") && period > 0 && -timeToNode > period) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, _maneuver.UT - period); } if (GUILayout.Button("+1 Orbit") && period > 0) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, _maneuver.UT + period); } if (GUILayout.Button("+10 Orbit") && period > 0) { _maneuver.OnGizmoUpdated(_maneuver.DeltaV, _maneuver.UT + (10.0 * period)); } GUILayout.EndHorizontal(); } else { _windowPos.height = 0; } } else if (_maneuver != null) { _maneuver = null; _windowPos.height = 0; } GUILayout.EndVertical(); GUI.DragWindow(); }
public override void OnFixedUpdate() { if (!vessel.patchedConicsUnlocked() || !vessel.patchedConicSolver.maneuverNodes.Any()) { Abort(); return; } //check if we've finished a node: ManeuverNode node = vessel.patchedConicSolver.maneuverNodes.First(); double dVLeft = node.GetBurnVector(orbit).magnitude; if (dVLeft < tolerance && core.attitude.attitudeAngleFromTarget() > 5) { burnTriggered = false; node.RemoveSelf(); if (mode == Mode.ONE_NODE) { Abort(); return; } else if (mode == Mode.ALL_NODES) { if (!vessel.patchedConicSolver.maneuverNodes.Any()) { Abort(); return; } else { node = vessel.patchedConicSolver.maneuverNodes.First(); } } } //aim along the node core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.MANEUVER_NODE, this); double halfBurnTime; double burnTime = BurnTime(dVLeft, out halfBurnTime); double timeToNode = node.UT - vesselState.time; if (timeToNode < halfBurnTime) { burnTriggered = true; if (!MuUtils.PhysicsRunning()) { core.warp.MinimumWarp(); } } //autowarp, but only if we're already aligned with the node if (autowarp && !burnTriggered) { if (core.attitude.attitudeAngleFromTarget() < 1 || (core.attitude.attitudeAngleFromTarget() < 10 && !MuUtils.PhysicsRunning())) { core.warp.WarpToUT(node.UT - halfBurnTime - leadTime); } else if (!MuUtils.PhysicsRunning() && core.attitude.attitudeAngleFromTarget() > 10 && timeToNode < 600) { //realign core.warp.MinimumWarp(); } } core.thrust.targetThrottle = 0; if (burnTriggered) { if (alignedForBurn) { if (core.attitude.attitudeAngleFromTarget() < 90) { double timeConstant = (dVLeft > 10 || vesselState.minThrustAccel > 0.25 * vesselState.maxThrustAccel ? 0.5 : 2); core.thrust.ThrustForDV(dVLeft + tolerance, timeConstant); } else { alignedForBurn = false; } } else { if (core.attitude.attitudeAngleFromTarget() < 2) { alignedForBurn = true; } } } }
public override void OnFixedUpdate() { throttle.target = 0.0; if (vessel.patchedConicSolver.maneuverNodes.Count == 0) { Debug.Log("NodeExecutor: no maneuver node to execute"); Disable(); return; } ManeuverNode node = vessel.patchedConicSolver.maneuverNodes[0]; double dVLeft = node.GetBurnVector(orbit).magnitude; if (dVLeft < tolerance && attitude.AngleFromTarget() > 5) { Debug.Log("NodeExecutor: done with node, removing it"); node.RemoveSelf(); Disable(); return; } attitude.attitudeTo(Vector3d.forward, AttitudeReference.MANEUVER_NODE); double BurnUT = node.UT - BurnTime(dVLeft) / 2.0; if (vesselState.time < (BurnUT - 300)) { /* way before the burn */ if (attitude.AngleFromTarget() < 1 && CheckAngularVelocity(ref checkOneStart)) { warp.WarpToUT(this, BurnUT - leadTime); } } else if (vesselState.time < (BurnUT - leadTime)) { /* before the burn */ if (attitude.AngleFromTarget() < 1 && CheckAngularVelocity(ref checkTwoStart)) { warp.WarpToUT(this, BurnUT - leadTime); } if (attitude.AngleFromTarget() > 5) { warp.MinimumWarp(this); } } else if (vesselState.time < BurnUT) { /* settling time */ warp.MinimumWarp(this); } else { /* feeling the burn */ warp.MinimumWarp(this); throttle.target = 0.0; if (attitude.AngleFromTarget() > 5) { seeking = true; } else if (attitude.AngleFromTarget() < 1 || !seeking) { double thrustToMass = vesselState.thrustMaximum / vesselState.mass; throttle.target = Utils.Clamp(dVLeft / thrustToMass / 2.0, 0.01, 1.0); seeking = false; } } }
protected void MaintainAerobrakeNode() { if (makeAerobrakeNodes) { //Remove node after finishing aerobraking: if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode)) { if (aerobrakeNode.UT < vesselState.time && vesselState.altitudeASL > mainBody.RealMaxAtmosphereAltitude()) { aerobrakeNode.RemoveSelf(); aerobrakeNode = null; } } //Update or create node if necessary: ReentrySimulation.Result r = Result; if (r != null && r.outcome == ReentrySimulation.Outcome.AEROBRAKED) { //Compute the node dV: Orbit preAerobrakeOrbit = GetReenteringPatch(); //Put the node at periapsis, unless we're past periapsis. In that case put the node at the current time. double UT; if (preAerobrakeOrbit == orbit && vesselState.altitudeASL < mainBody.RealMaxAtmosphereAltitude() && vesselState.speedVertical > 0) { UT = vesselState.time; } else { UT = preAerobrakeOrbit.NextPeriapsisTime(preAerobrakeOrbit.StartUT); } Orbit postAerobrakeOrbit = MuUtils.OrbitFromStateVectors(r.WorldAeroBrakePosition(), r.WorldAeroBrakeVelocity(), r.body, r.aeroBrakeUT); Vector3d dV = OrbitalManeuverCalculator.DeltaVToChangeApoapsis(preAerobrakeOrbit, UT, postAerobrakeOrbit.ApR); if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode)) { //update the existing node Vector3d nodeDV = preAerobrakeOrbit.DeltaVToManeuverNodeCoordinates(UT, dV); aerobrakeNode.UpdateNode(nodeDV, UT); } else { //place a new node aerobrakeNode = vessel.PlaceManeuverNode(preAerobrakeOrbit, dV, UT); } } else { //no aerobraking, remove the node: if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode)) { aerobrakeNode.RemoveSelf(); } } } else { //Remove aerobrake node when it is turned off: if (aerobrakeNode != null && vessel.patchedConicSolver.maneuverNodes.Contains(aerobrakeNode)) { aerobrakeNode.RemoveSelf(); } } }