public void Set() { if (parent.ActiveText != this.name.Text && parent.Active != -1) { var elements = new Structures.OrbitalElements() { semilatusrectum = SLRScale.Value * AU, eccentricity = EScale.Value, inclination = IncScale.Value * deg, ascendingNodeLongitude = ANLScale.Value * deg, periapsisArgument = PAScale.Value * deg, trueAnomaly = TAScale.Value * deg }; body = new Structures.Body(menu.new_bodies.FirstOrDefault(b => b.body.name == parent.ActiveText).body, elements); } body.name = this.name.Text; body.stdGrav = Math.Pow(Math.E, MassScale.Value) * G * 1e22; body.radius = RadiusScale.Value * 1e3; body.color = new Vector3(RScale.Value, GScale.Value, BScale.Value); }
} // paramaterless constructor for serialisation public Body(Body parent, OrbitalElements elements) { // First check the values are reasonable. If parent == null it is assumed that // position and velocity are set explicitly, and this constructor is not used if (parent == null) { return; } this.parent = parent; if (elements.eccentricity < 0 || elements.semilatusrectum < 0 || elements.inclination < 0 || elements.inclination > Math.PI || elements.ascendingNodeLongitude < 0 || elements.ascendingNodeLongitude >= 2 * Math.PI || elements.periapsisArgument < 0 || elements.periapsisArgument >= 2 * Math.PI || elements.trueAnomaly < 0 || elements.trueAnomaly >= 2 * Math.PI ) { // Throw an exception if the arguments are out of bounds throw new ArgumentException(); } // working in perifocal coordinates (periapsis along the x axis, orbit in the x,y plane): double mag_peri_radius = elements.semilatusrectum / (1 + elements.eccentricity * Math.Cos(elements.trueAnomaly)); Vector3 peri_radius = mag_peri_radius * new Vector3(Math.Cos(elements.trueAnomaly), Math.Sin(elements.trueAnomaly), 0); Vector3 peri_velocity = Math.Sqrt(parent.stdGrav / elements.semilatusrectum) * new Vector3( -Math.Sin(elements.trueAnomaly), Math.Cos(elements.trueAnomaly) + elements.eccentricity, 0 ); // useful constants to setup transformation matrix var sini = Math.Sin(elements.inclination); // i <- inclination var cosi = Math.Cos(elements.inclination); var sino = Math.Sin(elements.ascendingNodeLongitude); // capital omega <- longitude of ascending node var coso = Math.Cos(elements.ascendingNodeLongitude); var sinw = Math.Sin(elements.periapsisArgument); // omega <- argument of periapsis var cosw = Math.Cos(elements.periapsisArgument); // Transform perifocal coordinates to i,j,k coordinates Matrix3 transform = new Matrix3( new Vector3( coso * cosw - sino * sinw * cosi, -coso * sinw - sino * cosw * cosi, sino * sini ), new Vector3( sino * cosw + coso * sinw * cosi, -sino * sinw + coso * cosw * cosi, -coso * sini ), new Vector3( sinw * sini, cosw * sini, cosi ) ); // add the parent's position and velocity since that could be orbiting something too this.position = transform * peri_radius + parent.position; this.velocity = transform * peri_velocity + parent.velocity; }
public static bool BodyTest() { var sun = new Body { stdGrav = 1.3271440019e20, radius = 6.95e8 }; var elem = new OrbitalElements() { semilatusrectum = 3.2 * AU, eccentricity = 0.7, inclination = 1.2, ascendingNodeLongitude = 0.1, periapsisArgument = 4.3, trueAnomaly = 3.7 }; Body sun2 = (Body)sun.Clone(); sun2.position += new Vector3(3, 2, 6); sun2.velocity += new Vector3(1, 5, 3); var e1 = new Body(sun, elem); var e2 = new Body(sun2, elem); e2.position -= new Vector3(3, 2, 6); e2.velocity -= new Vector3(1, 5, 3); if (e1.position != e2.position || e1.velocity != e2.velocity) { Console.WriteLine("Parent r/v not considered"); return(false); } for (double i = 0; i < Math.PI; i += 0.2) { for (double j = 0; j < 2 * Math.PI; j += 0.2) { for (double k = 0; k < 2 * Math.PI; k += 0.2) { for (double l = 0; l < 2 * Math.PI; l += 0.2) { for (double m = 0; l < 1; l += 0.1) { var earthElements = new OrbitalElements() { semilatusrectum = 1 * AU, eccentricity = m, inclination = i, ascendingNodeLongitude = j, periapsisArgument = k, trueAnomaly = l }; var earth = new Body(sun, earthElements) { stdGrav = 3.986004419e14, radius = 6.371e6, color = new Vector3(0, 0.2, 0.8), }; if (m == 0) { if (!(Math.Abs(Vector3.Magnitude(earth.velocity) - 3e4) < 1e3)) { Console.WriteLine($"{i},{j},{k},{l},{earth.velocity}"); return(false); } else if (!(Math.Abs(Vector3.Magnitude(earth.position) - 1 * AU) < 1e-4)) { Console.WriteLine($"{i},{j},{k},{l},{Vector3.Magnitude(earth.position)/AU}"); return(false); } } var earthElements2 = new OrbitalElements(earth.position, earth.velocity, sun.stdGrav); foreach (Tuple <string, double, double> t in new List <Tuple <string, double, double> >() { new Tuple <string, double, double>("l", earthElements.ascendingNodeLongitude, earthElements2.ascendingNodeLongitude), new Tuple <string, double, double>("e", earthElements.eccentricity, earthElements2.eccentricity), new Tuple <string, double, double>("i", earthElements.inclination, earthElements2.inclination), new Tuple <string, double, double>("w", earthElements.periapsisArgument, earthElements2.periapsisArgument), new Tuple <string, double, double>("p", earthElements.semilatusrectum, earthElements2.semilatusrectum), new Tuple <string, double, double>("v", earthElements.trueAnomaly, earthElements2.trueAnomaly), }) { if ((t.Item2 - t.Item3) / t.Item2 > 1e-6) { if (t.Item1 == "l" && i == 0 || (t.Item1 == "w" || t.Item1 == "v") && m == 0) { // They are undefined, don't worry continue; } Console.WriteLine($"Orbital element test failed: {t.Item1}, {t.Item2}, {t.Item3}, {((t.Item2 - t.Item3)/t.Item2)*100}%"); return(false); } } } } } } } var elemx = new OrbitalElements() { inclination = 2 * Math.PI, ascendingNodeLongitude = 7.5 * Math.PI, trueAnomaly = 27 * Math.PI, periapsisArgument = 3.75 * Math.PI }; if ( elemx.inclination > 1e-10 || (elemx.ascendingNodeLongitude - (1.5 * Math.PI)) / (1.5 * Math.PI) > 1e-10 || (elemx.trueAnomaly - Math.PI) / Math.PI > 1e-10 || (elemx.periapsisArgument - 1.75 * Math.PI) / (1.75 * Math.PI) > 1e-10 ) { Console.WriteLine("Implicit angle readjustment failed"); Console.WriteLine(elemx.trueAnomaly / Math.PI); } return(true); }