| Earth Observation Mission CFI Software Usage Guide for Object Oriented Software |

# COORDINATE TRANSFORMATIONS

The Earth Observation CFI software provides the following classes in [LIB_SUM]for handling coordinate systems and object state vectors:

- Topocentric:It contais a set of topocentric coordinates in term of azimuth, elevation, range and its derivatives.
- Geodetic: It contains a set of geodetic coordinates (longitude, latitude, altitude and its derivatives).
  This class provides a method to compute the distance between two geodetic points.
- Kepler: It contains the keplerian elements (mean or osculating) for the satellite vector
- Coord: It contains a set of cartesian coordinates for a position, velocity and acceleration vectors in a given CS. This class allows the following operations:
  - Transform between cartesian and geodetic coordinates.
  - Transform between cartesian and keplerian elements.
  - Get spherical coordianates (RA and decliantion)
  - Transform between cartesian and topocentric coordinates

- StateVector: It contatins a set of coordinates (as a Coord object) assciated to a time (as a Time object). This class allows the following operations:

  - Transform between different coordinate systems.
  - Get Sun, Moon or a Planet coordinates for a given time.
  - Get the true latitude for the satellite position.

- StarData: It contains the position and velocity of an star in term of RA, Declination, parallax and proper motion. It allows:
  - transformation to cartesian coordinates as a Coord object.
  - to get the position of the star at a given time
  - to get the star coordinates in a new star catalogue.

Together with these classes, the change method for the Attitude class (in Pointing Library) allows to transform between two reference frames, including satellite or instrument attitude CS. This CS change can include the translation between the frames or only the rotation. For more info about how to set the Attitude go to Attitude computation.

