//////////////////////////////////////////////////////////////////// /// OrbitingBody.cs /// © 2005 Carl Johansen /// /// Base class for orbiting-body classes. /// /// OrbitingBody implements simplified orbits, so it ignores some of the quantities that /// are normally used to describe orbits. /// * It assumes that the orbit stays in the ecliptic plane, so inclination is zero. /// * It does not implement the concept of longitude. /// /// It uses the following properties to describe the orbit: /// Semi-Major Axis, a [ = half the major axis distance, i.e. the body's mean distance from its primary (the Sun) ] /// Eccentricity, e (non-circular orbits only) [ = ratio of the distance between the foci to the length of the major axis ] /// Period, P [ = time to complete one revolution ] /// True Anomaly, v [ = angular distance of a point in an orbit past the point of periapsis ] /// Days Elapsed [ = the number of days since the body started orbiting ] /// /// The unit of measure for distance is the Astronomical Unit (AU) - the mean distance between the Earth and the Sun. /// The unit of measure for time is Earth days. //////////////////////////////////////////////////////////////////// using System; using System.Drawing; namespace CarlInc.Demos.Hohmann { /// /// Base class for orbiting-body classes. /// public class OrbitingBody { private int orbitalPeriodDays; private double semiMajorAxis; private int daysElapsed; private double currX, currY; public PointF GetCurrXY() { return new PointF((float) currX, (float) currY); } public virtual double SemiMajorAxis { get { return semiMajorAxis ; } set { semiMajorAxis = value; //For body orbiting the sun, Period (in years) equals sqrt(a ^ 3) (a in AU) orbitalPeriodDays = (int) (Math.Sqrt(semiMajorAxis * semiMajorAxis * semiMajorAxis) * 365); } } public int OrbitalPeriod { get { return orbitalPeriodDays ; } } /// /// The angle between the body and the sun (in radians). /// The base method returns the angle for circular orbits, which is simply the /// percentage of the period completed gives the percentage of the circle covered /// (therefore, by definition, angle at start of simulation = zero) /// public virtual double GetTrueAnomaly() { return ((double) (GetDaysElapsed() % OrbitalPeriod) / OrbitalPeriod) * 2 * Math.PI; } public int GetDaysElapsed() { return daysElapsed; } /// /// Returns a rectangle that bounds the orbit ellipse. The base method simply returns a square /// centered on (0, 0) whose side length is the orbit's major axis length. /// public virtual RectangleF OrbitBoundingRectUnrotated { get { return new RectangleF((float) (-1 * semiMajorAxis), (float) (-1 * -semiMajorAxis),(float) (2 * semiMajorAxis),(float) (2 * semiMajorAxis)); } } /// /// Returns the distance from the primary to the body at its current position. The base method /// simply returns the semi-major axis length (which will always be the correct current radius /// if the orbit is circular) /// public virtual double CurrentRadius(double bodyOffsetAngle) { return semiMajorAxis; } public void Init() { daysElapsed = 0; GetCurrPos(); } /// /// Move the body on in its orbit by one day and update the (x,y) position. /// Returns the new true anomaly of the body (in radians). /// public double AdvanceOneDay() { daysElapsed++; return GetCurrPos(); } private double GetCurrPos() { double bodyOffsetAngle = GetTrueAnomaly(); double currRadius = CurrentRadius(bodyOffsetAngle); // since the sun is at (0,0) in our reference frame, we have easy formulae for (x,y) currX = -1 * currRadius * Math.Sin(bodyOffsetAngle); currY = -1 * currRadius * Math.Cos(bodyOffsetAngle); return(bodyOffsetAngle); } } }