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; /// /// An orbit is treated as one stationary body at one focus of the orbit's ellipse. /// The satellite is treated as a massless point. /// /// Mass of the object being orbited /// The orbiting body 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 }); } } }