Example #1
0
        /// <summary>
        /// The True Anomaly in radians
        /// https://en.wikipedia.org/wiki/True_anomaly#From_state_vectors
        /// </summary>
        /// <returns>The True Anomaly in radians</returns>
        /// <param name="eccentVector">Eccentricity vector.</param>
        /// <param name="position">Position ralitive to parent</param>
        /// <param name="velocity">Velocity ralitive to parent</param>
        public static double TrueAnomaly(Vector3 eccentVector, Vector3 position, Vector3 velocity)
        {
            double e = eccentVector.Length(); //eccentricity
            double r = position.Length();

            if (e > Epsilon) //if eccentricity is bigger than a tiny amount, it's a circular orbit.
            {
                double dotEccPos = Vector3.Dot(eccentVector, position);
                double talen     = e * r;
                talen = dotEccPos / talen;
                talen = GMath.Clamp(talen, -1, 1);
                var trueAnomoly = Math.Acos(talen);

                if (Vector3.Dot(position, velocity) < 0)
                {
                    trueAnomoly = Math.PI * 2 - trueAnomoly;
                }

                return(Angle.NormaliseRadiansPositive(trueAnomoly));
            }
            else
            {
                return(Angle.NormaliseRadiansPositive(Math.Atan2(position.Y, position.X))); //circular orbit, assume AoP is 0;
            }
        }
Example #2
0
        /// <summary>
        /// Generates Data for a star based on it's spectral type and populates it with the data.
        /// </summary>
        /// <remarks>
        /// This function randomly generates the Radius, Temperature, Luminosity, Mass and Age of a star and then returns a star populated with those generated values.
        /// What follows is a brief description of how that is done for each data point:
        /// <list type="Bullet">
        /// <item>
        /// <b>Temperature:</b> The Temp. of the star is obtained by using the Randon.Next(min, max) function to get a random Temp. in the range a star of the given
        /// spectral type.
        /// </item>
        /// <item>
        /// <b>Luminosity:</b> The Luminosity of a star is calculated by using the RNG_NextDoubleRange() function to get a random Luminosity in the range a star of the
        /// given spectral type.
        /// </item>
        /// <item>
        /// <b>Age:</b> The possible ages for a star depend largely on its mass. The bigger and heaver the star the more pressure is put on its core where fusion occur
        /// which increases the rate that it burns Hydrogen which reduces the life of the star. The Big O class stars only last a few million years before either
        /// going Hyper Nova or devolving into a class B star. on the other hand a class G star (like Sol) has a life expectancy of about 10 billion years while a
        /// little class M star could last 100 billion years or more (hard to tell given that the Milky way is 13.2 billion years old and the universe is only
        /// about a billion years older then that). Given this we first use the mass of the star to produce a number between 0 and 1 that we can use to pick a
        /// possible age from the range (just like all the above). To get the number between 0 and 1 we use the following formula:
        /// <c>1 - Mass / MaxMassOfStarOfThisType</c>
        /// </item>
        /// </list>
        /// </remarks>
        /// <param name="starMVDB">The SystemBodyDB of the star.</param>
        /// <param name="spectralType">The Spectral Type of the star.</param>
        /// <param name="randomSelection">Random selection to generate consistent values.</param>
        /// <returns>A StarInfoDB Populated with data generated based on Spectral Type and SystemBodyDB information provided.</returns>
        private StarInfoDB GenerateStarInfo(MassVolumeDB starMVDB, SpectralType spectralType, double randomSelection)
        {
            double maxStarAge = _galaxyGen.Settings.StarAgeBySpectralType[spectralType].Max;

            StarInfoDB starData = new StarInfoDB {// for star age we will make it proportional to the inverse of the stars mass ratio (for that type of star).
                // while this will produce the same age for the same mass/type of star the chances of getting the same
                // mass/type are tiny. Tho there will still be the obvious inverse relationship here.
                Age          = (1 - starMVDB.Mass / _galaxyGen.Settings.StarMassBySpectralType[spectralType].Max) * maxStarAge,
                SpectralType = spectralType,
                Temperature  = (uint)Math.Round(GMath.SelectFromRange(_galaxyGen.Settings.StarTemperatureBySpectralType[spectralType], randomSelection)),
                Luminosity   = (float)GMath.SelectFromRange(_galaxyGen.Settings.StarLuminosityBySpectralType[spectralType], randomSelection)
            };

            // Generate a string specifying the full spectral class form a star.
            // start by getting the sub-division, which is based on temp.
            double sub = starData.Temperature / _galaxyGen.Settings.StarTemperatureBySpectralType[starData.SpectralType].Max; // temp range from 0 to 1.

            starData.SpectralSubDivision = (ushort)Math.Round((1 - sub) * 10);                                                // invert temp range as 0 is hottest, 9 is coolest.

            // now get the luminosity class
            //< @todo For right now everthing is just main sequence. see http://en.wikipedia.org/wiki/Stellar_classification
            // on how this should be done. For right now tho class V is fine (its just flavor text).
            starData.LuminosityClass = LuminosityClass.V;

            // finally add them all up to get the class string:
            starData.Class = starData.SpectralType + starData.SpectralSubDivision.ToString() + "-" + starData.LuminosityClass;

            return(starData);
        }
