//--------------------------------------------------------------------- // //--------------------------------------------------------------------- public void get_ecliptic_coords(double theta, ref EclipticPos ecoords) { double Omega = data.orbit.Omega * math.RAD; double omega = data.orbit.omega * math.RAD; double i = data.orbit.i * math.RAD; double V = theta; ecoords.beta = Math.Asin(Math.Sin(i) * Math.Sin(omega + V)); double sin_lambda = (Math.Sin(Omega) * Math.Cos(V + omega) + Math.Cos(Omega) * Math.Cos(i) * Math.Sin(V + omega)) / Math.Cos(ecoords.beta); double cos_lambda = (Math.Cos(Omega) * Math.Cos(V + omega) - Math.Sin(Omega) * Math.Cos(i) * Math.Sin(V + omega)) / Math.Cos(ecoords.beta); ecoords.lambda = math.arg(sin_lambda, cos_lambda); }
//--------------------------------------------------------------------- // Cartesian system position of body //--------------------------------------------------------------------- public Vector3D get_cartesian_pos(double theta) { double r = 0; double e = data.orbit.e; if ( (e > -1) && (e < 1) ) r = data.orbit.a * (1 - e * e) / (1 + e * Math.Cos(theta)); if (e == 1) r = 2 * data.orbit.a / (1 + e * Math.Cos(theta)); if (e > 1) r = data.orbit.a * (e*e - 1) / (1 + e * Math.Cos(theta)); EclipticPos epos = new EclipticPos(); get_ecliptic_coords(theta, ref epos); double x = r * Math.Cos(epos.beta) * Math.Cos(epos.lambda); double y = r * Math.Cos(epos.beta) * Math.Sin(epos.lambda); ; double z = r * Math.Sin(epos.beta); return new Vector3D(x, y, z); }
//--------------------------------------------------------------------- // //--------------------------------------------------------------------- public static double LambdaErr(double t, CelestialBody arivBody, CelestialBody destBody, double phi) { Orbit orbit = new Orbit(); double destLambda = 0; double transTime = get_transfer_orbit(t, arivBody, destBody, phi, ref orbit, ref destLambda); OrbitPos pos = new OrbitPos(); EclipticPos epos = new EclipticPos(); destBody.get_position(t + transTime, ref pos); destBody.get_ecliptic_coords(pos.theta, ref epos); return get_phase(epos.lambda - destLambda); }
//--------------------------------------------------------------------- // Get transfer orbit //--------------------------------------------------------------------- public static double get_transfer_orbit(double t, CelestialBody depBody, CelestialBody arrivBody, double phi, ref Orbit orbit, ref double destLambda) { // Is bodies has same reference body if (depBody.get_ref_body() != arrivBody.get_ref_body()) return -1; OrbitPos pos = new OrbitPos(); EclipticPos epos = new EclipticPos(); depBody.get_position(t, ref pos); depBody.get_ecliptic_coords(pos.theta, ref epos); destLambda = epos.lambda + Math.PI - phi; destLambda = math.Trunc2PiN(destLambda); double destTheta = get_dest_theta(arrivBody, destLambda); Vector3D x1 = depBody.get_cartesian_pos(pos.theta); Vector3D x2 = arrivBody.get_cartesian_pos(destTheta); double u = 0; get_transfer_orientation(x1, x2, ref orbit.i, ref orbit.Omega, ref u); double r1 = x1.lenght(); double r2 = x2.lenght(); orbit.omega = u / math.RAD; BodyData data = new BodyData(); arrivBody.get_data(ref data); double transTime = 0; double mu = depBody.get_refGravParameter(); double E = 0; double theta = 0; theta = x1.angle(x2); orbit.e = (r2 - r1) / (r1 - r2 * Math.Cos(theta)); if ( (orbit.e > - 1) && (orbit.e < 1) ) { orbit.a = r1 / (1 - orbit.e); double n = Math.Sqrt(mu / orbit.a) / orbit.a; double tgE2 = Math.Sqrt((1 - orbit.e) / (1 + orbit.e)) * Math.Tan(theta / 2); E = 2 * Math.Atan(tgE2); double M = E - orbit.e * Math.Sin(E); transTime = M / n; } if (orbit.e == 1) { orbit.a = 2*r1; transTime = r1*Math.Sqrt(2*r1/mu)*(Math.Tan(theta/2) + Math.Pow(Math.Tan(theta/2), 3)/3); } if (orbit.e > 1) { orbit.a = r1 / (orbit.e - 1); double n = Math.Sqrt(mu / orbit.a) / orbit.a; double thE2 = Math.Sqrt((orbit.e - 1) / (orbit.e + 1)) * Math.Tan(theta / 2); double H = Math.Log((1 + thE2) / (1 - thE2)); double M = orbit.e * Math.Sinh(H) - H; transTime = M / n; } return transTime; }
//--------------------------------------------------------------------- // //--------------------------------------------------------------------- void DrawTransOrbit(Panel panel, Transfer trans, CelestialBody arivBody, CelestialBody destBody, CelestialBody craft) { Graphics graph = panel.CreateGraphics(); graph.Clear(Color.Black); Pen pen = new Pen(Color.LightGray, 2.0F); int width = panel.Width; int height = panel.Height; float x0 = width / 2; float y0 = height / 2; float x = 0; float y = 0; float x1 = 0; float y1 = 0; float x2 = 0; float y2 = 0; double scale = 0; int Delta = 25; BodyData ariv_data = new BodyData(); BodyData dest_data = new BodyData(); arivBody.get_data(ref ariv_data); destBody.get_data(ref dest_data); double ariv_ra = ariv_data.orbit.a / (1 - ariv_data.orbit.e); double dest_ra = dest_data.orbit.a / (1 - dest_data.orbit.e); double r_max = 0; if (ariv_ra > dest_ra) r_max = ariv_ra; else r_max = dest_ra; if (width > height) { scale = (height / 2 - Delta) / r_max; } else { scale = (width / 2 - Delta) / r_max; } // Arrive Body orbit Vector3D pos; OrbitPos orbit_pos = new OrbitPos(); double V0 = 0; double V = V0; double V1 = 360.0; double dV = 5.0; while (V <= V1) { pos = arivBody.get_cartesian_pos(V * RAD); x1 = x0 + Convert.ToSingle(scale * pos.x); y1 = y0 - Convert.ToSingle(scale * pos.y); V += dV; pos = arivBody.get_cartesian_pos(V * RAD); x2 = x0 + Convert.ToSingle(scale * pos.x); y2 = y0 - Convert.ToSingle(scale * pos.y); if (pos.z >= 0) pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; else pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; graph.DrawLine(pen, x1, y1, x2, y2); } // Departure Body orbit V0 = 0; V = V0; V1 = 360.0; dV = 5.0; while (V <= V1) { pos = destBody.get_cartesian_pos(V * RAD); x1 = x0 + Convert.ToSingle(scale * pos.x); y1 = y0 - Convert.ToSingle(scale * pos.y); V += dV; pos = destBody.get_cartesian_pos(V * RAD); x2 = x0 + Convert.ToSingle(scale * pos.x); y2 = y0 - Convert.ToSingle(scale * pos.y); if (pos.z >= 0) pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; else pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; graph.DrawLine(pen, x1, y1, x2, y2); } V0 = 0; V = V0; V1 = Lambert.get_dest_theta(craft, trans.destLambda) / RAD; dV = 5.0; pen.Color = Color.Red; do { pos = craft.get_cartesian_pos(V * RAD); x1 = x0 + Convert.ToSingle(scale * pos.x); y1 = y0 - Convert.ToSingle(scale * pos.y); V += dV; pos = craft.get_cartesian_pos(V * RAD); x2 = x0 + Convert.ToSingle(scale * pos.x); y2 = y0 - Convert.ToSingle(scale * pos.y); if (pos.z >= 0) pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; else pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; graph.DrawLine(pen, x1, y1, x2, y2); } while (V <= V1); // Destination body position SolidBrush brush = new SolidBrush(Color.Blue); // Draw Planets at departure date float radius = 5.0F; destBody.get_position(trans.arrivTime, ref orbit_pos); pos = destBody.get_cartesian_pos(orbit_pos.theta); x = x0 + Convert.ToSingle(scale * pos.x); y = y0 - Convert.ToSingle(scale * pos.y); float x5 = x; float y5 = y; graph.FillEllipse(brush, x - radius, y - radius, 2 * radius, 2 * radius); arivBody.get_position(trans.arrivTime, ref orbit_pos); pos = arivBody.get_cartesian_pos(orbit_pos.theta); x = x0 + Convert.ToSingle(scale * pos.x); y = y0 - Convert.ToSingle(scale * pos.y); graph.FillEllipse(brush, x - radius, y - radius, 2 * radius, 2 * radius); brush.Color = Color.Red; // Draw Planets at arrival date destBody.get_position(trans.depTime, ref orbit_pos); pos = destBody.get_cartesian_pos(orbit_pos.theta); x = x0 + Convert.ToSingle(scale * pos.x); y = y0 - Convert.ToSingle(scale * pos.y); graph.FillEllipse(brush, x - radius, y - radius, 2 * radius, 2 * radius); arivBody.get_position(trans.depTime, ref orbit_pos); pos = arivBody.get_cartesian_pos(orbit_pos.theta); x = x0 + Convert.ToSingle(scale * pos.x); y = y0 - Convert.ToSingle(scale * pos.y); float x3 = x; float y3 = y; EclipticPos epos = new EclipticPos(); arivBody.get_ecliptic_coords(orbit_pos.theta, ref epos); epos.lambda += Math.PI; double opos_theta = Lambert.get_dest_theta(destBody, epos.lambda); pos = destBody.get_cartesian_pos(opos_theta); float x4 = x0 + Convert.ToSingle(scale * pos.x); float y4 = y0 - Convert.ToSingle(scale * pos.y); graph.FillEllipse(brush, x - radius, y - radius, 2 * radius, 2 * radius); // Draw Psi angle pen.Color = Color.LightGray; pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot; pen.Width = 1.0F; graph.DrawLine(pen, x3, y3, x4, y4); graph.DrawLine(pen, x0, y0, x5, y5); // float sunRadius = 10.0F; if (ariv_data.refBody == "Sun") brush.Color = Color.Yellow; else brush.Color = Color.Blue; graph.FillEllipse(brush, x0 - sunRadius, y0 - sunRadius, 2 * sunRadius, 2 * sunRadius); }
//----------------------------------------------------------- // //----------------------------------------------------------- private void DrawPlanet(Panel panel, double theta, int body_idx) { int width = panel.Width; int height = panel.Height; float x0 = width / 2; float y0 = height / 2; float x = 0; float y = 0; Graphics graph = panel.CreateGraphics(); graph.Clear(Color.Black); Pen myPen = new Pen(Color.LightGray, 2.0F); // Draw trajectory double scale = 0; int Delta = 25; float delta = 5.0F; BodyData data = new BodyData(); Bodies[body_idx].get_data(ref data); int kerbin_idx = get_body_index("Kerbin"); OrbitPos kerbin_pos = new OrbitPos(); double t = KCalendar.date_to_sec(int.Parse(textYear.Text.ToString()), int.Parse(comboDay.Text.ToString()), int.Parse(comboHour.Text.ToString()), int.Parse(comboMin.Text.ToString()), int.Parse(comboSec.Text.ToString())); Bodies[kerbin_idx].get_position(t, ref kerbin_pos); EclipticPos kerbin_epos = new EclipticPos(); Bodies[kerbin_idx].get_ecliptic_coords(kerbin_pos.theta, ref kerbin_epos); double ra = data.orbit.a / (1 - data.orbit.e); double r_max = ra; float r0 = 0; if (width > height) { scale = (height / 2 - Delta) / r_max; r0 = height / 2 - Delta; } else { scale = (width / 2 - Delta) / r_max; r0 = width / 2 - Delta; } double V = 0; double dV = 5.0; Vector3D pos; // Draw planet orbit while (V <= 360.0) { pos = Bodies[body_idx].get_cartesian_pos(V * RAD); float x1 = x0 + Convert.ToSingle(scale * pos.x); float y1 = y0 - Convert.ToSingle(scale * pos.y); V += dV; pos = Bodies[body_idx].get_cartesian_pos(V * RAD); float x2 = x0 + Convert.ToSingle(scale * pos.x); float y2 = y0 - Convert.ToSingle(scale * pos.y); if (pos.z >= 0) myPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; else myPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; graph.DrawLine(myPen, x1, y1, x2, y2); } // Draw planet position pos = Bodies[body_idx].get_cartesian_pos(theta); EclipticPos epos = new EclipticPos(); Bodies[body_idx].get_ecliptic_coords(theta, ref epos); double phi = Lambert.get_phase(epos.lambda - kerbin_epos.lambda) / RAD; x = x0 + Convert.ToSingle(scale * pos.x); y = y0 - Convert.ToSingle(scale * pos.y); myPen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot; graph.DrawLine(myPen, x0, y0, x, y); // Title SolidBrush brush = new SolidBrush(Color.LightGray); Font font = new Font("Courier New", 10); string title = data.name + " position UT: " + textYear.Text + "y " + comboDay.Text + "d " + comboHour.Text + "h " + comboMin.Text + "m " + comboSec.Text + "s"; graph.DrawString(title, font, brush, delta, delta); graph.DrawString("\u03b2 = " + Math.Round(epos.beta / RAD, 4).ToString(), font, brush, delta, delta + font.Height); graph.DrawString("\u03bb = " + Math.Round(epos.lambda / RAD, 4).ToString(), font, brush, delta, delta + 2*font.Height); graph.DrawString("Kerbin phase: " + Math.Round(phi, 4).ToString(), font, brush, delta, height - delta - font.Height); graph.DrawString("\u03b8 = " + Math.Round(Bodies[body_idx].get_rotation_angle(t), 4).ToString(), font, brush, delta, delta + 3 * font.Height); // Draw Ref Body myPen.Color = Color.Yellow; float sunRadius = 10.0F; if (data.refBody == "Sun") brush.Color = Color.Yellow; else brush.Color = Color.Blue; graph.FillEllipse(brush, x0 - sunRadius, y0 - sunRadius, 2*sunRadius, 2*sunRadius); // Draw Planet float radius = 5.0F; brush.Color = Color.Green; graph.FillEllipse(brush, x - radius, y - radius, 2 * radius, 2 * radius); // Draw Kerbin direction myPen.Color = Color.Red; myPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; x = x0 + r0 * Convert.ToSingle(Math.Cos(kerbin_epos.lambda)); y = y0 - r0 * Convert.ToSingle(Math.Sin(kerbin_epos.lambda)); graph.DrawLine(myPen, x0, y0, x, y); }
//----------------------------------------------------------- // //----------------------------------------------------------- private void buttonEphCalc_Click(object sender, EventArgs e) { int body_idx = get_body_index(BodiesList.Text.ToString()); if (body_idx == -1) { MessageBox.Show("There are no " + BodiesList.Text.ToString() + " in data base"); return; } double t = KCalendar.date_to_sec(int.Parse(textYear.Text.ToString()), int.Parse(comboDay.Text.ToString()), int.Parse(comboHour.Text.ToString()), int.Parse(comboMin.Text.ToString()), int.Parse(comboSec.Text.ToString())); OrbitPos pos = new OrbitPos(); EclipticPos ecoords = new EclipticPos(); Bodies.ElementAt(body_idx).get_position(t, ref pos); Bodies.ElementAt(body_idx).get_ecliptic_coords(pos.theta, ref ecoords); labelTrueAnomaly.Text = Math.Round(pos.theta / RAD, 4).ToString() + " deg"; labelRadiusVector.Text = Math.Round(pos.r, 0).ToString() + " m"; labelEccAnomaly.Text = Math.Round(pos.E, 4).ToString() + " rad"; labelLat.Text = Math.Round(ecoords.beta / RAD, 4).ToString() + " deg"; labelLon.Text = Math.Round(ecoords.lambda / RAD, 4).ToString() + " deg"; labelAltitude.Text = Math.Round(pos.refAltitude, 0).ToString() + " m"; DrawPlanet(panelBodyPos, pos.theta, body_idx); }