// Programa para encontrar la orbita de los tres cuerpos usando matrices

//--- Librerias ---
#include <iostream>
#include <cmath>
#include <fstream>
#include <cstdio>
//-----------------

//--- Directiva de using ---
using namespace std;
//--------------------------

// --- CONSTANTE GLOBAL ---
const double pi = acos(-1.0);
const double GMs = 4 * pi * pi; // u.a.^3 / año^2 (para el Sol)[cite: 2]

// Estructura matricial para almacenar estados de los 3 cuerpos en 3D (Fila: Cuerpo, Columna: Coordenada x,y,z)
struct Matriz3x3 {
    double m[3][3];
};

struct CCeleste {
    double r[3]; // r[0]->x, r[1]->y, r[2]->z[cite: 1, 2]
    double v[3]; // v[0]->vx, v[1]->vy, v[2]->vz[cite: 1, 2]
    double m_cuerpo;
    double Periodo;

    void EulerCromer(double Dt, CCeleste Planeta[], int j, int Np)
    {
        double ax = 0.0;
        double ay = 0.0;
        double az = 0.0;

        // Suma de fuerzas gravitacionales de los demás cuerpos (Ecuación de N cuerpos)[cite: 1]
        for (int k = 0; k < Np; k++) {
            if (k == j) continue;

            double rx = r[0] - Planeta[k].r[0];
            double ry = r[1] - Planeta[k].r[1];
            double rz = r[2] - Planeta[k].r[2];
            double r2 = rx * rx + ry * ry + rz * rz;
            double r3 = r2 * sqrt(r2);

            // GM_k en función de la masa del Sol[cite: 2]
            double GMk = GMs * (Planeta[k].m_cuerpo / Planeta[0].m_cuerpo);

            ax -= (GMk * rx) / r3;
            ay -= (GMk * ry) / r3;
            az -= (GMk * rz) / r3;
        }

        v[0] += ax * Dt;
        v[1] += ay * Dt;
        v[2] += az * Dt;

        r[0] += v[0] * Dt;
        r[1] += v[1] * Dt;
        r[2] += v[2] * Dt;
    }
};

