public KeplerElements GetElements() { // if there is not a change in Dv then the kepler elements wont have changed, it might be better to store them? double myMass = OwningEntity.GetDataBlob <MassVolumeDB>().MassDry; var sgp = OrbitMath.CalculateStandardGravityParameterInM3S2(myMass, ParentMass); var pos = OwningEntity.GetDataBlob <PositionDB>().RelativePosition_m; var dateTime = OwningEntity.StarSysDateTime; var ke = OrbitMath.KeplerFromPositionAndVelocity(sgp, pos, CurrentVector_ms, dateTime); return(ke); }
public static double CalcDVDifference_m(Entity entity1, Entity entity2) { double dvDif = 0; Entity parent; double parentMass; double sgp; double r1; double r2; Entity soi1 = Entity.GetSOIParentEntity(entity1); Entity soi2 = Entity.GetSOIParentEntity(entity2); if (soi1 == soi2) { parent = soi1; parentMass = parent.GetDataBlob <MassVolumeDB>().MassDry; sgp = OrbitMath.CalculateStandardGravityParameterInM3S2(0, parentMass); var state1 = Entity.GetRalitiveState(entity1); var state2 = Entity.GetRalitiveState(entity2); r1 = state1.pos.Length(); r2 = state2.pos.Length(); } else { StaticRefLib.EventLog.AddEvent(new Event("Cargo calc failed, entities must have same soi parent")); return(double.PositiveInfinity); } var hohmann = InterceptCalcs.Hohmann(sgp, r1, r2); return(dvDif = hohmann[0].deltaV.Length() + hohmann[1].deltaV.Length()); }
/// <summary> /// creates an asteroid that will collide with the given entity on the given date. /// </summary> /// <param name="starSys"></param> /// <param name="target"></param> /// <param name="collisionDate"></param> /// <returns></returns> public static Entity CreateAsteroid(StarSystem starSys, Entity target, DateTime collisionDate, double asteroidMass = -1.0) { //todo rand these a bit. double radius = Distance.KmToAU(0.5); double mass; if (asteroidMass < 0) { mass = 1.5e+12; //about 1.5 billion tonne } else { mass = asteroidMass; } var speed = 40000; Vector3 velocity = new Vector3(speed, 0, 0); var massVolume = MassVolumeDB.NewFromMassAndRadius_AU(mass, radius); var planetInfo = new SystemBodyInfoDB(); var name = new NameDB("Ellie"); var AsteroidDmg = new AsteroidDamageDB(); AsteroidDmg.FractureChance = new PercentValue(0.75f); var dmgPfl = EntityDamageProfileDB.AsteroidDamageProfile(massVolume.Volume_km3, massVolume.Density, massVolume.RadiusInM, 50); var sensorPfil = new SensorProfileDB(); planetInfo.SupportsPopulations = false; planetInfo.BodyType = BodyType.Asteroid; Vector3 targetPos = OrbitProcessor.GetAbsolutePosition_m(target.GetDataBlob <OrbitDB>(), collisionDate); TimeSpan timeToCollision = collisionDate - StaticRefLib.CurrentDateTime; var parent = target.GetDataBlob <OrbitDB>().Parent; var parentMass = parent.GetDataBlob <MassVolumeDB>().Mass; var myMass = massVolume.Mass; double sgp = OrbitMath.CalculateStandardGravityParameterInM3S2(myMass, parentMass); OrbitDB orbit = OrbitDB.FromVector(parent, myMass, parentMass, sgp, targetPos, velocity, collisionDate); var currentpos = OrbitProcessor.GetAbsolutePosition_AU(orbit, StaticRefLib.CurrentDateTime); var posDB = new PositionDB(currentpos.X, currentpos.Y, currentpos.Z, parent.Manager.ManagerGuid, parent); var planetDBs = new List <BaseDataBlob> { posDB, massVolume, planetInfo, name, orbit, AsteroidDmg, dmgPfl, sensorPfil }; Entity newELE = new Entity(starSys, planetDBs); return(newELE); }
/// <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>().MassDry; 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 sgp = OrbitMath.CalculateStandardGravityParameterInM3S2(mass_Kg, parentMass_kg); 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_FoRO_m; //how much dv needed to complete the manuver. Vector3 totalDVFromThrust = new Vector3(0, 0, 0); if (manuverDV.Length() > 0) { 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. totalDVFromThrust = Vector3.Normalise(manuverDV) * deltaVThisStep; //remove the deltaV we're expending from the max (TODO: Remove fuel from cargo, change mass of ship) newtonThrust.BurnDeltaV(deltaVThisStep); //remove the vectorDV from the amount needed to fully complete the manuver. newtonMoveDB.DeltaVForManuver_FoRO_m -= totalDVFromThrust; } //convert prograde to global frame of reference for thrust direction Vector3 globalCoordDVFromThrust = OrbitMath.ProgradeToParentVector(sgp, totalDVFromThrust, positionDB.RelativePosition_m, newtonMoveDB.CurrentVector_ms); Vector3 totalDV = totalDVFromGrav + globalCoordDVFromThrust; 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>().MassDry; 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_FoRO_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 { if (entity.HasDataBlob <ProjectileInfoDB>()) //this feels a bit hacky. { var newOrbit = OrbitDB.FromKeplerElements(parentEntity, mass_Kg, kE, dateTime); var fastOrbit = new OrbitUpdateOftenDB(newOrbit); entity.RemoveDataBlob <NewtonMoveDB>(); entity.SetDataBlob(fastOrbit); positionDB.SetParent(parentEntity); var newPos = OrbitProcessor.GetPosition_m(fastOrbit, dateTime); positionDB.RelativePosition_m = newPos; } else { 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; }