Beispiel #1
0
        public bool GetAscendingNode(out Vector3d asc)
        {
            var norm     = CelestialBodyUtils.CrossProduct(orbitNormal, eclipticNormal);
            var s        = CelestialBodyUtils.DotProduct(CelestialBodyUtils.CrossProduct(norm, semiMajorAxisBasis), orbitNormal) < 0;
            var ecc      = 0d;
            var trueAnom = Vector3d.Angle(norm, centerPoint) * Mathd.Deg2Rad;

            if (eccentricity < 1)
            {
                var cosT = System.Math.Cos(trueAnom);
                ecc = System.Math.Acos((eccentricity + cosT) / (1d + eccentricity * cosT));
                if (!s)
                {
                    ecc = Mathd.PI_2 - ecc;
                }
            }
            else
            {
                trueAnom = Vector3d.Angle(-norm, centerPoint) * Mathd.Deg2Rad;
                if (trueAnom >= Mathd.Acos(-1d / eccentricity))
                {
                    asc = new Vector3d();
                    return(false);
                }
                var cosT = System.Math.Cos(trueAnom);
                ecc = CelestialBodyUtils.Acosh((eccentricity + cosT) / (1 + eccentricity * cosT)) * (!s ? -1 : 1);
            }
            asc = GetFocalPositionAtEccentricAnomaly(ecc);
            return(true);
        }
Beispiel #2
0
		/// <summary>
		/// When first time called this method makes orbit clockwise, next time - oposite
		/// Orbit plane will be unchanged.
		/// </summary>
		public void MakeOrbitCircle() {
			if (attractor) {
#if UNITY_EDITOR
				if (!Application.isPlaying) {
					FindReferences();
					attractor.FindReferences();
					Undo.RecordObject(this, "Round orbit");
				}
#endif
				var v = CelestialBodyUtils.CalcCircleOrbitVelocity(
					attractor._position,
					_position,
					attractor.mass,
					mass,
					orbitData.orbitNormal,
					simControlRef.gravitationalConstant
				);
				if (relativeVelocity == v) {
					relativeVelocity = -v;
				} else {
					relativeVelocity = v;
				}
				orbitData.isDirty = true;
			}
#if UNITY_EDITOR
 else {
				Debug.Log("SpaceGravity2D: Can't round orbit. " + name + " has no attractor");
			}
#endif
		}
        /// <summary>
        /// Gets the descending node of orbit.
        /// </summary>
        /// <param name="desc">The desc.</param>
        /// <returns><c>true</c> if descending node exists, otherwise <c>false</c></returns>
        public bool GetDescendingNode(out Vector3d desc)
        {
            var norm     = CelestialBodyUtils.CrossProduct(OrbitNormal, EclipticNormal);
            var s        = CelestialBodyUtils.DotProduct(CelestialBodyUtils.CrossProduct(norm, SemiMajorAxisBasis), OrbitNormal) < 0;
            var ecc      = 0d;
            var trueAnom = Vector3d.Angle(norm, -CenterPoint) * Mathd.Deg2Rad;

            if (Eccentricity < 1)
            {
                var cosT = Math.Cos(trueAnom);
                ecc = Math.Acos((Eccentricity + cosT) / (1d + Eccentricity * cosT));
                if (s)
                {
                    ecc = Mathd.PI_2 - ecc;
                }
            }
            else
            {
                trueAnom = Vector3d.Angle(norm, CenterPoint) * Mathd.Deg2Rad;
                if (trueAnom >= Mathd.Acos(-1d / Eccentricity))
                {
                    desc = new Vector3d();
                    return(false);
                }
                var cosT = Math.Cos(trueAnom);
                ecc = CelestialBodyUtils.Acosh((Eccentricity + cosT) / (1 + Eccentricity * cosT)) * (s ? -1 : 1);
            }
            desc = GetFocalPositionAtEccentricAnomaly(ecc);
            return(true);
        }