Example #3
0
        private void CalculateExtendedParameters()
        {
            if (IsStationary)
            {
                return;
            }
            // Calculate extended parameters.
            // http://en.wikipedia.org/wiki/Standard_gravitational_parameter#Two_bodies_orbiting_each_other
            GravitationalParameter_Km3S2 = GMath.GravitationalParameter_Km3s2(_parentMass + _myMass);  // Normalize GravitationalParameter from m^3/s^2 to km^3/s^2
            GravitationalParameterAU     = GMath.GrabitiationalParameter_Au3s2(_parentMass + _myMass); // (149597870700 * 149597870700 * 149597870700);
            GravitationalParameter_m3S2  = GMath.StandardGravitationalParameter(_parentMass + _myMass);

            double orbitalPeriod = 2 * Math.PI * Math.Sqrt(Math.Pow(Distance.AuToKm(SemiMajorAxis_AU), 3) / (GravitationalParameter_Km3S2));

            if (orbitalPeriod * 10000000 > long.MaxValue)
            {
                OrbitalPeriod = TimeSpan.MaxValue;
            }
            else
            {
                OrbitalPeriod = TimeSpan.FromSeconds(orbitalPeriod);
            }

            // http://en.wikipedia.org/wiki/Mean_motion
            MeanMotion_DegreesSec = Math.Sqrt(GravitationalParameter_Km3S2 / Math.Pow(Distance.AuToKm(SemiMajorAxis_AU), 3)); // Calculated in radians.
            MeanMotion_DegreesSec = Angle.ToDegrees(MeanMotion_DegreesSec);                                                   // Stored in degrees.

            Apoapsis_AU  = (1 + Eccentricity) * SemiMajorAxis_AU;
            Periapsis_AU = (1 - Eccentricity) * SemiMajorAxis_AU;

            SOI_m = OrbitMath.GetSOI(SemiMajorAxis, _myMass, _parentMass);
        }
Example #4
0
        internal static void MineResources(Entity colonyEntity)
        {
            Dictionary <Guid, int> mineRates = colonyEntity.GetDataBlob <ColonyMinesDB>().MineingRate;
            Dictionary <Guid, MineralDepositInfo> planetMinerals = colonyEntity.GetDataBlob <ColonyInfoDB>().PlanetEntity.GetDataBlob <SystemBodyInfoDB>().Minerals;
            //Dictionary<Guid, int> colonyMineralStockpile = colonyEntity.GetDataBlob<ColonyInfoDB>().MineralStockpile;
            CargoStorageDB stockpile   = colonyEntity.GetDataBlob <CargoStorageDB>();
            float          mineBonuses = 1;//colonyEntity.GetDataBlob<ColonyBonusesDB>().GetBonus(AbilityType.Mine);

            foreach (var kvp in mineRates)
            {
                double accessability = planetMinerals[kvp.Key].Accessibility;
                double actualRate    = kvp.Value * mineBonuses * accessability;
                int    mineralsMined = (int)Math.Min(actualRate, planetMinerals[kvp.Key].Amount);
                long   capacity      = StorageSpaceProcessor.RemainingCapacity(stockpile, stockpile.CargoTypeID(kvp.Key));
                if (capacity > 0)
                {
                    //colonyMineralStockpile.SafeValueAdd<Guid>(kvp.Key, mineralsMined);
                    StorageSpaceProcessor.AddItemToCargo(stockpile, kvp.Key, mineralsMined);
                    MineralDepositInfo mineralDeposit = planetMinerals[kvp.Key];
                    int newAmount = mineralDeposit.Amount -= mineralsMined;

                    accessability = Math.Pow((float)mineralDeposit.Amount / mineralDeposit.HalfOriginalAmount, 3) * mineralDeposit.Accessibility;
                    double newAccess = GMath.Clamp(accessability, 0.1, mineralDeposit.Accessibility);

                    mineralDeposit.Amount        = newAmount;
                    mineralDeposit.Accessibility = newAccess;
                }
            }
        }
Example #5
0
        public static double GetEccentricAnomalyFromStateVectors(Vector3 position, double semiMajAxis, double linierEccentricity, double aop)
        {
            var x = (position.X * Math.Cos(-aop)) - (position.Y * Math.Sin(-aop));

            x = linierEccentricity + x;
            double foo = GMath.Clamp(x / semiMajAxis, -1, 1); //because sometimes we were getting a floating point error that resulted in numbers infinatly smaller than -1

            return(Math.Acos(foo));
        }
