/// <summary> /// Sets the mean anomaly and updates all other anomalies. /// </summary> /// <param name="m">The m.</param> public void SetMeanAnomaly(double m) { if (!IsValidOrbit) { return; } MeanAnomaly = m % KeplerOrbitUtils.PI_2; if (Eccentricity < 1.0) { if (MeanAnomaly < 0) { MeanAnomaly += KeplerOrbitUtils.PI_2; } EccentricAnomaly = KeplerOrbitUtils.KeplerSolver(MeanAnomaly, Eccentricity); TrueAnomaly = KeplerOrbitUtils.ConvertEccentricToTrueAnomaly(EccentricAnomaly, Eccentricity); } else if (Eccentricity > 1.0) { EccentricAnomaly = KeplerOrbitUtils.KeplerSolverHyperbolicCase(MeanAnomaly, Eccentricity); TrueAnomaly = KeplerOrbitUtils.ConvertEccentricToTrueAnomaly(EccentricAnomaly, Eccentricity); } else { EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(MeanAnomaly, Eccentricity); TrueAnomaly = EccentricAnomaly; } SetPositionByCurrentAnomaly(); SetVelocityByCurrentAnomaly(); }
/// <summary> /// Updates the value of orbital anomalies by defined deltatime. /// </summary> /// <param name="deltaTime">The delta time.</param> /// <remarks> /// Only anomalies values will be changed. /// Position and velocity states needs to be updated too after this method call. /// </remarks> public void UpdateOrbitAnomaliesByTime(double deltaTime) { if (Eccentricity < 1.0) { MeanAnomaly += MeanMotion * deltaTime; MeanAnomaly %= KeplerOrbitUtils.PI_2; if (MeanAnomaly < 0) { MeanAnomaly = KeplerOrbitUtils.PI_2 - MeanAnomaly; } EccentricAnomaly = KeplerOrbitUtils.KeplerSolver(MeanAnomaly, Eccentricity); double cosE = Math.Cos(EccentricAnomaly); TrueAnomaly = Math.Acos((cosE - Eccentricity) / (1 - Eccentricity * cosE)); if (MeanAnomaly > Math.PI) { TrueAnomaly = KeplerOrbitUtils.PI_2 - TrueAnomaly; } } else if (Eccentricity > 1.0) { MeanAnomaly = MeanAnomaly + MeanMotion * deltaTime; EccentricAnomaly = KeplerOrbitUtils.KeplerSolverHyperbolicCase(MeanAnomaly, Eccentricity); TrueAnomaly = Math.Atan2(Math.Sqrt(Eccentricity * Eccentricity - 1.0) * Math.Sinh(EccentricAnomaly), Eccentricity - Math.Cosh(EccentricAnomaly)); } else { MeanAnomaly = MeanAnomaly + MeanMotion * deltaTime; EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(MeanAnomaly, Eccentricity); TrueAnomaly = EccentricAnomaly; } }
/// <summary> /// Create and initialize new orbit state from orbital elements. /// </summary> /// <param name="eccentricity">Eccentricity.</param> /// <param name="semiMajorAxis">Main axis semi width.</param> /// <param name="meanAnomalyDeg">Mean anomaly in degrees.</param> /// <param name="inclinationDeg">Orbit inclination in degrees.</param> /// <param name="argOfPerifocusDeg">Orbit argument of perifocus in degrees.</param> /// <param name="ascendingNodeDeg">Longitude of ascending node in degrees.</param> /// <param name="attractorMass">Attractor mass.</param> /// <param name="gConst">Gravitational constant.</param> public KeplerOrbitData(double eccentricity, double semiMajorAxis, double meanAnomalyDeg, double inclinationDeg, double argOfPerifocusDeg, double ascendingNodeDeg, double attractorMass, double gConst) { this.Eccentricity = eccentricity; this.SemiMajorAxis = semiMajorAxis; if (eccentricity < 1.0) { this.SemiMinorAxis = SemiMajorAxis * Math.Sqrt(1 - Eccentricity * Eccentricity); } else if (eccentricity > 1.0) { this.SemiMinorAxis = SemiMajorAxis * Math.Sqrt(Eccentricity * Eccentricity - 1); } else { this.SemiMajorAxis = 0; } var normal = EclipticNormal.normalized; var ascendingNode = EclipticRight.normalized; ascendingNodeDeg %= 360; if (ascendingNodeDeg > 180) { ascendingNodeDeg -= 360; } inclinationDeg %= 360; if (inclinationDeg > 180) { inclinationDeg -= 360; } argOfPerifocusDeg %= 360; if (argOfPerifocusDeg > 180) { argOfPerifocusDeg -= 360; } ascendingNode = KeplerOrbitUtils.RotateVectorByAngle(ascendingNode, ascendingNodeDeg * KeplerOrbitUtils.Deg2Rad, normal).normalized; normal = KeplerOrbitUtils.RotateVectorByAngle(normal, inclinationDeg * KeplerOrbitUtils.Deg2Rad, ascendingNode).normalized; Periapsis = ascendingNode; Periapsis = KeplerOrbitUtils.RotateVectorByAngle(Periapsis, argOfPerifocusDeg * KeplerOrbitUtils.Deg2Rad, normal).normalized; this.SemiMajorAxisBasis = Periapsis; this.SemiMinorAxisBasis = Vector3d.Cross(Periapsis, normal); this.MeanAnomaly = meanAnomalyDeg * KeplerOrbitUtils.Deg2Rad; this.EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(this.MeanAnomaly, this.Eccentricity); this.TrueAnomaly = KeplerOrbitUtils.ConvertEccentricToTrueAnomaly(this.EccentricAnomaly, this.Eccentricity); this.AttractorMass = attractorMass; this.GravConst = gConst; CalculateOrbitStateFromOrbitalElements(); }
/// <summary> /// Create and initialize new orbit state from orbital elements and main axis vectors. /// </summary> /// <param name="eccentricity">Eccentricity.</param> /// <param name="semiMajorAxis">Semi major axis vector.</param> /// <param name="semiMinorAxis">Semi minor axis vector.</param> /// <param name="meanAnomalyDeg">Mean anomaly in degrees.</param> /// <param name="attractorMass">Attractor mass.</param> /// <param name="gConst">Gravitational constant.</param> public KeplerOrbitData(double eccentricity, Vector3d semiMajorAxis, Vector3d semiMinorAxis, double meanAnomalyDeg, double attractorMass, double gConst) { this.Eccentricity = eccentricity; this.SemiMajorAxisBasis = semiMajorAxis.normalized; this.SemiMinorAxisBasis = semiMinorAxis.normalized; this.SemiMajorAxis = semiMajorAxis.magnitude; this.SemiMinorAxis = semiMinorAxis.magnitude; this.MeanAnomaly = meanAnomalyDeg * KeplerOrbitUtils.Deg2Rad; this.EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(this.MeanAnomaly, this.Eccentricity); this.TrueAnomaly = KeplerOrbitUtils.ConvertEccentricToTrueAnomaly(this.EccentricAnomaly, this.Eccentricity); this.AttractorMass = attractorMass; this.GravConst = gConst; CalculateOrbitStateFromOrbitalElements(); }
/// <summary> /// Sets the eccentricity and updates all corresponding orbit state values. /// </summary> /// <param name="e">The new eccentricity value.</param> public void SetEccentricity(double e) { if (!IsValidOrbit) { return; } e = Math.Abs(e); double periapsis = PeriapsisDistance; // Periapsis remains constant Eccentricity = e; double compresion = Eccentricity < 1 ? (1 - Eccentricity * Eccentricity) : (Eccentricity * Eccentricity - 1); SemiMajorAxis = Math.Abs(periapsis / (1 - Eccentricity)); FocalParameter = SemiMajorAxis * compresion; SemiMinorAxis = SemiMajorAxis * Math.Sqrt(compresion); CenterPoint = SemiMajorAxis * Math.Abs(Eccentricity) * SemiMajorAxisBasis; if (Eccentricity < 1.0) { EccentricAnomaly = KeplerOrbitUtils.KeplerSolver(MeanAnomaly, Eccentricity); double cosE = Math.Cos(EccentricAnomaly); TrueAnomaly = Math.Acos((cosE - Eccentricity) / (1 - Eccentricity * cosE)); if (MeanAnomaly > Math.PI) { TrueAnomaly = KeplerOrbitUtils.PI_2 - TrueAnomaly; } } else if (Eccentricity > 1.0) { EccentricAnomaly = KeplerOrbitUtils.KeplerSolverHyperbolicCase(MeanAnomaly, Eccentricity); TrueAnomaly = Math.Atan2(Math.Sqrt(Eccentricity * Eccentricity - 1) * Math.Sinh(EccentricAnomaly), Eccentricity - Math.Cosh(EccentricAnomaly)); } else { EccentricAnomaly = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(MeanAnomaly, Eccentricity); TrueAnomaly = EccentricAnomaly; } SetVelocityByCurrentAnomaly(); SetPositionByCurrentAnomaly(); CalculateOrbitStateFromOrbitalVectors(); }
private List <Vector3d> CalculateVelocityDifference(KeplerOrbitMover a, KeplerOrbitMover b, KeplerOrbitData transitionOrbit, double departureTime, double duration, double eccAnomalyDeparture, double eccAnomalyArrival) { var aMeanAnomalyAtDeparture = a.OrbitData.MeanAnomaly + a.OrbitData.MeanMotion * departureTime; var aEccAnomAtDeparture = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(aMeanAnomalyAtDeparture, a.OrbitData.Eccentricity); var aVelocityAtDeparture = a.OrbitData.GetVelocityAtEccentricAnomaly(aEccAnomAtDeparture); var bMeanAnomalyAtArrival = b.OrbitData.MeanAnomaly + b.OrbitData.MeanMotion * (departureTime + duration); var bEccAnomAtArrival = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(aMeanAnomalyAtDeparture, a.OrbitData.Eccentricity); var bVelocityAtArrival = a.OrbitData.GetVelocityAtEccentricAnomaly(aEccAnomAtDeparture); var transitionVeloctyStart = transitionOrbit.GetVelocityAtEccentricAnomaly(eccAnomalyDeparture); var transitionVelcityEnd = transitionOrbit.GetVelocityAtEccentricAnomaly(eccAnomalyArrival); var result = new List <Vector3d>(); result.Add(transitionVeloctyStart - aVelocityAtDeparture); result.Add(bVelocityAtArrival - transitionVelcityEnd); return(result); }
/// <summary> /// Get world space position vector at given time. /// </summary> /// <param name="target">Target body.</param> /// <param name="time">Time, relative to current time.</param> /// <param name="attractors">Optional chain of attractors. Order of attractors must be from closest to furthest in hierarchy.</param> /// <returns>Position at given time.</returns> /// <remarks> /// Zero time is considered current state. /// For example, at time 0 result position vector will be equal to current target position. /// This method allows to progress orbit in time forward (or backward, if passed time is negative) and get position of body at that time. /// If attractors collection is not null or empty, then evaluation process will propagate through all attractors, which will affect result. /// </remarks> public static Vector3 GetPositionAtGivenTime(KeplerOrbitMover target, float time, KeplerOrbitMover[] attractorsChain = null) { if (target == null) { return(new Vector3()); } if (!target.OrbitData.IsValidOrbit || target.AttractorSettings.AttractorObject == null) { return(target.transform.position); } if (attractorsChain == null || attractorsChain.Length == 0) { if (!target.enabled || target.TimeScale == 0f) { return(target.transform.position); } else { var finalMeanAnom = target.OrbitData.MeanAnomaly + target.OrbitData.MeanMotion * time; var finalEccAnom = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(finalMeanAnom, target.OrbitData.Eccentricity); var result = target.AttractorSettings.AttractorObject.transform.position + (Vector3)target.OrbitData.GetFocalPositionAtEccentricAnomaly(finalEccAnom); return(result); } } else { var relativePosition = new Vector3(); for (int i = 0; i < attractorsChain.Length; i++) { bool isLast = i == attractorsChain.Length - 1; if (attractorsChain[i].OrbitData.IsValidOrbit && attractorsChain[i].AttractorSettings.AttractorObject != null) { if (attractorsChain[i].enabled) { var attrMeanAnom = attractorsChain[i].OrbitData.MeanAnomaly + attractorsChain[i].OrbitData.MeanMotion * attractorsChain[i].TimeScale * time; var attrEccAnom = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(attrMeanAnom, attractorsChain[i].OrbitData.Eccentricity); relativePosition += (Vector3)attractorsChain[i].OrbitData.GetFocalPositionAtEccentricAnomaly(attrEccAnom); } else { relativePosition += attractorsChain[i].transform.position - attractorsChain[i].AttractorSettings.AttractorObject.transform.position; } if (isLast) { relativePosition += attractorsChain[i].AttractorSettings.AttractorObject.position; } } else { if (isLast || attractorsChain[i].AttractorSettings.AttractorObject == null) { relativePosition += attractorsChain[i].transform.position; } else { relativePosition += (Vector3)attractorsChain[i].OrbitData.Position; } } } if (!target.enabled || target.TimeScale == 0f) { relativePosition += target.transform.position - target.AttractorSettings.AttractorObject.position; } else { var finalMeanAnom = target.OrbitData.MeanAnomaly + target.OrbitData.MeanMotion * time; var finalEccAnom = KeplerOrbitUtils.ConvertMeanToEccentricAnomaly(finalMeanAnom, target.OrbitData.Eccentricity); relativePosition += (Vector3)target.OrbitData.GetFocalPositionAtEccentricAnomaly(finalEccAnom); } return(relativePosition); } }