/// <summary> /// Gets a future position for this entity, regarless of wheter it's orbit or newtonion trajectory /// </summary> /// <param name="entity"></param> /// <param name="atDateTime"></param> /// <param name="ralitive"></param> /// <returns>In Meters</returns> /// <exception cref="Exception"></exception> public static Vector3 GetPosition_m(Entity entity, DateTime atDateTime, bool ralitive = true) { if (entity.HasDataBlob<OrbitDB>()) { if (ralitive) return OrbitProcessor.GetPosition_m(entity.GetDataBlob<OrbitDB>(), atDateTime); else return OrbitProcessor.GetAbsolutePosition_m(entity.GetDataBlob<OrbitDB>(), atDateTime); } else if (entity.HasDataBlob<NewtonMoveDB>()) { if (ralitive) return NewtonionMovementProcessor.GetPositon_m(entity, entity.GetDataBlob<NewtonMoveDB>(), atDateTime).pos; else return NewtonionMovementProcessor.GetAbsulutePositon_m(entity, entity.GetDataBlob<NewtonMoveDB>(), atDateTime).pos; } else if (entity.HasDataBlob<PositionDB>()) { if(ralitive) return entity.GetDataBlob<PositionDB>().RelativePosition_m; else return entity.GetDataBlob<PositionDB>().AbsolutePosition_m; } else { throw new Exception("Entity is positionless"); } }
/// <summary> /// Gets a future position for this entity, regarless of wheter it's orbit or newtonion trajectory /// </summary> /// <param name="entity"></param> /// <param name="atDateTime"></param> /// <returns>In Meters</returns> /// <exception cref="Exception"> if entity doesn't have one of the correct datablobs</exception> public static Vector3 GetRalitiveFuturePosition(Entity entity, DateTime atDateTime) { if (entity.HasDataBlob <OrbitDB>()) { return(OrbitProcessor.GetPosition_m(entity.GetDataBlob <OrbitDB>(), atDateTime)); } else if (entity.HasDataBlob <OrbitUpdateOftenDB>()) { return(OrbitProcessor.GetPosition_m(entity.GetDataBlob <OrbitUpdateOftenDB>(), atDateTime)); } else if (entity.HasDataBlob <NewtonMoveDB>()) { return(NewtonionMovementProcessor.GetRelativeState(entity, entity.GetDataBlob <NewtonMoveDB>(), atDateTime).pos); } else if (entity.HasDataBlob <PositionDB>()) { return(entity.GetDataBlob <PositionDB>().RelativePosition_m); } else { throw new Exception("Entity is positionless"); } }
public static void UpdateOrbit(OrbitUpdateOftenDB entityOrbitDB, DateTime toDate) { PositionDB entityPosition = entityOrbitDB.OwningEntity.GetDataBlob <PositionDB>(PositionTypeIndex); try { Vector3 newPosition = OrbitProcessor.GetPosition_m(entityOrbitDB, toDate); entityPosition.RelativePosition_m = newPosition; } catch (OrbitProcessor.OrbitProcessorException e) { var entity = e.Entity; string name = "Un-Named"; if (entity.HasDataBlob <NameDB>()) { name = entity.GetDataBlob <NameDB>().OwnersName; } //Do NOT fail to the UI. There is NO data-corruption on this exception. // In this event, we did NOT update our position. Event evt = new Event(StaticRefLib.CurrentDateTime, "Non Critical Position Exception thrown in OrbitProcessor for EntityItem " + name + " " + entity.Guid + " " + e.Message); evt.EventType = EventType.Opps; StaticRefLib.EventLog.AddEvent(evt); } }
/// <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); }
/// <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; }