Example #6
0
        public static void UpdateAtmosphere(AtmosphereDB atmoDB, SystemBodyInfoDB bodyDB)
        {
            if (atmoDB.Exists)
            {
                // clear old values.
                atmoDB.Pressure           = 0;
                atmoDB.GreenhousePressure = 0;

                foreach (var gas in atmoDB.Composition)
                {
                    atmoDB.Pressure += gas.Value;

                    // only add a greenhouse gas if it is not frozen or liquid:
                    if (atmoDB.SurfaceTemperature >= gas.Key.BoilingPoint)
                    {
                        // actual greenhouse pressure adjusted by gas GreenhouseEffect.
                        // note that this produces the same affect as in aurora if all GreenhouseEffect bvalue are -1, 0 or 1.
                        atmoDB.GreenhousePressure += (float)gas.Key.GreenhouseEffect * gas.Value;
                    }
                }

                if (bodyDB.BodyType == BodyType.GasDwarf ||
                    bodyDB.BodyType == BodyType.GasGiant ||
                    bodyDB.BodyType == BodyType.IceGiant)
                {
                    // special gas giant stuff, needed because we do not apply greenhouse factor to them:
                    atmoDB.SurfaceTemperature = bodyDB.BaseTemperature * (1 - atmoDB.Albedo);
                    atmoDB.Pressure           = 1; // because thats the definition of the surface of these planets, when
                    // atmosphereic pressure = the pressure of earths atmosphere at its surface (what we call 1 atm).
                }
                else
                {
                    // From Aurora: Greenhouse Factor = 1 + (Atmospheric Pressure /10) + Greenhouse Pressure   (Maximum = 3.0)
                    atmoDB.GreenhouseFactor = (atmoDB.Pressure * 0.035F) + atmoDB.GreenhousePressure;  // note that we do without the extra +1 as it seems to give us better temps.
                    atmoDB.GreenhouseFactor = (float)GMath.Clamp(atmoDB.GreenhouseFactor, -3.0, 3.0);

                    // From Aurora: Surface Temperature in Kelvin = Base Temperature in Kelvin x Greenhouse Factor x Albedo
                    atmoDB.SurfaceTemperature  = Temperature.ToKelvin(bodyDB.BaseTemperature);
                    atmoDB.SurfaceTemperature += atmoDB.SurfaceTemperature * atmoDB.GreenhouseFactor * (float)Math.Pow(1 - atmoDB.Albedo, 0.25);   // We need to raise albedo to the power of 1/4, see: http://en.wikipedia.org/wiki/Stefan%E2%80%93Boltzmann_law
                    atmoDB.SurfaceTemperature  = Temperature.ToCelsius(atmoDB.SurfaceTemperature);
                }
            }
            else
            {
                // simply apply albedo, see here: http://en.wikipedia.org/wiki/Stefan%E2%80%93Boltzmann_law
                atmoDB.Pressure           = 0;
                atmoDB.SurfaceTemperature = Temperature.ToKelvin(bodyDB.BaseTemperature);
                atmoDB.SurfaceTemperature = atmoDB.SurfaceTemperature * (float)Math.Pow(1 - atmoDB.Albedo, 0.25);   // We need to raise albedo to the power of 1/4
            }

            // update the descriptions:
            atmoDB.GenerateDescriptions();
        }
Example #7
0
        /*
         * /// <summary>
         * /// The True Anomaly in radians
         * /// </summary>
         * /// <returns>The anomaly.</returns>
         * /// <param name="position">Position.</param>
         * /// <param name="loP">Lo p.</param>
         * public static double TrueAnomaly(Vector4 position, double loP)
         * {
         *  return Math.Atan2(position.Y, position.X) - loP;
         * }
         */
        /// <summary>
        /// The True Anomaly in radians
        /// https://en.wikipedia.org/wiki/True_anomaly#From_state_vectors
        /// </summary>
        /// <returns>The True Anomaly in radians</returns>
        /// <param name="eccentVector">Eccentricity vector.</param>
        /// <param name="position">Position ralitive to parent</param>
        /// <param name="velocity">Velocity ralitive to parent</param>
        public static double TrueAnomaly(Vector3 eccentVector, Vector3 position, Vector3 velocity)
        {
            var dotEccPos = Vector3.Dot(eccentVector, position);
            var talen     = eccentVector.Length() * position.Length();

            talen = dotEccPos / talen;
            talen = GMath.Clamp(talen, -1, 1);
            var trueAnomoly = Math.Acos(talen);

            if (Vector3.Dot(position, velocity) < 0)
            {
                trueAnomoly = Math.PI * 2 - trueAnomoly;
            }

            return(trueAnomoly);
        }
