Exemple #1
0
        public static double GetTrueAnomaly(KeplerElements orbit, DateTime time)
        {
            TimeSpan timeSinceEpoch = time - orbit.Epoch;

            // Don't attempt to calculate large timeframes.
            while (timeSinceEpoch.TotalSeconds > orbit.OrbitalPeriod && orbit.OrbitalPeriod != 0)
            {
                double years = timeSinceEpoch.TotalSeconds / orbit.OrbitalPeriod;
                timeSinceEpoch -= TimeSpan.FromSeconds(years * orbit.OrbitalPeriod);
                orbit.Epoch    += TimeSpan.FromSeconds(years * orbit.OrbitalPeriod);
            }

            double m0 = orbit.MeanAnomalyAtEpoch;
            double n  = orbit.MeanMotion;
            double currentMeanAnomaly = OrbitMath.GetMeanAnomalyFromTime(m0, n, timeSinceEpoch.TotalSeconds);

            double eccentricAnomaly = GetEccentricAnomaly(orbit, currentMeanAnomaly);

            return(OrbitMath.TrueAnomalyFromEccentricAnomaly(orbit.Eccentricity, eccentricAnomaly));

            /*
             * var x = Math.Cos(eccentricAnomaly) - orbit.Eccentricity;
             * var y = Math.Sqrt(1 - orbit.Eccentricity * orbit.Eccentricity) * Math.Sin(eccentricAnomaly);
             * return Math.Atan2(y, x);
             */
        }
Exemple #2
0
        public static Vector3 GetPosition_m(KeplerElements orbit, double trueAnomaly)
        {
            // http://en.wikipedia.org/wiki/True_anomaly#Radius_from_true_anomaly
            double radius = orbit.SemiMajorAxis * (1 - orbit.Eccentricity * orbit.Eccentricity) / (1 + orbit.Eccentricity * Math.Cos(trueAnomaly));

            double incl = orbit.Inclination;

            //https://downloads.rene-schwarz.com/download/M001-Keplerian_Orbit_Elements_to_Cartesian_State_Vectors.pdf
            double lofAN = orbit.LoAN;
            //double aofP = Angle.ToRadians(orbit.ArgumentOfPeriapsis);
            double angleFromLoAN = trueAnomaly + orbit.AoP;

            double x = Math.Cos(lofAN) * Math.Cos(angleFromLoAN) - Math.Sin(lofAN) * Math.Sin(angleFromLoAN) * Math.Cos(incl);
            double y = Math.Sin(lofAN) * Math.Cos(angleFromLoAN) + Math.Cos(lofAN) * Math.Sin(angleFromLoAN) * Math.Cos(incl);
            double z = Math.Sin(incl) * Math.Sin(angleFromLoAN);

            return(new Vector3(x, y, z) * radius);
        }
Exemple #3
0
        /// <summary>
        /// In Meters
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="myMass"></param>
        /// <param name="ke">in m</param>
        /// <param name="atDateTime"></param>
        /// <returns></returns>
        public static OrbitDB FromKeplerElements(Entity parent, double myMass, KeplerElements ke, DateTime atDateTime)
        {
            OrbitDB orbit = new OrbitDB(parent)
            {
                SemiMajorAxis            = ke.SemiMajorAxis,
                Eccentricity             = ke.Eccentricity,
                Inclination              = ke.Inclination,
                LongitudeOfAscendingNode = ke.LoAN,
                ArgumentOfPeriapsis      = ke.AoP,
                MeanAnomalyAtEpoch       = ke.MeanAnomalyAtEpoch,
                Epoch = atDateTime,

                _parentMass = parent.GetDataBlob <MassVolumeDB>().Mass,
                _myMass     = myMass
            };

            orbit.IsStationary = false;
            orbit.CalculateExtendedParameters();
            return(orbit);
        }
