void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double R, P, T, wl;
    double A,B;
    
    if(nrhs>4) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
        
    //Get the relative humidity
    if(nrhs>0&&mxGetM(prhs[0])!=0) {
       R=getDoubleFromMatlab(prhs[0]);
    } else {//Otherwise get the value from the Constants class.
       R=getScalarMatlabClassConst("Constants","standardRelHumid");
    }
    
    //Get the pressure
    if(nrhs>1&&mxGetM(prhs[1])!=0) {
        P=getDoubleFromMatlab(prhs[1]);
    } else {//Otherwise, get the value from the Constants class.
        P=getScalarMatlabClassConst("Constants","standardAtmosphericPressure");
    }
    
    //Get the temperature
    if(nrhs>2&&mxGetM(prhs[2])!=0) {
        T=getDoubleFromMatlab(prhs[2]);
    } else {//Otherwise get the value from the Constants class.
        T=getScalarMatlabClassConst("Constants","standardTemp");
    }

    //wl is inputted in meters, but needs to be in micrometers for the
    //function iauAtco13
    if(nrhs>3&&mxGetM(prhs[3])!=0) {
       wl= getDoubleFromMatlab(prhs[3]);
    } else {
       wl=0.574e-6;
    }
    
    //Convert from Pascals to millibars.
    P*=0.01;
    //Convert from degrees Kelvin to degrees Centigrade.
    T+=-273.15;
    //Convert from meters to micrometers.
    wl*=1e6;
    
    //Get the parameters for the simple refraction model.
    iauRefco(P, T, R, wl,&A, &B);
    
    //Allocate space for the return values.
    plhs[0]=doubleMat2Matlab(&A,1,1);
    if(nlhs>1) {
        plhs[1]=doubleMat2Matlab(&B,1,1);
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double c, *vObsFrame, *vObjInFrame, *vObjRef;
    mxArray *retMATLAB;
    size_t i, numVec;

    if(nrhs!=2) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }

    if(nlhs>1) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }

    numVec=mxGetN(prhs[0]);
    if(numVec!=mxGetN(prhs[1])||mxGetM(prhs[0])!=3||mxGetM(prhs[1])!=3) {
        mexErrMsgTxt("The input vectors have the wrong dimensionality.");
        return;
    }

    checkRealDoubleArray(prhs[0]);
    vObsFrame=(double*)mxGetData(prhs[0]);
    checkRealDoubleArray(prhs[1]);
    vObjInFrame=(double*)mxGetData(prhs[1]);

    c=getScalarMatlabClassConst("Constants","speedOfLight");

    //Allocate space for the return values.
    retMATLAB=mxCreateDoubleMatrix(3,numVec,mxREAL);
    vObjRef=(double*)mxGetData(retMATLAB);

    for(i=0; i<numVec; i++) {
        relVecAddC(c,vObsFrame+3*i,vObjInFrame+3*i,vObjRef+3*i);
    }

    plhs[0]=retMATLAB;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numRow,numVec;
    mxArray *retMat;
    double *xVec, *retData;
    double TT1, TT2, UT11, UT12;
    //The if-statements below should properly initialize all of the EOP.
    //The following initializations to zero are to suppress warnings when
    //compiling with -Wconditional-uninitialized.
    double dX=0;
    double dY=0;
    double deltaT=0;
    double LOD=0;
    double GCRS2TIRS[3][3];
    //Polar motion matrix. ITRS=POM*TIRS. We will just be setting it to the
    //identity matrix as polar motion is not taken into account when going
    //to the TIRS.
    double rident[3][3]={{1,0,0},{0,1,0},{0,0,1}};
    double Omega[3];//The rotation vector in the TIRS
    
    if(nrhs<3||nrhs>6){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
    }
    
    checkRealDoubleArray(prhs[0]);
    
    numRow = mxGetM(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(!(numRow==3||numRow==6)) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    xVec=(double*)mxGetData(prhs[0]);
    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);
    
    //If some values from the function getEOP will be needed
    if(nrhs<=5||mxIsEmpty(prhs[3])||mxIsEmpty(prhs[4])||mxIsEmpty(prhs[5])) {
        mxArray *retVals[5];
        double *dXdY;
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        int retVal;
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
        
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(5,retVals,2,JulUTCMATLAB,"getEOP");
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
        
        //%We do not need the polar motion coordinates.
        mxDestroyArray(retVals[0]);
        
        checkRealDoubleArray(retVals[1]);
        if(mxGetM(retVals[1])!=2||mxGetN(retVals[1])!=1) {
            mxDestroyArray(retVals[1]);
            mxDestroyArray(retVals[2]);
            mxDestroyArray(retVals[3]);
            mxDestroyArray(retVals[4]);
            mexErrMsgTxt("Error using the getEOP function.");
            return;
        }
        
        dXdY=(double*)mxGetData(retVals[1]);
        dX=dXdY[0];
        dY=dXdY[1];
        
        //This is TT-UT1
        deltaT=getDoubleFromMatlab(retVals[3]);
        LOD=getDoubleFromMatlab(retVals[4]);
        //Free the returned arrays.
        mxDestroyArray(retVals[1]);
        mxDestroyArray(retVals[2]);
        mxDestroyArray(retVals[3]);
        mxDestroyArray(retVals[4]);
    }
    
    //If deltaT=TT-UT1 is given
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        deltaT=getDoubleFromMatlab(prhs[3]);
    }
    
    //Obtain UT1 from terestrial time and deltaT.
    iauTtut1(TT1, TT2, deltaT, &UT11, &UT12);
    
    //Get celestial pole offsets, if given.
    if(nrhs>4&&!mxIsEmpty(prhs[4])) {
        size_t dim1, dim2;
        
        checkRealDoubleArray(prhs[4]);
        dim1 = mxGetM(prhs[4]);
        dim2 = mxGetN(prhs[4]);
        
        if((dim1==2&&dim2==1)||(dim1==1&&dim2==2)) {
            double *dXdY=(double*)mxGetData(prhs[4]);
        
            dX=dXdY[0];
            dY=dXdY[1];
        } else {
            mexErrMsgTxt("The celestial pole offsets have the wrong dimensionality.");
            return;
        }
    }
    
    //If LOD is given
    if(nrhs>5&&mxIsEmpty(prhs[5])) {
        LOD=getDoubleFromMatlab(prhs[5]);
    }
    
    //Compute the rotation matrix for going from GCRS to ITRS as well as
    //the instantaneous vector angular momentum due to the Earth's rotation
    //in TIRS coordinates.
    {
    double x, y, s, era;
    double rc2i[3][3];
    double omega;
        
    //Get the X,Y coordinates of the Celestial Intermediate Pole (CIP) and
    //the Celestial Intermediate Origin (CIO) locator s, using the IAU 2006
    //precession and IAU 2000A nutation models.
    iauXys06a(TT1, TT2, &x, &y, &s);
    
    //Add the CIP offsets.
    x += dX;
    y += dY;
    
    //Get the GCRS-to-CIRS matrix
    iauC2ixys(x, y, s, rc2i);
    
    //Find the Earth rotation angle for the given UT1 time. 
    era = iauEra00(UT11, UT12);
    
    //Set the polar motion matrix to the identity matrix so that the
    //conversion stops at the TIRS instead of the ITRS.

    //Combine the GCRS-to-CIRS matrix, the Earth rotation angle, and use
    //the identity matrix instead of the polar motion matrix to get a
    //to get the rotation matrix to go from GCRS to TIRS.
    iauC2tcio(rc2i, era, rident,GCRS2TIRS);
    
    //Next, to be able to transform the velocity, the rotation of the Earth
    //has to be taken into account. 
    
    //The angular velocity vector of the Earth in the TIRS in radians.
    omega=getScalarMatlabClassConst("Constants","IERSMeanEarthRotationRate");
    //Adjust for LOD
    omega=omega*(1-LOD/86400.0);//86400.0 is the number of seconds in a TT
                                //day.
    Omega[0]=0;
    Omega[1]=0;
    Omega[2]=omega;
    }
    
    //Allocate space for the return vectors.
    retMat=mxCreateDoubleMatrix(numRow,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);
    
    {
        size_t curVec;
        for(curVec=0;curVec<numVec;curVec++) {
            //Multiply the position vector with the rotation matrix.
            iauRxp(GCRS2TIRS, xVec+numRow*curVec, retData+numRow*curVec);
            
            //If a velocity vector was given.
            if(numRow>3) {
                double *posGCRS=xVec+numRow*curVec;
                double posTIRS[3];
                double *velGCRS=xVec+numRow*curVec+3;//Velocity in GCRS
                double velTIRS[3];
                double *retDataVel=retData+numRow*curVec+3;
                double rotVel[3];
                //If a velocity was provided with the position, first
                //convert to TIRS coordinates, then account for the
                //rotation of the Earth.
                
                //Convert velocity from GCRS to TIRS.
                iauRxp(GCRS2TIRS, velGCRS, velTIRS);
                //Convert position from GCRS to TIRS
                iauRxp(GCRS2TIRS, posGCRS, posTIRS);
                                
                //Evaluate the cross product for the angular velocity due
                //to the Earth's rotation.
                iauPxp(Omega, posTIRS, rotVel);
                
                //Subtract out the instantaneous velocity due to rotation.
                iauPmp(velTIRS, rotVel, retDataVel);
            }
        }
    }
    plhs[0]=retMat;
    
    //If the rotation matrix is desired on the output.
    if(nlhs>1) {
        double *elPtr;
        size_t i,j;
        
        plhs[1]=mxCreateDoubleMatrix(3,3,mxREAL);
        elPtr=(double*)mxGetData(plhs[1]);
        
        for (i=0;i<3;i++) {
            for(j=0;j<3;j++) {
                elPtr[i+3*j]=GCRS2TIRS[i][j];
            }
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double TT1,TT2,*xVec;
    double deltaT=0;
    double LOD=0;
    size_t numRow,numVec;
    double CIRS2TIRS[3][3];
    double TIRS2CIRS[3][3];
    double Omega[3];//The rotation vector in the TIRS
    mxArray *retMat;
    double *retData;

    if(nrhs<3||nrhs>5){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
    }
    
    checkRealDoubleArray(prhs[0]);
    
    numRow = mxGetM(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(!(numRow==3||numRow==6)) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    xVec=(double*)mxGetData(prhs[0]);
    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);
        
    //If some values from the function getEOP will be needed
    if(nrhs<=4||mxIsEmpty(prhs[3])||mxIsEmpty(prhs[4])) {
        mxArray *retVals[5];
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        int retVal;
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
        
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(5,retVals,2,JulUTCMATLAB,"getEOP");
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
        
        //We do not need the polar motion coordinates.
        mxDestroyArray(retVals[0]);
        //We do not need the celestial pole offsets.
        mxDestroyArray(retVals[1]);

        //This is TT-UT1
        deltaT=getDoubleFromMatlab(retVals[3]);
        LOD=getDoubleFromMatlab(retVals[4]);
        //Free the returned arrays.
        mxDestroyArray(retVals[2]);
        mxDestroyArray(retVals[3]);
        mxDestroyArray(retVals[4]);
    }

    //If deltaT=TT-UT1 is given
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        deltaT=getDoubleFromMatlab(prhs[3]);
    }
    //If LOD is given
    if(nrhs>4&&!mxIsEmpty(prhs[4])) {
        LOD=getDoubleFromMatlab(prhs[4]);
    }
    
    //Compute the rotation matrix for going from CIRS to TIRS as well as
    //the instantaneous vector angular momentum due to the Earth's rotation
    //in GCRS coordinates.
    {
        double UT11, UT12;
        double era, omega;
        //Obtain UT1 from terestrial time and deltaT.
        iauTtut1(TT1, TT2, deltaT, &UT11, &UT12);
 
        //Find the Earth rotation angle for the given UT1 time. 
        era = iauEra00(UT11, UT12);
        
        //Construct the rotation matrix.
        CIRS2TIRS[0][0]=1;
        CIRS2TIRS[0][1]=0;
        CIRS2TIRS[0][2]=0;
        CIRS2TIRS[1][0]=0;
        CIRS2TIRS[1][1]=1;
        CIRS2TIRS[1][2]=0;
        CIRS2TIRS[2][0]=0;
        CIRS2TIRS[2][1]=0;
        CIRS2TIRS[2][2]=1;     
        iauRz(era, CIRS2TIRS);
        
        //To go from the TIRS to the GCRS, we need to use the inverse rotation
        //matrix, which is just the transpose of the rotation matrix.
        iauTr(CIRS2TIRS, TIRS2CIRS);
        
        //Next, to be able to transform the velocity, the rotation of the Earth
        //has to be taken into account. 

        //The angular velocity vector of the Earth in the TIRS in radians.
        omega=getScalarMatlabClassConst("Constants","IERSMeanEarthRotationRate");
        //Adjust for LOD
        omega=omega*(1-LOD/86400.0);//86400.0 is the number of seconds in a TT
                                    //day.
        Omega[0]=0;
        Omega[1]=0;
        Omega[2]=omega;
    }
    
    //Allocate space for the return vectors.
    retMat=mxCreateDoubleMatrix(numRow,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);
    {
        size_t curVec;
        for(curVec=0;curVec<numVec;curVec++) {
            //Multiply the position vector with the rotation matrix.
            iauRxp(TIRS2CIRS, xVec+numRow*curVec, retData+numRow*curVec);
            
            //If a velocity vector was given.
            if(numRow>3) {
                double *posTIRS=xVec+numRow*curVec;
                double *velTIRS=xVec+numRow*curVec+3;//Velocity in GCRS
                double *retDataVel=retData+numRow*curVec+3;
                double rotVel[3];

                //Evaluate the cross product for the angular velocity due
                //to the Earth's rotation.
                iauPxp(Omega, posTIRS, rotVel);
                
                //Add the instantaneous velocity due to rotation.
                iauPpp(velTIRS, rotVel, retDataVel);
                
                //Rotate from TIRS to GCRS
                iauRxp(TIRS2CIRS, retDataVel, retDataVel);
            }
        }
    }
    plhs[0]=retMat;
    
    if(nlhs>1) {
        double *elPtr;
        size_t i,j;
        
        plhs[1]=mxCreateDoubleMatrix(3,3,mxREAL);
        elPtr=(double*)mxGetData(plhs[1]);
        
        for (i=0;i<3;i++) {
            for(j=0;j<3;j++) {
                elPtr[i+3*j]=TIRS2CIRS[i][j];
            }
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numRow,numVec;
    mxArray *retMat;
    double *xVec, *retData;
    double TT1, TT2, UT11, UT12;
    //The if-statements below should properly initialize all of the EOP.
    //The following initializations to zero are to suppress warnings when
    //compiling with -Wconditional-uninitialized.
    double xp=0;
    double yp=0;
    double deltaT=0;
    double LOD=0;
    double ITRS2TEME[3][3];
    double PEF2TEME[3][3];
    double WInv[3][3];//The inverse polar motion matrix to go from ITRS to PEF.
    double Omega[3];//The angular velocity vector for the Earth's rotation.
    
        
    if(nrhs<3||nrhs>6){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
 
    checkRealDoubleArray(prhs[0]);
    
    numRow = mxGetM(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(!(numRow==3||numRow==6)) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    xVec=(double*)mxGetData(prhs[0]);
    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);
    
    //If some values from the function getEOP will be needed
    if(nrhs<6||mxIsEmpty(prhs[3])||mxIsEmpty(prhs[4])||mxIsEmpty(prhs[5])) {
        mxArray *retVals[5];
        double *xpyp;
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        int retVal;
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
        
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(5,retVals,2,JulUTCMATLAB,"getEOP");
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
        
        checkRealDoubleArray(retVals[0]);
        checkRealDoubleArray(retVals[1]);
        if(mxGetM(retVals[0])!=2||mxGetN(retVals[0])!=1||mxGetM(retVals[1])!=2||mxGetN(retVals[1])!=1) {
            mxDestroyArray(retVals[0]);
            mxDestroyArray(retVals[1]);
            mxDestroyArray(retVals[2]);
            mxDestroyArray(retVals[3]);
            mxDestroyArray(retVals[4]);
            mexErrMsgTxt("Error using the getEOP function.");
            return;
        }
        
        xpyp=(double*)mxGetData(retVals[0]);
        xp=xpyp[0];
        yp=xpyp[1];
        //The celestial pole offsets are not used.
        
        //This is TT-UT1
        deltaT=getDoubleFromMatlab(retVals[3]);
        LOD=getDoubleFromMatlab(retVals[4]);
        //Free the returned arrays.
        mxDestroyArray(retVals[0]);
        mxDestroyArray(retVals[1]);
        mxDestroyArray(retVals[2]);
        mxDestroyArray(retVals[3]);
        mxDestroyArray(retVals[4]);
    }
    
    //If deltaT=TT-UT1 is given
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        deltaT=getDoubleFromMatlab(prhs[3]);
    }
    
    //Obtain UT1 from terestrial time and deltaT.
    iauTtut1(TT1, TT2, deltaT, &UT11, &UT12);
    
    //Get polar motion values, if given.
    if(nrhs>4&&!mxIsEmpty(prhs[4])) {
        size_t dim1, dim2;
        
        checkRealDoubleArray(prhs[4]);
        dim1 = mxGetM(prhs[4]);
        dim2 = mxGetN(prhs[4]);
        
        if((dim1==2&&dim2==1)||(dim1==1&&dim2==2)) {
            double *xpyp=(double*)mxGetData(prhs[4]);
        
            xp=xpyp[0];
            yp=xpyp[1];
        } else {
            mexErrMsgTxt("The celestial pole offsets have the wrong dimensionality.");
            return;
        }
    }
    
    //If LOD is given
    if(nrhs>5&&!mxIsEmpty(prhs[5])) {
        LOD=getDoubleFromMatlab(prhs[5]);
    }

    {
     double GMST1982=iauGmst82(UT11, UT12);
     double TEME2PEF[3][3];
     double TEME2ITRS[3][3];
     double W[3][3];
     double omega;
    
     //Get Greenwhich mean sidereal time under the IAU's 1982 model. This
     //is given in radians and will be used to build a rotation matrix to
     //rotate into the PEF system.
     GMST1982=iauGmst82(UT11, UT12);
     {
         double cosGMST,sinGMST;
         cosGMST=cos(GMST1982);
         sinGMST=sin(GMST1982);
         //Build the rotation matrix to rotate by GMST about the z-axis. This
         //will put the position vector in the PEF system.
         TEME2PEF[0][0]=cosGMST;
         TEME2PEF[0][1]=sinGMST;
         TEME2PEF[0][2]=0;
         TEME2PEF[1][0]=-sinGMST;
         TEME2PEF[1][1]=cosGMST;
         TEME2PEF[1][2]=0;
         TEME2PEF[2][0]=0;
         TEME2PEF[2][1]=0;
         TEME2PEF[2][2]=1.0;
     }
     //The inverse rotation is just the transpose
     iauTr(TEME2PEF, PEF2TEME);
     //To go from PEF to ITRS, we need to build the polar motion matrix
     //using the IAU's 1980 conventions.
     {
         double cosXp,sinXp,cosYp,sinYp;
         cosXp=cos(xp);
         sinXp=sin(xp);
         cosYp=cos(yp);
         sinYp=sin(yp);
         W[0][0]=cosXp;
         W[0][1]=sinXp*sinYp;
         W[0][2]=sinXp*cosYp;
         W[1][0]=0;
         W[1][1]=cosYp;
         W[1][2]=-sinYp;
         W[2][0]=-sinXp;
         W[2][1]=cosXp*sinXp;
         W[2][2]=cosXp*cosYp;
     }
     //The inverse rotation is just the transpose
     iauTr(W, WInv);
     
     //The total rotation matrix is thus the product of the two rotations.
     //TEME2ITRS=W*TEME2PEF;
     iauRxr(W, TEME2PEF, TEME2ITRS);
     //We want the inverse rotation
     iauTr(TEME2ITRS, ITRS2TEME);
     //The angular velocity vector of the Earth in the TIRS in radians.
     omega=getScalarMatlabClassConst("Constants","IERSMeanEarthRotationRate");
     //Adjust for LOD
     omega=omega*(1-LOD/86400.0);//86400.0 is the number of seconds in a TT day.
     Omega[0]=0;
     Omega[1]=0;
     Omega[2]=omega;     
    }
    
    //Allocate space for the return vectors.
    retMat=mxCreateDoubleMatrix(numRow,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);
    
    {
        size_t curVec;
        
        for(curVec=0;curVec<numVec;curVec++) {
            //Multiply the position vector with the rotation matrix.
            iauRxp(ITRS2TEME, xVec+numRow*curVec, retData+numRow*curVec);
            //If a velocity vector was given.
            if(numRow>3) {
                double *posITRS=xVec+numRow*curVec;
                double *velITRS=xVec+numRow*curVec+3;//Velocity in TEME
                double posPEF[3];
                double velPEF[3];
                double *retDataVel=retData+numRow*curVec+3;
                double rotVel[3];
                //If a velocity was provided with the position, first
                //convert to PEF coordinates, then account for the rotation
                //of the Earth, then rotate into TEME coordinates.
                
                //Convert velocity from ITRS to PEF.
                iauRxp(WInv, velITRS, velPEF);
                //Convert position from ITRS to PEF
                iauRxp(WInv, posITRS, posPEF);

                //Evaluate the cross product for the angular velocity due
                //to the Earth's rotation.
                iauPxp(Omega, posPEF, rotVel);

                //Add the instantaneous velocity due to rotation.
                iauPpp(velPEF, rotVel, retDataVel);

                //Rotate from the PEF into the TEME
                iauRxp(PEF2TEME, retDataVel, retDataVel);
            }
        }
    }
    
    plhs[0]=retMat;
    
    if(nlhs>1) {
        double *elPtr;
        size_t i,j;
        
        plhs[1]=mxCreateDoubleMatrix(3,3,mxREAL);
        elPtr=(double*)mxGetData(plhs[1]);
        
        for (i=0;i<3;i++) {
            for(j=0;j<3;j++) {
                elPtr[i+3*j]=ITRS2TEME[i][j];
            }
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double *points,a,b,b2,f,e2,eps2,ec;
    size_t numVec,i;
    mxArray *retMat;
    double *retData;
    
    if(nrhs>3||nrhs<1){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
    
    checkRealDoubleArray(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(mxGetM(prhs[0])!=3) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    points=(double*)mxGetData(prhs[0]);
    //points[0] is x
    //points[1] is y
    //points[2] is z
    
    if(nrhs>1) {
        a=getDoubleFromMatlab(prhs[1]);
    } else {
        a=getScalarMatlabClassConst("Constants", "WGS84SemiMajorAxis");
    }

    if(nrhs>2) {
        f=getDoubleFromMatlab(prhs[2]);
    } else {
        f=getScalarMatlabClassConst("Constants", "WGS84Flattening");   
    }
    
    b=a*(1-f);//The semi-minor axis of the reference ellipsoid.
    b2=b*b;

    //The square of the first numerical eccentricity. 
    e2=2*f-f*f;
    //The square of the second numerical eccentricity.
    eps2=a*a/(b2)-1;

    //This value is used if Fukushima's method is chosen.
    ec=sqrt(1-e2);

    //Allocate space for the return variables.
    retMat=mxCreateDoubleMatrix(3,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);
    
    for(i=0;i<numVec;i++) {
        double *phi, *lambda, *h;
        double x0,y0,z0;
        double r0,p,s,q;
        
        //Get the Cartesian point to convert.
        x0=points[3*i];
        y0=points[3*i+1];
        z0=points[3*i+2];
        
        //Get the addresses of where the converted components will go
        phi=retData+3*i;
        lambda=retData+3*i+1;
        h=retData+3*i+2;
        
        r0=sqrt(x0*x0+y0*y0);
        p=fabs(z0)/eps2;
        s=r0*r0/(e2*eps2);
        q=p*p-b2+s;
    
        *lambda=atan2(y0,x0);
        if(q>=0) {//Use Sofair's algorithm
            double u,v,P,Q,t,c,w,z,Ne,val;
            
            u=p/sqrt(q);
            v=b2*u*u/q;
            P=27.0*v*s/q;
            Q=pow(sqrt(P+1.0)+sqrt(P),2.0/3.0);
            t=(1.0+Q+1/Q)/6.0;
            c=u*u-1+2*t;
            //This condition prevents finite precision problems due to
            //subtraction within the square root.
            c=fMax(c,0);
            c=sqrt(c);
            w=(c-u)/2.0;

        //The z coordinate of the closest point projected on the ellipsoid.
        //The fmax command deals with precision problems when the argument
        //is nearly zero. The problems arise due to the subtraction within
        //the square root.
            z=sqrt(t*t+v)-u*w-t/2.0-1.0/4.0;
            z=fMax(z,0);
            z=copySign(sqrt(q)*(w+sqrt(z)),z0);
            
            Ne=a*sqrt(1+eps2*z*z/b2);

            //The min and max terms deals with finite precision problems.
            val=fMin(z*(eps2+1)/Ne,1);
            val=fMax(val,-1.0);
            *phi=asin(val);
            *h=r0*cos(*phi)+z0*sin(*phi)-a*a/Ne;
        } else {//Use Fukushima's algorithm.
            double Cc,P,Z,S,C;
            //A gets a value within the loop. This initialization is just
            //to silence a warning when compiling with
            //-Wconditional-uninitialized
            double A=0;
            size_t curIter;
            const size_t maxIter=6;
            
            P=r0/a;
            Z=(ec/a)*fabs(z0);

            S=Z;
            C=ec*P;

            //Loop until convergence. Assume convergence in 6 iterations.
            for(curIter=0;curIter<maxIter;curIter++) {
                double B,F,D,SNew,CNew;
                
                A=sqrt(S*S+C*C);
                B=1.5*e2*S*C*C*((P*S-Z*C)*A-e2*S*C);
                F=P*A*A*A-e2*C*C*C;
                D=Z*A*A*A+e2*S*S*S;

                SNew=D*F-B*S;
                CNew=F*F-B*C;

                SNew=SNew/CNew;
                
                if(!isFinite(SNew)) {
                    S=SNew;
                    C=1;
                    A=sqrt(S*S+C*C);
                    break;
                } else {
                    S=SNew;
                    C=1;
                }
            }
            Cc=ec*C;

            //If the point is along the z-axis, then SNew and CNew will
            //both be zero, leading to a non-finite result.
            if(!isFinite(S)) {
                *phi=copySign(pi/2,z0);
                *h=fabs(z0)-b;
            } else {
                *phi=copySign(atan(S/Cc),z0);
                *h=(r0*Cc+fabs(z0)*S-b*A)/sqrt(Cc*Cc+S*S);
            }
        }
    }

    plhs[0]=retMat;
}
Exemplo n.º 7
0
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double *vOrig;
    double *obsVel;
    mxArray *retMATLAB;
    double c, *retVec;
    size_t numVec;
    
    if(nrhs<2||nrhs>3) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }

    numVec=mxGetN(prhs[0]);
    if(numVec!=mxGetN(prhs[1])||mxGetM(prhs[0])!=3||mxGetM(prhs[1])!=3) {
        mexErrMsgTxt("The input vectors have the wrong dimensionality.");
        return;
    }
    
    checkRealDoubleArray(prhs[0]);
    vOrig=(double*)mxGetData(prhs[0]);
    checkRealDoubleArray(prhs[1]);
    obsVel=(double*)mxGetData(prhs[1]);
    
    c=getScalarMatlabClassConst("Constants","speedOfLight");
    
    //Allocate space for the return values.
    retMATLAB=mxCreateDoubleMatrix(3,numVec,mxREAL);
    retVec=(double*)mxGetData(retMATLAB);
    
    //If the third parameter is provided, then use the algorithm from the IAU.
    if(nrhs>2) {
        double AU, *sunDist;
        size_t curVec;
        
        //Needed to convert units.
        AU=getScalarMatlabClassConst("Constants","AstronomialUnit");
        
        //If the dimensionality is wrong.
        if(!((mxGetM(prhs[2])==1&&mxGetN(prhs[2])==numVec)||(mxGetM(prhs[2])==numVec&&mxGetN(prhs[2])==1))) {
            mxDestroyArray(retMATLAB);
            mexErrMsgTxt("The input vectors have the wrong dimensionality.");
            return;
        }
        checkRealDoubleArray(prhs[0]);
        sunDist=(double*)mxGetData(prhs[2]);

        for(curVec=0;curVec<numVec;curVec++) {
            double vecMag,unitVec[3];
            double v[3];
            double s;
            double bm1;
            
            //Get a unit direction vector and magnitude.
            iauPn(vOrig+3*curVec, &vecMag, unitVec);
            
            //Convert the velocity to units of the speed of light.
            v[0]=obsVel[3*curVec]/c;
            v[1]=obsVel[3*curVec+1]/c;
            v[2]=obsVel[3*curVec+2]/c;
            
            //The distance to the sun in AU.
            s=sunDist[curVec]/AU;
            //The reciprocal of the Lorentz factor.
            bm1=sqrt(1-(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]));
            
            //Perform the correction with the IAU's function.
            iauAb(unitVec, v, s, bm1,retVec+3*curVec);
            
            //Set the magnitude back to what it was.
            retVec[3*curVec]*=vecMag;
            retVec[3*curVec+1]*=vecMag;
            retVec[3*curVec+2]*=vecMag;
        }
    } else {
    //If the distance to the sun is not given, then just perform a normal
    //special relativistic correction.
        size_t curVec;
        
        for(curVec=0;curVec<numVec;curVec++) {
            double vecMag,lightVec[3];
            
            //Get a unit direction vector and magnitude.
            iauPn(vOrig+3*curVec, &vecMag, lightVec);
            
            //The light is in direction lightVec with speed c
            lightVec[0]*=c;
            lightVec[1]*=c;
            lightVec[2]*=c;
            
            //The light travels at speed c with true direction uPosition.
            //Add the velocity vector of the observer to that of light.
            relVecAddC(c,obsVel+3*curVec,lightVec,retVec+3*curVec);
            //Because one vector had a magnitude of c, the returned vector
            //must have the same magnitude. Restore the previous magnitude.
            retVec[3*curVec]*=vecMag/c;
            retVec[3*curVec+1]*=vecMag/c;
            retVec[3*curVec+2]*=vecMag/c;
        }
    }

    //Set the return value.
    plhs[0]=retMATLAB;
}