/// <summary>
        /// Sets the mean anomaly and updates all other anomalies.
        /// </summary>
        /// <param name="m">The m.</param>
        public void SetMeanAnomaly(double m)
        {
            if (!IsValidOrbit)
            {
                return;
            }

            MeanAnomaly = m % KeplerOrbitUtils.PI_2;
            if (Eccentricity < 1.0)
            {
                if (MeanAnomaly < 0)
                {
                    MeanAnomaly += KeplerOrbitUtils.PI_2;
                }

                EccentricAnomaly = KeplerOrbitUtils.KeplerSolver(MeanAnomaly, Eccentricity);
                TrueAnomaly      = KeplerOrbitUtils.ConvertEccentricToTrueAnomaly(EccentricAnomaly, Eccentricity);
            }
            else if (Eccentricity > 1.0)
            {
                EccentricAnomaly = KeplerOrbitUtils.KeplerSolverHyperbolicCase(MeanAnomaly, Eccentricity);
                TrueAnomaly      = KeplerOrbitUtils.ConvertEccentricToTrueAnomaly(EccentricAnomaly, Eccentricity);
            }
            else
            {
                EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(MeanAnomaly, Eccentricity);
                TrueAnomaly      = EccentricAnomaly;
            }

            SetPositionByCurrentAnomaly();
            SetVelocityByCurrentAnomaly();
        }
        /// <summary>
        /// Updates the value of orbital anomalies by defined deltatime.
        /// </summary>
        /// <param name="deltaTime">The delta time.</param>
        /// <remarks>
        /// Only anomalies values will be changed.
        /// Position and velocity states needs to be updated too after this method call.
        /// </remarks>
        public void UpdateOrbitAnomaliesByTime(double deltaTime)
        {
            if (Eccentricity < 1.0)
            {
                MeanAnomaly += MeanMotion * deltaTime;
                MeanAnomaly %= KeplerOrbitUtils.PI_2;

                if (MeanAnomaly < 0)
                {
                    MeanAnomaly = KeplerOrbitUtils.PI_2 - MeanAnomaly;
                }

                EccentricAnomaly = KeplerOrbitUtils.KeplerSolver(MeanAnomaly, Eccentricity);
                double cosE = Math.Cos(EccentricAnomaly);
                TrueAnomaly = Math.Acos((cosE - Eccentricity) / (1 - Eccentricity * cosE));
                if (MeanAnomaly > Math.PI)
                {
                    TrueAnomaly = KeplerOrbitUtils.PI_2 - TrueAnomaly;
                }
            }
            else if (Eccentricity > 1.0)
            {
                MeanAnomaly      = MeanAnomaly + MeanMotion * deltaTime;
                EccentricAnomaly = KeplerOrbitUtils.KeplerSolverHyperbolicCase(MeanAnomaly, Eccentricity);
                TrueAnomaly      = Math.Atan2(Math.Sqrt(Eccentricity * Eccentricity - 1.0) * Math.Sinh(EccentricAnomaly), Eccentricity - Math.Cosh(EccentricAnomaly));
            }
            else
            {
                MeanAnomaly      = MeanAnomaly + MeanMotion * deltaTime;
                EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(MeanAnomaly, Eccentricity);
                TrueAnomaly      = EccentricAnomaly;
            }
        }
        /// <summary>
        /// Create and initialize new orbit state from orbital elements.
        /// </summary>
        /// <param name="eccentricity">Eccentricity.</param>
        /// <param name="semiMajorAxis">Main axis semi width.</param>
        /// <param name="meanAnomalyDeg">Mean anomaly in degrees.</param>
        /// <param name="inclinationDeg">Orbit inclination in degrees.</param>
        /// <param name="argOfPerifocusDeg">Orbit argument of perifocus in degrees.</param>
        /// <param name="ascendingNodeDeg">Longitude of ascending node in degrees.</param>
        /// <param name="attractorMass">Attractor mass.</param>
        /// <param name="gConst">Gravitational constant.</param>
        public KeplerOrbitData(double eccentricity, double semiMajorAxis, double meanAnomalyDeg, double inclinationDeg, double argOfPerifocusDeg, double ascendingNodeDeg, double attractorMass,
                               double gConst)
        {
            this.Eccentricity  = eccentricity;
            this.SemiMajorAxis = semiMajorAxis;
            if (eccentricity < 1.0)
            {
                this.SemiMinorAxis = SemiMajorAxis * Math.Sqrt(1 - Eccentricity * Eccentricity);
            }
            else if (eccentricity > 1.0)
            {
                this.SemiMinorAxis = SemiMajorAxis * Math.Sqrt(Eccentricity * Eccentricity - 1);
            }
            else
            {
                this.SemiMajorAxis = 0;
            }

            var normal        = EclipticNormal.normalized;
            var ascendingNode = EclipticRight.normalized;

            ascendingNodeDeg %= 360;
            if (ascendingNodeDeg > 180)
            {
                ascendingNodeDeg -= 360;
            }
            inclinationDeg %= 360;
            if (inclinationDeg > 180)
            {
                inclinationDeg -= 360;
            }
            argOfPerifocusDeg %= 360;
            if (argOfPerifocusDeg > 180)
            {
                argOfPerifocusDeg -= 360;
            }

            ascendingNode = KeplerOrbitUtils.RotateVectorByAngle(ascendingNode, ascendingNodeDeg * KeplerOrbitUtils.Deg2Rad, normal).normalized;
            normal        = KeplerOrbitUtils.RotateVectorByAngle(normal, inclinationDeg * KeplerOrbitUtils.Deg2Rad, ascendingNode).normalized;
            Periapsis     = ascendingNode;
            Periapsis     = KeplerOrbitUtils.RotateVectorByAngle(Periapsis, argOfPerifocusDeg * KeplerOrbitUtils.Deg2Rad, normal).normalized;

            this.SemiMajorAxisBasis = Periapsis;
            this.SemiMinorAxisBasis = Vector3d.Cross(Periapsis, normal);

            this.MeanAnomaly      = meanAnomalyDeg * KeplerOrbitUtils.Deg2Rad;
            this.EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(this.MeanAnomaly, this.Eccentricity);
            this.TrueAnomaly      = KeplerOrbitUtils.ConvertEccentricToTrueAnomaly(this.EccentricAnomaly, this.Eccentricity);
            this.AttractorMass    = attractorMass;
            this.GravConst        = gConst;
            CalculateOrbitStateFromOrbitalElements();
        }
