Planetary Motion Source Code

This code is from my demo Android app offering a tutorial in coding Keppler's first two laws in Java for Android. The snippet here is intended to be read with the truly excellent work of Jean Meeus in his book, which I strongly recommend to anyone with an interest in astronomy and computing.

Feel free to use this code for any purpose. I don't guarantee it works. The code isn't written for speed or efficiency, just so it works and you can see what is going on. Feel free to improve it.

Keppler

Mr Keppler. What a guy. Also, Jean Meeus. I thank you both. In Meeus's book, chapter 30, he describes the process of "calculating the position of a body (planet, minor planet or periodic comet) on its elliptical orbit around the Sun at a given instant ... from the orbital elements of the body".

My notes here do not teach you all about this topic - you go and do the work yourself, following Mr Meeus. My code here is just one way of calculating the position of the body, according to Meeus's description.

I'm assuming you know how to create an Android app, know Java and have a copy of his book.

This is my method for drawing the planet at the 'next' position in the orbit. Think of the steps like stepping round a circle, one degree at a time, on a circle which has the same period as the planet you are trying to track. Outside of this method I use a global double as the step counter - called dTime, which contains a number of degrees of rotation.

The key parameters passed to the method are, dEccentricty, dScalar (a scaling factor so the orbit all fits on the display), dYear (the duration of the orbit in Earth years) and to orient the orbit so that perihelion is at the right place on the dial, so to speak, dLongPeri - the Longitude of Perihelion.

```public void drawPlanet (double dEccentricity, double dScalar, double dYear, Canvas canvas, Paint paint,
String sName, Bitmap bmp, double dLongPeri)
{
double dE, dr, dv, dSatX, dSatY, dSatXCorrected, dSatYCorrected;
float fX, fY;
int iSunXOffset = getWidth() / 2;
int iSunYOffset = getHeight() / 2;

// get the value of E from the angle travelled in this 'tick'

dE = getE (dTime * (1 / dYear), dEccentricity);

// get r: the length of 'radius' vector

dr = getRfromE (dE, dEccentricity, dScalar);

// calculate v - the true anomaly

dv = 2 * Math.atan (
Math.sqrt((1 + dEccentricity) / (1 - dEccentricity))
*
Math.tan(dE / 2)
);

// get X and Y coords based on the origin

dSatX = dr / Math.sin(Math.PI / 2) * Math.sin(dv);
dSatY = Math.sin((Math.PI / 2) - dv) * (dSatX / Math.sin(dv));

// now correct for Longitude of Perihelion for this planet

dSatXCorrected = dSatX * (float)Math.cos (Math.toRadians(dLongPeri)) -
dSatYCorrected = dSatX * (float)Math.sin (Math.toRadians(dLongPeri)) +

// offset the origin to nearer the centre of the display

fX = (float)dSatXCorrected + (float)iSunXOffset;
fY = (float)dSatYCorrected + (float)iSunYOffset;

if (bDrawOrbits)
{
// draw the path of the orbit travelled
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);

// get the size of the rect which encloses the elliptical orbit

dE = getE (0.0, dEccentricity);
dr = getRfromE (dE, dEccentricity, dScalar);
rectOval.bottom = (float)dr;
dE = getE (180.0, dEccentricity);
dr = getRfromE (dE, dEccentricity, dScalar);
rectOval.top = (float)(0 - dr);

// calculate minor axis from major axis and eccentricity
// http://www.1728.org/ellipse.htm

double dMajor = rectOval.bottom - rectOval.top;
double dMinor = Math.sqrt(1 - (dEccentricity * dEccentricity)) * dMajor;

rectOval.left = 0 - (float)(dMinor / 2);
rectOval.right = (float)(dMinor / 2);

rectOval.left += (float)iSunXOffset;
rectOval.right += (float)iSunXOffset;
rectOval.top += (float)iSunYOffset;
rectOval.bottom += (float)iSunYOffset;

// now correct for Longitude of Perihelion for this orbit's path

canvas.save();
canvas.rotate((float)dLongPeri, (float)iSunXOffset, (float)iSunYOffset);
canvas.drawOval(rectOval, paint);
canvas.restore();
}

int iBitmapHeight = bmp.getHeight();

canvas.drawBitmap(bmp, fX - (iBitmapHeight / 2), fY - (iBitmapHeight / 2), null);

// draw planet label

myPaint.setColor(Color.WHITE);
paint.setTextSize(30);
canvas.drawText(sName, fX+20, fY-20, paint);
}

```

The method above calls two further methods which provide values of E (the mean anomaly) and r, the length of the vector at the end of which the planet is found. Check out the equation numbers and line numbers in Meeus's Basic program on page 206:

```    public double getE (double dTime, double dEccentricity)
{
// we are passed the degree count in degrees (duh)
// and the eccentricity value
// the method returns E

double dM1, dD, dE0, dE = 0; // return value E = the mean anomaly
double dM; // local value of M in radians

int iSign = 1;

if (dM > 0) iSign = 1; else iSign = -1;

dM = Math.abs(dM) / (2 * Math.PI); // Meeus, p 206, line 110
dM = (dM - (long)dM) * (2 * Math.PI) * iSign; // line 120
if (dM < 0)
dM = dM + (2 * Math.PI); // line 130
iSign = 1;
if (dM > Math.PI) iSign = -1; // line 150
if (dM > Math.PI) dM = 2 * Math.PI - dM; // line 160

dE0 = Math.PI / 2; // line 170
dD = Math.PI / 4; // line 170

for (int i = 0; i < 33; i++) // line 180
{
dM1 = dE0 - dEccentricity * Math.sin(dE0); // line 190
dE0 = dE0 + dD * Math.signum((float)(dM - dM1));
dD = dD / 2;
}

dE = dE0 * iSign;

return dE;
}

```

And once you have E, you need the length of the vector r:

```public double getRfromE (double dE, double dEccentricty, double dScalar)
{
return Math.min(getWidth(), getHeight()) / 2 * dScalar * (1 - (dEccentricty * Math.cos(dE)));
}
```

If you would like the entire source code of my app, go here.