shmodot/scripts/orbits/Orbit.cs

85 lines
2.1 KiB
C#

using Godot;
using System;
using Vim.Math3d;
public class Orbit : IOrbit
{
#region IEllipse
public double a => Ellipse.a;
public double b => Ellipse.b;
public double e => Ellipse.e;
public DVector2[] Foci => Ellipse.Foci;
#endregion
public IEllipse Ellipse { get; set; }
private double U => Kepler.U(_massive.Mass);
private readonly IMassive _massive;
private readonly ILocation _satellite;
/// <summary>
/// An orbit is treated as one stationary body at one focus of the orbit's ellipse.
/// The satellite is treated as a massless point.
/// </summary>
/// <param name="massive">Mass of the object being orbited</param>
/// <param name="satellite">The orbiting body</param>
public Orbit(IMassive massive, ILocation satellite)
{
// semi-major axis is distance of satellite from origin
var a = satellite.Position.Magnitude();
// TODO: determine eccentricity better
var e = 0.8f;
this.Ellipse = new Ellipse(a, e);
_massive = massive;
_satellite = satellite;
}
public DVector3 GetPosition(float t)
{
var a = Ellipse.a;
var e = Ellipse.e;
Kepler.GetPeriod(a, U);
// TODO: determine period from mass of orbiting bodies
var P = 10f;
var M = Kepler.GetMeanAnomaly(t, P);
var E = Kepler.GetEccentricAnomaly(e, M) + Math.PI;
var p = Kepler.GetEccentricPosition2D(e, a, t);
return new DVector3(p.X, 0, p.Y);
}
public void Draw(ImmediateGeometry geo)
{
geo.Clear();
geo.Begin(Mesh.PrimitiveType.LineLoop);
DrawEllipse(geo);
geo.End();
}
private void DrawEllipse(ImmediateGeometry geo)
{
geo.SetColor(new Color(1, 0, 0));
int steps = 100;
for (int i = 0; i < steps; i++)
{
float t = i / (float)steps;
float a = t * Mathf.Tau;
var v2 = Ellipse.Foci[0] + Ellipse.GetPosition(a);
geo.AddVertex(new Godot.Vector3
{
x = (float)v2.X,
z = (float)v2.Y
});
}
}
}