Exemple #4
0
        /// <summary>
        /// Calculates the current Eccentric Anomaly given certain orbital parameters.
        /// </summary>
        public static double GetEccentricAnomaly(KeplerElements orbit, double currentMeanAnomaly)
        {
            //Kepler's Equation
            const int    numIterations = 1000;
            var          e             = new double[numIterations];
            const double epsilon       = 1E-12; // Plenty of accuracy.
            int          i             = 0;

            if (orbit.Eccentricity > 0.8)
            {
                e[i] = Math.PI;
            }
            else
            {
                e[i] = currentMeanAnomaly;
            }

            do
            {
                // Newton's Method.

                /*					 E(n) - e sin(E(n)) - M(t)
                 * E(n+1) = E(n) - ( ------------------------- )
                 *					      1 - e cos(E(n)
                 *
                 * E == EccentricAnomaly, e == Eccentricity, M == MeanAnomaly.
                 * http://en.wikipedia.org/wiki/Eccentric_anomaly#From_the_mean_anomaly
                 */
                e[i + 1] = e[i] - (e[i] - orbit.Eccentricity * Math.Sin(e[i]) - currentMeanAnomaly) / (1 - orbit.Eccentricity * Math.Cos(e[i]));
                i++;
            } while (Math.Abs(e[i] - e[i - 1]) > epsilon && i + 1 < numIterations);

            if (i + 1 >= numIterations)
            {
                Event gameEvent = new Event("Non-convergence of Newton's method while calculating Eccentric Anomaly from kepler Elements.");
                gameEvent.EventType = EventType.Opps;
                StaticRefLib.EventLog.AddEvent(gameEvent);
            }

            return(e[i - 1]);
        }
Exemple #5
0
        public KeplerElements GetElements()
        {
            KeplerElements ke = new KeplerElements();

            ke.SemiMajorAxis      = SemiMajorAxis;                                              //a
            ke.SemiMinorAxis      = SemiMajorAxis * Math.Sqrt(1 - Eccentricity * Eccentricity); //b
            ke.Eccentricity       = Eccentricity;                                               //e
            ke.Periapsis          = Periapsis;                                                  //q
            ke.Apoapsis           = Apoapsis;                                                   //Q
            ke.LoAN               = LongitudeOfAscendingNode;                                   //Ω (upper case Omega)
            ke.AoP                = ArgumentOfPeriapsis;                                        //ω (lower case omega)
            ke.Inclination        = Inclination;                                                //i
            ke.MeanMotion         = MeanMotion;                                                 //n
            ke.MeanAnomalyAtEpoch = MeanAnomalyAtEpoch;                                         //M0
            ke.Epoch              = Epoch;
            ke.LinearEccentricity = Eccentricity * SemiMajorAxis;                               //ae
            ke.OrbitalPeriod      = OrbitalPeriod.TotalSeconds;

            //ke.TrueAnomalyAtEpoch  ;   //ν or f or  θ
            return(ke);
        }
