Add orbit calculation
This commit is contained in:
		
							parent
							
								
									518ee9d429
								
							
						
					
					
						commit
						7aa59ff795
					
				@ -2,6 +2,7 @@ using System.Diagnostics;
 | 
			
		||||
using Godot;
 | 
			
		||||
using ImGuiNET;
 | 
			
		||||
using Quadratic.Carto.MathExt;
 | 
			
		||||
using Quadratic.Carto.Orbital;
 | 
			
		||||
using Vim.Math3d;
 | 
			
		||||
 | 
			
		||||
namespace Quadratic.Carto.Craft;
 | 
			
		||||
@ -23,6 +24,8 @@ public sealed partial class Krakensbane : Node3D
 | 
			
		||||
    const float maxDistance = 500.0f;
 | 
			
		||||
    const float planetRadius = 6372.0f;
 | 
			
		||||
 | 
			
		||||
    CelestialBody celestialBody = CelestialBody.FromSurfaceGravity(9.81, planetRadius, 86164.1);
 | 
			
		||||
 | 
			
		||||
    DVector3 originPosition = DVector3.UnitY * planetRadius;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@ -80,7 +83,7 @@ public sealed partial class Krakensbane : Node3D
 | 
			
		||||
                var gravityVector = -globalPosition.Normalize();
 | 
			
		||||
                var floatGravityVector = gravityVector.AsSingle().AsGodot();
 | 
			
		||||
                var distance = globalPosition.Length();
 | 
			
		||||
                var gravity = 9.81f * planetRadius * planetRadius / (distance * distance);
 | 
			
		||||
                var gravity = celestialBody.Mu / (distance * distance);
 | 
			
		||||
                rb.ApplyCentralForce(floatGravityVector * (float)gravity);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -94,8 +97,28 @@ public sealed partial class Krakensbane : Node3D
 | 
			
		||||
 | 
			
		||||
    public override void _Process(double delta)
 | 
			
		||||
    {
 | 
			
		||||
        // Debug the orbit of the focused vessel
 | 
			
		||||
        KeplerianElements? elements = null;
 | 
			
		||||
        if (FocusedVessel != null && FocusedVessel is RigidBody3D rigidBody3D)
 | 
			
		||||
        {
 | 
			
		||||
            var position = GetPositionOf(rigidBody3D);
 | 
			
		||||
            var velocity = rigidBody3D.LinearVelocity.AsVim().AsDouble();
 | 
			
		||||
            var state = new DStateVector(position, velocity);
 | 
			
		||||
            elements = KeplerianElements.FromMotionState(state, celestialBody.Mu);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ImGui.Begin("Krakensbane");
 | 
			
		||||
        ImGui.Text($"Origin: {originPosition}");
 | 
			
		||||
        ImGui.Text($"Focused vessel: {FocusedVessel?.Name}");
 | 
			
		||||
        if (elements != null)
 | 
			
		||||
        {
 | 
			
		||||
            ImGui.Text("Orbit");
 | 
			
		||||
            ImGui.BeginGroup();
 | 
			
		||||
            ImGui.Text($"Ap: {elements.Apoapsis}");
 | 
			
		||||
            ImGui.Text($"Pe: {elements.Periapsis}");
 | 
			
		||||
            ImGui.Text($"Period: {elements.Period(celestialBody.Mu)}");
 | 
			
		||||
            ImGui.EndGroup();
 | 
			
		||||
        }
 | 
			
		||||
        ImGui.End();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										44
									
								
								src/Orbital/CelestialBody.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/Orbital/CelestialBody.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
namespace Quadratic.Carto.Orbital;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Represents the basic properties of a celestial body.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="Mass">The mass of the body, in kilograms</param>
 | 
			
		||||
/// <param name="Radius">The radius of the body, in meters</param>
 | 
			
		||||
/// <param name="RotationPeriod">The rotation period of the body, in seconds</param>
 | 
			
		||||
public sealed record CelestialBody(
 | 
			
		||||
    double Mass,
 | 
			
		||||
    double Radius,
 | 
			
		||||
    double RotationPeriod
 | 
			
		||||
)
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The gravitational parameter of the body, mu = G(M+m), in cubic meters per second squared.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public double Mu => PhysicalConstants.GravitationalConstant * Mass;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The surface gravity of the body, in meters per second squared.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public double SurfaceGravity => Mu / (Radius * Radius);
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Get the celestial body from its surface gravity, radius, and rotation period.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="surfaceGravity"></param>
 | 
			
		||||
    /// <param name="radius"></param>
 | 
			
		||||
    /// <param name="rotationPeriod"></param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public static CelestialBody FromSurfaceGravity(double surfaceGravity, double radius, double rotationPeriod)
 | 
			
		||||
    {
 | 
			
		||||
        var mass = surfaceGravity * radius * radius / PhysicalConstants.GravitationalConstant;
 | 
			
		||||
        return new CelestialBody(mass, radius, rotationPeriod);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static CelestialBody Earth = new CelestialBody(5.972e24, 6371e3, 86164.1);
 | 
			
		||||
 | 
			
		||||
    public override string ToString()
 | 
			
		||||
    {
 | 
			
		||||
        return $"CelestialBody(Mass: {Mass}, Radius: {Radius}, RotationPeriod: {RotationPeriod})";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										121
									
								
								src/Orbital/KeplerianElements.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/Orbital/KeplerianElements.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Vim.Math3d;
 | 
			
		||||
 | 
			
		||||
namespace Quadratic.Carto.Orbital;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// A list of keplerian orbital elements, representing the orbit around a celestial body.
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <remarks>
 | 
			
		||||
/// https://orbital-mechanics.space/classical-orbital-elements/orbital-elements-and-the-state-vector.html
 | 
			
		||||
/// </remarks>
 | 
			
		||||
public sealed class KeplerianElements(
 | 
			
		||||
    double ecc, double sma, double inc,
 | 
			
		||||
    double lan, double ape, double ta
 | 
			
		||||
)
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Eccentricity of the orbit.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public double ecc = ecc;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Semi-major axis of the orbit, in meters.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public double sma = sma;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Inclination of the orbit, in radians [0, π).
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public double inc = inc;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Longitude of the ascending node, in radians [0, 2π).
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public double lan = lan;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Argument of periapsis, in radians [0, 2π).
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public double ape = ape;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// True anomaly, in radians [0, 2π).
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public double ta = ta;
 | 
			
		||||
 | 
			
		||||
    public double IncDegree => inc * Math.PI / 180;
 | 
			
		||||
    public double LanDegree => lan * Math.PI / 180;
 | 
			
		||||
    public double ApeDegree => ape * Math.PI / 180;
 | 
			
		||||
    public double TaDegree => ta * Math.PI / 180;
 | 
			
		||||
 | 
			
		||||
    public double Apoapsis => sma * (1 + ecc);
 | 
			
		||||
    public double Periapsis => sma * (1 - ecc);
 | 
			
		||||
 | 
			
		||||
    public double Period(double mu)
 | 
			
		||||
    {
 | 
			
		||||
        return 2 * Math.PI * Math.Sqrt(sma * sma * sma / mu);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override string ToString()
 | 
			
		||||
    {
 | 
			
		||||
        return $"KeplerianElements(ecc: {ecc:F6}, sma: {sma:F6}, inc: {inc:F6}, lan: {lan:F6}, ape: {ape:F6}, ta: {ta:F6})";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Returns the position and velocity of the body at the given time.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="mu">The standard gravitational parameter, mu = G(M+m)</param>
 | 
			
		||||
    /// <param name="epoch">The time of the query</param>
 | 
			
		||||
    /// <returns></returns>
 | 
			
		||||
    public DStateVector MotionStateAt(double mu, double epoch)
 | 
			
		||||
    {
 | 
			
		||||
        throw new NotImplementedException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static KeplerianElements FromMotionState(DStateVector state, double mu)
 | 
			
		||||
    {
 | 
			
		||||
        DVector3 position = state.Position;
 | 
			
		||||
        DVector3 velocity = state.Velocity;
 | 
			
		||||
 | 
			
		||||
        double radius = position.Length();
 | 
			
		||||
        double speed = velocity.Length();
 | 
			
		||||
        double vRadial = DVector3.Dot(position, velocity) / radius;
 | 
			
		||||
        double vTangential = Math.Sqrt(speed * speed - vRadial * vRadial);
 | 
			
		||||
 | 
			
		||||
        DVector3 angularMomentum = position.Cross(velocity);
 | 
			
		||||
        double h = angularMomentum.Length();
 | 
			
		||||
 | 
			
		||||
        double inclination = Math.Acos(angularMomentum.Z / h);
 | 
			
		||||
 | 
			
		||||
        DVector3 kHat = new DVector3(0, 0, 1);
 | 
			
		||||
        DVector3 n = kHat.Cross(angularMomentum);
 | 
			
		||||
        double nNorm = n.Length();
 | 
			
		||||
        double lan = Math.Acos(n.X / nNorm);
 | 
			
		||||
 | 
			
		||||
        DVector3 eVec = velocity.Cross(angularMomentum) / mu - position / radius;
 | 
			
		||||
        double ecc = eVec.Length();
 | 
			
		||||
 | 
			
		||||
        double a = 1 / (2 / radius - speed * speed / mu);
 | 
			
		||||
 | 
			
		||||
        double ta = Math.Acos((a * (1 - ecc * ecc) / radius - 1) / ecc);
 | 
			
		||||
 | 
			
		||||
        return new KeplerianElements(ecc, a, inclination, lan, 0, ta);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static KeplerianElements EquatorialCircular(double sma, double ta)
 | 
			
		||||
    {
 | 
			
		||||
        return new KeplerianElements(0, sma, 0, 0, 0, ta);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static KeplerianElements Circular(double sma, double inc, double lan, double ta)
 | 
			
		||||
    {
 | 
			
		||||
        return new KeplerianElements(0, sma, inc, lan, 0, ta);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public struct DStateVector(DVector3 position, DVector3 velocity)
 | 
			
		||||
{
 | 
			
		||||
    public DVector3 Position = position;
 | 
			
		||||
    public DVector3 Velocity = velocity;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								src/Orbital/PhysicalConstants.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/Orbital/PhysicalConstants.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
namespace Quadratic.Carto.Orbital;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Provides commonly used physical constants.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class PhysicalConstants
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The speed of light in a vacuum, in meters per second.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const double LightSpeed = 299_792_458.0;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// The gravitational constant, in cubic meters per kilogram per second squared.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const double GravitationalConstant = 6.67430e-11;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Alias for the speed of light in a vacuum, in meters per second.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const double c = LightSpeed;
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Alias for the gravitational constant, in cubic meters per kilogram per second squared.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public const double G = GravitationalConstant;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user