Beispiel #4
0
 public void SetEccentricAnomaly(double e)
 {
     if (!isValidOrbit)
     {
         return;
     }
     e %= Mathd.PI_2;
     eccentricAnomaly = e;
     if (eccentricity < 1)
     {
         if (e < 0)
         {
             e = Mathd.PI_2 + e;
         }
         eccentricAnomaly = e;
         trueAnomaly      = CelestialBodyUtils.ConvertEccentricToTrueAnomaly(e, eccentricity);
         meanAnomaly      = eccentricAnomaly - eccentricity * System.Math.Sin(eccentricAnomaly);
     }
     else
     {
         trueAnomaly = CelestialBodyUtils.ConvertEccentricToTrueAnomaly(e, eccentricity);
         meanAnomaly = System.Math.Sinh(eccentricAnomaly) * eccentricity - eccentricAnomaly;
     }
     SetPositionByCurrentAnomaly();
     SetVelocityByCurrentAnomaly();
 }
        /// <summary>
        /// Sets the true anomaly and updates all other anomalies.
        /// </summary>
        /// <param name="t">The t.</param>
        public void SetTrueAnomaly(double t)
        {
            if (!IsValidOrbit)
            {
                return;
            }
            t %= Mathd.PI_2;

            if (Eccentricity < 1)
            {
                if (t < 0)
                {
                    t += Mathd.PI_2;
                }
                EccentricAnomaly = CelestialBodyUtils.ConvertTrueToEccentricAnomaly(t, Eccentricity);
                MeanAnomaly      = EccentricAnomaly - Eccentricity * Math.Sin(EccentricAnomaly);
            }
            else
            {
                EccentricAnomaly = CelestialBodyUtils.ConvertTrueToEccentricAnomaly(t, Eccentricity);
                MeanAnomaly      = Math.Sinh(EccentricAnomaly) * Eccentricity - EccentricAnomaly;
            }
            SetPositionByCurrentAnomaly();
            SetVelocityByCurrentAnomaly();
        }
 /// <summary>
 /// Sets the eccentric anomaly and updates all other anomalies.
 /// </summary>
 /// <param name="e">The e.</param>
 public void SetEccentricAnomaly(double e)
 {
     if (!IsValidOrbit)
     {
         return;
     }
     e %= Mathd.PI_2;
     EccentricAnomaly = e;
     if (Eccentricity < 1)
     {
         if (e < 0)
         {
             e = Mathd.PI_2 + e;
         }
         EccentricAnomaly = e;
         TrueAnomaly      = CelestialBodyUtils.ConvertEccentricToTrueAnomaly(e, Eccentricity);
         MeanAnomaly      = EccentricAnomaly - Eccentricity * Math.Sin(EccentricAnomaly);
     }
     else
     {
         TrueAnomaly = CelestialBodyUtils.ConvertEccentricToTrueAnomaly(e, Eccentricity);
         MeanAnomaly = Math.Sinh(EccentricAnomaly) * Eccentricity - EccentricAnomaly;
     }
     SetPositionByCurrentAnomaly();
     SetVelocityByCurrentAnomaly();
 }
        private void DrawOrbitInEditorFor(CelestialBody body)
        {
            int pointsCount = _simControl.SceneElementsDisplayParameters.OrbitPointsCount;

            if (body.isActiveAndEnabled)
            {
                if (!Application.isPlaying && body.AttractorRef != null && body.OrbitData.IsDirty)
                {
                    if (body.AttractorRef.Mass <= 0)
                    {
                        body.AttractorRef.Mass = 1e-007;//to avoid div by zero
                    }
                    body.CalculateNewOrbitData();
                }
                Handles.color = Color.white;
                Vector3d[] points = null;
                body.GetOrbitPointsNoAlloc(ref points, pointsCount, false, (float)_simControl.SceneElementsDisplayParameters.MaxOrbitDistance);
                for (int i = 1; i < points.Length; i++)
                {
                    Handles.DrawLine((Vector3)points[i - 1], (Vector3)points[i]);
                }
                if (_simControl.SceneElementsDisplayParameters.DrawOrbitsEclipticProjection && points.Length > 0)
                {
                    var point1 = points[0] - _simControl.EclipticNormal * CelestialBodyUtils.DotProduct(points[0], _simControl.EclipticNormal);
                    var point2 = Vector3d.zero;
                    Handles.color = Color.gray;
                    for (int i = 1; i < points.Length; i++)
                    {
                        point2 = points[i] - _simControl.EclipticNormal * CelestialBodyUtils.DotProduct(points[i], _simControl.EclipticNormal);
                        Handles.DrawLine((Vector3)point1, (Vector3)point2);
                        point1 = point2;
                    }
                }
            }
        }
Beispiel #8
0
		/// <summary>
		/// Orbit plane will be unchanged.
		/// </summary>
		public void MakeOrbitCircle(bool clockwise) {
			if (attractor) {
#if UNITY_EDITOR
				if (!Application.isPlaying) {
					FindReferences();
					attractor.FindReferences();
					Undo.RecordObject(this, "Round orbit");
				}
#endif
				var dotProduct = CelestialBodyUtils.DotProduct(orbitData.orbitNormal, simControlRef.eclipticNormal); //sign of this value determines orbit orientation
				if (Mathd.Abs(orbitData.orbitNormal.sqrMagnitude - 1d) > 0.5d) {
					orbitData.orbitNormal = simControlRef.eclipticNormal;
				}
				var v = CelestialBodyUtils.CalcCircleOrbitVelocity(
					attractor._position,
					_position,
					attractor.mass,
					mass,
					orbitData.orbitNormal * ( clockwise && dotProduct >= 0 || !clockwise && dotProduct < 0 ? 1 : -1 ),
					simControlRef.gravitationalConstant
				);
				if (relativeVelocity != v) {
					relativeVelocity = v;
					orbitData.isDirty = true;
				}
			}
		}
