Example #1
0
        //Allows for automatic initiation and termination of burns
        private void automation(ManeuverNode myNode)
        {
            //Auto shutdown
            if (autoShutdown)
            {
                if ((myNode.GetBurnVector(FlightGlobals.ActiveVessel.orbit).magnitude < 0.5 || offTarget(myNode.GetBurnVector(FlightGlobals.ActiveVessel.orbit), 7.6f)) && timeToBurn < 1)
                {
                    autoShutdown = false;
                    FlightInputHandler.state.mainThrottle = 0;
                    Log.Info("(SG) Burn complete, throttle back.");
                }
            }

            //if (offTarget(myNode.GetBurnVector(FlightGlobals.ActiveVessel.orbit),7.2f)) Log.Info("Off target!");
            //Auto burn
            if (autoBurn)
            {
                if (timeToBurn <= 5)
                {
                    TimeWarp.SetRate(0, true);
                }
                if (timeToBurn <= 50 && TimeWarp.CurrentRateIndex > 2)
                {
                    TimeWarp.SetRate(2, true);
                }
                if (timeToBurn <= 500 && TimeWarp.CurrentRateIndex > 3)
                {
                    TimeWarp.SetRate(3, true);
                }
                if (timeToBurn <= 5000 && TimeWarp.CurrentRateIndex > 4)
                {
                    TimeWarp.SetRate(4, true);
                }
                if (timeToBurn < 1 && FlightInputHandler.state.mainThrottle == 0 && !offTarget(myNode.GetBurnVector(FlightGlobals.ActiveVessel.orbit), 2f))
                {
                    //Add check for w/in 2 degrees
                    autoBurn = false;
                    FlightInputHandler.state.mainThrottle = 1;
                    Log.Info("(SG) Node reached, commencing burn!");
                }
            }
            //update min delta V every .2 seconds
            if (Planetarium.GetUniversalTime() > lastTime + 0.2)
            {
                lastTime = Planetarium.GetUniversalTime();
                if (myNode.GetBurnVector(FlightGlobals.ActiveVessel.orbit).magnitude < minDv)
                {
                    minDv = myNode.GetBurnVector(FlightGlobals.ActiveVessel.orbit).magnitude;
                }
                if (timeToBurn > 0)
                {
                    minDv = myNode.DeltaV.magnitude;                    //suck it blue!
                }
            }
        }
Example #2
0
            public override AutopilotStep Drive(FlightCtrlState s)
            {
                if (node != null)
                {
                    double dVLeft = node.GetBurnVector(orbit).magnitude;

                    core.thrust.targetThrottle = 0;


                    if (burnTriggered && alignedForBurn)
                    {
                        if (core.attitude.attitudeAngleFromTarget() < 90)
                        {
                            double timeConstant = (dVLeft > 10 || vesselState.minThrustAccel > 0.25 * vesselState.maxThrustAccel ? 0.5 : 2);
                            core.thrust.ThrustForDV(dVLeft + core.node.tolerance, timeConstant);
                        }
                        else
                        {
                            alignedForBurn = false;
                        }
                    }
                    else
                    {
                        //aim along the node
                        core.attitude.attitudeTo(Vector3d.forward, AttitudeReference.MANEUVER_NODE, this);
                        if (core.attitude.attitudeAngleFromTarget() < 2)
                        {
                            alignedForBurn = true;
                        }
                    }
                }

                return(this);
            }
Example #3
0
        void Update()
        {
            if (!HighLogic.LoadedSceneIsFlight)
            {
                return;
            }
            Vessel _vessel = FlightGlobals.ActiveVessel;

            string[] _keys   = Enum.GetNames(typeof(QKey.Key));
            int      _length = _keys.Length;

            for (int _key = 1; _key < _length; _key++)
            {
                QKey.Key _getKey = (QKey.Key)_key;
                if (_getKey == QKey.Key.WarpToNode)
                {
                    continue;
                }
                if (QKey.isKeyDown(_getKey))
                {
                    StartCoroutine(startSAS(QKey.GetAutoPilot(_getKey)));
                    ScreenMessages.PostScreenMessage(string.Format("[{0}] {1}", MOD, QKey.GetText(_getKey)), 5, ScreenMessageStyle.UPPER_CENTER);
                    Log(QKey.GetText(_getKey), "QSAS");
                }
            }
            if (QKey.isKeyDown(QKey.Key.WarpToNode))
            {
                if (_vessel.patchedConicSolver.maneuverNodes.Count != 0)
                {
                    double       _UT;
                    ManeuverNode _manNode = _vessel.patchedConicSolver.maneuverNodes[0];
                    if (!QSettings.Instance.WarpToEnhanced)
                    {
                        _UT = _manNode.UT - 60;
                    }
                    else
                    {
                        double _estimatedBurnTime = _manNode.GetBurnVector(_vessel.orbit).magnitude / _vessel.specificAcceleration;
                        _UT = _manNode.UT - (_estimatedBurnTime / 2) - 15;
                    }
                    if (Planetarium.GetUniversalTime() > _UT)
                    {
                        ScreenMessages.PostScreenMessage(string.Format("[{0}] No need to time warp!", MOD), 5, ScreenMessageStyle.UPPER_CENTER);
                        Log("No need to time warp!", "QSAS");
                        return;
                    }
                    TimeWarp.fetch.WarpTo(_UT);
                    Log(QKey.GetText(QKey.Key.WarpToNode), "QSAS");
                }
                else
                {
                    ScreenMessages.PostScreenMessage(string.Format("[{0}] No maneuver node!", MOD), 5, ScreenMessageStyle.UPPER_CENTER);
                    Log("No maneuver node!", "QSAS");
                }
            }
        }
        public string NextNodeCountdown()
        {
            if (!vessel.patchedConicsUnlocked() || !vessel.patchedConicSolver.maneuverNodes.Any())
            {
                return("-");
            }
            ManeuverNode node = vessel.patchedConicSolver.maneuverNodes.First();
            double       dV   = node.GetBurnVector(orbit).magnitude;

            return(GuiUtils.TimeToDHMS(node.UT - BurnTime(dV) * leadFraction - vesselState.time));
        }
        public string NextNodeBurnTime()
        {
            if (!vessel.patchedConicsUnlocked() || !vessel.patchedConicSolver.maneuverNodes.Any())
            {
                return("-");
            }
            ManeuverNode node = vessel.patchedConicSolver.maneuverNodes.First();
            double       dV   = node.GetBurnVector(orbit).magnitude;

            return(GuiUtils.TimeToDHMS(BurnTime(dV)));
        }
Example #6
0
 void update_maneuver_node()
 {
     Node            = Solver.maneuverNodes[0];
     InitialDeltaV   = Node.DeltaV.magnitude;
     ThresholdDeltaV = Math.Min(InitialDeltaV, 10);
     NodeDeltaV      = Node.GetBurnVector(VSL.orbit);
     if (VSL.Engines.MaxDeltaV < InitialDeltaV)
     {
         Status("yellow", "WARNING: there may be not enough propellant for the maneuver");
     }
 }
Example #7
0
 void update_maneuver_node()
 {
     Node        = Solver.maneuverNodes[0];
     NodeDeltaV  = Node.GetBurnVector(VSL.orbit);
     NodeCB      = Node.patch.referenceBody;
     TargetOrbit = Node.nextPatch;
     if (VSL.Engines.MaxDeltaV < Node.DeltaV.magnitude)
     {
         Status("yellow", "WARNING: there may be not enough propellant for the maneuver");
     }
 }
Example #8
0
        public string NextManeuverNodeBurnTime()
        {
            if (!vessel.patchedConicsUnlocked() || !vessel.patchedConicSolver.maneuverNodes.Any())
            {
                return("N/A");
            }

            ManeuverNode node     = vessel.patchedConicSolver.maneuverNodes.First();
            double       burnTime = node.GetBurnVector(node.patch).magnitude / vesselState.limitedMaxThrustAccel;

            return(GuiUtils.TimeToDHMS(burnTime));
        }
        public string NextNodeBurnTime()
        {
            if (!vessel.patchedConicsUnlocked() || vessel.patchedConicSolver.maneuverNodes.Count == 0)
            {
                return("-");
            }
            ManeuverNode node = vessel.patchedConicSolver.maneuverNodes[0];
            double       dV   = node.GetBurnVector(orbit).magnitude;
            double       halfBurnTIme;

            return(GuiUtils.TimeToDHMS(BurnTime(dV, out halfBurnTIme)));
        }
Example #10
0
            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);
            }
Example #11
0
        //Draws the digital readouts to the gauge
        private void drawNumbers(ManeuverNode myNode)
        {
            //dv = Isp * ln (m0 / m1)
            //e^(dv/ISP) = m0/m1
            //m1 = m0/e^(dv/ISP)    ...I think.
            //mass flow = thrust/isp
            deltaV    = myNode.DeltaV.magnitude;                                          //The burn's ΔV
            deltaVRem = myNode.GetBurnVector(FlightGlobals.ActiveVessel.orbit).magnitude; //Remaining ΔV in the burn
            //res r = calculateThrust(FlightGlobals.ActiveVessel);                    //Actually calculates thrust, mass, and Isp
            //Log.Info("Mass: " + Math.Round(r.mass, 2) + " Thrust: " + Math.Round(r.thrust, 2) + " ISP: " + Math.Round(r.isp, 2));
            //double mass = SteamShip.Mass / Math.Pow(Math.E, (deltaVRem / (SteamShip.ISP*9.82)));    //Mass after burn   Changed from 9.821
            //Log.Info("Final Mass: " + Math.Round(mass, 2)+" Burn Mass: "+Math.Round(r.mass-mass,2));
            //double rate = SteamShip.MaxThrust / (SteamShip.ISP*9.82);                                  //Mass flow rate, rounded to 5 digits
            //double burnTime = (SteamShip.Mass - mass)/rate;                                 //Mass to burn over rate should give time, but doesn't
            //burnTime += SteamShip.EngineAccel+SteamShip.EngineDecel;                        //Compensate for slow throttles
            double            burnTime = SteamShip.BurnTime;
            NavBallBurnVector bv       = UnityEngine.Object.FindObjectsOfType <NavBallBurnVector>()[0];
            double            bt2      = bv.estimatedBurnTime;

            if (double.IsInfinity(bt2) || double.IsNaN(bt2))
            {
                bt2 = 0;                                              //Assume its good if not infinity or NaN
            }
            //Draw values
            drawDigits(182, 131, deltaV);
            //If we are past the node time, time until burn is 0
            if (Planetarium.GetUniversalTime() < myNode.UT)
            {
                if (useCalculatedBurn)
                {
                    timeToBurn = (long)((myNode.UT - Planetarium.GetUniversalTime()) - (burnTime / 2.0));
                    drawTime(219, 198, timeToBurn);    //draw actual time to burn start
                }
                else
                {
                    timeToBurn = (long)((myNode.UT - Planetarium.GetUniversalTime()) - (bt2 / 2));
                    drawTime(219, 198, timeToBurn);    //draw actual time to KSP's burn start
                }
            }
            else
            {
                drawTime(219, 198, 0);    //Use 0 as time to burn if past node
            }
            if (useCalculatedBurn)
            {
                drawTime(219, 261, burnTime);   //Draw burn time.
            }
            else
            {
                drawTime(219, 261, bt2);        //Draw KSP's burn time
            }
        }
Example #12
0
 internal void FixedUpdate()
 {
     if (!FlightDriver.Pause)
     {
         PatchedConicSolver solver = NodeTools.getSolver();
         if (options.removeUsedNodes && solver.maneuverNodes.Count > 0)
         {
             ManeuverNode node = solver.maneuverNodes[0];
             if (node.GetBurnVector(FlightGlobals.ActiveVessel.orbit).magnitude < options.usedNodeThreshold)
             {
                 solver.RemoveManeuverNode(node);
                 //TODO: Clean up states after removing the node.
             }
         }
     }
 }
        public string NextNodeCountdown()
        {
            if (!vessel.patchedConicsUnlocked() || !vessel.patchedConicSolver.maneuverNodes.Any())
            {
                return("-");
            }
            ManeuverNode node = vessel.patchedConicSolver.maneuverNodes.First();
            double       dV   = node.GetBurnVector(orbit).magnitude;
            double       halfBurnTIme;
            double       burnTIme = BurnTime(dV, out halfBurnTIme);

            if (double.IsInfinity(halfBurnTIme))
            {
                halfBurnTIme = 0.0;
            }
            return(GuiUtils.TimeToDHMS(node.UT - halfBurnTIme - vesselState.time));
        }
Example #14
0
 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();
 }
Example #15
0
        private void RefreshNodeValues()
        {
            // Per KSP API wiki http://docuwiki-kspapi.rhcloud.com/#/classes/ManeuverNode:
            // The x-component of DeltaV represents the delta-V in the radial-plus direction.
            // The y-component of DeltaV  represents the delta-V in the normal-plus direction.
            // The z-component of DeltaV represents the delta-V in the prograde direction.
            // However... it is not returned in the basis of the orbit at the time of the
            // maneuver.  It needs transformed into the right basis.
            maneuverVector = node.GetBurnVector(orbit);
            nodeDV         = maneuverVector.magnitude;

            // Swizzle these into the right order.
            Vector3d mnvrVel = orbit.getOrbitalVelocityAtUT(node.UT).xzy;
            Vector3d mnvrPos = orbit.getRelativePositionAtUT(node.UT).xzy;

            Vector3d mnvrPrograde = mnvrVel.normalized; // Prograde vector at maneuver time
            Vector3d mnvrNml      = Vector3d.Cross(mnvrVel, mnvrPos).normalized;
            Vector3d mnvrRadial   = Vector3d.Cross(mnvrNml, mnvrPrograde);

            maneuverNodeComponentVector.x = Vector3d.Dot(maneuverVector, mnvrPrograde);
            maneuverNodeComponentVector.y = Vector3d.Dot(maneuverVector, mnvrNml);
            maneuverNodeComponentVector.z = Vector3d.Dot(maneuverVector, mnvrRadial);
        }
Example #16
0
        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();
        }
Example #17
0
        public Vector GetBurnVector()
        {
            CheckNodeRef();

            return(new Vector(nodeRef.GetBurnVector(vesselRef.GetOrbit())));
        }
Example #18
0
        public override void OnFixedUpdate()
        {
            if (!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;

                vessel.patchedConicSolver.RemoveManeuverNode(node);

                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 burnTime = BurnTime(dVLeft);

            double timeToNode = node.UT - vesselState.time;

            if (timeToNode < burnTime * leadFraction)
            {
                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 - burnTime * leadFraction - 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 ? 0.5 : 2);
                        double desiredAcceleration = dVLeft / timeConstant;
                        desiredAcceleration = Math.Max(tolerance, desiredAcceleration);

                        core.thrust.targetThrottle = Mathf.Clamp01((float)(desiredAcceleration / vesselState.maxThrustAccel));
                    }
                    else
                    {
                        alignedForBurn = false;
                    }
                }
                else
                {
                    if (core.attitude.attitudeAngleFromTarget() < 2)
                    {
                        alignedForBurn = true;
                    }
                }
            }
        }
Example #19
0
        /// <summary>
        /// Executes the maneuver burn for the configured maneuver node.
        /// </summary>
        /// <param name="computer">FlightComputer instance of the computer of the vessel the ManeuverCommand is for.</param>
        /// <param name="ctrlState">FlightCtrlState instance of the current state of the vessel.</param>
        /// <returns>true if the command has finished its work, false otherwise.</returns>
        public override bool Execute(FlightComputer computer, FlightCtrlState ctrlState)
        {
            // Halt the command if we reached our target or were command to abort by the previous tick
            if (this.RemainingDelta <= 0.01 || this.abortOnNextExecute)
            {
                this.AbortManeuver(computer);
                return(true);
            }

            // Orientate vessel to maneuver prograde
            var forward     = Node.GetBurnVector(computer.Vessel.orbit).normalized;
            var up          = (computer.SignalProcessor.Body.position - computer.SignalProcessor.Position).normalized;
            var orientation = Quaternion.LookRotation(forward, up);

            FlightCore.HoldOrientation(ctrlState, computer, orientation, true);

            // This represents the theoretical acceleration but is off by a few m/s^2, probably because some parts are partially physicsless
            double thrustToMass = (FlightCore.GetTotalThrust(computer.Vessel) / computer.Vessel.GetTotalMass());

            // We need to know if the engine was activated or not to show the proper info text in the command
            if (thrustToMass == 0.0)
            {
                this.EngineActivated = false;
                return(false);
            }
            this.EngineActivated = true;

            // Before any throttling, those two values may differ from after the throttling took place
            this.RemainingDelta = this.getRemainingDeltaV(computer);
            this.RemainingTime  = this.RemainingDelta / thrustToMass;

            // In case we would overpower with 100% thrust, calculate how much we actually need and set it.
            if (computer.Vessel.acceleration.magnitude > this.RemainingDelta)
            {
                // Formula which leads to this: a = ( vE – vS ) / dT
                this.throttle = this.RemainingDelta / computer.Vessel.acceleration.magnitude;
            }

            ctrlState.mainThrottle = (float)this.throttle;

            // TODO: THIS CAN PROBABLY BE REMOVED? RemainingDelta = this.getRemainingDeltaV(computer);

            // After throttling, the remaining time differs from beforehand (dividing delta by throttled thrustToMass)
            this.RemainingTime = this.RemainingDelta / (ctrlState.mainThrottle * thrustToMass);

            // We need to abort if the remaining delta was already low enough so it only takes exactly one more tick!
            double ticksRemaining = this.RemainingTime / TimeWarp.deltaTime;

            if (ticksRemaining <= 1)
            {
                this.throttle          *= ticksRemaining;
                ctrlState.mainThrottle  = (float)this.throttle;
                this.abortOnNextExecute = true;
                return(false);
            }

            // we only compare up to the fiftieth part due to some burn-up delay when just firing up the engines
            if (this.lowestDeltaV > 0 && // Do ignore the first tick
                (this.RemainingDelta - 0.02) > this.lowestDeltaV &&
                this.RemainingDelta < 1.0)      // be safe that we do not abort the command to early
            {
                // Aborting because deltaV was rising again!
                this.AbortManeuver(computer);
                return(true);
            }

            // Lowest delta always has to be stored to be able to compare it in the next tick
            if (this.lowestDeltaV == 0 || // Always do it on the first tick
                this.RemainingDelta < this.lowestDeltaV)
            {
                this.lowestDeltaV = this.RemainingDelta;
            }

            return(false);
        }
        public static void Update(bool target)
        {
            _update = false;

            if (FlightGlobals.ActiveVessel == null ||
                FlightGlobals.ActiveVessel.patchedConicSolver == null)
            {
                _updated = false;
                return;
            }

            PatchedConicSolver solver = FlightGlobals.ActiveVessel.patchedConicSolver;

            _node = solver.maneuverNodes[0];

            if (_node != null || _node.patch == null)
            {
                _maneuverTotal = _node.DeltaV.magnitude;

                _maneuverRemaining = _node.GetBurnVector(_node.patch).magnitude;

                if (BasicOrbitReflection.BetterBurnTimeLoaded)
                {
                    if (_bbVesselModule == null || _bbVesselReference != FlightGlobals.ActiveVessel)
                    {
                        for (int i = FlightGlobals.ActiveVessel.vesselModules.Count - 1; i >= 0; i--)
                        {
                            VesselModule vMod = FlightGlobals.ActiveVessel.vesselModules[i];

                            if (vMod == null)
                            {
                                continue;
                            }

                            if (vMod.GetType().Name != _bbModuleName)
                            {
                                continue;
                            }

                            _bbVesselModule    = vMod;
                            _bbVesselReference = FlightGlobals.ActiveVessel;
                            break;
                        }
                    }

                    if (_bbVesselModule != null)
                    {
                        string type = _bbVesselModule.Fields[_bbTypeName].GetValue(_bbVesselModule).ToString();

                        if (type == "Maneuver")
                        {
                            _burnLength = _bbVesselModule.Fields[_bbLengthName].GetValue <double>(_bbVesselModule);
                            _burnTime   = _bbVesselModule.Fields[_bbTimeName].GetValue <double>(_bbVesselModule);

                            if (double.IsNaN(_burnLength) || double.IsNaN(_burnTime))
                            {
                                _bbTimeLoaded = false;
                                _burnTime     = _node.UT;
                                _burnLength   = 0;
                            }
                            else
                            {
                                double half = _burnLength / 2;
                                _burnTime    -= half;
                                _bbTimeLoaded = true;
                            }
                        }
                        else
                        {
                            _bbTimeLoaded = false;
                            _burnTime     = _node.UT;
                        }
                    }
                    else
                    {
                        _bbTimeLoaded = false;
                        _burnTime     = _node.UT;
                    }
                }
                else
                {
                    _burnTime = _node.UT;
                }

                _showAngle         = false;
                _showPhasing       = false;
                _targetInclination = false;

                if (target)
                {
                    if (!BasicTargetting.IsVessel && !BasicTargetting.IsCelestial)
                    {
                        _vesselIntersect = false;
                        _bodyIntersect   = false;
                    }
                    else
                    {
                        Orbit targetOrbit = FlightGlobals.ActiveVessel.targetObject.GetOrbit();

                        Orbit active = FlightGlobals.ActiveVessel.orbit;

                        _targetPhasingOrbit = null;

                        if (active.referenceBody == targetOrbit.referenceBody)
                        {
                            _phasingNodePatch   = active;
                            _targetPhasingOrbit = targetOrbit;
                            _targetInclination  = true;
                        }
                        else
                        {
                            if (active.referenceBody != Planetarium.fetch.Sun)
                            {
                                _showAngle = true;
                            }

                            _showPhasing = true;

                            DrillDownOrbits(_node.patch, targetOrbit);
                        }

                        Vessel.Situations sit = FlightGlobals.ActiveVessel.situation;

                        if ((sit |= Vessel.Situations.LANDED | Vessel.Situations.SPLASHED | Vessel.Situations.PRELAUNCH) == 0)
                        {
                            _vesselIntersect = false;
                            _bodyIntersect   = false;
                        }
                        else
                        {
                            OrbitTargeter oTargeter = FlightGlobals.ActiveVessel.orbitTargeter;

                            if (oTargeter == null || solver == null)
                            {
                                _vesselIntersect = false;
                                _bodyIntersect   = false;
                            }
                            else if (!MapView.MapIsEnabled)
                            {
                                if (BasicTargetting.IsVessel)
                                {
                                    _bodyIntersect = false;

                                    Vessel tgt = FlightGlobals.ActiveVessel.targetObject.GetVessel();

                                    if (tgt == null || tgt.LandedOrSplashed)
                                    {
                                        _vesselIntersect = false;
                                        return;
                                    }

                                    Orbit _refPatch    = BasicOrbitReflection.GetRefPatch(oTargeter);
                                    Orbit _tgtRefPatch = BasicOrbitReflection.GetTargetRefPatch(oTargeter);

                                    _vesselIntersect = GetClosestVessel(_refPatch, _tgtRefPatch);
                                }
                                else
                                {
                                    _vesselIntersect = false;

                                    double Pe = GetLowestPeA(solver, BasicTargetting.TargetBody, _node.patch);

                                    if (Pe < BasicExtensions.AlmostMaxValue)
                                    {
                                        _closestDist   = Pe;
                                        _bodyIntersect = true;
                                    }
                                    else
                                    {
                                        Orbit _refPatch    = BasicOrbitReflection.GetRefPatch(oTargeter);
                                        Orbit _tgtRefPatch = BasicOrbitReflection.GetTargetRefPatch(oTargeter);

                                        if (_refPatch != null && _refPatch.closestTgtApprUT <= 0)
                                        {
                                            _bodyIntersect = false;
                                            return;
                                        }

                                        _bodyIntersect = GetClosestCelestial(_refPatch, _tgtRefPatch);
                                    }
                                }
                            }
                            else
                            {
                                if (BasicTargetting.Markers == null || BasicTargetting.Markers.Count <= 0)
                                {
                                    BasicTargetting.Markers = BasicOrbitReflection.GetOrbitMarkers(oTargeter);
                                }

                                if (BasicTargetting.IsVessel)
                                {
                                    _bodyIntersect = false;

                                    OrbitTargeter.ISectMarker _intersectOne = null;
                                    OrbitTargeter.ISectMarker _intersectTwo = null;

                                    for (int i = BasicTargetting.Markers.Count - 1; i >= 0; i--)
                                    {
                                        OrbitTargeter.Marker m = BasicTargetting.Markers[i];

                                        if (m == null)
                                        {
                                            continue;
                                        }

                                        if (!(m is OrbitTargeter.ISectMarker))
                                        {
                                            continue;
                                        }

                                        int num = ((OrbitTargeter.ISectMarker)m).num;

                                        if (num == 1)
                                        {
                                            _intersectOne = m as OrbitTargeter.ISectMarker;
                                        }
                                        else if (num == 2)
                                        {
                                            _intersectTwo = m as OrbitTargeter.ISectMarker;
                                        }
                                    }

                                    OrbitTargeter.ISectMarker _closestIntersect = null;

                                    if (_intersectOne != null && _intersectTwo != null)
                                    {
                                        _closestIntersect = _intersectOne.separation > _intersectTwo.separation ? _intersectTwo : _intersectOne;
                                    }
                                    else if (_intersectOne != null)
                                    {
                                        _closestIntersect = _intersectOne;
                                    }
                                    else if (_intersectTwo != null)
                                    {
                                        _closestIntersect = _intersectTwo;
                                    }
                                    else
                                    {
                                        _closestIntersect = null;
                                    }

                                    if (_closestIntersect == null)
                                    {
                                        _vesselIntersect = false;
                                    }
                                    else
                                    {
                                        _vesselIntersect = true;
                                        _closestDist     = _closestIntersect.separation * 1000;
                                        _closestRelVel   = _closestIntersect.relSpeed;
                                        _closestTime     = _closestIntersect.UT;
                                    }
                                }
                                else
                                {
                                    _vesselIntersect = false;

                                    double Pe = GetLowestPeA(solver, BasicTargetting.TargetBody, _node.patch);

                                    if (Pe < BasicExtensions.AlmostMaxValue)
                                    {
                                        _closestDist   = Pe;
                                        _bodyIntersect = true;
                                    }
                                    else
                                    {
                                        OrbitTargeter.ClApprMarker _approach = null;

                                        for (int i = BasicTargetting.Markers.Count - 1; i >= 0; i--)
                                        {
                                            OrbitTargeter.Marker m = BasicTargetting.Markers[i];

                                            if (m == null)
                                            {
                                                continue;
                                            }

                                            if (!(m is OrbitTargeter.ClApprMarker))
                                            {
                                                continue;
                                            }

                                            _approach = m as OrbitTargeter.ClApprMarker;
                                        }

                                        if (_approach == null)
                                        {
                                            _bodyIntersect = false;
                                        }
                                        else
                                        {
                                            _bodyIntersect = true;
                                            _closestDist   = _approach.separation * 1000;
                                            _closestTime   = (_approach.dT * -1) + Planetarium.GetUniversalTime();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                _updated = true;
            }
        }
Example #21
0
        private void OnHudTextWindow(int windowID)
        {
            Vessel vessel = FlightGlobals.fetch.activeVessel;
            double vel    = 0.0d;
            string speedLabel;

            GUIStyle hudTextStyle = new GUIStyle();

            hudTextStyle.normal.textColor = _values.HudTextColor;

            GUILayout.BeginVertical();

            bool isRCSOn = vessel.ActionGroups[KSPActionGroup.RCS];
            bool isSASOn = vessel.ActionGroups[KSPActionGroup.SAS];

            GUILayout.BeginHorizontal();
            if (isSASOn)
            {
                GUILayout.Label("SAS", hudTextStyle);
            }
            if (isRCSOn)
            {
                GUILayout.Label("RCS", hudTextStyle);
            }
            GUILayout.EndHorizontal();

            switch (FlightGlobals.speedDisplayMode) // Changed in 1.1 from FlightUIController.speedDisplayMode
            {
            case FlightGlobals.SpeedDisplayModes.Surface:
                vel        = FlightGlobals.ship_srfSpeed;
                speedLabel = "Surface: " + vel.ToString("F2") + "m/s";
                break;

            case FlightGlobals.SpeedDisplayModes.Orbit:
                vel        = FlightGlobals.ship_obtSpeed;
                speedLabel = "Orbit: " + vel.ToString("F2") + "m/s";
                break;

            case FlightGlobals.SpeedDisplayModes.Target:
                vel        = FlightGlobals.ship_tgtSpeed;
                speedLabel = "Target: " + vel.ToString("F2") + "m/s";
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            GUILayout.Label(speedLabel, hudTextStyle);
            GUILayout.Label("Throttle: " + vessel.ctrlState.mainThrottle.ToString("P1"), hudTextStyle);

            GUILayout.Label("Heading: " + FlightGlobals.ship_heading.ToString("F1"), hudTextStyle);
            GUILayout.Label("G Force: " + FlightGlobals.ship_geeForce.ToString("F1"), hudTextStyle);

            if (vessel != null && vessel.patchedConicSolver != null &&
                vessel.patchedConicSolver.maneuverNodes != null &&
                vessel.patchedConicSolver.maneuverNodes.Count > 0)
            {
                ManeuverNode node    = vessel.patchedConicSolver.maneuverNodes[0];
                double       burnDV  = node.DeltaV.magnitude;
                double       burnRem = node.GetBurnVector(vessel.orbit).magnitude;
                GUILayout.Label("Burn ΔV: " + burnRem.ToString("F2") + "m/s / " + burnDV.ToString("F2") + "m/s", hudTextStyle);

                if (burnRem != double.NaN)
                {
                    double totalThrust = 0.0;
                    double totalIsp    = 0.0;
                    calcThrust(ref totalThrust, ref totalIsp);
                    if (vessel.ctrlState.mainThrottle > 0.0)
                    {
                        totalThrust *= vessel.ctrlState.mainThrottle;
                    }

                    double burnTimeRem   = calcBurnTime(burnRem, vessel.GetTotalMass(), totalThrust, totalIsp);
                    double burnTimeTotal = calcBurnTime(burnDV, vessel.GetTotalMass(), totalThrust, totalIsp);
                    GUILayout.Label("Burn time: " + GetTimeString(burnTimeRem) + " / " + GetTimeString(burnTimeTotal),
                                    hudTextStyle);
                }

                double timeToNode = node.UT - Planetarium.GetUniversalTime();
                if (Math.Sign(timeToNode) >= 0)
                {
                    GUILayout.Label("Node in T - " + GetTimeString(Math.Abs(timeToNode)), hudTextStyle);
                }
                else
                {
                    GUILayout.Label("Node in T + " + GetTimeString(Math.Abs(timeToNode)), hudTextStyle);
                }
            }

            GUILayout.EndVertical();
            if (!_lockText)
            {
                GUI.DragWindow();
            }
        }
        /*
         * TARGET APIs
         */

        public void TargetNode(ManeuverNode node, double burntime)
        {
            if (status == PVGStatus.ENABLED)
            {
                return;
            }

            if (p == null || isCoasting())
            {
                PontryaginNode solver = p as PontryaginNode;
                if (solver == null)
                {
                    solver = new PontryaginNode(core: core, mu: mainBody.gravParameter, r0: vesselState.orbitalPosition, v0: vesselState.orbitalVelocity, pv0: node.GetBurnVector(orbit).normalized, pr0: Vector3d.zero, dV: node.GetBurnVector(orbit).magnitude, bt: burntime);
                }
                solver.intercept(node.nextPatch);
                p = solver;
            }
        }
        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;
                    }
                }
            }
        }
Example #24
0
        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;
                }
            }
        }
Example #25
0
            public ManeuverNode GetManeuverNode()
            {
                if (payload == null || node?.nextPatch == null)
                {
                    return(null);
                }
                var remainingDeltaV = node.nextPatch.GetFrameVelAtUT(node.UT)
                                      - payload.orbit.GetFrameVelAtUT(node.UT);
                var newNode = new ManeuverNode
                {
                    UT        = node.UT,
                    DeltaV    = Utils.Orbital2NodeDeltaV(payload.orbit, remainingDeltaV, node.UT),
                    patch     = new Orbit(payload.orbit),
                    nextPatch = new Orbit(node.nextPatch)
                };

                Utils.Debug($"new node: {newNode.ToConfigString()}\norbDeltaV: {Utils.Node2OrbitalDeltaV(newNode)}\nnode burn vector: {Utils.formatVector(node.GetBurnVector(payload.orbit))}\nnew node burn vec: {Utils.formatVector(newNode.GetBurnVector(payload.orbit))}");
                return(newNode);
            }
Example #26
0
        //This method is called periodically by the main thread,
        //then it decides if it is time to start a new thread or not
        public static void update()
        {
            now = Time.time;
            //double lc = lastCharge;
            //float lt = lastTime;
            //lastTime = now;
            double dt = TimeWarp.fixedDeltaTime;

            //Debug.Log("Starting simulation at " + Math.Round(now, 3));
            isReadable = false;
            //Reset some stuff
            ship              = FlightGlobals.ActiveVessel;
            body              = ship.mainBody;
            _gravity          = FlightGlobals.getGeeForceAtPosition(ship.CoM).magnitude;
            _electricCharge   = 0;
            _electricMax      = 0;
            _evamaxfuel       = 0;
            _evafuel          = 0;
            _liquidFuel       = 0;
            _liquidMax        = 0;
            _monoFuel         = 0;
            _monoMax          = 0;
            _airin            = 0;
            _airreq           = 0;
            _mass             = 0;
            _max_thrust       = 0;
            _cur_thrust       = 0;
            _isp              = 0;
            _engineaccel      = 0;
            _enginedecel      = 0;
            _max_temp_percent = 0;
            _max_temp_actual  = 0;
            double _best_temp     = 0;
            double _best_ablation = 0;

            _ablation = 1;
            _tarpos   = new Vector3();


//            int cur_stage = ship.currentStage;
//Debug.Log("##########################");
//Debug.Log("Current Stage: "+cur_stage);
            //Part loop - look at all the parts and modules for stuff.
            foreach (Part P in ship.parts)
            {
                /*Debug.Log("-------------------------------");
                *  Debug.Log(P.name);
                *  Debug.Log("inStageIndex: " + P.inStageIndex);
                *  Debug.Log("inv Stage: " + P.inverseStage);
                *  Debug.Log("Manual Stage Offset: " + P.manualStageOffset);
                *  Debug.Log("Computed Stage: " + (P.inverseStage + P.manualStageOffset));
                *  Debug.Log("Original Stage: " + P.originalStage);
                *  //Debug.Log("Stage After: " + P.stageAfter);
                *  //Debug.Log("Stage Before: " + P.stageBefore);
                *  Debug.Log("Stage Offset: " + P.stageOffset); */

                //Temperature
                //First, look at internal temps
                _best_temp = P.temperature / P.maxTemp;
                if (_best_temp > _max_temp_percent)
                {
                    _max_temp_percent = _best_temp;
                    _max_temp_actual  = P.temperature;
                }
                //Now look at skin temps
                _best_temp = P.skinTemperature / P.skinMaxTemp;
                if (_best_temp > _max_temp_percent)
                {
                    _max_temp_percent = _best_temp;
                    _max_temp_actual  = P.skinTemperature;
                }

                //if (P.temperature/P.maxTemp > .5) Debug.Log(P.partInfo.title + " Temp: " + (int)P.temperature + "⁰/" + (int)P.maxTemp + "⁰");



                //Vessel Mass
                if (P.physicalSignificance == Part.PhysicalSignificance.FULL)
                {
                    _mass += P.mass;
                    _mass += P.GetResourceMass();
                }
                //Resource loop
                foreach (PartResource pr in P.Resources)
                {
                    if (pr.resourceName.Equals("ElectricCharge"))
                    {
                        _electricCharge += pr.amount;
                        _electricMax    += pr.maxAmount;
                    }
                    else if (pr.resourceName.Equals("LiquidFuel"))
                    {
                        _liquidFuel += pr.amount;
                        _liquidMax  += pr.maxAmount;
                    }
                    else if (pr.resourceName.Equals("MonoPropellant"))
                    {
                        _monoFuel += pr.amount;
                        _monoMax  += pr.maxAmount;
                    }
                    else if (pr.resourceName.Equals("Ablator"))
                    {
                        _best_ablation = pr.amount / pr.maxAmount;
                        if (_best_ablation < _ablation)
                        {
                            _ablation = _best_ablation;
                        }
                    }
                }
                //Module loop
                foreach (PartModule pm in P.Modules)
                {
                    if (pm is KerbalEVA)
                    {
                        KerbalEVA eva = pm as KerbalEVA;
                        _evafuel    = eva.Fuel;
                        _evamaxfuel = eva.FuelCapacity;
                    }
                    else if (pm is ModuleWheelDeployment)
                    {
                        _gearstate = 0; //Gear up
                        ModuleWheelDeployment mlg = pm as ModuleWheelDeployment;
                        if (mlg.stateString.Equals("Deployed"))
                        {
                            _gearstate = 3;
                        }
                        if (mlg.stateString.StartsWith("Deploying"))
                        {
                            _gearstate = 2;
                        }
                        if (mlg.stateString.StartsWith("Retracting"))
                        {
                            _gearstate = 1;
                        }
                    }
                    else if (pm is ModuleEngines)
                    {
                        ModuleEngines ME = pm as ModuleEngines;
                        if (ME.engineShutdown || !ME.EngineIgnited) //We don't care about engines that aren't ready to fire
                        {
                            continue;
                        }
                        if (1 / ME.engineAccelerationSpeed > _engineaccel)
                        {
                            _engineaccel = 1 / ME.engineAccelerationSpeed;
                        }
                        if (1 / ME.engineDecelerationSpeed > _enginedecel)
                        {
                            _enginedecel = 1 / ME.engineDecelerationSpeed;
                        }
                        //Thrust/ISP
                        float thrust = ME.maxThrust * ME.thrustPercentage * 0.01f;

                        _isp        += thrust / ME.atmosphereCurve.Evaluate((float)ship.staticPressurekPa);
                        _max_thrust += thrust;
                        _cur_thrust += ME.finalThrust;  //I think this is the actual thrust being produced by each engine
                        //Intake Air
                        foreach (Propellant Pro in ME.propellants)
                        {
                            if (Pro.name.Equals("IntakeAir"))
                            {
                                _airreq += Pro.currentRequirement;
                            }
                        }
                        //Overheat stuff
                        //if (!ME.flameout)
                        //{
                        //    double temp = P.temperature / P.maxTemp;
                        //    if (temp > _max_temp) _max_temp = temp;
                        //}
                    }
                    else if (pm is ModuleEnginesFX)  //The newer engines all use this instead of ModuleEngines
                    {
                        ModuleEnginesFX MFX = pm as ModuleEnginesFX;
                        if (MFX.engineShutdown || !MFX.EngineIgnited)
                        {
                            continue;
                        }
                        //Thrust/ISP
                        float thrust = MFX.maxThrust * MFX.thrustPercentage * 0.01f;
                        _isp        += thrust / MFX.atmosphereCurve.Evaluate((float)ship.staticPressurekPa);
                        _max_thrust += thrust;
                        _cur_thrust += MFX.finalThrust;
                        //Overheat stuff
                        //if (!MFX.flameout)
                        //{
                        //    double temp = P.temperature / P.maxTemp;
                        //    if (temp > _max_temp) _max_temp = temp;
                        //}
                        if (1 / MFX.engineAccelerationSpeed > _engineaccel)
                        {
                            _engineaccel = 1 / MFX.engineAccelerationSpeed;
                        }
                        if (1 / MFX.engineDecelerationSpeed > _enginedecel)
                        {
                            _enginedecel = 1 / MFX.engineDecelerationSpeed;
                        }
                        foreach (Propellant Pro in MFX.propellants)
                        {
                            if (Pro.name.Equals("IntakeAir"))
                            {
                                _airreq += Pro.currentRequirement;
                            }
                        }
                    }
                    else if (pm is ModuleResourceIntake)
                    {
                        ModuleResourceIntake MRI = pm as ModuleResourceIntake;
                        if (MRI.intakeEnabled && MRI.resourceName.Equals("IntakeAir"))
                        {
                            _airin += MRI.airFlow * dt; //Using dt courtesy of FAR
                        }
                    }
                }
            }
            _isp = _max_thrust / _isp;    //Complete the average isp

            if (_engineaccel == 0)
            {
                _engineaccel = 2;                       //Default in case the engines don't define it
            }
            //Debug.Log("Engine Acceleration: " + Math.Round(_engineaccel, 2));

            //Electric charge rate
            if (now - lastTime > 0.1)
            {
                _chargeRate = (_electricCharge - lastCharge) / (now - lastTime);
                lastCharge  = _electricCharge;
                lastTime    = now;
            }
            //Clamp to +30/-30
            if (_chargeRate > 30)
            {
                _chargeRate = 30;
            }
            if (_chargeRate < -30)
            {
                _chargeRate = -30;
            }

            //Maneuver node burn calculations
            //dv = Isp * ln (m0 / m1)
            //e^(dv/ISP) = m0/m1
            //m1 = m0/e^(dv/ISP)
            //mass flow = thrust/isp
            try
            {
                ManeuverNode myNode    = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes.ToArray()[0];
                double       deltaVRem = myNode.GetBurnVector(ship.orbit).magnitude; //Remaining ΔV in the burn, per maneuver node
                //Debug.Log("dV: " + Math.Round(deltaVRem, 1));
                //Debug.Log("Mass: " + Math.Round(_mass, 1) + " ISP: " + Math.Round(_isp, 1));
                _final_mass = _mass / Math.Pow(Math.E, (deltaVRem / (_isp * 9.82)));                   //Mass after burn   Changed from 9.821
                //Debug.Log("Final Mass: " + Math.Round(_final_mass, 1));
                _mass_rate = _max_thrust / (_isp * 9.82);                                              //Mass flow rate
                //Debug.Log("Mass Rate: " + Math.Round(_mass_rate, 3));
                //Debug.Log("Burn Mass: " + Math.Round(_mass - _final_mass, 1));
                _burn_time = (_mass - _final_mass);// / _mass_rate;                                         //Time it takes for this burn
                //Debug.Log("Burn Mass: " + _burn_time);
                _burn_time = _burn_time / _mass_rate;
                //Debug.Log("Burn Time: " + _burn_time);
                _burn_time += 2d;
                //_burn_time += _engineaccel + _enginedecel;                                             //Factor in slow throttles
            }
            catch
            {
                _burn_time  = 0;
                _final_mass = 0;
                _mass_rate  = 0;
            }

            //Heading, courtesy of MechJeb

            /*Vector3d CoM, up, north, east, forward, rootPartPos;
             * Quaternion rotationSurface, rotationVesselSurface;
             * CoM = ship.findWorldCenterOfMass();
             * up = (CoM - body.position).normalized;
             * Rigidbody rigidBody = ship.rootPart.rigidbody;
             * if (rigidBody != null) rootPartPos = rigidBody.position;
             * north = Vector3d.Exclude(up, (body.position + body.transform.up * (float)body.Radius) - CoM).normalized;
             * east = body.getRFrmVel(CoM).normalized;
             * forward = ship.GetTransform().up;
             * rotationSurface = Quaternion.LookRotation(north, up);
             * rotationVesselSurface = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(ship.GetTransform().rotation) * rotationSurface);
             * _heading = rotationVesselSurface.eulerAngles.y; */
            _heading = FlightGlobals.ship_heading;
            //Debug.Log("FlightGlobals Heading: " + FlightGlobals.ship_heading + " MechJeb Heading: " + _heading);   //good
            //Debug.Log("Ship temp: " + FlightGlobals.ship_temp);    //not useful
            //Debug.Log("Get dV: " + FlightGlobals.ActiveVessel.GetDeltaV());    //nothing
            //Debug.Log("Surface Height: " + FlightGlobals.ActiveVessel.GetHeightFromSurface() + " Terrain Height: "+FlightGlobals.ActiveVessel.GetHeightFromTerrain()); //not useful
            //Debug.Log("GetMass(): " + FlightGlobals.ActiveVessel.GetTotalMass()+" myMass: "+_mass);    //good
            //Debug.Log("IAS: " + FlightGlobals.ActiveVessel.indicatedAirSpeed + " M: " + FlightGlobals.ActiveVessel.mach);  //good
            //Waypoint distance code
            //Uses the Spherical Law of Cosines from http://www.movable-type.co.uk/scripts/latlong.html
            NavWaypoint nW = NavWaypoint.fetch; //The active nav waypoint

            FinePrint.WaypointManager WM;
            WM = FinePrint.WaypointManager.Instance();
            if (nW != null && nW.IsActive)
            {
                //Convert these all to radians to do actual math on them.
                double Aa = ship.latitude * Math.PI / 180;
                double Ao = ship.longitude * Math.PI / 180;
                double Ba = nW.Latitude * Math.PI / 180;
                double Bo = nW.Longitude * Math.PI / 180;
                _nav_dist = Math.Acos(Math.Sin(Aa) * Math.Sin(Ba) + Math.Cos(Aa) * Math.Cos(Ba) * Math.Cos(Bo - Ao)) * FlightGlobals.currentMainBody.Radius;  //used to be 600000
                double y = Math.Sin(Bo - Ao) * Math.Cos(Ba);
                double x = Math.Cos(Aa) * Math.Sin(Ba) - Math.Sin(Aa) * Math.Cos(Ba) * Math.Cos(Bo - Ao);
                double b = Math.Atan2(y, x) * 180 / Math.PI; //Converted to degrees.
                _nav_heading = (b + 360f) % 360f;            //Convert to 0-360 from -180 to 180
            }
            else if (_nav_waypoint != 0)
            {
                //defaults
                _nav_heading = -1;
                _nav_dist    = -1;
                //now try actually calculating things
                int count = 0;
                foreach (FinePrint.Waypoint W in WM.Waypoints)
                {
                    //we clearly only care about waypoints on this planet
                    if (W.celestialName.Equals(body.name))
                    {
                        count++;
                        if (count == _nav_waypoint)
                        {
                            //Convert these all to radians to do actual math on them.
                            double Aa = ship.latitude * Math.PI / 180;
                            double Ao = ship.longitude * Math.PI / 180;
                            double Ba = W.latitude * Math.PI / 180;
                            double Bo = W.longitude * Math.PI / 180;
                            _nav_dist = Math.Acos(Math.Sin(Aa) * Math.Sin(Ba) + Math.Cos(Aa) * Math.Cos(Ba) * Math.Cos(Bo - Ao)) * FlightGlobals.currentMainBody.Radius;
                            double y = Math.Sin(Bo - Ao) * Math.Cos(Ba);
                            double x = Math.Cos(Aa) * Math.Sin(Ba) - Math.Sin(Aa) * Math.Cos(Ba) * Math.Cos(Bo - Ao);
                            double b = Math.Atan2(y, x) * 180 / Math.PI; //Converted to degrees.
                            _nav_heading = (b + 360f) % 360f;            //Convert to 0-360 from -180 to 180
                        }
                    }
                }
            }
            else
            {
                _nav_dist    = -1;    //Both of these at -1 implies no nav data
                _nav_heading = -1f;
            }

            //Pitch, yaw, roll

            /*NavBall ball = FlightUIController.fetch.GetComponentInChildren<NavBall>();
             * Quaternion vesselRot = Quaternion.Inverse(ball.relativeGymbal);
             * pitch = (vesselRot.eulerAngles.x > 180) ? (360 - vesselRot.eulerAngles.x) : -vesselRot.eulerAngles.x;
             * roll = (vesselRot.eulerAngles.z > 180) ? (360 - vesselRot.eulerAngles.z) : -vesselRot.eulerAngles.z;
             * yaw = vesselRot.eulerAngles.y;    //Heading, more or less
             * _rel_yaw = AngleAroundNormal(ship.GetObtVelocity(), ship.ReferenceTransform.up, ship.ReferenceTransform.forward);
             * _rel_pitch = AngleAroundNormal(ship.GetObtVelocity(), ship.ReferenceTransform.up, ship.ReferenceTransform.right);
             *
             * //Polars
             * if (pitch > 0f)
             * {
             *  Quaternion polarRot = Quaternion.Euler(90, 0, 0) * vesselRot;
             *  polar_yaw = (polarRot.eulerAngles.y + 180f) % 360f - 180f;
             *  polar_pitch = (polarRot.eulerAngles.x + 180f) % 360f - 180f;
             *  polar_roll = polarRot.eulerAngles.z;
             * }
             * else
             * {
             *  Quaternion polarRot = Quaternion.Euler(-90, 0, 0) * vesselRot;
             *  polar_yaw = (polarRot.eulerAngles.y + 180f) % 360f - 180f;
             *  polar_pitch = (polarRot.eulerAngles.x + 180f) % 360f - 180f;
             *  polar_roll = polarRot.eulerAngles.z;
             * }*/

            //Airspeed stuff
            getAirspeedInfo(ship, out _mach, out _tas, out _eas);

            //Max Altitude
            if (ship.Landed)
            {
                max_altitude = ship.altitude;               //Reset max altitude upon landing/takeoff
            }
            if (ship.altitude > max_altitude)
            {
                max_altitude = ship.altitude;
            }

            //RA
            double terrain = ship.terrainAltitude;

            if (terrain < 0)
            {
                terrain = 0;
            }
            _ra = (long)(body.GetAltitude(ship.CoM) - terrain);

            //In orbit?
            inOrbit = false;
            //Minimum periapsis of 5km
            if (ship.orbit.PeA > 5000)
            {
                //Make sure our orbit is out of the atmosphere, if there is one.
                if (body.atmosphere)
                {
                    if (ship.orbit.PeA > body.atmosphereDepth)  //is this the same as max altitude?
                    {
                        inOrbit = true;
                    }
                }
                else
                {
                    inOrbit = true;
                }
            }

            //Closest approach and time, target distance and speed
            if (FlightGlobals.fetch.VesselTarget != null)
            {
                Orbit    TO   = FlightGlobals.fetch.VesselTarget.GetOrbit();
                Vector3d aPos = ship.ReferenceTransform.position;                                   //Control source's position
                Vector3d tPos = _tarpos = FlightGlobals.fetch.VesselTarget.GetTransform().position; //Rough distance
                if (FlightGlobals.fetch.VesselTarget is ModuleDockingNode)                          //Use more precise distance
                {
                    ModuleDockingNode targetDockingPort = FlightGlobals.fetch.VesselTarget as ModuleDockingNode;
                    tPos = _tarpos = targetDockingPort.controlTransform.position;
                }
                // MechJeb guidance targets _don't have an orbit_!
                else if (TO != null)
                {
                    // This is in the wrong coordinate system for _tarpos, and only usable for distance
                    aPos = ship.GetOrbit().pos;
                    tPos = TO.pos;
                }
                _target_dist = Vector3d.Distance(aPos, tPos);
            }
            else
            {
                _target_dist = 0;
            }

            var target = FlightGlobals.fetch.VesselTarget;

            // MechJeb guidance targets _don't have an orbit!
            // Also, landed targets often have invalid orbit that causes error spam and lag.
            if (target != null && target.GetOrbit() != null)
            {
                Orbit O  = ship.GetOrbit();
                Orbit TO = target.GetOrbit();

                double t = Planetarium.GetUniversalTime();
                Func <double, Vector3d> targetPosAt = (d => TO.getPositionAtUT(t + d));

                // For landed targets the orbit doesn't make sense, so calculate planet rotation
                if (target.GetVessel() != null && target.GetVessel().LandedOrSplashed)
                {
                    Vessel        ves   = target.GetVessel();
                    CelestialBody vbody = ves.mainBody;
                    Vector3d      pos   = vbody.GetRelSurfacePosition(ves.latitude, ves.longitude, ves.altitude);

                    targetPosAt = delegate(double d) {
                        double angle = vbody.rotates ? d * 360.0 / vbody.rotationPeriod : 0;
                        return(vbody.position + QuaternionD.AngleAxis(angle, Vector3d.down) * pos);
                    };
                }

                //I chunck my orbit into 100 pieces, and find between which two chuncks the minimum occurs...
                double period   = O.period;
                double bestDist = double.MaxValue;
                double bestTime = 0;

                for (double d = 0; d < period; d += period / 100)    //Look at 100 places around the orbit
                {
                    if (d == 0)
                    {
                        continue;           //skip the first time
                    }
                    double dist = Vector3d.Distance(O.getPositionAtUT(t + d), targetPosAt(d));
                    if (dist < bestDist)
                    {
                        bestDist = dist;
                        bestTime = d;
                    }
                }
                //Now, do it again, but over a small section of the orbit centered on the above
                double start = bestTime - (period / 100);
                double end   = bestTime + (period / 100);
                for (double d = start; d < end; d += period / 1000)    //Look at 100 places within this chunck of orbit
                {
                    if (d == start)
                    {
                        continue;               //Skip the first time
                    }
                    double dist = Vector3d.Distance(O.getPositionAtUT(t + d), targetPosAt(d));
                    if (dist < bestDist)
                    {
                        bestDist = dist;
                        bestTime = d;
                    }
                }
                //And one last time, which is probably overkill
                start = bestTime - (period / 1000);
                end   = bestTime + (period / 1000);
                for (double d = start; d < end; d += period / 10000)    //Look at 100 places within this chunck of orbit
                {
                    if (d == start)
                    {
                        continue;               //For ease of computation
                    }
                    double dist = Vector3d.Distance(O.getPositionAtUT(t + d), targetPosAt(d));
                    if (dist < bestDist)
                    {
                        bestDist = dist;
                        bestTime = d;   //previous time is my start time
                    }
                }
                _closest_time     = bestTime;
                _closest_approach = bestDist;
            }
            else
            {
                _closest_approach = 0;
                _closest_time     = 0;
            }

            //Time to Impact calculations
            double vertspeed = FlightGlobals.ActiveVessel.verticalSpeed;

            if (!ship.Landed && vertspeed < 0 && ship.orbit.PeA <= 0 && !ship.mainBody.atmosphere)
            {
                double Vf = Math.Sqrt((vertspeed * vertspeed) + 2 * _ra * _gravity);
                //t = 2d/(Vi+Vf)
                _tti = (Math.Abs(Vf) - Math.Abs(vertspeed)) / _gravity;
                _tti++;  //So you hit the ground at 0, not 1 second after 0
            }
            else
            {
                _tti = 0;
            }
            //Suicide Altitude calculations
            if (ship.Landed || ship.orbit.PeA > 0 || body.atmosphere)
            {
                _sa = -1;  //Not calculating this
            }
            else
            {
                _sa = 0;
                double avgG = body.gravParameter / ((body.Radius + ship.terrainAltitude) * (body.Radius + ship.terrainAltitude));
                avgG += FlightGlobals.getGeeForceAtPosition(ship.CoM).magnitude;
                avgG /= 2;
                //Debug.Log("Average G: " + Math.Round(avgG, 2));
                double vdv = Math.Sqrt((2 * avgG * _ra) + (ship.verticalSpeed * ship.verticalSpeed));
                //Debug.Log("Vertical Delta V: " + Math.Round(vdv, 1));
                //Altitude Fraction = (Vertical dv ^2) / (2 * 1000 * Thrust (kN))
                double altFrac = (vdv * vdv) / (2 * 1000 * _max_thrust);
                //Debug.Log("Altitude Fraction: " + Math.Round(altFrac, 2));
                //m-avg = (m0 + (m0 / e ^ (dv / (Isp * 9.82)))) / 2
                double avgMass = (_mass / Math.Pow(Math.E, (vdv / (_isp * 9.82))));
                avgMass = (_mass + avgMass) / 2;
                //Debug.Log("Average mass: " + Math.Round(avgMass, 1));
                _sa = (long)Math.Round(altFrac * avgMass * 1000);
                //Debug.Log("Suicide Altitude: " + Math.Round(_sa));
            }

            //Cleanup
            isReadable = true;
            //Debug.Log("Thread simulation complete at " + Math.Round(Time.time, 3));
        }
Example #27
0
        private RawOrbitPlanData GenerateRawOrbitPlanData()
        {
            RawOrbitPlanData dataOut = new RawOrbitPlanData
            {
                CurrentOrbitPatches = new List <OrbitData>(),
                ManPatchNum         = -1,
                PlannedOrbitPatches = new List <OrbitData>(),
                TargetName          = "???",
                Mans = new List <ManData>(),
            };
            Orbit patch, lastPatch = null;

            patch = AV.orbit;
            while (patch != null && patch.activePatch)
            {
                dataOut.CurrentOrbitPatches.Add(OrbUtil.GetOrbitData(lastPatch = patch));
                patch = patch.nextPatch;
            }
            if (AV.patchedConicSolver != null)
            {
                if (AV.patchedConicSolver.maneuverNodes != null)
                {
                    if (AV.patchedConicSolver.maneuverNodes.Count > 0)
                    {
                        for (int i = 0; i < AV.patchedConicSolver.flightPlan.Count; i++)
                        {
                            if (AV.patchedConicSolver.flightPlan[i].patchStartTransition == Orbit.PatchTransitionType.MANEUVER)
                            {
                                dataOut.ManPatchNum = i;
                                break;
                            }
                        }
                        patch = AV.patchedConicSolver.maneuverNodes[0].nextPatch;
                        while (patch != null && patch.activePatch)
                        {
                            dataOut.PlannedOrbitPatches.Add(OrbUtil.GetOrbitData(lastPatch = patch));
                            patch = patch.nextPatch;
                        }
                        for (int i = 0; i < AV.patchedConicSolver.maneuverNodes.Count; i++)
                        {
                            ManeuverNode m = AV.patchedConicSolver.maneuverNodes[i];
                            dataOut.Mans.Add(new ManData
                            {
                                DV = (float)m.GetBurnVector(m.patch).magnitude,
                                UT = m.UT,
                                X  = (float)m.DeltaV.x,
                                Y  = (float)m.DeltaV.y,
                                Z  = (float)m.DeltaV.z,
                            });
                        }
                    }
                }
            }

            if (HasTarget())
            {
                dataOut.TargetName = AV.targetObject.GetName();
                OrbitData o = OrbUtil.GetOrbitData(AV.targetObject.GetOrbit());
                if (AV.targetObject is CelestialBody)
                {
                    o.transEnd   = (byte)PatchTransitionType.FINAL;
                    o.anomolyEnd = o.anomoly + Math.PI * 2;
                }
                dataOut.TargetOrbit = (o);
                //lastPatch.GetDTforTrueAnomaly
                dataOut.Rendezvous.ANAnom       = (float)(FinePrint.Utilities.OrbitUtilities.AngleOfAscendingNode(lastPatch, AV.targetObject.GetOrbit()) * Deg2Rad);
                dataOut.Rendezvous.TargetANAnom = (float)(FinePrint.Utilities.OrbitUtilities.AngleOfAscendingNode(AV.targetObject.GetOrbit(), lastPatch) * Deg2Rad);

                dataOut.Rendezvous.T2AN = (int)OrbUtil.T2TAnom(lastPatch, dataOut.Rendezvous.ANAnom) % o.period;
                dataOut.Rendezvous.T2DN = (int)OrbUtil.T2TAnom(lastPatch, dataOut.Rendezvous.ANAnom + Math.PI) % o.period;

                dataOut.Rendezvous.RelInc = (float)FinePrint.Utilities.OrbitUtilities.GetRelativeInclination(lastPatch, AV.targetObject.GetOrbit());

                double dist;
                double time = OrbUtil.CalcClosestAproach(lastPatch, AV.targetObject.GetOrbit(), lastPatch.StartUT, out dist);
                dataOut.Rendezvous.T2CA         = (int)(time - Planetarium.GetUniversalTime());
                dataOut.Rendezvous.SepAtCA      = (int)dist;
                dataOut.Rendezvous.CAAnom       = (float)lastPatch.TrueAnomalyAtUT(time);
                dataOut.Rendezvous.TargetCAAnom = (float)AV.targetObject.GetOrbit().TrueAnomalyAtUT(time);
            }

            return(dataOut);
        }