Example #8
0
        private void MineResources(Entity colonyEntity)
        {
            Dictionary <Guid, int> mineRates = colonyEntity.GetDataBlob <MiningDB>().MineingRate;
            Dictionary <Guid, MineralDepositInfo> planetMinerals = colonyEntity.GetDataBlob <ColonyInfoDB>().PlanetEntity.GetDataBlob <SystemBodyInfoDB>().Minerals;

            VolumeStorageDB stockpile   = colonyEntity.GetDataBlob <VolumeStorageDB>();
            float           mineBonuses = 1;//colonyEntity.GetDataBlob<ColonyBonusesDB>().GetBonus(AbilityType.Mine);

            foreach (var kvp in mineRates)
            {
                ICargoable mineral         = _minerals[kvp.Key];
                Guid       cargoTypeID     = mineral.CargoTypeID;
                double     itemMassPerUnit = mineral.MassPerUnit;

                double accessability        = planetMinerals[kvp.Key].Accessibility;
                double actualRate           = kvp.Value * mineBonuses * accessability;
                int    unitsMinableThisTick = (int)Math.Min(actualRate, planetMinerals[kvp.Key].Amount);

                if (!stockpile.TypeStores.ContainsKey(mineral.CargoTypeID))
                {
                    var    type  = StaticRefLib.StaticData.CargoTypes[mineral.CargoTypeID];
                    string erstr = "We didn't mine a potential " + unitsMinableThisTick + " of " + mineral.Name + " because we have no way to store " + type.Name + " cargo.";
                    StaticRefLib.EventLog.AddPlayerEntityErrorEvent(colonyEntity, erstr);
                    continue;    //can't store this mineral
                }

                var unitsMinedThisTick = stockpile.AddCargoByUnit(mineral, unitsMinableThisTick);

                if (unitsMinableThisTick > unitsMinedThisTick)
                {
                    var    dif   = unitsMinableThisTick - unitsMinedThisTick;
                    var    type  = StaticRefLib.StaticData.CargoTypes[mineral.CargoTypeID];
                    string erstr = "We didn't mine a potential " + dif + " of " + mineral.Name + " because we don't have enough space to store it.";
                    StaticRefLib.EventLog.AddPlayerEntityErrorEvent(colonyEntity, erstr);
                }

                MineralDepositInfo mineralDeposit = planetMinerals[kvp.Key];
                int newAmount = mineralDeposit.Amount -= unitsMinedThisTick;

                accessability = Math.Pow((float)mineralDeposit.Amount / mineralDeposit.HalfOriginalAmount, 3) * mineralDeposit.Accessibility;
                double newAccess = GMath.Clamp(accessability, 0.1, mineralDeposit.Accessibility);

                mineralDeposit.Amount        = newAmount;
                mineralDeposit.Accessibility = newAccess;
            }
        }
Example #9
0
        /// <summary>
        /// This returns the heading mesured from the periapsis (AoP) and is on the plane of the object
        /// Add the LoP to this to get the true heading in a 2d orbit.
        /// </summary>
        /// <returns>The from periaps.</returns>
        /// <param name="pos">Position.</param>
        /// <param name="eccentcity">Eccentcity.</param>
        /// <param name="semiMajorAxis">Semi major axis.</param>
        /// <param name="trueAnomaly">True anomaly.</param>
        public static double HeadingFromPeriaps(Vector3 pos, double eccentcity, double semiMajorAxis, double trueAnomaly)
        {
            double r = pos.Length();
            double a = semiMajorAxis;
            double e = eccentcity;
            double k = r / a;
            double f = trueAnomaly;

            double bar   = ((2 - 2 * e * e) / (k * (2 - k))) - 1;
            double foo   = GMath.Clamp(bar, -1, 1);
            double alpha = Math.Acos(foo);

            if (trueAnomaly > Math.PI || trueAnomaly < 0)
            {
                alpha = -alpha;
            }
            double heading = f + ((Math.PI - alpha) / 2);

            return(heading);
        }