Example #4
0
        /// <summary>
        /// Create and initialize new orbit state from orbital elements and main axis vectors.
        /// </summary>
        /// <param name="eccentricity">Eccentricity.</param>
        /// <param name="semiMajorAxis">Semi major axis vector.</param>
        /// <param name="semiMinorAxis">Semi minor axis vector.</param>
        /// <param name="meanAnomalyDeg">Mean anomaly in degrees.</param>
        /// <param name="attractorMass">Attractor mass.</param>
        /// <param name="gConst">Gravitational constant.</param>
        public KeplerOrbitData(double eccentricity, Vector3d semiMajorAxis, Vector3d semiMinorAxis, double meanAnomalyDeg, double attractorMass, double gConst)
        {
            this.Eccentricity       = eccentricity;
            this.SemiMajorAxisBasis = semiMajorAxis.normalized;
            this.SemiMinorAxisBasis = semiMinorAxis.normalized;
            this.SemiMajorAxis      = semiMajorAxis.magnitude;
            this.SemiMinorAxis      = semiMinorAxis.magnitude;

            this.MeanAnomaly      = meanAnomalyDeg * KeplerOrbitUtils.Deg2Rad;
            this.EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(this.MeanAnomaly, this.Eccentricity);
            this.TrueAnomaly      = KeplerOrbitUtils.ConvertEccentricToTrueAnomaly(this.EccentricAnomaly, this.Eccentricity);
            this.AttractorMass    = attractorMass;
            this.GravConst        = gConst;
            CalculateOrbitStateFromOrbitalElements();
        }
        /// <summary>
        /// Sets the eccentricity and updates all corresponding orbit state values.
        /// </summary>
        /// <param name="e">The new eccentricity value.</param>
        public void SetEccentricity(double e)
        {
            if (!IsValidOrbit)
            {
                return;
            }

            e = Math.Abs(e);
            double periapsis = PeriapsisDistance;             // Periapsis remains constant

            Eccentricity = e;
            double compresion = Eccentricity < 1 ? (1 - Eccentricity * Eccentricity) : (Eccentricity * Eccentricity - 1);

            SemiMajorAxis  = Math.Abs(periapsis / (1 - Eccentricity));
            FocalParameter = SemiMajorAxis * compresion;
            SemiMinorAxis  = SemiMajorAxis * Math.Sqrt(compresion);
            CenterPoint    = SemiMajorAxis * Math.Abs(Eccentricity) * SemiMajorAxisBasis;
            if (Eccentricity < 1.0)
            {
                EccentricAnomaly = KeplerOrbitUtils.KeplerSolver(MeanAnomaly, Eccentricity);
                double cosE = Math.Cos(EccentricAnomaly);
                TrueAnomaly = Math.Acos((cosE - Eccentricity) / (1 - Eccentricity * cosE));
                if (MeanAnomaly > Math.PI)
                {
                    TrueAnomaly = KeplerOrbitUtils.PI_2 - TrueAnomaly;
                }
            }
            else if (Eccentricity > 1.0)
            {
                EccentricAnomaly = KeplerOrbitUtils.KeplerSolverHyperbolicCase(MeanAnomaly, Eccentricity);
                TrueAnomaly      = Math.Atan2(Math.Sqrt(Eccentricity * Eccentricity - 1) * Math.Sinh(EccentricAnomaly), Eccentricity - Math.Cosh(EccentricAnomaly));
            }
            else
            {
                EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(MeanAnomaly, Eccentricity);
                TrueAnomaly      = EccentricAnomaly;
            }

            SetVelocityByCurrentAnomaly();
            SetPositionByCurrentAnomaly();

            CalculateOrbitStateFromOrbitalVectors();
        }
        private List <Vector3d> CalculateVelocityDifference(KeplerOrbitMover a, KeplerOrbitMover b, KeplerOrbitData transitionOrbit, double departureTime, double duration, double eccAnomalyDeparture, double eccAnomalyArrival)
        {
            var aMeanAnomalyAtDeparture = a.OrbitData.MeanAnomaly + a.OrbitData.MeanMotion * departureTime;
            var aEccAnomAtDeparture     = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(aMeanAnomalyAtDeparture, a.OrbitData.Eccentricity);
            var aVelocityAtDeparture    = a.OrbitData.GetVelocityAtEccentricAnomaly(aEccAnomAtDeparture);

            var bMeanAnomalyAtArrival = b.OrbitData.MeanAnomaly + b.OrbitData.MeanMotion * (departureTime + duration);
            var bEccAnomAtArrival     = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(aMeanAnomalyAtDeparture, a.OrbitData.Eccentricity);
            var bVelocityAtArrival    = a.OrbitData.GetVelocityAtEccentricAnomaly(aEccAnomAtDeparture);

            var transitionVeloctyStart = transitionOrbit.GetVelocityAtEccentricAnomaly(eccAnomalyDeparture);
            var transitionVelcityEnd   = transitionOrbit.GetVelocityAtEccentricAnomaly(eccAnomalyArrival);

            var result = new List <Vector3d>();

            result.Add(transitionVeloctyStart - aVelocityAtDeparture);
            result.Add(bVelocityAtArrival - transitionVelcityEnd);
            return(result);
        }
 /// <summary>
 /// Get world space position vector at given time.
 /// </summary>
 /// <param name="target">Target body.</param>
 /// <param name="time">Time, relative to current time.</param>
 /// <param name="attractors">Optional chain of attractors. Order of attractors must be from closest to furthest in hierarchy.</param>
 /// <returns>Position at given time.</returns>
 /// <remarks>
 /// Zero time is considered current state.
 /// For example, at time 0 result position vector will be equal to current target position.
 /// This method allows to progress orbit in time forward (or backward, if passed time is negative) and get position of body at that time.
 /// If attractors collection is not null or empty, then evaluation process will propagate through all attractors, which will affect result.
 /// </remarks>
 public static Vector3 GetPositionAtGivenTime(KeplerOrbitMover target, float time, KeplerOrbitMover[] attractorsChain = null)
 {
     if (target == null)
     {
         return(new Vector3());
     }
     if (!target.OrbitData.IsValidOrbit || target.AttractorSettings.AttractorObject == null)
     {
         return(target.transform.position);
     }
     if (attractorsChain == null || attractorsChain.Length == 0)
     {
         if (!target.enabled || target.TimeScale == 0f)
         {
             return(target.transform.position);
         }
         else
         {
             var finalMeanAnom = target.OrbitData.MeanAnomaly + target.OrbitData.MeanMotion * time;
             var finalEccAnom  = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(finalMeanAnom, target.OrbitData.Eccentricity);
             var result        = target.AttractorSettings.AttractorObject.transform.position + (Vector3)target.OrbitData.GetFocalPositionAtEccentricAnomaly(finalEccAnom);
             return(result);
         }
     }
     else
     {
         var relativePosition = new Vector3();
         for (int i = 0; i < attractorsChain.Length; i++)
         {
             bool isLast = i == attractorsChain.Length - 1;
             if (attractorsChain[i].OrbitData.IsValidOrbit && attractorsChain[i].AttractorSettings.AttractorObject != null)
             {
                 if (attractorsChain[i].enabled)
                 {
                     var attrMeanAnom = attractorsChain[i].OrbitData.MeanAnomaly + attractorsChain[i].OrbitData.MeanMotion * attractorsChain[i].TimeScale * time;
                     var attrEccAnom  = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(attrMeanAnom, attractorsChain[i].OrbitData.Eccentricity);
                     relativePosition += (Vector3)attractorsChain[i].OrbitData.GetFocalPositionAtEccentricAnomaly(attrEccAnom);
                 }
                 else
                 {
                     relativePosition += attractorsChain[i].transform.position - attractorsChain[i].AttractorSettings.AttractorObject.transform.position;
                 }
                 if (isLast)
                 {
                     relativePosition += attractorsChain[i].AttractorSettings.AttractorObject.position;
                 }
             }
             else
             {
                 if (isLast || attractorsChain[i].AttractorSettings.AttractorObject == null)
                 {
                     relativePosition += attractorsChain[i].transform.position;
                 }
                 else
                 {
                     relativePosition += (Vector3)attractorsChain[i].OrbitData.Position;
                 }
             }
         }
         if (!target.enabled || target.TimeScale == 0f)
         {
             relativePosition += target.transform.position - target.AttractorSettings.AttractorObject.position;
         }
         else
         {
             var finalMeanAnom = target.OrbitData.MeanAnomaly + target.OrbitData.MeanMotion * time;
             var finalEccAnom  = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(finalMeanAnom, target.OrbitData.Eccentricity);
             relativePosition += (Vector3)target.OrbitData.GetFocalPositionAtEccentricAnomaly(finalEccAnom);
         }
         return(relativePosition);
     }
 }