Completed implementation of all basic manoeuvre node readouts.
[VesselSimulator.git] / KerbalEngineer / Flight / Readouts / Orbital / ManoeuvreNode / ManoeuvreProcessor.cs
blob:a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/ManoeuvreProcessor.cs -> blob:b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/ManoeuvreProcessor.cs
--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/ManoeuvreProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/ManoeuvreProcessor.cs
@@ -30,6 +30,8 @@
 
 namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
 {
+    using Helpers;
+
     public class ManoeuvreProcessor : IUpdatable, IUpdateRequest
     {
         #region Fields
@@ -47,6 +49,7 @@
         public static double AvailableDeltaV { get; private set; }
 
         public static double BurnTime { get; private set; }
+
         public static int FinalStage { get; private set; }
 
         public static double HalfBurnTime { get; private set; }
@@ -59,6 +62,10 @@
         }
 
         public static double NormalDeltaV { get; private set; }
+
+        public static double PostBurnAp { get; private set; }
+
+        public static double PostBurnPe { get; private set; }
 
         public static double ProgradeDeltaV { get; private set; }
 
@@ -90,7 +97,11 @@
 
         public void Update()
         {
-            if (FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.Count == 0 || !SimulationProcessor.ShowDetails)
+            // Extra tests for low level tracking station not supporting patched conics and maneuver nodes
+            if (FlightGlobals.ActiveVessel.patchedConicSolver == null ||
+                FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes == null ||
+                FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.Count == 0 ||
+                !SimulationProcessor.ShowDetails)
             {
                 ShowDetails = false;
                 return;
@@ -103,6 +114,8 @@
             NormalDeltaV = deltaV.y;
             RadialDeltaV = deltaV.x;
             TotalDeltaV = node.GetBurnVector(FlightGlobals.ship_orbit).magnitude;
+            PostBurnAp = node.nextPatch != null ? node.nextPatch.ApA : 0;
+            PostBurnPe = node.nextPatch != null ? node.nextPatch.PeA : 0;
 
             UniversalTime = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].UT;
             AngleToPrograde = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].patch.GetAngleToPrograde(UniversalTime);
@@ -110,7 +123,7 @@
 
             var burnTime = 0.0;
             var midPointTime = 0.0;
-            HasDeltaV = GetBurnTime((float)TotalDeltaV, ref burnTime, ref midPointTime);
+            HasDeltaV = GetBurnTime(TotalDeltaV, ref burnTime, ref midPointTime);
             AvailableDeltaV = SimulationProcessor.LastStage.totalDeltaV;
 
             BurnTime = burnTime;
@@ -123,47 +136,50 @@
 
         #region Methods: private
 
-        private static bool GetBurnTime(float deltaV, ref double burnTime, ref double midPointTime)
+        private static bool GetBurnTime(double deltaV, ref double burnTime, ref double midPointTime)
         {
             var setMidPoint = false;
-            var deltaVMidPoint = deltaV * 0.5f;
+            var deltaVMidPoint = deltaV * 0.5;
 
-            for (var i = SimulationProcessor.Stages.Length - 1; i >= 0; i--)
+            for (var i = SimulationProcessor.Stages.Length - 1; i > -1; i--)
             {
                 var stage = SimulationProcessor.Stages[i];
-                var stageDeltaV = (float)stage.deltaV;
+                var stageDeltaV = stage.deltaV;
+                var startMass = stage.totalMass;
 
                 ProcessStageDrain:
-                if (deltaV <= Single.Epsilon)
+                if (deltaV <= Double.Epsilon)
                 {
-                    FinalStage = ++i;
-                    return true;
+                    break;
                 }
-                if (stageDeltaV <= Single.Epsilon)
+                if (stageDeltaV <= Double.Epsilon)
                 {
                     continue;
                 }
 
-                float deltaVDrain;
+                FinalStage = i;
+
+                double deltaVDrain;
                 if (deltaVMidPoint > 0.0)
                 {
-                    deltaVDrain = Mathf.Clamp(deltaV, 0.0f, Mathf.Clamp(deltaVMidPoint, 0.0f, stageDeltaV));
+                    deltaVDrain = deltaV.Clamp(0.0, stageDeltaV.Clamp(0.0, deltaVMidPoint));
                     deltaVMidPoint -= deltaVDrain;
-                    setMidPoint = deltaVMidPoint <= Single.Epsilon;
+                    setMidPoint = deltaVMidPoint <= Double.Epsilon;
                 }
                 else
                 {
-                    deltaVDrain = Mathf.Clamp(deltaV, 0.0f, stageDeltaV);
+                    deltaVDrain = deltaV.Clamp(0.0, stageDeltaV);
                 }
 
-                var startMass = stage.totalMass - (stage.resourceMass * (1.0f - (stageDeltaV / stage.deltaV)));
-                var endMass = startMass - (stage.resourceMass * (deltaVDrain / stageDeltaV));
-                var minimumAcceleration = stage.thrust / startMass;
-                var maximumAcceleration = stage.thrust / endMass;
+                var exhaustVelocity = stage.isp * Units.GRAVITY;
+                var flowRate = stage.thrust / exhaustVelocity;
+                var endMass = Math.Exp(Math.Log(startMass) - deltaVDrain / exhaustVelocity);
+                var deltaMass = (startMass - endMass) * Math.Exp(-(deltaVDrain * 0.001) / exhaustVelocity);
+                burnTime += deltaMass / flowRate;
 
-                burnTime += deltaVDrain / ((minimumAcceleration + maximumAcceleration) * 0.5);
                 deltaV -= deltaVDrain;
                 stageDeltaV -= deltaVDrain;
+                startMass -= deltaMass;
 
                 if (setMidPoint)
                 {
@@ -172,7 +188,7 @@
                     goto ProcessStageDrain;
                 }
             }
-            return false;
+            return deltaV <= Double.Epsilon;
         }
 
         #endregion