Beispiel #9
0
        public void SetTrueAnomaly(double t)
        {
            if (!isValidOrbit)
            {
                return;
            }
            t %= Mathd.PI_2;

            if (eccentricity < 1)
            {
                if (t < 0)
                {
                    t += Mathd.PI_2;
                }
                eccentricAnomaly = CelestialBodyUtils.ConvertTrueToEccentricAnomaly(t, eccentricity);
                meanAnomaly      = eccentricAnomaly - eccentricity * System.Math.Sin(eccentricAnomaly);
            }
            else
            {
                eccentricAnomaly = CelestialBodyUtils.ConvertTrueToEccentricAnomaly(t, eccentricity);
                meanAnomaly      = System.Math.Sinh(eccentricAnomaly) * eccentricity - eccentricAnomaly;
            }
            SetPositionByCurrentAnomaly();
            SetVelocityByCurrentAnomaly();
        }
        /// <summary>
        /// Draw two crossing lines in scene view.
        /// </summary>
        private static void DrawX(Vector3 pos, float size, Color col, Vector3 normal, Vector3 up)
        {
            Handles.color = col;
            Vector3 right = CelestialBodyUtils.CrossProduct(up, normal).normalized;

            Handles.DrawLine(pos + up * size, pos - up * size);
            Handles.DrawLine(pos + right * size, pos - right * size);
        }
Beispiel #11
0
        public static Vector3[] CalcOrbitPoints(Vector3 attractorPos, Vector3 bodyPos, double attractorMass, double bodyMass, Vector3 relVelocity, double gConst, int pointsCount)
        {
            if (pointsCount < 3 || pointsCount > 10000)
            {
                return(new Vector3[0]);
            }
            var focusPoint            = CalcCenterOfMass(attractorPos, attractorMass, bodyPos, bodyMass);
            var radiusVector          = bodyPos - focusPoint;
            var radiusVectorMagnitude = radiusVector.magnitude;
            var orbitNormal           = CelestialBodyUtils.CrossProduct(radiusVector, relVelocity);
            var MG              = (attractorMass + bodyMass) * gConst;
            var eccVector       = CelestialBodyUtils.CrossProduct(relVelocity, orbitNormal) / (float)MG - radiusVector / radiusVectorMagnitude;
            var focalParameter  = orbitNormal.sqrMagnitude / MG;
            var eccentricity    = eccVector.magnitude;
            var minorAxisNormal = -CelestialBodyUtils.CrossProduct(orbitNormal, eccVector).normalized;
            var majorAxisNormal = -CelestialBodyUtils.CrossProduct(orbitNormal, minorAxisNormal).normalized;

            orbitNormal.Normalize();
            double  orbitCompressionRatio;
            double  semiMajorAxys;
            double  semiMinorAxys;
            Vector3 relFocusPoint;
            Vector3 centerPoint;

            if (eccentricity < 1)
            {
                orbitCompressionRatio = 1 - eccentricity * eccentricity;
                semiMajorAxys         = focalParameter / orbitCompressionRatio;
                semiMinorAxys         = semiMajorAxys * System.Math.Sqrt(orbitCompressionRatio);
                relFocusPoint         = (float)semiMajorAxys * eccVector;
                centerPoint           = focusPoint - relFocusPoint;
            }
            else
            {
                orbitCompressionRatio = eccentricity * eccentricity - 1f;
                semiMajorAxys         = focalParameter / orbitCompressionRatio;
                semiMinorAxys         = semiMajorAxys * System.Math.Sqrt(orbitCompressionRatio);
                relFocusPoint         = -(float)semiMajorAxys * eccVector;
                centerPoint           = focusPoint - relFocusPoint;
            }

            var    points = new Vector3[pointsCount];
            double eccVar = 0f;

            for (int i = 0; i < pointsCount; i++)
            {
                Vector3 result = eccentricity < 1 ?
                                 new Vector3((float)(System.Math.Sin(eccVar) * semiMinorAxys), -(float)(System.Math.Cos(eccVar) * semiMajorAxys)) :
                                 new Vector3((float)(System.Math.Sinh(eccVar) * semiMinorAxys), (float)(System.Math.Cosh(eccVar) * semiMajorAxys));
                eccVar   += Mathf.PI * 2f / (float)(pointsCount - 1);
                points[i] = minorAxisNormal * result.x + majorAxisNormal * result.y + centerPoint;
            }
            return(points);
        }
        private void DrawInclinationMarkForBody(CelestialBody body, float scale)
        {
            var norm = CelestialBodyUtils.CrossProduct((Vector3)body.OrbitData.OrbitNormal, (Vector3)_simControl.EclipticNormal);

            Handles.color = Color.white;
            var p = CelestialBodyUtils.CrossProduct(norm, (Vector3)_simControl.EclipticNormal).normalized;

            Handles.DrawLine((Vector3)body.OrbitFocusPoint, (Vector3)body.OrbitFocusPoint + p * 3f * scale);
            Handles.DrawLine((Vector3)body.OrbitFocusPoint, (Vector3)body.OrbitFocusPoint + CelestialBodyUtils.RotateVectorByAngle(p, (float)body.OrbitData.Inclination, -norm.normalized) * 3f * scale);
            Handles.DrawWireArc((Vector3)body.OrbitFocusPoint, -norm, p, (float)(body.OrbitData.Inclination * Mathd.Rad2Deg), 1f * scale);
            DrawLabelScaled((Vector3)body.OrbitFocusPoint + p * scale, (body.OrbitData.Inclination * Mathd.Rad2Deg).ToString("0") + "\u00B0", Color.white, 10);
        }
