예제 #1
0
        /// <summary>
        /// Get the largest potential torque provided by the part, in Newton meters in the pitch, yaw and roll axes.
        /// Returns a pair of torques: the positive torque around each axis, and the negative torque.
        /// </summary>
        public static Torque GetPotentialTorque(this ITorqueProvider torqueProvider)
        {
            Vector3 pos;
            Vector3 neg;

            torqueProvider.GetPotentialTorque(out pos, out neg);
            Vector3d posd = pos;
            Vector3d negd = neg;

            return(new Torque(posd * 1000.0d, negd * 1000.0d));
        }
예제 #2
0
        /// <summary>
        /// Get the total torque for a vessel.
        /// </summary>
        /// <param name="vessel">The vessel from which ot get the total torque.</param>
        /// <returns>The vessel torque as a Vector3.</returns>
        public static Vector3 GetVesselTorque(Vessel vessel)
        {
            // the resulting torque
            Vector3 vesselTorque = Vector3.zero;

            // positive and negative vessel torque for all part modules that are torque providers
            Vector3 positiveTorque = Vector3.zero;
            Vector3 negativeTorque = Vector3.zero;

            // cycle through all vessel parts.
            int partCount = vessel.Parts.Count;

            for (int iPart = 0; iPart < partCount; ++iPart)
            {
                Part part = vessel.Parts[iPart];

                // loop through all modules for the part
                int moduleCount = part.Modules.Count;
                for (int iModule = 0; iModule < moduleCount; ++iModule)
                {
                    // find modules in part that are torque providers.
                    ITorqueProvider torqueProvider = part.Modules[iModule] as ITorqueProvider;
                    if (torqueProvider == null)
                    {
                        continue;
                    }

                    // pos and neg torque for this part module
                    Vector3 posTorque;
                    Vector3 negTorque;

                    // get potential torque for the current module and update pos and neg torques.
                    torqueProvider.GetPotentialTorque(out posTorque, out negTorque);
                    positiveTorque += posTorque;
                    negativeTorque += negTorque;
                }
            }

            // get max torque from all components of pos and neg torques.
            vesselTorque.x = Mathf.Max(positiveTorque.x, negativeTorque.x);
            vesselTorque.y = Mathf.Max(positiveTorque.y, negativeTorque.y);
            vesselTorque.z = Mathf.Max(positiveTorque.z, negativeTorque.z);

            return(vesselTorque);
        }
예제 #3
0
 public void UpdateControlParts()
 {
     if (internalVessel.parts.Count != vesselParts)
     {
         vesselParts = internalVessel.parts.Count;
         torqueProviders.Clear();
         foreach (Part part in internalVessel.Parts)
         {
             foreach (PartModule pm in part.Modules)
             {
                 ITorqueProvider tp = pm as ITorqueProvider;
                 if (tp != null)
                 {
                     torqueProviders.Add(pm, tp);
                 }
             }
         }
     }
 }
예제 #4
0
        private void AnalyzeOtherTorque()
        {
            torqueOthers.Reset();

            /* this is a special list of ITorqueProvider-containing Parts that are *NOT* Engines, RW, RCS, Control Surfaces */
            foreach (var pair in otherTorque)
            {
                Part p = pair.Key;

                List <ITorqueProvider> mlist = p.Modules.GetModules <ITorqueProvider>();

                for (int m = 0; m < mlist.Count; m++)
                {
                    Vector3         pos;
                    Vector3         neg;
                    ITorqueProvider it = mlist[m];
                    it.GetPotentialTorque(out pos, out neg);
                    torqueOthers.Add(pos);
                    torqueOthers.Add(-neg);
                }
            }
        }