Example #10
0
        private void MineResources(Entity colonyEntity)
        {
            Dictionary <Guid, int> mineRates = colonyEntity.GetDataBlob <MiningDB>().MineingRate;
            Dictionary <Guid, MineralDepositInfo> planetMinerals = colonyEntity.GetDataBlob <ColonyInfoDB>().PlanetEntity.GetDataBlob <SystemBodyInfoDB>().Minerals;

            CargoStorageDB stockpile   = colonyEntity.GetDataBlob <CargoStorageDB>();
            float          mineBonuses = 1;//colonyEntity.GetDataBlob<ColonyBonusesDB>().GetBonus(AbilityType.Mine);

            foreach (var kvp in mineRates)
            {
                ICargoable mineral         = _minerals[kvp.Key];
                Guid       cargoTypeID     = mineral.CargoTypeID;
                int        itemMassPerUnit = mineral.Mass;


                double accessability         = planetMinerals[kvp.Key].Accessibility;
                double actualRate            = kvp.Value * mineBonuses * accessability;
                int    amountMinableThisTick = (int)Math.Min(actualRate, planetMinerals[kvp.Key].Amount);

                long freeCapacity = stockpile.StoredCargoTypes[mineral.CargoTypeID].FreeCapacity;

                long weightMinableThisTick = itemMassPerUnit * amountMinableThisTick;
                weightMinableThisTick = Math.Min(weightMinableThisTick, freeCapacity);

                int  actualAmountToMineThisTick = (int)(weightMinableThisTick / itemMassPerUnit);                                        //get the number of items from the mass transferable
                long actualweightMinaedThisTick = actualAmountToMineThisTick * itemMassPerUnit;

                StorageSpaceProcessor.AddCargo(stockpile, mineral, actualAmountToMineThisTick);

                MineralDepositInfo mineralDeposit = planetMinerals[kvp.Key];
                int newAmount = mineralDeposit.Amount -= actualAmountToMineThisTick;

                accessability = Math.Pow((float)mineralDeposit.Amount / mineralDeposit.HalfOriginalAmount, 3) * mineralDeposit.Accessibility;
                double newAccess = GMath.Clamp(accessability, 0.1, mineralDeposit.Accessibility);

                mineralDeposit.Amount        = newAmount;
                mineralDeposit.Accessibility = newAccess;
            }
        }
Example #11
0
        /// <summary>
        /// In calculation this is referred to as RAAN or LoAN or Ω
        /// </summary>
        /// <param name="nodeVector">The node vector of the Kepler elements</param>
        /// <returns>Radians as a double</returns>
        public static double CalculateLongitudeOfAscendingNode(Vector3 nodeVector)
        {
            double longitudeOfAscendingNodeLength = nodeVector.X / nodeVector.Length();

            if (double.IsNaN(longitudeOfAscendingNodeLength))
            {
                longitudeOfAscendingNodeLength = 0;
            }
            else
            {
                longitudeOfAscendingNodeLength = GMath.Clamp(longitudeOfAscendingNodeLength, -1, 1);
            }

            double longitudeOfAscendingNode = 0;

            if (longitudeOfAscendingNodeLength != 0)
            {
                longitudeOfAscendingNode = Math.Acos(longitudeOfAscendingNodeLength);
            }

            return(longitudeOfAscendingNode);
        }
Example #12
0
        /// <summary>
        /// Heading on the orbital plane.
        /// </summary>
        /// <returns>The from periaps.</returns>
        /// <param name="pos">Position.</param>
        /// <param name="eccentricity">Eccentricity.</param>
        /// <param name="semiMajAxis">Semi major axis.</param>
        /// <param name="trueAnomaly">True anomaly.</param>
        /// <param name="aoP">Argument Of Periapsis</param>
        ///
        public static double ObjectLocalHeading(Vector3 pos, double eccentricity, double semiMajAxis, double trueAnomaly, double aoP)
        {
            double r = pos.Length();
            double a = semiMajAxis;
            double e = eccentricity;
            double k = r / a;
            double f = trueAnomaly;

            double bar   = ((2 - 2 * e * e) / (k * (2 - k))) - 1;
            double foo   = GMath.Clamp(bar, -1, 1);
            double alpha = Math.Acos(foo);

            if (trueAnomaly > Math.PI || trueAnomaly < 0)
            {
                alpha = -alpha;
            }
            double heading = ((Math.PI - alpha) / 2) + f;

            heading += aoP;
            Angle.NormaliseRadiansPositive(heading);
            return(heading);
        }
Example #13
0
        public static Entity CreateJumpPoint(StarSystemFactory ssf, StarSystem system)
        {
            var primaryStarInfoDB = system.GetFirstEntityWithDataBlob <StarInfoDB>().GetDataBlob <OrbitDB>().Root.GetDataBlob <StarInfoDB>();

            NameDB        jpNameDB        = new NameDB("Jump Point");
            PositionDB    jpPositionDB    = new PositionDB(0, 0, 0, system.Guid);
            TransitableDB jpTransitableDB = new TransitableDB();

            jpTransitableDB.IsStabilized = system.Game.Settings.AllJumpPointsStabilized ?? false;

            if (!jpTransitableDB.IsStabilized)
            {
                // TODO: Introduce a random chance to stablize jumppoints.
            }

            var jpPositionLimits = new MinMaxStruct(ssf.GalaxyGen.Settings.OrbitalDistanceByStarSpectralType[primaryStarInfoDB.SpectralType].Min, ssf.GalaxyGen.Settings.OrbitalDistanceByStarSpectralType[primaryStarInfoDB.SpectralType].Max);

            jpPositionDB.X_AU = GMath.SelectFromRange(jpPositionLimits, system.RNG.NextDouble());
            jpPositionDB.Y_AU = GMath.SelectFromRange(jpPositionLimits, system.RNG.NextDouble());

            // Randomly flip the position sign to allow negative values.
            if (system.RNG.Next(0, 100) < 50)
            {
                jpPositionDB.X_AU = 0 - jpPositionDB.X_AU;
            }
            if (system.RNG.Next(0, 100) < 50)
            {
                jpPositionDB.Y_AU = 0 - jpPositionDB.Y_AU;
            }

            var dataBlobs = new List <BaseDataBlob> {
                jpNameDB, jpTransitableDB, jpPositionDB
            };

            Entity jumpPoint = Entity.Create(system, Guid.Empty, dataBlobs);

            return(jumpPoint);
        }