//--- Funcion principal ---
int main()
{
    const int Np = 3; // Sol (0), Tierra (1), Luna (2)[cite: 1]

    string Nombre[Np] = {"Sol", "Tierra", "Luna"};
    double Masa[Np];

    // Masas en kg[cite: 2]
    Masa[0] = 1.989E30; // Sol
    Masa[1] = 5.972E24; // Tierra
    Masa[2] = 7.342E22; // Luna

    CCeleste Planeta[Np];

    for (int j = 0; j < Np; j++) {
        Planeta[j].m_cuerpo = Masa[j];
    }

    // --- MATRICES DE CONDICIONES INICIALES SEGÚN LA GUÍA ---[cite: 2, 3]
    Matriz3x3 R_CM; // Posiciones iniciales (Sol y CM Tierra-Luna)
    Matriz3x3 V_CM; // Velocidades iniciales en au/día

    // Sol (0)
    R_CM.m[0][0] =  4.504795855674601E-3;
    R_CM.m[0][1] =  7.732544746890742E-4;
    R_CM.m[0][2] =  2.685039985573271E-4;
    V_CM.m[0][0] = -3.524457445683394E-7;
    V_CM.m[0][1] =  5.177637780672221E-6;
    V_CM.m[0][2] =  2.229113252400401E-6;

    // Tierra en CM Tierra-Luna (1)
    R_CM.m[1][0] =  1.205197129002194E-1;
    R_CM.m[1][1] = -9.258323035784091E-1;
    R_CM.m[1][2] = -4.015377611192672E-1;
    V_CM.m[1][0] =  1.681126759384403E-2;
    V_CM.m[1][1] =  1.748308899617618E-3;
    V_CM.m[1][2] =  7.582041930175932E-4;

    // Luna en CM Tierra-Luna (2)
    R_CM.m[2][0] = -8.081772358351251E-4;
    R_CM.m[2][1] = -1.994630037441996E-3;
    R_CM.m[2][2] = -1.087262721620868E-3;
    V_CM.m[2][0] =  6.010848314829119E-4;
    V_CM.m[2][1] = -1.674454691500606E-4;
    V_CM.m[2][2] = -8.556208109904861E-5;

    // --- TRANSFORMACIÓN DE MATRICES AL SISTEMA ABSOLUTO (INERCIAL) ---[cite: 3]
    double m2 = Masa[1];
    double m3 = Masa[2];
    double factor_r3 = m3 / (m2 + m3);
    double factor_r2 = m2 / (m2 + m3);

    Matriz3x3 R_Abs;
    Matriz3x3 V_Abs;

    // Sol Absoluto
    for (int k = 0; k < 3; k++) {
        R_Abs.m[0][k] = R_CM.m[0][k];
        V_Abs.m[0][k] = V_CM.m[0][k] * 365.25; // Conversión de au/día a au/año[cite: 3]
    }

    // Tierra y Luna Absolutas usando operaciones matriciales por componentes[cite: 3]
    for (int k = 0; k < 3; k++) {
        // r_2 = r_2' - [m3/(m2+m3)] * r_3'
        R_Abs.m[1][k] = R_CM.m[1][k] - factor_r3 * R_CM.m[2][k];
        V_Abs.m[1][k] = (V_CM.m[1][k] - factor_r3 * V_CM.m[2][k]) * 365.25;

        // r_3 = r_2' + [m2/(m2+m3)] * r_3'
        R_Abs.m[2][k] = R_CM.m[1][k] + factor_r2 * R_CM.m[2][k];
        V_Abs.m[2][k] = (V_CM.m[2][k] + factor_r2 * V_CM.m[2][k]) * 365.25;
    }

    // Asignar a los objetos celestes
    for (int j = 0; j < Np; j++) {
        Planeta[j].m_cuerpo = Masa[j];
        for (int k = 0; k < 3; k++) {
            Planeta[j].r[k] = R_Abs.m[j][k];
            Planeta[j].v[k] = V_Abs.m[j][k];
        }
    }

    ofstream archivos[Np];
    ofstream archivosLz[Np];

    for (int i = 0; i < Np; i++) {
        string nombre = Nombre[i] + ".dat";
        archivos[i].open(nombre);

        string nombreLz = Nombre[i] + "_Lz.dat";
        archivosLz[i].open(nombreLz);

        if (!archivos[i] || !archivosLz[i]) {
            cout << "Error al crear los archivos de salida." << endl;
            return 1;
        }
    }

    double dt = 0.001; // Paso temporal recomendado en la guía[cite: 2]
    int N_pasos = 1000;

    //===========================================================
    // SIMULACION DE LAS ORBITAS Y CALCULO DEL MOMENTO ANGULAR
    //===========================================================

    for (int j = 0; j < Np; j++) {
        double t = 0.0;
        archivos[j] << t << " " << Planeta[j].r[0] << " " << Planeta[j].r[1] << " " << Planeta[j].r[2] << "\n";

        double Lz = Planeta[j].m_cuerpo * (Planeta[j].r[0] * Planeta[j].v[1] - Planeta[j].r[1] * Planeta[j].v[0]);
        double dAdt = 0.5 * (Planeta[j].r[0] * Planeta[j].v[1] - Planeta[j].r[1] * Planeta[j].v[0]);

        archivosLz[j] << t << " " << Lz << " " << dAdt << "\n";
    }

    for (int k = 1; k <= N_pasos; k++) {
        double t = k * dt;

        // Actualizar todos los cuerpos mediante el método matricial Euler-Cromer
        for (int j = 0; j < Np; j++) {
            Planeta[j].EulerCromer(dt, Planeta, j, Np);
        }

        for (int j = 0; j < Np; j++) {
            double Lz = Planeta[j].m_cuerpo * (Planeta[j].r[0] * Planeta[j].v[1] - Planeta[j].r[1] * Planeta[j].v[0]);
            double dAdt = 0.5 * (Planeta[j].r[0] * Planeta[j].v[1] - Planeta[j].r[1] * Planeta[j].v[0]);

            archivosLz[j] << t << " " << Lz << " " << dAdt << "\n";
            archivos[j] << t << " " << Planeta[j].r[0] << " " << Planeta[j].r[1] << " " << Planeta[j].r[2] << "\n";
        }
    }

    for (int j = 0; j < Np; j++) {
        Planeta[j].Periodo = N_pasos * dt;
        archivos[j].close();
        archivosLz[j].close();

        cout << "Cuerpo: " << Nombre[j] << endl;
        cout << "Tiempo simulado: " << Planeta[j].Periodo << " años" << endl;
        cout << "-----------------------------------" << endl;
    }

    //===========================================================
    // GRAFICAS CON GNUPLOT
    //===========================================================

    FILE* gnuplotPipe = popen("gnuplot", "w");

    if (gnuplotPipe != nullptr) {
        fprintf(gnuplotPipe, "set terminal pngcairo size 800,800 font 'Arial,12'\n");
        fprintf(gnuplotPipe, "set grid\n");
        fprintf(gnuplotPipe, "set zeroaxis lt 1 lc rgb 'gray' lw 1\n");

        for (int j = 0; j < Np; j++) {
            string archivoPNG = Nombre[j] + "_orbita3D.png";
            string archivoDAT = Nombre[j] + ".dat";

            fprintf(gnuplotPipe, "set output '%s'\n", archivoPNG.c_str());
            fprintf(gnuplotPipe, "set title 'Orbita Tridimensional de %s'\n", Nombre[j].c_str());
            fprintf(gnuplotPipe, "set xlabel 'Posicion X (u.a.)'\n");
            fprintf(gnuplotPipe, "set ylabel 'Posicion Y (u.a.)'\n");
            fprintf(gnuplotPipe, "set zlabel 'Posicion Z (u.a.)'\n");
            // Gráfica 3D solicitada en la guía usando splot[cite: 3]
            fprintf(gnuplotPipe, "splot '%s' using 2:3:4 with lines lw 2 lc rgb '#1f77b4' title 'Trayectoria'\n", archivoDAT.c_str());

            cout << "Grafica '" << archivoPNG << "' generada." << endl;
        }

        fprintf(gnuplotPipe, "unset output\n");
        pclose(gnuplotPipe);

        cout << "\nTodas las graficas se han generado correctamente." << endl;
    } else {
        cerr << "No se pudo conectar con Gnuplot." << endl;
    }

    return 0;
}

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: