This script calculates the position of the body as a function of time based on the formulas for mean, eccentric and true anomaly.
Since the equation for the eccentric anomaly cannot be solved algebraically, I wrote a simple numerical solver using the bisection method (RootFinder).
public class Orbiter : MonoBehaviour
{
public float period, distance, eccentricity;
public float time = 0;
private Transform Trs;
private float M, E, T, r, tmp;
private Vector2 pos = new Vector2();
private float Ecc(float X)
{
return X - eccentricity * Mathf.Sin(X) - M;
}
void Start ()
{
Trs = GetComponent<Transform>();
}
void Update ()
{
//M
M = ((time / period) * 2 * Mathf.PI) % (2 * Mathf.PI);
//E
try { E = RootFinder.Find(Ecc, 0, 2 * Mathf.PI, 1e-3f); } catch { Debug.Log("Range"); }
//T
tmp = Mathf.Cos(E);
T = Mathf.Acos(eccentricity / (tmp * eccentricity - 1) - tmp / (tmp * eccentricity - 1));
if (E > Mathf.PI) T = 2 * Mathf.PI - T;
//R
tmp = Mathf.Cos(T);
r = distance / (1 + eccentricity * tmp);
//Pos
pos.x = r * Mathf.Sin(T);
pos.y = r * tmp;
Trs.localPosition = pos;
//Time
time += Time.deltaTime;
}
}
public class RootFinder
{
public static uint maxIter = 100;
public delegate float Function(float x);
public static float Find(Function F, float A, float B, float P)
{
float
C = (A + B) / 2,
Cv = F(C),
Av = F(A),
Bv = F(B);
uint i = 0;
if (Mathf.Abs(Av) <= P) return A;
if (Mathf.Abs(Bv) <= P) return B;
if (Mathf.Sign(Av) == Mathf.Sign(Bv)) throw new Exception("Bad Interval");
while (Mathf.Abs(Cv) > P && i < maxIter)
{
if (Cv > 0)
{
if (Av > 0)
{
A = C;
Av = Cv;
}
else
{
B = C;
Bv = Cv;
}
}
else
{
if (Av > 0)
{
B = C;
Bv = Cv;
}
else
{
A = C;
Av = Cv;
}
}
C = (A + B) / 2;
Cv = F(C);
i++;
}
return C;
}
}
0 comments