Beispiel #13
0
 public void SetAutoCircleOrbit()
 {
     if (AttractorObjectRef != null)
     {
         OrbitData.Velocity = CelestialBodyUtils.CalcCircleOrbitVelocity(Vector3d.zero, OrbitData.Position, OrbitData.AttractorMass, 1f, OrbitData.OrbitNormal, OrbitData.GravitationalConstant);
         OrbitData.CalculateNewOrbitData();
         if (VelocityHandleRef != null)
         {
             VelocityHandleRef.position = transform.position + (Vector3)OrbitData.Velocity;
         }
     }
 }
Beispiel #14
0
        /// <summary>
        /// Return ratio of perturbation force from third body relative to attraction force of mainAttractor
        /// </summary>
        /// <param name="targetBody"></param>
        /// <param name="mainAttractor"></param>
        /// <param name="perturbatingAttractor"></param>
        public static double RelativePerturbationRatio(CelestialBody targetBody, CelestialBody mainAttractor, CelestialBody perturbatingAttractor)
        {
            double mainAcceleration = CelestialBodyUtils.AccelerationByAttractionForce(
                targetBody.position,
                mainAttractor.position,
                mainAttractor.MG).magnitude;
            double perturbAcceleration = CelestialBodyUtils.AccelerationByAttractionForce(
                targetBody.position,
                perturbatingAttractor.position,
                perturbatingAttractor.MG).magnitude;

            return(perturbAcceleration / mainAcceleration);
        }
Beispiel #15
0
        public static Vector3 GetRayPlaneIntersectionPoint(Vector3 pointOnPlane, Vector3 normal, Vector3 rayOrigin, Vector3 rayDirection)
        {
            var dotProd = CelestialBodyUtils.DotProduct(rayDirection, normal);

            if (Mathd.Abs(dotProd) < 1e-5)
            {
                return(new Vector3());
            }
            var p = rayOrigin + rayDirection * CelestialBodyUtils.DotProduct((pointOnPlane - rayOrigin), normal) / dotProd;

            p = p - normal * CelestialBodyUtils.DotProduct(p - pointOnPlane, normal);             //projection. for better precision
            return(p);
        }