Example #14
0
        /// <summary>
        /// Creates on Orbit at current location from a given velocity
        /// </summary>
        /// <returns>The Orbit Does not attach the OrbitDB to the entity!</returns>
        /// <param name="parent">Parent. must have massdb</param>
        /// <param name="entity">Entity. must have massdb</param>
        /// <param name="velocity_m">Velocity in meters.</param>
        public static OrbitDB FromVelocity_m(Entity parent, Entity entity, Vector3 velocity_m, DateTime atDateTime)
        {
            var parentMass = parent.GetDataBlob <MassVolumeDB>().Mass;
            var myMass     = entity.GetDataBlob <MassVolumeDB>().Mass;

            //var epoch1 = parent.Manager.ManagerSubpulses.StarSysDateTime; //getting epoch from here is incorrect as the local datetime doesn't change till after the subpulse.

            //var parentPos = OrbitProcessor.GetAbsolutePosition_AU(parent.GetDataBlob<OrbitDB>(), atDateTime); //need to use the parent position at the epoch
            var posdb = entity.GetDataBlob <PositionDB>();

            posdb.SetParent(parent);
            var ralitivePos = posdb.RelativePosition_m;//entity.GetDataBlob<PositionDB>().AbsolutePosition_AU - parentPos;

            if (ralitivePos.Length() > OrbitProcessor.GetSOI_m(parent))
            {
                throw new Exception("Entity not in target SOI");
            }

            //var sgp = GameConstants.Science.GravitationalConstant * (myMass + parentMass) / 3.347928976e33;
            var sgp_m = GMath.StandardGravitationalParameter(myMass + parentMass);
            var ke_m  = OrbitMath.KeplerFromPositionAndVelocity(sgp_m, ralitivePos, velocity_m, atDateTime);


            OrbitDB orbit = new OrbitDB(parent)
            {
                SemiMajorAxis            = ke_m.SemiMajorAxis,
                Eccentricity             = ke_m.Eccentricity,
                Inclination              = ke_m.Inclination,
                LongitudeOfAscendingNode = ke_m.LoAN,
                ArgumentOfPeriapsis      = ke_m.AoP,
                MeanAnomalyAtEpoch       = ke_m.MeanAnomalyAtEpoch,
                Epoch = atDateTime,

                _parentMass = parentMass,
                _myMass     = myMass
            };

            orbit.CalculateExtendedParameters();

            var pos = OrbitProcessor.GetPosition_m(orbit, atDateTime);
            var d   = (pos - ralitivePos).Length();

            if (d > 1)
            {
                var e = new Event(atDateTime, "Positional difference of " + Stringify.Distance(d) + " when creating orbit from velocity");
                e.Entity     = entity;
                e.SystemGuid = entity.Manager.ManagerGuid;
                e.EventType  = EventType.Opps;
                //e.Faction =  entity.FactionOwner;
                StaticRefLib.EventLog.AddEvent(e);

                //other info:
                var keta  = Angle.ToDegrees(ke_m.TrueAnomalyAtEpoch);
                var obta  = Angle.ToDegrees(OrbitProcessor.GetTrueAnomaly(orbit, atDateTime));
                var tadif = Angle.ToDegrees(Angle.DifferenceBetweenRadians(keta, obta));
                var pos1  = OrbitProcessor.GetPosition_m(orbit, atDateTime);
                var pos2  = OrbitProcessor.GetPosition_m(orbit, ke_m.TrueAnomalyAtEpoch);
                var d2    = (pos1 - pos2).Length();
            }


            return(orbit);
        }