예제 #5
0
        /// <summary>
        /// See https://github.com/KSP-KOS/KOS/issues/2814 for why this wrapper around KSP's API call exists.
        /// <para />
        /// </summary>
        void CorrectedGetPotentialTorque(ITorqueProvider tp, out Vector3 pos, out Vector3 neg)
        {
            if (tp is ModuleRCS)
            {
                // The stock call GetPotentialTorque is completely broken in the case of ModuleRCS.  So
                // this replaces it entirely until KSP ever fixes the bug that's been in their
                // bug list forever (probably won't get fixed).
                ModuleRCS rcs = tp as ModuleRCS;
                Part      p   = rcs.part;

                // This is the list of various reasons this RCS module might
                // be suppressed right now.  It would be nice if all this
                // stuff flipped one common flag during Update for all the
                // rest of the code to check, but sadly that doesn't seem to
                // be the case and you have to check these things individually:
                if (p.ShieldedFromAirstream || !rcs.rcsEnabled || !rcs.isEnabled ||
                    rcs.isJustForShow || rcs.flameout || !rcs.rcs_active)
                {
                    pos = new Vector3(0f, 0f, 0f);
                    neg = new Vector3(0f, 0f, 0f);
                }
                else
                {
                    // The algorithm here is adapted from code in the MandatoryRCS mod
                    // that had to solve this same problem:

                    // Note the swapping of Y and Z axes to align with "part space":
                    Vector3 rotateEnables    = new Vector3(rcs.enablePitch ? 1 : 0, rcs.enableRoll ? 1 : 0, rcs.enableYaw ? 1 : 0);
                    Vector3 translateEnables = new Vector3(rcs.enableX ? 1 : 0, rcs.enableZ ? 1 : 0, rcs.enableY ? 1 : 0);

                    pos = new Vector3(0f, 0f, 0f);
                    neg = new Vector3(0f, 0f, 0f);
                    for (int i = rcs.thrusterTransforms.Count - 1; i >= 0; --i)
                    {
                        Transform rcsTransform  = rcs.thrusterTransforms[i];
                        Vector3   rcsPosFromCoM = rcsTransform.position - Vessel.CurrentCoM;
                        Vector3   rcsThrustDir  = rcs.useZaxis ? -rcsTransform.forward : rcsTransform.up;
                        float     powerFactor   = rcs.thrusterPower * rcs.thrustPercentage * 0.01f;
                        // Normally you'd check for precision mode to nerf powerFactor here,
                        // but kOS doesn't obey that.
                        Vector3 thrust            = powerFactor * rcsThrustDir;
                        Vector3 torque            = Vector3d.Cross(rcsPosFromCoM, thrust);
                        Vector3 transformedTorque = Vector3.Scale(Vessel.ReferenceTransform.InverseTransformDirection(torque), rotateEnables);
                        pos += Vector3.Max(transformedTorque, Vector3.zero);
                        neg += Vector3.Min(transformedTorque, Vector3.zero);
                    }
                }
            }
            else if (tp is ModuleReactionWheel)
            {
                // Although ModuleReactionWheel *mostly* works, the stock version ignores
                // the authority limiter slider.  It would have been possible to just take
                // the result it gives and multiply it by the slider, but that relies on
                // stock KSP never fixing it themselves and thus kOS would end up double-
                // applying that multiplitation.  To avoid that, it seems better to just
                // make the entire thing homemade from scratch for now so if KSP ever fixes it
                // on their end that doesn't break it on kOS's end:
                ModuleReactionWheel wheel = tp as ModuleReactionWheel;

                if (!wheel.moduleIsEnabled || wheel.wheelState != ModuleReactionWheel.WheelState.Active || wheel.actuatorModeCycle == 2)
                {
                    pos = new Vector3(0f, 0f, 0f);
                    neg = new Vector3(0f, 0f, 0f);
                }
                else
                {
                    float nerf = wheel.authorityLimiter / 100f;
                    pos = new Vector3(nerf * wheel.PitchTorque, nerf * wheel.RollTorque, nerf * wheel.YawTorque);
                    neg = -1 * pos;
                }
            }
            else
            {
                tp.GetPotentialTorque(out pos, out neg);
            }
        }