Beispiel #16
0
        /// <summary>
        /// Get orbit curve points without array allocation, if current orbit state is valid.
        /// </summary>
        /// <remarks>
        /// Note: array allocation may sometimes occur, if specified array is null or lenght is not equal to target points count.
        /// </remarks>
        /// <param name="points">Resulting orbit curve array.</param>
        /// <param name="pointsCount">Max orbit curve points count.</param>
        /// <param name="origin">World position of attractor (focus of orbit).</param>
        /// <param name="maxDistance">Max distance for orbit curve points.</param>
        public void GetOrbitPointsNoAlloc(ref Vector3d[] points, int pointsCount, Vector3d origin, double maxDistance = 1000d)
        {
            if (pointsCount < 2)
            {
                points = new Vector3d[0];
                return;
            }
            if (Eccentricity < 1)
            {
                if (points == null || points.Length != pointsCount)
                {
                    points = new Vector3d[pointsCount];
                }

                if (ApoapsisDistance < maxDistance)
                {
                    for (var i = 0; i < pointsCount; i++)
                    {
                        points[i] = GetFocalPositionAtEccentricAnomaly(i * Mathd.PI_2 / (pointsCount - 1d)) + origin;
                    }
                }
                else
                {
                    var maxAngle = CelestialBodyUtils.CalcTrueAnomalyForDistance(maxDistance, Eccentricity, SemiMajorAxis);
                    for (int i = 0; i < pointsCount; i++)
                    {
                        points[i] = GetFocalPositionAtTrueAnomaly(-maxAngle + i * 2d * maxAngle / (pointsCount - 1)) + origin;
                    }
                }
            }
            else
            {
                if (maxDistance < PeriapsisDistance)
                {
                    points = new Vector3d[0];
                    return;
                }

                if (points == null || points.Length != pointsCount)
                {
                    points = new Vector3d[pointsCount];
                }

                var maxAngle = CelestialBodyUtils.CalcTrueAnomalyForDistance(maxDistance, Eccentricity, SemiMajorAxis);
                for (int i = 0; i < pointsCount; i++)
                {
                    points[i] = GetFocalPositionAtTrueAnomaly(-maxAngle + i * 2d * maxAngle / (pointsCount - 1)) + origin;
                }
            }
        }
        /// <summary>
        /// Calculate and apply n-body gravitational acceleration to target body, using algorythm Runge-Kutta.
        /// In result body will change it's velocity according to global gravity.
        /// </summary>
        /// <param name="body">Target body.</param>
        /// <param name="dt">Delta time.</param>
        /// <param name="minRange">Minimal attraction range for attractors.</param>
        /// <param name="maxRange">Maximal attraction range for attractors.</param>
        /// <param name="allAttractors">List of all attractors on scene.</param>
        public static void CalcAccelerationRungeKuttaForBody(CelestialBody body, double dt, double minRange, double maxRange, List <CelestialBody> allAttractors)
        {
            Vector3d result = Vector3d.zero;

            body._position += body.Velocity * (dt / 2d);
            for (int i = 0; i < allAttractors.Count; i++)
            {
                if (allAttractors[i] == body)
                {
                    continue;
                }
                var t1 = CelestialBodyUtils.AccelerationByAttractionForce(
                    body._position,
                    allAttractors[i].Position,
                    allAttractors[i].MG,
                    minRange,
                    Mathd.Min(maxRange, allAttractors[i].MaxAttractionRange)
                    ) * dt;
                var t2 = CelestialBodyUtils.AccelerationByAttractionForce(
                    body._position + t1 * 0.5d,
                    allAttractors[i].Position,
                    allAttractors[i].MG,
                    minRange,
                    Mathd.Min(maxRange, allAttractors[i].MaxAttractionRange)
                    ) * dt;
                var t3 = CelestialBodyUtils.AccelerationByAttractionForce(
                    body._position + t2 * 0.5d,
                    allAttractors[i].Position,
                    allAttractors[i].MG,
                    minRange,
                    Mathd.Min(maxRange, allAttractors[i].MaxAttractionRange)
                    ) * dt;
                var t4 = CelestialBodyUtils.AccelerationByAttractionForce(
                    body._position + t3,
                    allAttractors[i].Position,
                    allAttractors[i].MG,
                    minRange,
                    Mathd.Min(maxRange, allAttractors[i].MaxAttractionRange)
                    ) * dt;
                result += new Vector3d(
                    (t1.x + t2.x * 2d + t3.x * 2d + t4.x) / 6d,
                    (t1.y + t2.y * 2d + t3.y * 2d + t4.y) / 6d,
                    (t1.z + t2.z * 2d + t3.z * 2d + t4.z) / 6d);
            }
            if (!result.isZero)
            {
                body.Velocity += result;
            }
        }
        public CelestialBody FindMostProperAttractor(CelestialBody body)
        {
            if (body == null)
            {
                return(null);
            }
            CelestialBody resultAttractor = null;

#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                bodies = new List <CelestialBody>(GameObject.FindObjectsOfType <CelestialBody>());
            }
#endif
            // Search logic:
            // calculate mutual perturbation for every pair of attractors in scene and select one,
            // which attracts the body with biggest force and is least affected by others.
            foreach (var otherBody in bodies)
            {
                if (otherBody == body || !otherBody.isActiveAndEnabled || otherBody.mass < minAttractorMass || (otherBody.position - body.position).magnitude > Mathd.Min(maxAttractionRange, otherBody.maxAttractionRange))
                {
                    continue;
                }
#if UNITY_EDITOR
                if (!Application.isPlaying)
                {
                    otherBody.FindReferences();
                }
#endif
                if (resultAttractor == null)
                {
                    resultAttractor = otherBody;
                }
                else
                if (CelestialBodyUtils.RelativePerturbationRatio(body, resultAttractor, otherBody) > CelestialBodyUtils.RelativePerturbationRatio(body, otherBody, resultAttractor))
                {
                    resultAttractor = otherBody;
                }
            }
#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                bodies.Clear();                 //bodies must be empty in editor mode
            }