## Example

    // ------------------------------------------------------------------------
    //
    //                           C++ Example Program.
    //                           COORDINATES
    //
    // ------------------------------------------------------------------------

    // Non-EOCFI include files
    #include <string>
    #include <vector>
    #include <iostream>

    // EOCFI includes
    #include "CfiError.h"
    #include "LibData.h"
    #include "TimeCorrelation.h"
    #include "EETime.h"
    #include "Coord.h"
    #include "StateVector.h"
    #include "Star.h"
    #include "SatId.h"
    #include "Geodetic.h"
    #include "LibFunc.h"
    #include "ModelId.h"

    // Namespaces
    using namespace EECFI;
    using namespace std;

    // Main program
    int main (int argc, char *argv[])
    {
      //-------------------------------------------------
      //-------------------------------------------------

      try
      {
        ModelId modelId;

        // ------------------------------------------------------------------------
        // Time references initialization
        // ------------------------------------------------------------------------

        double initTime[4];

        initTime[0] = -245.1000000000000000;   // TAI time [days]
        initTime[1] = -245.0995949074074074;   // UTC time [days] (= TAI - 35.0 s)
        initTime[2] = -245.0995879629629630;   // UT1 time [days] (= TAI - 35.6 s)
        initTime[3] = -245.0997800925925926;   // GPS time [days] (= TAI - 19.0 s)

        // Construct the TimeCorrelation object
        TimeCorrelation timeCorr(initTime);

        // ------------------------------------------------------------------------
        //  Transform cartesian coordinates.
        // ------------------------------------------------------------------------

        cout << "\n\nState vector: Change of reference frame" << endl;

        Time t(timeCorr, -2456.0, XLCFI_TIME_TAI);

        double efPos[3] = {4859964.138, -5265612.059, 0.002};
        double efVel[3] = {-1203.303801, -1098.845511, 7377.224410};
        double efAcc[3] = {0.0, 0.0, 0.0};

        Coord efCoord(XLCFI_CS_EF, XLCFI_DER_2ND, efPos, efVel, efAcc);

        StateVector efVector(t, efCoord);

        // Change From GM2000 to MOD
        StateVector todVector = efVector.change(modelId, XLCFI_DER_2ND, XLCFI_CS_TOD);

        cout << "Input state vector:" << endl;
        cout << "   Time = " << efVector.time.time << " ref= " << efVector.time.ref << endl;
        cout << "   Position (EF)    : " << efVector.coord.pos[0] << efVector.coord.pos[1] << efVector.coord.pos[2] << endl;
        cout << "   Velocity (EF)    : " << efVector.coord.vel[0] << efVector.coord.vel[1] << efVector.coord.vel[2] << endl;
        cout << "   Acceleration (EF): " << efVector.coord.acc[0] << efVector.coord.acc[1] << efVector.coord.acc[2] << endl;

        cout << "Output state vector:" << endl;
        cout << "   Time = " << todVector.time.time << " ref= " << todVector.time.ref << endl;
        cout << "   Position (EF)    : " << todVector.coord.pos[0] << todVector.coord.pos[1] << todVector.coord.pos[2] << endl;
        cout << "   Velocity (EF)    : " << todVector.coord.vel[0] << todVector.coord.vel[1] << todVector.coord.vel[2] << endl;
        cout << "   Acceleration (EF): " << todVector.coord.acc[0] << todVector.coord.acc[1] << todVector.coord.acc[2] << endl;

        // ------------------------------------------------------------------------
        // Transform  cartesian to and from geodetic coordinates
        // ------------------------------------------------------------------------

        cout << "\n\nGeodetic: Transform  cartesian to geodetic coordinates" << endl;

        //using efCoord from previous example
        Geodetic geo = efCoord.getGeodetic(modelId, XLCFI_DER_1ST);

        cout << "Input state vector:" << endl;
        cout << "   Position (EF)    : " << efCoord.pos[0] << efCoord.pos[1] << efCoord.pos[2] << endl;
        cout << "   Velocity (EF)    : " << efCoord.vel[0] << efCoord.vel[1] << efCoord.vel[2] << endl;
        cout << "   Acceleration (EF): " << efCoord.acc[0] << efCoord.acc[1] << efCoord.acc[2] << endl;

        cout << "Output geodetic coordinates:" << endl;
        cout << "   Longitude = " << geo.lon << endl;
        cout << "   Latitude  = " << geo.lat << endl;
        cout << "   Altitude  = " << geo.alt << endl;
        cout << "   Long. Der = " << geo.lonDer << endl;
        cout << "   Lat Der   = " << geo.latDer << endl;
        cout << "   Alt Der   = " << geo.altDer << endl;

        cout << "\n\nGeodetic: Transform geodetic to cartesian coordinates" << endl;

        efCoord.setGeodetic(modelId, XLCFI_DER_1ST, geo);

        cout << "Output state vector:" << endl;

        cout << "   Position (EF)    : " << efCoord.pos[0] << efCoord.pos[1] << efCoord.pos[2] << endl;
        cout << "   Velocity (EF)    : " << efCoord.vel[0] << efCoord.vel[1] << efCoord.vel[2] << endl;
        cout << "   Acceleration (EF): " << efCoord.acc[0] << efCoord.acc[1] << efCoord.acc[2] << endl;

        // ------------------------------------------------------------------------
        // Transform from cartesian state vector to keplerian elements
        // ------------------------------------------------------------------------

        cout << "\nCoord: Transform from cartesian state vector to keplerian elements" << endl;

        double pos[3] = {4859964.138, -5265612.059, 0.002};
        double vel[3] = {-1203.303801, -1098.845511, 7377.224410};
        double acc[3] = {0., 0., 0.};

        Coord coord2(XLCFI_CS_TOD, XLCFI_DER_1ST, pos, vel, acc);

        Kepler kep = coord2.getKepler(modelId, XLCFI_KEPLER_OSC);
        cout << "- Elements type  : "
             << (kep.mode == XLCFI_KEPLER_OSC? "OSCULATING": "MEAN") << endl;
        cout << "- Reference frame  : " << kep.cs << endl;
        cout << "- Semi-major axis  : " << kep.a  << endl;
        cout << "- Eccenticity      : " << kep.e  << endl;
        cout << "- Inclination      : " << kep.i  << endl;
        cout << "- RAAN             : " << kep.ra << endl;
        cout << "- Arg. of Perigee  : " << kep.w  << endl;
        cout << "- Mean Anomaly     : " << kep.m  << endl;

        // ------------------------------------------------------------------------
        // Transform from keplerian elements to cartesian state vector
        // ------------------------------------------------------------------------
        cout << "\nCoord: Transform from keplerian elements to cartesian state vector" << endl;

        Kepler kep2;

        kep2.mode = XLCFI_KEPLER_OSC;
        kep2.cs   = XLCFI_CS_TOD;
        kep2.a    = 7000.0;       // Semi-major axis          [m]
        kep2.e    =    0.001;     // Eccenticity
        kep2.i    =   92.0;       // Inclination            [deg]
        kep2.ra   =  128.0;       // R.A. of Ascending Node [deg]
        kep2.w    =  110.0;       // Arg. of Perigee        [deg]
        kep2.m    =   73.1;       // Mean Anomaly           [deg]

        Coord coord3;
        coord3.setKepler(modelId, kep2);

        cout << "Output state vector:" << endl;
        cout << "   Position (EF)    : " << coord3.pos[0] << coord3.pos[1] << coord3.pos[2] << endl;
        cout << "   Velocity (EF)    : " << coord3.vel[0] << coord3.vel[1] << coord3.vel[2] << endl;

        // ------------------------------------------------------------------------
        // Calculate the geodesic (minimum) distance between two points that lay
        // at a given altitude on the same ellipsoid
        // ------------------------------------------------------------------------
        cout << "\nGeodetic: Distance between two points on an ellipsoid" << endl;

        Geodetic geo2(4.17,  // longitude
                      10.0,  // latitude
                      0.0);  // altitude

        double distance, az1, az2, auxD;
        double lon, lat;

        // get geodesic distance to the following point
        lon = 90.0;
        lat = 0.0;

        distance = geo2.geoDistance(modelId, lon, lat,
                                    az1, az2);

        cout << "Geodesic distance = " << distance/1000. << " Km" << endl;
        cout << "Geodesic azimuth of initial point = " << az1 << " deg" << endl;
        cout << "Geodesic azimuth of final point = "   << az2 << " deg" << endl;

        // ------------------------------------------------------------------------
        // Calculate Sun, Moon and Planets position and velocity in the Earth Fixed CS
        // ------------------------------------------------------------------------
        cout << "\nStateVector: get Sun, Moon and Planets state vector" << endl;

        Time ut1Time(timeCorr, 0.0, XLCFI_TIME_UT1);

        StateVector sunVec, moonVec, planetVec;

        sunVec.setSun(modelId, ut1Time);
        moonVec.setMoon(modelId, ut1Time);
        planetVec.setPlanet(modelId, ut1Time, XLCFI_VENUS);

        cout << "Output Sun state vector:" << endl;

        cout << "   Time = " << sunVec.time.time << " ref= " << sunVec.time.ref << endl;
        cout << "   CS = "   << sunVec.coord.cs << "deriv = " << sunVec.coord.deriv << endl;
        cout << "   Position (EF)    : " << sunVec.coord.pos[0] << sunVec.coord.pos[1] << sunVec.coord.pos[2] << endl;
        cout << "   Velocity (EF)    : " << sunVec.coord.vel[0] << sunVec.coord.vel[1] << sunVec.coord.vel[2] << endl;
        cout << "   Acceleration (EF): " << sunVec.coord.acc[0] << sunVec.coord.acc[1] << sunVec.coord.acc[2] << endl;

        cout << "Output Moon state vector:" << endl;

        cout << "   Time = " << moonVec.time.time << " ref= " << moonVec.time.ref << endl;
        cout << "   CS = "   << moonVec.coord.cs << "deriv = " << moonVec.coord.deriv << endl;
        cout << "   Position (EF)    : " << moonVec.coord.pos[0] << moonVec.coord.pos[1] << moonVec.coord.pos[2] << endl;

        // [...]

        // ------------------------------------------------------------------------
        // Calculating star coordinates in the Mean of Date coordinate system
        // ------------------------------------------------------------------------
        cout << "\nStar: get star RA and Decl." << endl;

        ut1Time.time = -200.0; // using the same object as before

        double ra, dec;

        double ra0     =   0.35399670615; // Star right ascension in the Barycentric Mean of 2000.0 coordinate at J2000.0 [rad]
        double dec0    =   4.8672587;     // Star declination in the Barycentric Mean of 2000.0 coordinate at J2000.0 [rad]
        double muRa    =   0.001;           // Star proper motion in the right ascension [rad/century]
        double muDec   =  -0.001;           // Star proper motion in the declination [rad/century]
        double radVel  =   0.01;              // Star radial velocity [au/century]
        double par     =   0.0001;          // Star parallax [rad]

        StarData star(ra0,     dec0,
                      muRa,    muDec,
                      radVel,  radVel,
                      XLCFI_CS_BM2000);

        star.getStar(modelId, ut1Time, ra, dec);

        cout << "Output Star:" << endl;
        cout << "   RA  = " << ra  << endl;
        cout << "   Dec = " << dec << endl;

        // ------------------------------------------------------------------------
        // Calculation of the satellite orbital position (True Latitude)
        // ------------------------------------------------------------------------
        cout << "\nStateVector: getPositionOnOrbit" << endl;

        long angleType, deriv;
        double angle, angleRate, angleRateRate;

        pos[0] =          0.138;
        pos[1] =   -2365612.059;
        pos[2] =    6763859.946;

        vel[0] =       132.303801;
        vel[1] =     -1203.845511;
        vel[2] =     -1203.845511;

        acc[0] =         0.0634168;
        acc[1] =        -0.0249763;
        acc[2] =        -0.3018956;

        Time t1(timeCorr, 0.0, XLCFI_TIME_UT1);

        Coord coord4(XLCFI_CS_EF, XLCFI_DER_2ND, pos, vel, acc);

        StateVector sv (t1, coord4);

        angleType = XLCFI_ANGLE_TYPE_TRUE_LAT_TOD;
        deriv = XLCFI_DER_2ND;

        sv.getPositionOnOrbit(modelId, angleType, deriv,
                              angle, angleRate, angleRateRate);

        cout << "Output Position On Orbit = "
             << angle << "deg; "
             << angleRate << "deg/s; "
             << angleRateRate << "deg/s2 " << endl << endl;

        // ------------------------------------------------------------------------
        // Conversion between cartesian coordinates and RA and declination
        // ------------------------------------------------------------------------
        cout << "\nCoord: getRaDec & Star:getCart" << endl;

        double pc        = 3.08568025E16;

        pos[0] = -8.82*pc;
        pos[1] = -5.93*pc;
        pos[2] = 3.7*pc;

        vel[0] = -57.7E3;
        vel[1] = 31.5E3;
        vel[2] = -102.3E3;

        Coord coord5(XLCFI_CS_BM1950, XLCFI_DER_1ST, pos, vel, acc);

        // Get spherical coords.
        StarData radec = coord5.getRaDec(modelId, XLCFI_DER_1ST);

        cout << "Input cartesian coordinates" << endl;
        cout << "   CS = " << coord5.cs << endl;
        cout << "   Position = " << coord5.pos[0] << ", " << coord5.pos[1] << ", " << coord5.pos[2] << endl;
        cout << "   Velocity = " << coord5.vel[0] << ", " << coord5.vel[1] << ", " << coord5.vel[2] << endl;

        cout << "Output Star coordinates from input cartesian coordinates" << endl;
        cout << "   Right Ascension      = " << radec.ra       << endl;
        cout << "   Declination          = " << radec.dec      << endl;
        cout << "   Proper motion in RA  = " << radec.muRa     << endl;
        cout << "   Proper motion in Dec = " << radec.muDec    << endl;
        cout << "   Radial Velocity      = " << radec.radVel   << endl;
        cout << "   Parallax             = " << radec.parallax << endl << endl;

        // Get cartesian coords.
        Coord coordFromStar = radec.getCart(modelId, XLCFI_DER_1ST);

        cout << "Output Cartesian Star coordinates from previous spherical coordinates" << endl;
        cout << "   CS = " << coordFromStar.cs << endl;
        cout << "   Position = " << coordFromStar.pos[0] << ", " << coordFromStar.pos[1] << ", " << coordFromStar.pos[2] << endl;
        cout << "   Velocity = " << coordFromStar.vel[0] << ", " << coordFromStar.vel[1] << ", " << coordFromStar.vel[2] << endl;

        // ------------------------------------------------------------------------
        // Star coordinates conversion from Fk4 to FK5
        // ------------------------------------------------------------------------
        cout << "\nStar: changeCatalog" << endl;

        StarData star1(6.27906181420277,     // RA
                       -1.34986658532673,    // Dec
                       -0.0001394081738438,  // mu_ra
                       -0.0000857635400903,  // mu_dec
                       0.,                   // radial vel.
                       0.,                   // parallax
                       XLCFI_CS_BM1950);        // reference frame (XLCFI_FK4)

        Time starTime(timeCorr, 1646.0, XLCFI_TIME_UTC);

        long newCatalog = XLCFI_FK5;

        StarData star2 = star1.changeCatalog(modelId, starTime, newCatalog);

        cout << "   INPUTS." << endl;
        cout << "       UTC time = " << starTime.time << endl;
        cout << "       RA = " << star1.ra << " \tDec = " << star1.dec << endl;
        cout << "       mu_ra = " << star1.muRa << " \tmu_dec = " << star1.muDec << endl;
        cout << "       rad_vel = "  << star1.radVel << ", \tparallax = " << star1.parallax << endl;

        cout << "   OUTPUTS." << endl;
        cout << "       RA = " << star2.ra << " \tDec = " << star2.dec << endl << endl;

        // ------------------------------------------------------------------------
        // Conversion between EF and Topocentric coordinates
        // ------------------------------------------------------------------------
        cout << "\nCoord: topocentricToEf & efToTopocentric" << endl;

        Topocentric topo = {20, 30, 10000, 0, 0, 0};
        Topocentric topo2;

        pos[0] = 3460675.389;
        pos[1] = 2903851.443;
        pos[2] = 4487348.409;

        vel[0] = 0.;
        vel[1] = 0.;
        vel[2] = 0.;

        Coord topOrigin(XLCFI_CS_EF, XLCFI_DER_1ST, pos, vel, acc);

        Coord coordFromTop;

        // topocentric to EF CS
        coordFromTop.topocentricToEf(modelId, XLCFI_MODE_FLAG_LOCATION, XLCFI_DER_1ST,
                                     topOrigin, topo);

        cout << "Inputs." << endl;
        cout << "   Mode = LOCATION" << endl;
        cout << "   Deriv = 1st. Derivative" << endl;
        cout << "   Center of the Topocentric CS   = " << pos[0] <<",  " << pos[1] << ", " << pos[2] << endl;
        cout << "   Velocity of the Topocentric CS = " << vel[0] <<",  " << vel[1] << ", " << vel[2] << endl;
        cout << "   Azimuth, Elevation, Altitude = "
             << topo.azim << ",  " << topo.elev << ", " << topo.range << endl;
        cout << "   Rates for Azimuth, Elevation, Altitude = "
             << topo.azimDer  << ", " << topo.elevDer << ", " << topo.rangeDer << endl;

        cout << "Output Cartesian coordinates" << endl;
        cout << "   CS = " << coordFromStar.cs << endl;
        cout << "   Position = " << coordFromTop.pos[0] << ", " << coordFromTop.pos[1] << ", " << coordFromTop.pos[2] << endl;
        cout << "   Velocity = " << coordFromTop.vel[0] << ", " << coordFromTop.vel[1] << ", " << coordFromTop.vel[2] << endl;

        // EF to topocentric
        coordFromTop.efToTopocentric(modelId, XLCFI_MODE_FLAG_LOCATION, XLCFI_DER_1ST,
                                     topOrigin, topo2);

        cout << "Output topocentric parameters from previous cartesian coordinates" << endl;
        cout << "Topocentric Azimuth = "   << topo2.azim  << endl;
        cout << "Topocentric Elevation = " << topo2.elev  << endl;
        cout << "Topocentric Range = "     << topo2.range << endl;

        cout << "Topocentric Azimuth rate = "   << topo2.azimDer  << endl;
        cout << "Topocentric Elevation rate = " << topo2.elevDer  << endl;
        cout << "Topocentric Range rate = "     << topo2.rangeDer << endl;

      }//end try

      catch (CfiError cfiError)
      {
        //If an exception is thrown, there have been errors during execution
        vector<string> errorMessages;

        // Get error messages
        cfiError.getMsg(errorMessages);

        // Pring Error messages
        for (long i = 0; i < errorMessages.size(); i++)
        {
          cout << errorMessages[i] << endl;
        }
      }

      return 0;

    }