Exemple #6
0
        /// <summary>
        /// This was designed so that fast moving objects will get interpolated a lot more than slow moving objects
        /// so fast moving objects shouldn't loose positional acuracy when close to a planet,
        /// and slow moving objects won't have processor time wasted on them by calulcating too often.
        /// However this seems to be unstable and looses energy, unsure why. currently set it to just itterate/interpolate every second.
        /// so currently will be using more time to get through this than neccisary.
        /// </summary>
        /// <param name="entity">Entity.</param>
        /// <param name="deltaSeconds">Delta seconds.</param>
        public static void NewtonMove(Entity entity, int deltaSeconds)
        {
            NewtonMoveDB          newtonMoveDB = entity.GetDataBlob <NewtonMoveDB>();
            NewtonThrustAbilityDB newtonThrust = entity.GetDataBlob <NewtonThrustAbilityDB>();
            PositionDB            positionDB   = entity.GetDataBlob <PositionDB>();
            double mass_Kg       = entity.GetDataBlob <MassVolumeDB>().Mass;
            double parentMass_kg = newtonMoveDB.ParentMass;

            var      manager        = entity.Manager;
            DateTime dateTimeFrom   = newtonMoveDB.LastProcessDateTime;
            DateTime dateTimeNow    = manager.ManagerSubpulses.StarSysDateTime;
            DateTime dateTimeFuture = dateTimeNow + TimeSpan.FromSeconds(deltaSeconds);
            double   deltaT         = (dateTimeFuture - dateTimeFrom).TotalSeconds;

            double secondsToItterate = deltaT;

            while (secondsToItterate > 0)
            {
                //double timeStep = Math.Max(secondsToItterate / speed_kms, 1);
                //timeStep = Math.Min(timeStep, secondsToItterate);
                double timeStepInSeconds  = 1;//because the above seems unstable and looses energy.
                double distanceToParent_m = positionDB.GetDistanceTo_m(newtonMoveDB.SOIParent.GetDataBlob <PositionDB>());

                distanceToParent_m = Math.Max(distanceToParent_m, 0.1); //don't let the distance be 0 (once collision is in this will likely never happen anyway)

                double  gravForce       = GameConstants.Science.GravitationalConstant * (mass_Kg * parentMass_kg / Math.Pow(distanceToParent_m, 2));
                Vector3 gravForceVector = gravForce * -Vector3.Normalise(positionDB.RelativePosition_m);

                Vector3 totalDVFromGrav = (gravForceVector / mass_Kg) * timeStepInSeconds;

                double maxAccelFromThrust1 = newtonThrust.ExhaustVelocity * Math.Log(mass_Kg / (mass_Kg - newtonThrust.FuelBurnRate)); //per second
                double maxAccelFromThrust  = newtonThrust.ThrustInNewtons / mass_Kg;                                                   //per second


                Vector3 manuverDV = newtonMoveDB.DeltaVForManuver_m;                      //how much dv needed to complete the manuver.

                double dryMass = mass_Kg - newtonThrust.FuelBurnRate * timeStepInSeconds; //how much our ship weighs after a timestep of fuel is used.
                //how much dv can we get in this timestep.
                double deltaVThisStep = OrbitMath.TsiolkovskyRocketEquation(mass_Kg, dryMass, newtonThrust.ExhaustVelocity);
                deltaVThisStep = Math.Min(manuverDV.Length(), deltaVThisStep);  //don't use more Dv than what is called for.
                deltaVThisStep = Math.Min(newtonThrust.DeltaV, deltaVThisStep); //check we've got the deltaV to spend.

                Vector3 totalDVFromThrust = Vector3.Normalise(manuverDV) * deltaVThisStep;

                //remove the deltaV we're expending from the max (TODO: Remove fuel from cargo, change mass of ship)
                newtonThrust.DeltaV -= deltaVThisStep;
                //remove the vectorDV from the amount needed to fully complete the manuver.
                newtonMoveDB.DeltaVForManuver_m -= totalDVFromThrust;



                Vector3 totalDV     = totalDVFromGrav + totalDVFromThrust;
                Vector3 newVelocity = totalDV + newtonMoveDB.CurrentVector_ms;

                newtonMoveDB.CurrentVector_ms = newVelocity;
                Vector3 deltaPos = (newtonMoveDB.CurrentVector_ms + newVelocity) / 2 * timeStepInSeconds;

                positionDB.RelativePosition_m += deltaPos;

                double sOIRadius = OrbitProcessor.GetSOI_m(newtonMoveDB.SOIParent);



                if (positionDB.RelativePosition_m.Length() >= sOIRadius)
                {
                    Entity  newParent;
                    Vector3 parentRalitiveVector;
                    //if our parent is a regular kepler object (normaly this is the case)
                    if (newtonMoveDB.SOIParent.HasDataBlob <OrbitDB>())
                    {
                        var orbitDB = newtonMoveDB.SOIParent.GetDataBlob <OrbitDB>();
                        newParent = orbitDB.Parent;
                        var parentVelocity = OrbitProcessor.InstantaneousOrbitalVelocityVector_m(orbitDB, entity.StarSysDateTime);
                        parentRalitiveVector = newtonMoveDB.CurrentVector_ms + parentVelocity;
                    }
                    else //if (newtonMoveDB.SOIParent.HasDataBlob<NewtonMoveDB>())
                    {   //this will pretty much never happen.
                        newParent = newtonMoveDB.SOIParent.GetDataBlob <NewtonMoveDB>().SOIParent;
                        var parentVelocity = newtonMoveDB.SOIParent.GetDataBlob <NewtonMoveDB>().CurrentVector_ms;
                        parentRalitiveVector = newtonMoveDB.CurrentVector_ms + parentVelocity;
                    }
                    parentMass_kg = newParent.GetDataBlob <MassVolumeDB>().Mass;

                    Vector3 posRalitiveToNewParent = positionDB.AbsolutePosition_m - newParent.GetDataBlob <PositionDB>().AbsolutePosition_m;


                    var    dateTime = dateTimeNow + TimeSpan.FromSeconds(deltaSeconds - secondsToItterate);
                    double sgp      = GMath.StandardGravitationalParameter(parentMass_kg + mass_Kg);
                    var    kE       = OrbitMath.KeplerFromPositionAndVelocity(sgp, posRalitiveToNewParent, parentRalitiveVector, dateTime);

                    positionDB.SetParent(newParent);
                    newtonMoveDB.ParentMass       = parentMass_kg;
                    newtonMoveDB.SOIParent        = newParent;
                    newtonMoveDB.CurrentVector_ms = parentRalitiveVector;
                }

                if (newtonMoveDB.DeltaVForManuver_m.Length() <= 0) //if we've completed the manuver.
                {
                    var    dateTime = dateTimeNow + TimeSpan.FromSeconds(deltaSeconds - secondsToItterate);
                    double sgp      = GMath.StandardGravitationalParameter(parentMass_kg + mass_Kg);

                    KeplerElements kE = OrbitMath.KeplerFromPositionAndVelocity(sgp, positionDB.RelativePosition_m, newtonMoveDB.CurrentVector_ms, dateTime);

                    var parentEntity = Entity.GetSOIParentEntity(entity, positionDB);

                    if (kE.Eccentricity < 1) //if we're going to end up in a regular orbit around our new parent
                    {
                        var newOrbit = OrbitDB.FromKeplerElements(
                            parentEntity,
                            mass_Kg,
                            kE,
                            dateTime);
                        entity.RemoveDataBlob <NewtonMoveDB>();
                        entity.SetDataBlob(newOrbit);
                        positionDB.SetParent(parentEntity);
                        var newPos = OrbitProcessor.GetPosition_m(newOrbit, dateTime);
                        positionDB.RelativePosition_m = newPos;
                    }
                    break;
                }

                secondsToItterate -= timeStepInSeconds;
            }
            newtonMoveDB.LastProcessDateTime = dateTimeFuture;
        }