#endif
            return(resultAttractor);
        }
        /// <summary>
        /// Draw simple arrow in scene window at given world coordinates
        /// </summary>
        private static void DrawArrow(Vector3 from, Vector3 to, Color col, Vector3 normal)
        {
            var   dir        = to - from;
            float dist       = dir.magnitude;
            var   dirNorm    = dir / dist; //normalized vector
            float headSize   = dist / 6f;
            var   _colBefore = Handles.color;

            Handles.color = col;
            Vector3 sideNormal = CelestialBodyUtils.CrossProduct(dir, normal).normalized;

            Handles.DrawLine(from, from + dirNorm * (dist - headSize));
            Handles.DrawLine(from + dirNorm * (dist - headSize) + sideNormal * headSize / 2f, from + dirNorm * (dist - headSize) - sideNormal * headSize / 2f);
            Handles.DrawLine(from + dirNorm * (dist - headSize) + sideNormal * headSize / 2f, from + dir);
            Handles.DrawLine(from + dirNorm * (dist - headSize) - sideNormal * headSize / 2f, from + dir);
            Handles.color = _colBefore;
        }
        public void CalcAccelerationRungeKuttaForBody(CelestialBody body, double dt)
        {
            Vector3d result = Vector3d.zero;

            body._position += body.velocity * (dt / 2d);
            for (int i = 0; i < attractorsCache.Count; i++)
            {
                if (attractorsCache[i] == body)
                {
                    continue;
                }
                var t1 = CelestialBodyUtils.AccelerationByAttractionForce(
                    body._position,
                    attractorsCache[i].position,
                    attractorsCache[i].MG,
                    minAttractionRange,
                    Mathd.Min(maxAttractionRange, attractorsCache[i].maxAttractionRange)
                    ) * dt;
                var t2 = CelestialBodyUtils.AccelerationByAttractionForce(
                    body._position + t1 * 0.5d,
                    attractorsCache[i].position,
                    attractorsCache[i].MG,
                    minAttractionRange,
                    Mathd.Min(maxAttractionRange, attractorsCache[i].maxAttractionRange)
                    ) * dt;
                var t3 = CelestialBodyUtils.AccelerationByAttractionForce(
                    body._position + t2 * 0.5d,
                    attractorsCache[i].position,
                    attractorsCache[i].MG,
                    minAttractionRange,
                    Mathd.Min(maxAttractionRange, attractorsCache[i].maxAttractionRange)
                    ) * dt;
                var t4 = CelestialBodyUtils.AccelerationByAttractionForce(
                    body._position + t3,
                    attractorsCache[i].position,
                    attractorsCache[i].MG,
                    minAttractionRange,
                    Mathd.Min(maxAttractionRange, attractorsCache[i].maxAttractionRange)
                    ) * dt;
                result += new Vector3d(
                    (t1.x + t2.x * 2d + t3.x * 2d + t4.x) / 6d,
                    (t1.y + t2.y * 2d + t3.y * 2d + t4.y) / 6d,
                    (t1.z + t2.z * 2d + t3.z * 2d + t4.z) / 6d);
            }
            body.velocity += result;
        }
Beispiel #21
0
 /// <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)
     {
         if (Period > 1e-5)
         {
             MeanAnomaly += Mathd.PI_2 * deltaTime / Period;
         }
         MeanAnomaly %= Mathd.PI_2;
         if (MeanAnomaly < 0)
         {
             MeanAnomaly = Mathd.PI_2 - MeanAnomaly;
         }
         EccentricAnomaly = CelestialBodyUtils.KeplerSolver(MeanAnomaly, Eccentricity);
         var cosE = Math.Cos(EccentricAnomaly);
         TrueAnomaly = Math.Acos((cosE - Eccentricity) / (1 - Eccentricity * cosE));
         if (MeanAnomaly > Mathd.PI)
         {
             TrueAnomaly = Mathd.PI_2 - TrueAnomaly;
         }
         if (double.IsNaN(MeanAnomaly) || double.IsInfinity(MeanAnomaly))
         {
             Debug.Log("SpaceGravity2D: NaN(INF) MEAN ANOMALY"); //litle paranoya
             Debug.Break();
         }
         if (double.IsNaN(EccentricAnomaly) || double.IsInfinity(EccentricAnomaly))
         {
             Debug.Log("SpaceGravity2D: NaN(INF) ECC ANOMALY");
             Debug.Break();
         }
         if (double.IsNaN(TrueAnomaly) || double.IsInfinity(TrueAnomaly))
         {
             Debug.Log("SpaceGravity2D: NaN(INF) TRUE ANOMALY");
             Debug.Break();
         }
     }
     else
     {
         double n = Math.Sqrt(AttractorMass * GravitationalConstant / Math.Pow(SemiMajorAxis, 3));
         MeanAnomaly      = MeanAnomaly + n * deltaTime;
         EccentricAnomaly = CelestialBodyUtils.KeplerSolverHyperbolicCase(MeanAnomaly, Eccentricity);
         TrueAnomaly      = Math.Atan2(Math.Sqrt(Eccentricity * Eccentricity - 1.0) * Math.Sinh(EccentricAnomaly), Eccentricity - Math.Cosh(EccentricAnomaly));
     }
 }
        /// <summary>
        /// Find attractor, which have most gravitational influence at target body.
        /// </summary>
        /// <param name="body">Target body.</param>
        /// <returns>Most proper attractor or null.</returns>
        /// <remarks>
        /// Search logic:
        /// Calculate mutual perturbation for every pair of attractors in scene and select one,
        /// which attracts the body with biggest force and is least affected by others.
        /// </remarks>
        public CelestialBody FindMostProperAttractor(CelestialBody body)
        {
            if (body == null)
            {
                return(null);
            }
            CelestialBody resultAttractor = null;

#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                Bodies = new List <CelestialBody>(GameObject.FindObjectsOfType <CelestialBody>());
            }