Example #15
0
        /// <summary>
        /// Generates an entire group of stars for a starSystem.
        /// </summary>
        /// <remarks>
        /// Stars created with this method are sorted by mass.
        /// Stars created with this method are added to the newSystem's EntityManager.
        /// </remarks>
        /// <param name="system">The Star System the new stars belongs to.</param>
        /// <param name="numStars">The number of stars to create.</param>
        /// <returns>A mass-sorted list of entity ID's for the generated stars.</returns>
        public List <Entity> CreateStarsForSystem(StarSystem system, int numStars, DateTime currentDateTime)
        {
            // Argument Validation.
            if (system == null)
            {
                throw new ArgumentNullException("system");
            }

            if (numStars <= 0)
            {
                throw new ArgumentOutOfRangeException("numStars", "numStars must be greater than 0.");
            }

            // List of stars we'll be creating.
            var stars = new List <Entity>();

            while (stars.Count < numStars)
            {
                // Generate a SpectralType for the star.
                SpectralType starType;
                if (_galaxyGen.Settings.RealStarSystems)
                {
                    starType = _galaxyGen.Settings.StarTypeDistributionForRealStars.Select(system.RNG.NextDouble());
                }
                else
                {
                    starType = _galaxyGen.Settings.StarTypeDistributionForFakeStars.Select(system.RNG.NextDouble());
                }

                // We will use the one random number to select from all the spectral type ranges. Should give us saner numbers for stars.
                double randomSelection = system.RNG.NextDouble();

                // Generate the star's datablobs.
                MassVolumeDB starMVDB = MassVolumeDB.NewFromMassAndRadius(
                    GMath.SelectFromRange(_galaxyGen.Settings.StarMassBySpectralType[starType], randomSelection),
                    GMath.SelectFromRange(_galaxyGen.Settings.StarRadiusBySpectralType[starType], randomSelection));

                StarInfoDB starData = GenerateStarInfo(starMVDB, starType, randomSelection);

                // Initialize Position as 0,0,0. It will be updated when the star's orbit is calculated.
                PositionDB positionData = new PositionDB(0, 0, 0, system.Guid);

                var baseDataBlobs = new List <BaseDataBlob> {
                    starMVDB, starData, positionData
                };

                stars.Add(Entity.Create(system, Guid.Empty, baseDataBlobs));
            }

            // The root star must be the most massive. Find it.
            Entity rootStar = stars[0];

            double rootStarMass = rootStar.GetDataBlob <MassVolumeDB>().Mass;

            foreach (Entity currentStar in stars)
            {
                double currentStarMass = currentStar.GetDataBlob <MassVolumeDB>().Mass;

                if (rootStarMass < currentStarMass)
                {
                    rootStar     = currentStar;
                    rootStarMass = rootStar.GetDataBlob <MassVolumeDB>().Mass;
                }
            }

            // Swap the root star to index 0.
            int    rootIndex     = stars.IndexOf(rootStar);
            Entity displacedStar = stars[0];

            stars[rootIndex] = displacedStar;
            stars[0]         = rootStar;

            // Generate orbits.
            Entity       anchorStar   = stars[0];
            MassVolumeDB anchorMVDB   = anchorStar.GetDataBlob <MassVolumeDB>();
            Entity       previousStar = stars[0];

            previousStar.SetDataBlob(new OrbitDB());

            int starIndex = 0;

            foreach (Entity currentStar in stars)
            {
                StarInfoDB currentStarInfo   = currentStar.GetDataBlob <StarInfoDB>();
                NameDB     currentStarNameDB = new NameDB(system.NameDB.DefaultName + " " + (char)('A' + starIndex) + " " + currentStarInfo.SpectralType + currentStarInfo.SpectralSubDivision + currentStarInfo.LuminosityClass);
                currentStar.SetDataBlob(currentStarNameDB);

                if (previousStar == currentStar)
                {
                    // This is the "Anchor Star"
                    continue;
                }

                OrbitDB    previousOrbit    = previousStar.GetDataBlob <OrbitDB>();
                StarInfoDB previousStarInfo = previousStar.GetDataBlob <StarInfoDB>();

                double minDistance = _galaxyGen.Settings.OrbitalDistanceByStarSpectralType[previousStarInfo.SpectralType].Max + _galaxyGen.Settings.OrbitalDistanceByStarSpectralType[currentStarInfo.SpectralType].Max + previousOrbit.SemiMajorAxis;

                double sma          = minDistance * Math.Pow(system.RNG.NextDouble(), 3);
                double eccentricity = Math.Pow(system.RNG.NextDouble() * 0.8, 3);

                OrbitDB currentOrbit = OrbitDB.FromAsteroidFormat(anchorStar, anchorMVDB.Mass, currentStar.GetDataBlob <MassVolumeDB>().Mass, sma, eccentricity, _galaxyGen.Settings.MaxBodyInclination * system.RNG.NextDouble(), system.RNG.NextDouble() * 360, system.RNG.NextDouble() * 360, system.RNG.NextDouble() * 360, currentDateTime);
                currentStar.SetDataBlob(currentOrbit);
                currentStar.GetDataBlob <PositionDB>().SetParent(currentOrbit.Parent);
                previousStar = currentStar;
                starIndex++;
            }
            return(stars);
        }
