/// <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; } }
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; } } }
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)); }
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(); }
/* * /// <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); }
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; } }
/// <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); }
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; } }
/// <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); }
/// <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); }
/// <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); }