#endif
            foreach (var otherBody in Bodies)
            {
                if (otherBody == body || !otherBody.isActiveAndEnabled || otherBody.Mass < MinAttractorMass || (otherBody.Position - body.Position).magnitude > Mathd.Min(MaxAttractionRange, otherBody.MaxAttractionRange))
                {
                    continue;
                }
#if UNITY_EDITOR
                if (!Application.isPlaying)
                {
                    otherBody.FindReferences();
                }
#endif
                if (resultAttractor == null)
                {
                    resultAttractor = otherBody;
                }
                else
                if (CelestialBodyUtils.RelativePerturbationRatio(body, resultAttractor, otherBody) > CelestialBodyUtils.RelativePerturbationRatio(body, otherBody, resultAttractor))
                {
                    resultAttractor = otherBody;
                }
            }
#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                Bodies.Clear(); //bodies must be empty in editor mode
            }
#endif
            return(resultAttractor);
        }
Beispiel #23
0
 public void UpdateOrbitAnomaliesByTime(double deltaTime)
 {
     if (eccentricity < 1)
     {
         if (period > 1e-5)
         {
             meanAnomaly += Mathd.PI_2 * deltaTime / period;
         }
         meanAnomaly %= Mathd.PI_2;
         if (meanAnomaly < 0)
         {
             meanAnomaly = Mathd.PI_2 - meanAnomaly;
         }
         eccentricAnomaly = CelestialBodyUtils.KeplerSolver(meanAnomaly, eccentricity);
         var cosE = System.Math.Cos(eccentricAnomaly);
         trueAnomaly = System.Math.Acos((cosE - eccentricity) / (1 - eccentricity * cosE));
         if (meanAnomaly > Mathd.PI)
         {
             trueAnomaly = Mathd.PI_2 - trueAnomaly;
         }
         if (double.IsNaN(meanAnomaly) || double.IsInfinity(meanAnomaly))
         {
             Debug.Log("SpaceGravity2D: NaN(INF) MEAN ANOMALY");                     //litle paranoya
             Debug.Break();
         }
         if (double.IsNaN(eccentricAnomaly) || double.IsInfinity(eccentricAnomaly))
         {
             Debug.Log("SpaceGravity2D: NaN(INF) ECC ANOMALY");
             Debug.Break();
         }
         if (double.IsNaN(trueAnomaly) || double.IsInfinity(trueAnomaly))
         {
             Debug.Log("SpaceGravity2D: NaN(INF) TRUE ANOMALY");
             Debug.Break();
         }
     }
     else
     {
         double n = System.Math.Sqrt(attractorMass * gravConst / System.Math.Pow(semiMajorAxis, 3)) * Mathd.Sign(orbitNormalDotEclipticNormal);
         meanAnomaly      = meanAnomaly - n * deltaTime;
         eccentricAnomaly = CelestialBodyUtils.KeplerSolverHyperbolicCase(meanAnomaly, eccentricity);
         trueAnomaly      = System.Math.Atan2(System.Math.Sqrt(eccentricity * eccentricity - 1.0) * System.Math.Sinh(eccentricAnomaly), eccentricity - System.Math.Cosh(eccentricAnomaly));
     }
 }
Beispiel #24
0
		public void ProjectOntoEclipticPlane() {
#if UNITY_EDITOR
			if (!Application.isPlaying) {
				Undo.RecordObject(this, "ecliptic projection");
				Undo.RecordObject(transformRef, "ecliptic projection");
			}
#endif
			var projectedPos = _position - simControlRef.eclipticNormal * CelestialBodyUtils.DotProduct(_position, simControlRef.eclipticNormal);
			var projectedV = velocity - simControlRef.eclipticNormal * CelestialBodyUtils.DotProduct(velocity, simControlRef.eclipticNormal);
			_position = projectedPos;
			transformRef.position = (Vector3)projectedPos;
			velocity = projectedV;
			orbitData.isDirty = true;
#if UNITY_EDITOR
			if (!Application.isPlaying) {
				EditorUtility.SetDirty(this);
			}
#endif
		}
        public void CalcAccelerationEulerForBody(CelestialBody body, double dt)
        {
            Vector3d result = Vector3d.zero;

            for (int i = 0; i < attractorsCache.Count; i++)
            {
                if (attractorsCache[i] == body)
                {
                    continue;
                }
                result += CelestialBodyUtils.AccelerationByAttractionForce(
                    body.position,
                    attractorsCache[i].position,
                    attractorsCache[i].MG,
                    minAttractionRange,
                    Mathd.Min(maxAttractionRange, attractorsCache[i].maxAttractionRange)
                    );
            }
            body.velocity += result * dt;
        }
        public Vector3d CalcAccelerationEulerInPoint(Vector3d pos)
        {
            Vector3d result = new Vector3d();

            for (int i = 0; i < attractorsCache.Count; i++)
            {
                if (attractorsCache[i].position == pos)
                {
                    continue;
                }
                result += CelestialBodyUtils.AccelerationByAttractionForce(
                    pos,
                    attractorsCache[i].position,
                    attractorsCache[i].MG,
                    minAttractionRange,
                    Mathd.Min(maxAttractionRange, attractorsCache[i].maxAttractionRange)
                    );
            }
            return(result);
        }
        /// <summary>
        /// Calculate n-body gravitational acceleration at specified world point, using Euler algorythm.
        /// </summary>
        /// <param name="pos">World position.</param>
        /// <param name="minRange">Minimal attraction range for attractors.</param>
        /// <param name="maxRange">Maximal attraction range for attractors.</param>
        /// <param name="allAttractors">List of all attractors on scene.</param>
        /// <returns>Sum of accelerations vectors at position.</returns>
        public static Vector3d CalcAccelerationEulerInPoint(Vector3d pos, double minRange, double maxRange, List <CelestialBody> allAttractors)
        {
            Vector3d result = new Vector3d();

            for (int i = 0; i < allAttractors.Count; i++)
            {
                if (allAttractors[i].Position == pos)
                {
                    continue;
                }
                result += CelestialBodyUtils.AccelerationByAttractionForce(
                    pos,
                    allAttractors[i].Position,
                    allAttractors[i].MG,
                    minRange,
                    Mathd.Min(maxRange, allAttractors[i].MaxAttractionRange)
                    );
            }
            return(result);
        }