Example #16
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;
        }
Example #17
0
        /// <summary>
        /// Kepler elements from velocity and position.
        /// </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);

            //Vector4 eccentVector2 = EccentricityVector2(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;
            }

            /*
             * if (Math.Abs(eccentricity - 1.0) > 1e-15)
             * {
             *  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 loANlen   = nodeVector.X / nodeVector.Length();
            double longdOfAN = 0;

            if (double.IsNaN(loANlen))
            {
                loANlen = 0;
            }
            else
            {
                loANlen = GMath.Clamp(loANlen, -1, 1);
            }
            if (loANlen != 0)
            {
                longdOfAN = Math.Acos(loANlen); //RAAN or LoAN or Ω
            }
            double eccentricAnomoly = GetEccentricAnomalyFromStateVectors2(standardGravParam, semiMajorAxis, position, velocity);

            double trueAnomaly  = TrueAnomalyFromEccentricAnomaly(eccentricity, eccentricAnomoly);
            double argOfPeriaps = ArgumentOfPeriapsis2(position, inclination, longdOfAN, trueAnomaly);

            var meanMotion = Math.Sqrt(standardGravParam / Math.Pow(semiMajorAxis, 3));

            var meanAnomaly = eccentricAnomoly - eccentricity * Math.Sin(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);
        }
        public void ProcessEntity(Entity entity, int deltaSeconds)
        {
            var manager      = entity.Manager;
            var moveDB       = entity.GetDataBlob <TranslateMoveDB>();
            var propulsionDB = entity.GetDataBlob <PropulsionDB>();
            //var currentVector = propulsionDB.CurrentSpeed;
            var maxSpeed        = propulsionDB.MaximumSpeed;
            var positionDB      = entity.GetDataBlob <PositionDB>();
            var currentPosition = positionDB.AbsolutePosition;
            //targetPosition taking the range (how close we want to get) into account.
            var targetPos = moveDB.TargetPosition * (1 - (moveDB.MoveRangeInKM / GameConstants.Units.KmPerAu) / moveDB.TargetPosition.Length());

            var deltaVecToTarget = currentPosition - targetPos;


            var currentSpeed = GMath.GetVector(currentPosition, targetPos, maxSpeed);

            propulsionDB.CurrentVector = currentSpeed;
            moveDB.CurrentVector       = currentSpeed;
            StaticDataStore           staticData      = entity.Manager.Game.StaticData;
            CargoStorageDB            storedResources = entity.GetDataBlob <CargoStorageDB>();
            Dictionary <Guid, double> fuelUsePerMeter = propulsionDB.FuelUsePerKM;
            double maxKMeters = ShipMovementProcessor.CalcMaxFuelDistance(entity);

            var nextTPos = currentPosition + (currentSpeed * deltaSeconds);


            var distanceToTargetAU = deltaVecToTarget.Length();  //in au

            var deltaVecToNextT   = currentPosition - nextTPos;
            var fuelMaxDistanceAU = maxKMeters / GameConstants.Units.KmPerAu;



            Vector4 newPos = currentPosition;

            double distanceToNextTPos = deltaVecToNextT.Length();
            double distanceToMove;

            if (fuelMaxDistanceAU < distanceToNextTPos)
            {
                distanceToMove = fuelMaxDistanceAU;
                double percent = fuelMaxDistanceAU / distanceToNextTPos;
                newPos = nextTPos + deltaVecToNextT * percent;
                Event usedAllFuel = new Event(manager.ManagerSubpulses.SystemLocalDateTime, "Used all Fuel", entity.GetDataBlob <OwnedDB>().OwnedByFaction, entity);
                usedAllFuel.EventType = EventType.FuelExhausted;
                manager.Game.EventLog.AddEvent(usedAllFuel);
            }
            else
            {
                distanceToMove = distanceToNextTPos;
                newPos         = nextTPos;
            }



            if (distanceToTargetAU < distanceToMove) // moving would overtake target, just go directly to target
            {
                distanceToMove             = distanceToTargetAU;
                propulsionDB.CurrentVector = new Vector4(0, 0, 0, 0);
                newPos            = targetPos;
                moveDB.IsAtTarget = true;
                entity.RemoveDataBlob <TranslateMoveDB>();
            }

            positionDB.AbsolutePosition = newPos;
            int kMetersMoved = (int)(distanceToMove * GameConstants.Units.KmPerAu);

            foreach (var item in propulsionDB.FuelUsePerKM)
            {
                var fuel = staticData.GetICargoable(item.Key);
                StorageSpaceProcessor.RemoveCargo(storedResources, fuel, (long)(item.Value * kMetersMoved));
            }
        }