////////////////////////////////////////////////////////////////////
// Copyright © 2009 Carl Johansen
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more
// details ().
////////////////////////////////////////////////////////////////////
using System;
using System.Windows.Media.Media3D;
namespace GravityDemo
{
public class EllipticalOrbit
{
public Body CentralBody { get; set; }
public double SemiMajorAxis { get; set; }
public double Eccentricity { get; set; }
public double Inclination { get; set; }
public double AscendingNodeLongitude { get; set; }
public double ArgumentOfPeriapsis { get; set; }
public bool AnglesInDegrees { get; set; }
public bool DistancesInKilometres { get; set; }
public EllipticalOrbit()
{
AnglesInDegrees = true;
DistancesInKilometres = false; //Default assumes distances are in metres.
}
///
/// The time that the orbiting body will take to complete one orbit (in seconds).
///
public double Period
{
get
{
//Thanks to http://galileo.phys.virginia.edu/classes/152.mf1i.spring02/EllipticOrbits.htm.
double aCubed = SemiMajorAxis * SemiMajorAxis * SemiMajorAxis;
if (DistancesInKilometres)
aCubed *= 1000000000; //convert cubic km to cubic metres.
return Math.Sqrt((4 * Math.PI * Math.PI * aCubed) / CentralBody.GM);
}
}
public double GetEccentricAnomaly(double meanAnomaly)
{
double ma = meanAnomaly;
if (AnglesInDegrees)
{
double deg2Rad = Math.PI / 180;
ma *= deg2Rad;
}
double eca = ma + Eccentricity / 2.0;
double epsilon = .000001;
double eNew;
do
{
eNew = eca - (eca - Eccentricity * Math.Sin(eca) - ma) / (1 - Eccentricity * Math.Cos(eca));
eca = eNew;
} while (Math.Abs(eNew - eca) > epsilon);
return eca;
}
public OrbitStateVectorPair GetStateVectors(double meanAnomaly)
{
//Based on code from http://www.geocities.com/SiliconValley/2902/ele2vec.htm.
double a = SemiMajorAxis;
double ec = Eccentricity;
double i = Inclination;
double w0 = ArgumentOfPeriapsis;
double o0 = AscendingNodeLongitude;
double m0 = meanAnomaly;
if (AnglesInDegrees)
{
double deg2Rad = Math.PI / 180;
i *= deg2Rad;
o0 *= deg2Rad;
w0 *= deg2Rad;
m0 *= deg2Rad;
}
double eca = GetEccentricAnomaly(meanAnomaly);
double ceca = Math.Cos(eca);
double seca = Math.Sin(eca);
double e1 = a * Math.Sqrt(1 - ec * ec);
double xw = a * (ceca - ec);
double yw = e1 * seca;
double gm = CentralBody.GM;
if (DistancesInKilometres)
gm /= 1000000000; //Convert cubic km to cubic metres.
double edot = Math.Sqrt(gm / a) / (a * (1 - ec * ceca));
double xdw = -a * edot * seca;
double ydw = e1 * edot * ceca;
double cw = Math.Cos(w0);
double sw = Math.Sin(w0);
double co = Math.Cos(o0);
double so = Math.Sin(o0);
double ci = Math.Cos(i);
double si = Math.Sin(i);
double swci = sw * ci;
double cwci = cw * ci;
double px = cw * co - so * swci;
double py = cw * so + co * swci;
double pz = sw * si;
double qx = -sw * co - so * cwci;
double qy = -sw * so + co * cwci;
double qz = cw * si;
double x = xw * px + yw * qx;
double y = xw * py + yw * qy;
double z = xw * pz + yw * qz;
double xd = xdw * px + ydw * qx;
double yd = xdw * py + ydw * qy;
double zd = xdw * pz + ydw * qz;
//Two conversions to note:
// 1. From km to metres.
// 2. My system uses the convention of y-axis = up/down, so I swap the y/z
// values returned by this calculation.
double unitConversionFactor = (DistancesInKilometres ? 1000 : 1);
return new OrbitStateVectorPair
{
Position = Vector3D.Multiply(unitConversionFactor, new Vector3D(x, z, y)),
Velocity = Vector3D.Multiply(unitConversionFactor, new Vector3D(xd, zd, yd))
};
}
}
}