Beispiel #28
0
        public Vector3[] GetOrbitPoints(int pointsCount, Vector3 origin, float maxDistance = 1000f)
        {
            if (pointsCount < 2)
            {
                return(new Vector3[0]);
            }
            var result = new Vector3[pointsCount];

            if (eccentricity < 1)
            {
                if (apoapsisDistance < maxDistance)
                {
                    for (var i = 0; i < pointsCount; i++)
                    {
                        result[i] = (Vector3)GetFocalPositionAtEccentricAnomaly(i * Mathd.PI_2 / (pointsCount - 1d)) + origin;
                    }
                }
                else
                {
                    var maxAngle = CelestialBodyUtils.CalcTrueAnomalyForDistance(maxDistance, eccentricity, semiMajorAxis);
                    for (int i = 0; i < pointsCount; i++)
                    {
                        result[i] = (Vector3)GetFocalPositionAtTrueAnomaly(-maxAngle + i * 2d * maxAngle / (pointsCount - 1)) + origin;
                    }
                }
            }
            else
            {
                if (maxDistance < periapsisDistance)
                {
                    return(new Vector3[0]);
                }
                var maxAngle = CelestialBodyUtils.CalcTrueAnomalyForDistance(maxDistance, eccentricity, semiMajorAxis);

                for (int i = 0; i < pointsCount; i++)
                {
                    result[i] = (Vector3)GetFocalPositionAtTrueAnomaly(-maxAngle + i * 2d * maxAngle / (pointsCount - 1)) + origin;
                }
            }
            return(result);
        }
        /// <summary>
        /// Calculate and apply n-body gravitational acceleration to target body, using Euler algorythm.
        /// In result body will change it's velocity according to global gravity.
        /// </summary>
        /// <param name="body">Target body.</param>
        /// <param name="dt">Delta time.</param>
        /// <param name="minRange">Minimal attraction range for attractors.</param>
        /// <param name="maxRange">Maximal attraction range for attractors.</param>
        /// <param name="allAttractors">List of all attractors on scene.</param>
        public static void CalcAccelerationEulerForBody(CelestialBody body, double dt, double minRange, double maxRange, List <CelestialBody> allAttractors)
        {
            Vector3d result = Vector3d.zero;

            for (int i = 0; i < allAttractors.Count; i++)
            {
                if (object.ReferenceEquals(allAttractors[i], body))
                {
                    continue;
                }
                result += CelestialBodyUtils.AccelerationByAttractionForce(
                    body.Position,
                    allAttractors[i].Position,
                    allAttractors[i].MG,
                    minRange,
                    Mathd.Min(maxRange, allAttractors[i].MaxAttractionRange)
                    );
            }
            if (!result.isZero)
            {
                body.Velocity += result * dt;
            }
        }
Beispiel #30
0
 /// <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 % Mathd.PI_2;
     if (Eccentricity < 1)
     {
         if (MeanAnomaly < 0)
         {
             MeanAnomaly += Mathd.PI_2;
         }
         EccentricAnomaly = CelestialBodyUtils.KeplerSolver(MeanAnomaly, Eccentricity);
         TrueAnomaly      = CelestialBodyUtils.ConvertEccentricToTrueAnomaly(EccentricAnomaly, Eccentricity);
     }
     else
     {
         EccentricAnomaly = CelestialBodyUtils.KeplerSolverHyperbolicCase(MeanAnomaly, Eccentricity);
         TrueAnomaly      = CelestialBodyUtils.ConvertEccentricToTrueAnomaly(EccentricAnomaly, Eccentricity);
     }
     SetPositionByCurrentAnomaly();
     SetVelocityByCurrentAnomaly();
 }