예제 #6
0
        /// <summary>
        /// Import from MechJeb2
        /// https://github.com/MuMech/MechJeb2/blob/dev/MechJeb2/VesselState.cs
        /// </summary>
        public static void AnalyzeParts(Vessel vessel)
        {
            torqueAvailable = Vector3d.zero;
            Vector6 torqueReactionSpeed6 = new Vector6();

            torqueReactionWheel.Reset();
            torqueControlSurface.Reset();
            torqueGimbal.Reset();
            torqueOthers.Reset();

            UpdateRCSThrustAndTorque(vessel);

            for (int i = 0; i < vessel.parts.Count; i++)
            {
                Part p = vessel.parts[i];

                for (int m = 0; m < p.Modules.Count; m++)
                {
                    PartModule pm = p.Modules[m];
                    if (!pm.isEnabled)
                    {
                        continue;
                    }

                    ModuleReactionWheel rw = pm as ModuleReactionWheel;
                    if (rw != null)
                    {
                        Vector3 pos;
                        Vector3 neg;
                        rw.GetPotentialTorque(out pos, out neg);

                        // GetPotentialTorque reports the same value for pos & neg on ModuleReactionWheel
                        torqueReactionWheel.Add(pos);
                        torqueReactionWheel.Add(-neg);
                    }
                    else if (pm is ModuleControlSurface) // also does ModuleAeroSurface
                    {
                        ModuleControlSurface cs = (pm as ModuleControlSurface);

                        Vector3 ctrlTorquePos;
                        Vector3 ctrlTorqueNeg;

                        cs.GetPotentialTorque(out ctrlTorquePos, out ctrlTorqueNeg);

                        torqueControlSurface.Add(ctrlTorquePos);
                        torqueControlSurface.Add(ctrlTorqueNeg);

                        torqueReactionSpeed6.Add(Mathf.Abs(cs.ctrlSurfaceRange) / cs.actuatorSpeed * Vector3d.Max(ctrlTorquePos.Abs(), ctrlTorqueNeg.Abs()));
                    }
                    else if (pm is ModuleGimbal)
                    {
                        ModuleGimbal g = (pm as ModuleGimbal);

                        Vector3 pos;
                        Vector3 neg;

                        g.GetPotentialTorque(out pos, out neg);
                        // GetPotentialTorque reports the same value for pos & neg on ModuleGimbal

                        torqueGimbal.Add(pos);
                        torqueGimbal.Add(-neg);

                        if (g.useGimbalResponseSpeed)
                        {
                            torqueReactionSpeed6.Add((Mathf.Abs(g.gimbalRange) / g.gimbalResponseSpeed) * Vector3d.Max(pos.Abs(), neg.Abs()));
                        }
                    }
                    else if (pm is ModuleRCS)
                    {
                        // Handled separately
                    }
                    else if (pm is ITorqueProvider)
                    {
                        ITorqueProvider tp = pm as ITorqueProvider;

                        Vector3 pos;
                        Vector3 neg;
                        tp.GetPotentialTorque(out pos, out neg);

                        torqueOthers.Add(pos);
                        torqueOthers.Add(neg);
                    }
                }
            }

            torqueAvailable += Vector3d.Max(torqueReactionWheel.positive, torqueReactionWheel.negative);
            torqueAvailable += Vector3d.Max(rcsTorqueAvailable.positive, rcsTorqueAvailable.negative);
            torqueAvailable += Vector3d.Max(torqueControlSurface.positive, torqueControlSurface.negative);
            torqueAvailable += Vector3d.Max(torqueGimbal.positive, torqueGimbal.negative);
            torqueAvailable += Vector3d.Max(torqueOthers.positive, torqueOthers.negative);

            if (torqueAvailable.sqrMagnitude > 0)
            {
                torqueReactionSpeed = Vector3d.Max(torqueReactionSpeed6.positive, torqueReactionSpeed6.negative);
                torqueReactionSpeed.Scale(torqueAvailable.InvertNoNaN());
            }
            else
            {
                torqueReactionSpeed = Vector3d.zero;
            }
        }