Exemple #7
0
        public static OrbitDB FromKeplerElements(Entity parent, double parentMass, double myMass, KeplerElements ke, DateTime atDateTime)
        {
            OrbitDB orbit = new OrbitDB(parent, parentMass, myMass,
                                        ke.SemiMajorAxis,
                                        ke.Eccentricity,
                                        Angle.ToDegrees(ke.Inclination),
                                        Angle.ToDegrees(ke.LoAN),
                                        Angle.ToDegrees(ke.AoP),
                                        Angle.ToDegrees(ke.MeanAnomalyAtEpoch),
                                        ke.Epoch);// - TimeSpan.FromSeconds(ke.Epoch));

            //var pos = OrbitProcessor.GetAbsolutePosition_AU(orbit, atDateTime);
            return(orbit);
        }
Exemple #8
0
        private const double Epsilon = 1.0e-15; //TODO: test how low we can go

        /// <summary>
        /// Kepler elements from velocity and position.
        /// Note, to get correct results ensure all Sgp, position, and velocity values are all in the same type (ie meters, km, or AU)
        /// </summary>
        /// <returns>a struct of Kepler elements.</returns>
        /// <param name="standardGravParam">Standard grav parameter.</param>
        /// <param name="position">Position ralitive to parent</param>
        /// <param name="velocity">Velocity ralitive to parent</param>
        public static KeplerElements KeplerFromPositionAndVelocity(double standardGravParam, Vector3 position, Vector3 velocity, DateTime epoch)
        {
            KeplerElements ke = new KeplerElements();
            Vector3        angularVelocity = Vector3.Cross(position, velocity);
            Vector3        nodeVector      = Vector3.Cross(new Vector3(0, 0, 1), angularVelocity);

            Vector3 eccentVector = EccentricityVector(standardGravParam, position, velocity);

            double eccentricity = eccentVector.Length();

            double specificOrbitalEnergy = Math.Pow(velocity.Length(), 2) * 0.5 - standardGravParam / position.Length();

            double semiMajorAxis;
            double p;                                                                //p is where the ellipse or hypobola crosses a line from the focal point 90 degrees from the sma

            if (Math.Abs(eccentricity) > 1)                                          //hypobola
            {
                semiMajorAxis = -(-standardGravParam / (2 * specificOrbitalEnergy)); //in this case the sma is negitive
                p             = semiMajorAxis * (1 - eccentricity * eccentricity);
            }
            else if (Math.Abs(eccentricity) < 1) //ellipse
            {
                semiMajorAxis = -standardGravParam / (2 * specificOrbitalEnergy);
                p             = semiMajorAxis * (1 - eccentricity * eccentricity);
            }
            else //parabola
            {
                p             = angularVelocity.Length() * angularVelocity.Length() / standardGravParam;
                semiMajorAxis = double.MaxValue;
            }


            double semiMinorAxis      = EllipseMath.SemiMinorAxis(semiMajorAxis, eccentricity);
            double linierEccentricity = eccentricity * semiMajorAxis;

            double inclination = Math.Acos(angularVelocity.Z / angularVelocity.Length()); //should be 0 in 2d. or pi if counter clockwise orbit.

            if (double.IsNaN(inclination))
            {
                inclination = 0;
            }

            double longdOfAN = CalculateLongitudeOfAscendingNode(nodeVector);


            double trueAnomaly  = TrueAnomaly(eccentVector, position, velocity);
            double argOfPeriaps = GetArgumentOfPeriapsis2(position, inclination, longdOfAN, trueAnomaly);
            var    meanMotion   = Math.Sqrt(standardGravParam / Math.Pow(semiMajorAxis, 3));


            double eccentricAnomoly = GetEccentricAnomalyFromTrueAnomaly(trueAnomaly, eccentricity);
            var    meanAnomaly      = GetMeanAnomaly(eccentricity, eccentricAnomoly);

            ke.SemiMajorAxis = semiMajorAxis;
            ke.SemiMinorAxis = semiMinorAxis;
            ke.Eccentricity  = eccentricity;

            ke.Apoapsis           = EllipseMath.Apoapsis(eccentricity, semiMajorAxis);
            ke.Periapsis          = EllipseMath.Periapsis(eccentricity, semiMajorAxis);
            ke.LinierEccentricity = EllipseMath.LinierEccentricity(ke.Apoapsis, semiMajorAxis);
            ke.LoAN               = longdOfAN;
            ke.AoP                = argOfPeriaps;
            ke.Inclination        = inclination;
            ke.MeanMotion         = meanMotion;
            ke.MeanAnomalyAtEpoch = meanAnomaly;
            ke.TrueAnomalyAtEpoch = trueAnomaly;
            ke.Epoch              = epoch; //TimeFromPeriapsis(semiMajorAxis, standardGravParam, meanAnomaly);
            //Epoch(semiMajorAxis, semiMinorAxis, eccentricAnomoly, OrbitalPeriod(standardGravParam, semiMajorAxis));

            return(ke);
        }
Exemple #9
0
 public static Vector3 GetPosition_m(KeplerElements orbit, DateTime time)
 {
     return(GetPosition_m(orbit, GetTrueAnomaly(orbit, time)));
 }