void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double *Jul1,*Jul2, *Jul1Ret, *Jul2Ret;
    mxArray *Jul1RetMATLAB,*Jul2RetMATLAB;
    size_t numRow, numCol, numElements,i;

    if(nrhs!=2) {
        mexErrMsgTxt("Wrong number of inputs");
    }

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

    numRow=mxGetM(prhs[0]);
    numCol=mxGetN(prhs[0]);
    numElements=numRow*numCol;

    if(numElements==0||numRow!=mxGetM(prhs[1])||numCol!=mxGetN(prhs[1])) {
        mexErrMsgTxt("The dimensionalities of the inputs are incorrect.");
        return;
    }
    checkRealDoubleArray(prhs[0]);
    checkRealDoubleArray(prhs[1]);
    Jul1=(double*)mxGetData(prhs[0]);
    Jul2=(double*)mxGetData(prhs[1]);

    //Allocate space for the return variables.
    Jul1RetMATLAB=mxCreateDoubleMatrix(numRow,numCol,mxREAL);
    Jul1Ret=(double*)mxGetData(Jul1RetMATLAB);
    Jul2RetMATLAB=mxCreateDoubleMatrix(numRow,numCol,mxREAL);
    Jul2Ret=(double*)mxGetData(Jul2RetMATLAB);

    for(i=0; i<numElements; i++) {
        int retVal;
        /*Call the function in the SOFA library.*/
        retVal=iauUtctai(Jul1[i], Jul2[i], Jul1Ret+i, Jul2Ret+i);

        switch(retVal) {
        case 1:
            mexWarnMsgTxt("Dubious Date entered.");
            break;
        case -1:
            mxDestroyArray(Jul1RetMATLAB);
            mxDestroyArray(Jul2RetMATLAB);
            mexErrMsgTxt("Unacceptable date entered");
            break;
        default:
            break;
        }
    }

    plhs[0]=Jul1RetMATLAB;
    if(nlhs>1) {
        plhs[1]=Jul2RetMATLAB;
    } else {
        mxDestroyArray(Jul2RetMATLAB);
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numVertices;
    double *vertices, A;

    if(nrhs!=1) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Incorrect number of outputs.");
        return;
    }

    checkRealDoubleArray(prhs[0]);
    
    //If an empty matrix is passed, return zero area.
    if(mxIsEmpty(prhs[0])) {
        const double retVal=0;
        plhs[0]=doubleMat2Matlab(&retVal,1,1);
        return;
    }
    
    if(mxGetM(prhs[0])!=2) {
        mexErrMsgTxt("The points have the wrong dimensionality.");
        return;
    }
    
    numVertices=mxGetN(prhs[0]);
    vertices=reinterpret_cast<double*>(mxGetData(prhs[0]));
    
    A=signedPolygonAreaCPP(vertices,numVertices);
    plhs[0]=doubleMat2Matlab(&A,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[]) {
    double *Jul1,*Jul2,*epochJ;
    size_t numRow, numCol, numElements,i;
    mxArray *JulianEpochRetMATLAB;
    
    if(nrhs!=2){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>1){
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }

    numRow=mxGetM(prhs[0]);
    numCol=mxGetN(prhs[0]);
    numElements=numRow*numCol;
    
    if(numElements==0||numRow!=mxGetM(prhs[1])||numCol!=mxGetN(prhs[1])) {
        mexErrMsgTxt("The dimensionalities of the inputs are incorrect.");
        return;
    }
    checkRealDoubleArray(prhs[0]);
    checkRealDoubleArray(prhs[1]);
    Jul1=(double*)mxGetData(prhs[0]);
    Jul2=(double*)mxGetData(prhs[1]);
    
    JulianEpochRetMATLAB=mxCreateDoubleMatrix(numRow,numCol,mxREAL);
    epochJ=(double*)mxGetData(JulianEpochRetMATLAB);

    for(i=0;i<numElements;i++) {
    /*Call the function in the SOFA library.*/
        epochJ[i]=iauEpj(Jul1[i], Jul2[i]);
    }
    
    plhs[0]=JulianEpochRetMATLAB;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double *vec, *retVec, TT1,TT2;
    double rb[3][3], rp[3][3], rbp[3][3];
    mxArray *retMATLAB;
    size_t i, numItems;

    if(nrhs!=3) {
        mexErrMsgTxt("Wrong number of inputs");
        return;
    }

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

    numItems=mxGetN(prhs[0]);
    if(mxGetM(prhs[0])!=3) {
        mexErrMsgTxt("vec has the wrong dimensionality. It must be an 3XN matrix.");
        return;
    }
    checkRealDoubleArray(prhs[0]);
    vec=(double*)mxGetData(prhs[0]);

    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);

    //Allocate the return vector
    retMATLAB=mxCreateDoubleMatrix(3,numItems,mxREAL);
    retVec=mxGetData(retMATLAB);

    //Call the IAU function to get the rotation matrix.
    iauBp06(TT1, TT2, rb, rp, rbp);

    //Invert the rotation matrix by transposing it.
    iauTr(rb, rb);
    for(i=0; i<numItems; i++) {
        //Multiply the original vectors by the matrix to put it into the ICRS.
        iauRxp(rb, vec+3*i, retVec+3*i);
    }

    //Set the return value.
    plhs[0]=retMATLAB;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numRow, numCol,numPoints, foundIdx;
    double *arr;
    mxArray *retIdx;
    
    if(nrhs<1){
        mexErrMsgTxt("Not enough inputs.");
        return;
    }
    
    if(nrhs>1) {
        mexErrMsgTxt("Too many inputs.");
        return;
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Too many outputs.");
    }
    
    /*Verify the validity of the vector to search.*/
    checkRealDoubleArray(prhs[0]);
    numRow = mxGetM(prhs[0]);
    numCol = mxGetN(prhs[0]);
    if(numRow>1&&numCol>1){
        mexErrMsgTxt("Too many dimensions in the array provided.");
        return;
    } else {
        if(numRow>numCol) {
            numPoints=numRow;
        } else {
            numPoints=numCol;
        }
    }
    
    arr = reinterpret_cast<double*>(mxGetData(prhs[0]));
    foundIdx= findFirstMaxCPP(arr,numPoints);
    
    //Set the return value
    retIdx=allocUnsignedSizeMatInMatlab(1,1);
    *reinterpret_cast<size_t *>(mxGetData(retIdx))=foundIdx+1;
    plhs[0]=retIdx;
}
void mexFunction(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[]) {
    double a,c,scalFactor;
    double *point;
    ClusterSetCPP<double> CStdDev;
    ClusterSetCPP<double> SStdDev;
    size_t numPoints;
    size_t i, M, totalNumEls;
    mxArray *sigma2MATLAB;
    //This variable is only used if nlhs>1. It is set to zero here to
    //suppress a warning if compiled using -Wconditional-uninitialized.
    mxArray *SigmaMATLAB=NULL;
    double *sigma2,*Sigma;
    bool didOverflow;
    size_t *theOffsetArray, *theClusterSizes;
    
    if(nrhs!=6) {
        mexErrMsgTxt("Wrong number of inputs.");
    }
    
    if(nlhs>3) {
        mexErrMsgTxt("Invalid number of outputs.");
    }
    
    //Check the validity of the ClusterSets
    checkRealDoubleArray(prhs[0]);
    checkRealDoubleArray(prhs[1]);
    
    //Make sure that both of the coefficient sets have the same number of
    //elements and are not empty.
    if(mxIsEmpty(prhs[0])||mxIsEmpty(prhs[1])||mxGetM(prhs[0])!=mxGetM(prhs[1])||mxGetN(prhs[0])!=mxGetN(prhs[1])) {
        mexErrMsgTxt("Invalid ClusterSet data passed.");
    }

    CStdDev.clusterEls=reinterpret_cast<double*>(mxGetData(prhs[0]));
    SStdDev.clusterEls=reinterpret_cast<double*>(mxGetData(prhs[1]));

    //The number of elements in the ClusterSets
    totalNumEls=mxGetM(prhs[0])*mxGetN(prhs[0]);
    
    //We do not want to trust that the offset arrays and the cluster arrays
    //are valid. Also, the data types of the passed values can vary (e.g.,
    //might be doubles). Thus, we this function does not take the offset
    //and number of clusters data from a ClusterSet class. Rather, it
    //recreates the values based on the length of the data. This avoids
    //possibly reading past the end of an array.
    
    //Since the total number of points in a ClusterSet
    //is (M+1)*(M+2)/2, where M is the number of clusters -1, we can easily
    //verify that a valid number of points was passed.
    //Some versions of Windows SDK have problems with passing an integer
    //type to the sqrt function, so this explicit typecasting should take
    //care of the problem.
    M=(-3+static_cast<size_t>(sqrt(static_cast<double>(1+8*totalNumEls))))/2;        
    if((M+1)*(M+2)/2!=totalNumEls) {
        mexErrMsgTxt("The ClusterSets contain an inconsistent number of elements.");
    }
    
    //Otherwise, fill in the values for the cluster sizes and the ofset
    //array.
    CStdDev.numClust=M+1;
    SStdDev.numClust=M+1;
    
    theOffsetArray=new size_t[M+1];
    theClusterSizes=new size_t[M+1];
    theClusterSizes[0]=1;
    theOffsetArray[0]=0;
    for(i=1;i<=M;i++) {
       theOffsetArray[i]=theOffsetArray[i-1]+theClusterSizes[i-1];
       theClusterSizes[i]=i+1; 
    }

    CStdDev.totalNumEl=totalNumEls;
    SStdDev.totalNumEl=totalNumEls;
    CStdDev.offsetArray=theOffsetArray;
    SStdDev.offsetArray=theOffsetArray;
    CStdDev.clusterSizes=theClusterSizes;
    SStdDev.clusterSizes=theClusterSizes;

    //Get the other parameters.
    checkRealDoubleArray(prhs[2]);
    point=reinterpret_cast<double*>(mxGetData(prhs[2]));
    numPoints=mxGetN(prhs[2]);
    a=getDoubleFromMatlab(prhs[3]);
    c=getDoubleFromMatlab(prhs[4]);
    scalFactor=getDoubleFromMatlab(prhs[5]);
    
    //Allocate space for the return values
    sigma2MATLAB=mxCreateDoubleMatrix(numPoints, 1,mxREAL);
    sigma2=reinterpret_cast<double*>(mxGetData(sigma2MATLAB));
    
    if(nlhs>1) {
        mwSize dims[3];
        //A 3X3X numPoints array is needed for the covariance matrices.
        dims[0]=3;
        dims[1]=3;
        dims[2]=numPoints;
        
        SigmaMATLAB=mxCreateNumericArray(3,dims,mxDOUBLE_CLASS,mxREAL);
        Sigma=reinterpret_cast<double*>(mxGetData(SigmaMATLAB));
    } else {
        Sigma=NULL;
    }
    didOverflow=spherHarmonicCovCPP(sigma2,Sigma,CStdDev,SStdDev,point,numPoints,a,c,scalFactor);
            
    //Free the allocated space for the offet array and cluster sizes
    delete[] theOffsetArray;
    delete[] theClusterSizes;
            
    plhs[0]=sigma2MATLAB;
    
    if(nlhs>1) {
        plhs[1]=SigmaMATLAB;
        if(nlhs>2) {
            plhs[2]=boolMat2Matlab(&didOverflow,1,1);
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    //The Julan date in TT at the epoch used in the orbital propagation
    //algorithm: 0:00 January 1 1950
    const double epochDate=2433281.5;
    double *deltaT;
    size_t numTimes;
    double SGP4Elements[7],elementEpochTime;
    bool opsMode=0;
    char opsChar;
    bool gravityModel=0;
    gravconsttype gravConstType;
    mxArray *retMat;
    double *retVec;
    mxArray *errorMat;
    double *errorVals;

    if(nrhs<2||nrhs>6||nrhs==3) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
    
    {
        const size_t M=mxGetM(prhs[0]);
        const size_t N=mxGetN(prhs[0]);
        if(!((M==7&&N==1)||(N==7&&M==1))) {
            mexErrMsgTxt("The SGP4 elements have the wrong dimensionality.");
            return; 
        }
    }
    
    checkRealDoubleArray(prhs[0]);
    {
        size_t i;
        double *theEls;
        theEls=(double*)mxGetData(prhs[0]);
        
        //Copy the elements into SGP4Elements, adjusting the units from SI
        //to the values used here.
        for(i=0;i<5;i++) {
            SGP4Elements[i]=theEls[i];
        }
        //The multipliation by 60 changes the value from radians per second
        //to radians per minute as desired by the SGP4 code.
        SGP4Elements[5]=theEls[5]*60.0;
        SGP4Elements[6]=theEls[6];
    }
    
    {
        const size_t M=mxGetM(prhs[1]);
        const size_t N=mxGetN(prhs[1]);
        
        if((M!=1&&N!=1)||mxIsEmpty(prhs[1])) {
            mexErrMsgTxt("The times have the wrong dimensionality.");
            return;
        }
        numTimes=std::max(M,N);
    }
    checkRealDoubleArray(prhs[1]);
    deltaT=(double*)mxGetData(prhs[1]);

    if(nrhs>2&&!mxIsEmpty(prhs[2])&&!mxIsEmpty(prhs[3])) {
        const double TT1=getDoubleFromMatlab(prhs[2]);
        const double TT2=getDoubleFromMatlab(prhs[3]);
        
        if(TT1>TT2) {
            elementEpochTime=(TT1-epochDate)+TT2;
        } else {
            elementEpochTime=(TT2-epochDate)+TT1;
        }
    } else {
        //No time is given. Make sure that the deep space propagator is not
        //going to be used. Otherwise, the time value does not matter.
        elementEpochTime=0;
        
        if(2*pi/SGP4Elements[5]>=225) {
            mexErrMsgTxt("The elements imply the use of the deep space propagator, but no time was given.");
            return;  
        }
    }
    
    if(nrhs>4) {
        opsMode=getBoolFromMatlab(prhs[4]);
    }
    
    if(opsMode==0) {
        opsChar='a';
    } else {
        opsChar='i';
    }
    
    if(nrhs>5) {
        gravityModel=getBoolFromMatlab(prhs[5]);
    }
    
    if(gravityModel==0) {
        gravConstType=wgs72;
    } else {
        gravConstType=wgs84;
    }
    
    //Allocate space for the return values
    retMat=mxCreateDoubleMatrix(6,numTimes,mxREAL);
    retVec=(double*)mxGetData(retMat);
    errorMat=mxCreateDoubleMatrix(numTimes,1,mxREAL);
    errorVals=(double*)mxGetData(errorMat);
    {
        //This will be filled with the ephemeris information needed for
        //propagating the satellite.
        elsetrec satRec;
        size_t i;
        
        sgp4init(gravConstType,//Specified WGS-84 or WGS-72
                 opsChar,
                 elementEpochTime,//Epoch time of the orbital elements.
                 SGP4Elements[6],//BSTAR drag term.
                 SGP4Elements[0],//Eccentricity
                 SGP4Elements[2],//Argument of perigee
                 SGP4Elements[1],//Inclination
                 SGP4Elements[4],//Mean anomaly
                 SGP4Elements[5],//Mean motion
                 SGP4Elements[3],//Righ ascension of the ascending node.
                 satRec);//Gets filled by the function.
                
        //Do the actual propagation.
        //The division by 60 transforms the time value from seconds to
        //minutes, as the SGP4 code wants the result in minutes.
        for(i=0;i<numTimes;i++) {
            double *r=retVec+6*i;
            double *v=retVec+6*i+3;
            int j;
            
            sgp4(gravConstType, satRec,  deltaT[i]/60.0, r,  v);
            
            //Convert the units from kilometers and kilometers per second
            //to meters and meters per second.
            for(j=0;j<3;j++) {
                r[j]=1000*r[j];
                v[j]=1000*v[j];
            }
            
            errorVals[i]=(double)satRec.error;
        }
    }
    
    //Save the result
    plhs[0]=retMat;
    
    //If the error value is desired.
    if(nlhs>1) {
        plhs[1]=errorMat;
    } else{
        mxDestroyArray(errorMat);
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t n;
    size_t prodDim;
    double *A, *B, *K;
    mxArray *retMat;
    const double sqrt2=sqrt(2);
    const double dblSqrt2=2*sqrt2;
    
    if(nrhs!=2) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }

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

    if((mxIsEmpty(prhs[0])&&!mxIsEmpty(prhs[1]))||(!mxIsEmpty(prhs[0])&&mxIsEmpty(prhs[1]))) {
        mexErrMsgTxt("Invalid use of empty matrices as inputs.");
        return;
    }
    
    //If two empty matrices are passed, then just return an empty matrix.
    if(mxIsEmpty(prhs[0])&&mxIsEmpty(prhs[1])) {
        plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
        return;
    }
    
    checkRealDoubleArray(prhs[0]);
    checkRealDoubleArray(prhs[1]);
    
    if(mxGetNumberOfDimensions(prhs[0])>2||mxGetNumberOfDimensions(prhs[1])>2) {
        mexErrMsgTxt("This function does not work with hypermatrices.");
        return; 
    }
    
    n=mxGetN(prhs[0]);
    if(n!=mxGetM(prhs[0])||n!=mxGetN(prhs[1])||n!=mxGetM(prhs[1])) {
        mexErrMsgTxt("This function only works with pairs of squares matrices.");
        return;
    }
    
    prodDim=(n*(n+1))/2;
    
    //Allocate space for the return matrix
    retMat=mxCreateDoubleMatrix(prodDim,prodDim,mxREAL);
    A=(double*)mxGetData(prhs[0]);
    B=(double*)mxGetData(prhs[1]);
    K=(double*)mxGetData(retMat);
    
    {
       size_t i1,i2,j1,j2;
        
        for(i1=1;i1<=n;i1++) {
            size_t col=i1+((i1-1)*(2*n-i1))/2;
            for(j1=1;j1<=n;j1++) {
                size_t KIdx=prodDim*(col-1)+j1+((j1-1)*(2*n-j1))/2-1;
                const size_t j1i1=j1+n*(i1-1)-1;
                size_t j2i1=j1i1;
                
                K[KIdx]=(A[j1i1]*B[j1i1]+B[j1i1]*A[j1i1])/2;
                for(j2=(j1+1);j2<=n;j2++) {
                    KIdx++;
                    j2i1++;
                    
                    K[KIdx]=(A[j1i1]*B[j2i1]+B[j1i1]*A[j2i1])/sqrt2;
                }
            }

            for(i2=(i1+1);i2<=n;i2++) {
                col++;
                for(j1=1;j1<=n;j1++) {
                    size_t KIdx=prodDim*(col-1)+j1+((j1-1)*(2*n-j1))/2-1;
                    const size_t j1i1=j1+n*(i1-1)-1;
                    const size_t j1i2=j1+n*(i2-1)-1;
                    size_t j2i1=j1i1;
                    size_t j2i2=j1i2;

                    K[KIdx]=(A[j1i1]*B[j1i2]+A[j1i2]*B[j1i1]+B[j1i1]*A[j1i2]+B[j1i2]*A[j1i1])/dblSqrt2;     
                    for(j2=(j1+1);j2<=n;j2++) {
                        KIdx++;
                        j2i1++;
                        j2i2++;
                        
                        K[KIdx]=(A[j1i1]*B[j2i2]+A[j1i2]*B[j2i1]+B[j1i1]*A[j2i2]+B[j1i2]*A[j2i1])/2;
                    }
                }
            }
        }
    }
    
    plhs[0]=retMat;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    const mxArray *MatlabFunctionHandle;
    direct_algorithm theAlgorithm=DIRECT_ORIGINAL;
    const direct_objective_func f=&MatlabCallback;
    size_t numDim;
    double *lowerBounds;
    double *upperBounds;
    int maxFEval=500;
    int maxIter=100;
    double epsilon=1e-4;
    double epsilonAbs=0;
    double volumeRelTol=1e-10;
    double sigmaRelTol=0;
    double fGlobal=DIRECT_UNKNOWN_FGLOBAL;
    double fGlobalRelTol=DIRECT_UNKNOWN_FGLOBAL;
    int maxDiv=5000;
    //To hold return values
    direct_return_code retVal;
    double *x;
    double fVal;
    
    if(nrhs<3||nrhs>4){
        mexErrMsgTxt("Wrong number of inputs");
    }

    if(nlhs>3) {
        mexErrMsgTxt("Wrong number of outputs.");
    }
    
    //Check that a function handle was passed.
    if(!mxIsClass(prhs[0],"function_handle")) {
        mexErrMsgTxt("The first input must be a function handle.");
    }
    MatlabFunctionHandle=prhs[0];
    
    //Check the lower and upper bounds
    checkRealDoubleArray(prhs[1]);
    checkRealDoubleArray(prhs[2]);
    numDim=mxGetM(prhs[1]);
    if(numDim<1||mxGetN(prhs[1])!=1) {
        mexErrMsgTxt("The lower bounds have the wrong dimensionality.");
    }
    if(mxGetM(prhs[2])!=numDim||mxGetN(prhs[1])!=1) {
        mexErrMsgTxt("The upper bounds have the wrong dimensionality.");
    }
    
    //The function in the library only uses integers for dimensions.
    if(numDim>INT_MAX) {
        mexErrMsgTxt("The problem has too many dimensions to be solved using this function.");
    }
    
    lowerBounds=(double*)mxGetData(prhs[1]);
    upperBounds=(double*)mxGetData(prhs[2]);
    
    //If a structure of options was given
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        //We have to check for every possible structure member.
        mxArray *theField;
        
        if(!mxIsStruct(prhs[3])) {
            mexErrMsgTxt("The options must be given in a structure.");
        }
    
        theField=mxGetField(prhs[3],0,"algorithm");
        
        if(theField!=NULL) {//If the field is present.
            int algType=getIntFromMatlab(theField);
            
            //Algorithm type
            switch(algType) {
              case 0:
                  theAlgorithm=DIRECT_ORIGINAL;
                  break;
              case 1:
                  theAlgorithm=DIRECT_GABLONSKY;
                  break;
              default:
                  mexErrMsgTxt("Invalid algorithm specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"maxDiv");
        if(theField!=NULL) {//If the field is present.
            maxDiv=getIntFromMatlab(theField);
            if(maxDiv<1) {
                mexErrMsgTxt("Invalid maxDiv specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"maxIter");
        if(theField!=NULL) {//If the field is present.
            maxIter=getIntFromMatlab(theField);
            if(maxIter<1) {
                mexErrMsgTxt("Invalid maxIter specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"maxFEval");
        if(theField!=NULL) {//If the field is present.
            maxFEval=getIntFromMatlab(theField);
            if(maxIter<1) {
                mexErrMsgTxt("Invalid maxFEval specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"epsilon");
        if(theField!=NULL) {//If the field is present.
            epsilon=getDoubleFromMatlab(theField);
            if(fabs(epsilon)>=1) {
                mexErrMsgTxt("Invalid epsilon specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"epsilonAbs");
        if(theField!=NULL) {//If the field is present.
            epsilonAbs=getDoubleFromMatlab(theField);
            if(epsilonAbs>=1||epsilonAbs<0) {
                mexErrMsgTxt("Invalid epsilonAbs specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"volumeRelTol");
        if(theField!=NULL) {//If the field is present.
            volumeRelTol=getDoubleFromMatlab(theField);
            if(volumeRelTol>=1||volumeRelTol<0) {
                mexErrMsgTxt("Invalid volumeRelTol specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"sigmaRelTol");
        if(theField!=NULL) {//If the field is present.
            sigmaRelTol=getDoubleFromMatlab(theField);
            if(sigmaRelTol>=1||sigmaRelTol<0) {
                mexErrMsgTxt("Invalid sigmaRelTol specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"fGlobal");
        if(theField!=NULL) {//If the field is present.
            fGlobal=getDoubleFromMatlab(theField);
            fGlobalRelTol=1e-12;//Default value if fGlobal is given.
        }
        
        theField=mxGetField(prhs[3],0,"fGlobalRelTol");
        if(theField!=NULL) {//If the field is present.
            fGlobalRelTol=getDoubleFromMatlab(theField);
            if(fGlobalRelTol<0) {
                mexErrMsgTxt("Invalid fGlobalRelTol specified");
            }
        }      
    }
    
    //Allocate space for the return values
    x=mxCalloc(numDim, sizeof(double));

    retVal=direct_optimize(f,//Objective function pointer
            (void*)MatlabFunctionHandle,//Data that passed to the objective function. Here, the function handle passed by the user.
            (int)numDim,//The dimensionality of the problem
            lowerBounds,//Array of the lower bound of each dimension.
            upperBounds,//Array of the upper bound of each dimension.
            x,//An array that will be set to the optimum value on return.
            &fVal,//On return, set to the minimum value.
            maxFEval,//Maximum number of function evaluations.
            maxIter,//Maximum number of iterations
            epsilon,//Jones' epsilon parameter (1e-4 is recommended)
            epsilonAbs,//An absolute version of magic_eps
            //Relative tolerance on the hypercube volume (use 0 if none). This is
            //a percentage (0-1) of the volume of the original hypercube
            volumeRelTol,
            //Relative tolerance on the hypercube measure (0 if none)
            sigmaRelTol,
            //A pointer to a variable that can terminate the optimization. This is
            //in the library's code so that an external thread can write to this
            //and force the optimization to stop. Here, we are not using it, so we
            //can pass NULL.
            NULL,
            fGlobal,//Function value of the global optimum, if known. Use DIRECT_UNKNOWN_FGLOBAL if unknown.
            fGlobalRelTol,//Relative tolerance for convergence if fglobal is known. If unknown, use DIRECT_UNKNOWN_FGLOBAL.
            NULL,//There is no output to a file.
            theAlgorithm,//The algorithm to use
            maxDiv);//The maximum number of hyperrectangle divisions

    //If an error occurred
    if(retVal<0) {
        mxFree(x);
        switch(retVal){
            case DIRECT_INVALID_BOUNDS:
                mexErrMsgTxt("Upper bounds are <= lower bounds for one or more dimensions.");
            case DIRECT_MAXFEVAL_TOOBIG:
                mexErrMsgTxt("maxFEval is too large.");
            case DIRECT_INIT_FAILED:
                mexErrMsgTxt("An initialization step failed.");
            case DIRECT_SAMPLEPOINTS_FAILED:
                 mexErrMsgTxt("An error occurred creating sampling points.");
            case DIRECT_SAMPLE_FAILED:
                mexErrMsgTxt("An error occurred while sampling the function.");
            case DIRECT_OUT_OF_MEMORY:
                mexErrMsgTxt("Out of memory");
            case DIRECT_INVALID_ARGS:
                mexErrMsgTxt("Invalid arguments provided");
            //These errors should not occur either because they should
            //never be called or because retVal>=0 so these are not
            //actually errors.
            case DIRECT_FORCED_STOP:
            case DIRECT_MAXFEVAL_EXCEEDED:
            case DIRECT_MAXITER_EXCEEDED:
            case DIRECT_GLOBAL_FOUND:
            case DIRECT_VOLTOL:
            case DIRECT_SIGMATOL:
            case DIRECT_MAXTIME_EXCEEDED:
            default:
                mexErrMsgTxt("An unknown error occurred.");
            
        }
    }
    
    //Set the return values
    plhs[0]=mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
    mxFree(mxGetPr(plhs[0]));
    mxSetPr(plhs[0], x);
    mxSetM(plhs[0], numDim);
    mxSetN(plhs[0], 1);

    if(nlhs>1) {
        plhs[1]=doubleMat2Matlab(&fVal,1,1);
        if(nlhs>2) {
            plhs[2]=intMat2MatlabDoubles(&retVal,1,1);
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numRow,numVec;
    mxArray *retMat;
    double *retData;
    double ITRS2TIRS[3][3];//Inverse polar motion matrix
    double *xVec, TT1, TT2;
    double xp=0;
    double yp=0;//The polar motion coordinates
    
    if(nrhs<3||nrhs>4){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
    }
    
    numRow = mxGetM(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(!(numRow==3||numRow==6)) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    checkRealDoubleArray(prhs[0]);
    xVec=(double*)mxGetData(prhs[0]);
    
    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);
    //If xpyp should be found using the function getEOP.
   if(nrhs<4||mxIsEmpty(prhs[3])) {
        mxArray *retVals[1];
        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(1,retVals,2,JulUTCMATLAB,"getEOP");
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
        
        checkRealDoubleArray(retVals[0]);
        if(mxGetM(retVals[0])!=2||mxGetN(retVals[0])!=1) {
            mxDestroyArray(retVals[0]);
            mexErrMsgTxt("Error using the getEOP function.");
            return;
        }
        
        xpyp=(double*)mxGetData(retVals[0]);
        xp=xpyp[0];
        yp=xpyp[1];

        //Free the returned array.
        mxDestroyArray(retVals[0]);
    }
    
     //Get polar motion coordinates, if given.
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        size_t dim1, dim2;
        
        checkRealDoubleArray(prhs[3]);
        dim1 = mxGetM(prhs[3]);
        dim2 = mxGetN(prhs[3]);
        
        if((dim1==2&&dim2==1)||(dim1==1&&dim2==2)) {
            double *xpyp=(double*)mxGetData(prhs[3]);
        
            xp=xpyp[0];
            yp=xpyp[1];
        } else {
            mexErrMsgTxt("The polar motion coordinates have the wrong dimensionality.");
            return;
        }
    }

    //Get the rotation matrix from TIRS to ITRS.
    {
        double sp;
        double TIRS2ITRS[3][3];//Polar motion matrix
        //Get the Terrestrial Intermediate Origin (TIO) locator s' in
        //radians
        sp=iauSp00(TT1,TT2);
        
        //Get the polar motion matrix
        iauPom00(xp,yp,sp,TIRS2ITRS);
        
        //The inverse polar motion matrix is given by the transpose of the
        //polar motion matrix.
        iauTr(TIRS2ITRS, ITRS2TIRS); 
    }
    
    //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(ITRS2TIRS, xVec+numRow*curVec, retData+numRow*curVec);
        
        //Multiply the velocity vector with the rotation matrix.
        if(numRow>3) {
            double *velITRS=xVec+numRow*curVec+3;//Velocity in ITRS
            double *retDataVel=retData+numRow*curVec+3;//Velocity in ITRS

            //Convert velocity from ITRS to TIRS.
            iauRxp(ITRS2TIRS, velITRS, 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]=ITRS2TIRS[i][j];
            }
        }
    }
}
Esempio n. 12
0
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double *year,*month,*day,*hour,*minute,*second,*Jul1,*Jul2;
    mxArray *Jul1MATLAB,*Jul2MATLAB;
    size_t numRow,numCol,numElements,i;

    if(nrhs!=6){
        mexErrMsgTxt("Wrong number of inputs");
    }
      
    if(nlhs>2){
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
    
    numRow=mxGetM(prhs[0]);
    numCol=mxGetN(prhs[0]);
    numElements=numRow*numCol;
    
    if(numElements==0) {
        mexErrMsgTxt("The dimensionalities of the inputs are incorrect.");
        return;
    }
    
    for(i=0;i<6;i++) {
        if(numRow==mxGetM(prhs[i])&&numCol==mxGetN(prhs[i])) {
            checkRealDoubleArray(prhs[i]);
        } else {
            mexErrMsgTxt("The dimensionalities of the inputs are incorrect.");
            return;
        }
    }
    
    /*Extract the input arguments.*/
    year=(double*)mxGetData(prhs[0]);
    month=(double*)mxGetData(prhs[1]);
    day=(double*)mxGetData(prhs[2]);
    hour=(double*)mxGetData(prhs[3]);
    minute=(double*)mxGetData(prhs[4]);
    second=(double*)mxGetData(prhs[5]);
    
    //Allocate space for the return variables.
    Jul1MATLAB=mxCreateDoubleMatrix(numRow,numCol,mxREAL);
    Jul1=(double*)mxGetData(Jul1MATLAB);
    Jul2MATLAB=mxCreateDoubleMatrix(numRow,numCol,mxREAL);
    Jul2=(double*)mxGetData(Jul2MATLAB);
    
/*Call the function in the SOFA library.*/
    
    for(i=0;i<numElements;i++) {
        int retVal;
        
        retVal=iauDtf2d("UTC",(int)year[i],(int)month[i],(int)day[i],(int)hour[i],(int)minute[i],second[i], &Jul1[i], &Jul2[i]);
        
        switch(retVal){
            case 3:
                mexWarnMsgTxt("The time is after the end of the day and the year is dubious.");
                break;
            case 2:
                mexWarnMsgTxt("The time is after the end of the day.");
                break;
            case 1:
                mexWarnMsgTxt("The year is dubious.");
                break;
            case -1:
                mxDestroyArray(Jul1MATLAB);
                mxDestroyArray(Jul2MATLAB);
                mexErrMsgTxt("Bad year given.");
                return;
            case -2:
                mxDestroyArray(Jul1MATLAB);
                mxDestroyArray(Jul2MATLAB);
                mexErrMsgTxt("Bad month given.");
                return;
            case -3:
                mxDestroyArray(Jul1MATLAB);
                mxDestroyArray(Jul2MATLAB);
                mexErrMsgTxt("Bad day given.");
                return;
            case -4:
                mxDestroyArray(Jul1MATLAB);
                mxDestroyArray(Jul2MATLAB);
                mexErrMsgTxt("Bad hour given.");
                return;
            case -5:
                mxDestroyArray(Jul1MATLAB);
                mxDestroyArray(Jul2MATLAB);
                mexErrMsgTxt("Bad minute given.");
                return;
            case-6:
                mxDestroyArray(Jul1MATLAB);
                mxDestroyArray(Jul2MATLAB);
                mexErrMsgTxt("Bad second given.");
                return;
            default:
                break;
        }
    }
    
    plhs[0]=Jul1MATLAB;
    if(nlhs>1) {
        plhs[1]=Jul2MATLAB;
    } else {
        mxDestroyArray(Jul2MATLAB);
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t i, numRows,numCols, numEls;
    double minBound, maxBound, *vals, *wrapVals;
    mxArray *retMat;
    bool mirrorWrap=false;
    
    
    if(nrhs<3){
        mexErrMsgTxt("Not enough inputs.");
        return;
    }
    
    if(nrhs>4) {
        mexErrMsgTxt("Too many inputs.");
        return;
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Too many outputs.");
        return;
    }
    
    checkRealDoubleArray(prhs[0]);
    numRows=mxGetM(prhs[0]);
    numCols=mxGetN(prhs[0]);
    numEls=numRows*numCols;
    
    //If given an empty matrix, return an empty matrix.
    if(numEls==0) {
        plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
        return;
    }
    
    vals=(double*)mxGetData(prhs[0]);
    
    minBound=getDoubleFromMatlab(prhs[1]);
    maxBound=getDoubleFromMatlab(prhs[2]);
    
    if(maxBound<=minBound) {
        mexErrMsgTxt("the maximum bound must be less than the minimum bound.");
    }
    
    if(nrhs>3) {
        mirrorWrap=getBoolFromMatlab(prhs[3]);
    }
    
    //Allocate space for the return values.
    retMat=mxCreateDoubleMatrix(numRows,numCols,mxREAL);
    wrapVals=(double*)mxGetData(retMat);
    
    if(mirrorWrap) {
        for(i=0;i<numEls;i++) {
            wrapVals[i]=wrapRangeMirrorCPP(vals[i],minBound,maxBound);
        }
    } else {
       for(i=0;i<numEls;i++) {
            wrapVals[i]=wrapRangeCPP(vals[i],minBound,maxBound);
        }
    }
    
    plhs[0]=retMat;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numSource, numBodies, baseIdx,curBody,curSource;
    double *vObsSource,posObs[3], *MSolar, *xBody, *deflecLimit;
    iauLDBODY *bodyParam;
    mxArray *vDeflMATLAB;
    double *vDefl;

    if(nrhs<4||nrhs>5) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }

    //Check the inputs
    checkRealDoubleArray(prhs[0]);
    checkRealDoubleArray(prhs[1]);
    checkRealDoubleArray(prhs[2]);
    
    //Check the inputs
    numSource=mxGetN(prhs[0]);

    if(mxGetM(prhs[0])!=3||numSource==0) {
        mexErrMsgTxt("The input vObsSource has the wrong dimensionality.");
    }

    if(mxGetM(prhs[1])!=3||mxGetN(prhs[1])!=1) {
        mexErrMsgTxt("The input posObs has the wrong dimensionality.");
    }

    numBodies=mxGetM(prhs[2]);

    if(numBodies==0||mxGetN(prhs[2])!=1) {
        mexErrMsgTxt("The input MSolar has the wrong dimensionality.");
    }

    if(mxGetM(prhs[3])!=6||mxGetN(prhs[2])!=numBodies) {
        mexErrMsgTxt("The input xBody has the wrong dimensionality.");
    }

    if(nrhs>3) {
        checkRealDoubleArray(prhs[4]); 

        if(mxGetM(prhs[4])!=numBodies||mxGetN(prhs[4])!=1) {
           mexErrMsgTxt("The input deflecLimit has the wrong dimensionality."); 
        }

    } else {
        deflecLimit=NULL;
    }

    vObsSource=(double*)mxGetData(prhs[0]);
            
    //Get the observer position and convert from meters to AU.
    {
        double *temp=(double*)mxGetData(prhs[1]);
        posObs[0]=temp[0]/DAU;
        posObs[1]=temp[1]/DAU;
        posObs[2]=temp[2]/DAU;
    }
    
    MSolar=(double*)mxGetData(prhs[2]);
    //The units have to be converted to AU and AU/Day
    xBody=(double*)mxGetData(prhs[3]);
       
    //Allocate space to hold the parameters of the astronomical bodies in a
    //manner suitable for the iauLdn function.
    bodyParam=(iauLDBODY*)mxMalloc(sizeof(iauLDBODY)*numBodies);
             
    baseIdx=0;
    for(curBody=0;curBody<numBodies;curBody++) {
        int i;
        
        bodyParam[curBody].bm=MSolar[curBody];
        if(deflecLimit!=NULL) {
            bodyParam[curBody].dl=deflecLimit[curBody];
        } else {
            //A value suitably small for Saturn.
            bodyParam[curBody].dl=3e-10;
        }
        
        //Position
        for(i=0;i<3;i++) {
            //The division converts from meters to AU.
            bodyParam[curBody].pv[0][i]=xBody[baseIdx+i]/DAU;
        }
        
        //Velocity
        for(i=0;i<3;i++) {
            //Convert from meters per second BCRS to AU/ day.
            bodyParam[curBody].pv[1][i]=xBody[3+baseIdx+i]*(1/DAU)*(1/DAYSEC);
        }
        
        baseIdx+=6;
    }
    
    //Allocate space for the return values.
    vDeflMATLAB=mxCreateDoubleMatrix(3,numSource,mxREAL);
    vDefl=(double*)mxGetData(vDeflMATLAB);
    
    baseIdx=0;
    for(curSource=0;curSource<numSource;curSource++) {
        double vecMag, sc[3];//Unit vector to the source
        
        //Get a unit direction vector and magnitude to the current source.
        iauPn(vObsSource+baseIdx, &vecMag, sc);
        
        iauLdn(numBodies, bodyParam, posObs, sc,vDefl+baseIdx);
        
        //Deal with possibly non-unit magnitudes on the input.
        vDefl[baseIdx]*=vecMag;
        vDefl[baseIdx+1]*=vecMag;
        vDefl[baseIdx+2]*=vecMag;
        
        baseIdx+=3;
    }
    
    //Free temporary memory; set the return value.
    mxFree(bodyParam);
    plhs[0]=vDeflMATLAB;
}
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;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    char cmd[64];
    metricTreeCPP *theTree;
    
    if(nrhs>4) {
        mexErrMsgTxt("Too many inputs.");   
    }
    
    //Get the command string that is passed.
    mxGetString(prhs[0], cmd, sizeof(cmd));
    
    //prhs[0] is assumed to be the string telling
    if(!strcmp("metricTreeCPP", cmd)){
        size_t k, N;
        mxArray *retPtr;
        
        k=getSizeTFromMatlab(prhs[1]);
        N=getSizeTFromMatlab(prhs[2]);
        
        theTree =  new metricTreeCPP(k,N);
        
        //Convert the pointer to a Matlab matrix to return.
        retPtr=ptr2Matlab<metricTreeCPP*>(theTree);
        
        //Lock this mex file so that it can not be cleared until the object
        //has been deleted (This avoids a memory leak).
        mexLock();
        //Return the pointer to the tree
        plhs[0]=retPtr;
    } else if(!strcmp("buildTreeFromBatch",cmd)) {
        double *dataBatch;
        
        //Get the pointer back from Matlab.
        theTree=Matlab2Ptr<metricTreeCPP*>(prhs[1]);   
        
        checkRealDoubleArray(prhs[2]);
        dataBatch=reinterpret_cast<double*>(mxGetData(prhs[2]));
        
        theTree->buildTreeFromBatch(dataBatch);
    } else if(!strcmp("searchRadius",cmd)) {
        size_t numPoints;
        ClusterSetCPP<size_t> pointClust;
        ClusterSetCPP<double> distClust;
        double *point;
        double *radius;
        mxArray *clustParams[3];
        
        //Get the inputs
        theTree=Matlab2Ptr<metricTreeCPP*>(prhs[1]);
        checkRealDoubleArray(prhs[2]);
        checkRealDoubleArray(prhs[3]);
        point=reinterpret_cast<double*>(mxGetData(prhs[2]));
        radius=reinterpret_cast<double*>(mxGetData(prhs[3]));
        
        numPoints=mxGetN(prhs[2]);
        if(mxGetM(prhs[2])!=theTree->k){
            mexErrMsgTxt("Invalid point size passed.");
        }
        
        //Run the search; rangeCluster now contains the results.
        theTree->searchRadius(pointClust,distClust,point,radius, numPoints);
        
        //Put the results into an instance of the ClusterSet container 
        //class in Matlab.
        clustParams[0]=unsignedSizeMat2Matlab(pointClust.clusterEls,pointClust.totalNumEl,1);
        clustParams[1]=unsignedSizeMat2Matlab(pointClust.clusterSizes,pointClust.numClust,1);
        clustParams[2]=unsignedSizeMat2Matlab(pointClust.offsetArray,pointClust.numClust,1);
        
        //Return a ClusterSet containing the appropriate data.
        mexCallMATLAB(1, &(plhs[0]), 3,  clustParams, "ClusterSet");
        
        //If the distances should also be returned.
        if(nlhs>1) {
            clustParams[0]=doubleMat2Matlab(distClust.clusterEls,distClust.totalNumEl,1);
            clustParams[1]=unsignedSizeMat2Matlab(distClust.clusterSizes,distClust.numClust,1);
            clustParams[2]=unsignedSizeMat2Matlab(distClust.offsetArray,distClust.numClust,1);
        
            //Return a ClusterSet containing the appropriate data.
            mexCallMATLAB(1, &(plhs[1]), 3,  clustParams, "ClusterSet");
        }
    } else if(!strcmp("~metricTreeCPP", cmd)){
        theTree=Matlab2Ptr<metricTreeCPP*>(prhs[1]);

        delete theTree;
        //Unlock the mex file allowing it to be cleared.
        mexUnlock();
    } else if(!strcmp("getAllData", cmd)){
        size_t N;
        size_t k;
        
        theTree=Matlab2Ptr<metricTreeCPP*>(prhs[1]);
        N=theTree->N;
        k=theTree->k;
        
        plhs[0]=unsignedSizeMat2Matlab(theTree->DATAIDX,N, 1);
        if(nlhs>1) {
            plhs[1]=signedSizeMat2Matlab(theTree->innerChild,N, 1);
            if(nlhs>2) {
                plhs[2]=signedSizeMat2Matlab(theTree->outerChild,N, 1);
                if(nlhs>3) {
                    plhs[3]=doubleMat2Matlab(theTree->innerRadii,N, 1);
                    if(nlhs>4) {
                        plhs[4]=doubleMat2Matlab(theTree->outerRadii,N, 1);
                        if(nlhs>5) {
                            plhs[5]=doubleMat2Matlab(theTree->data,k, N);
                        }
                    }
                }
            }   
        }
    } else if(!strcmp("getN", cmd)) {
        theTree=Matlab2Ptr<metricTreeCPP*>(prhs[1]);
        plhs[0]=unsignedSizeMat2Matlab(&(theTree->N),1,1);
    } else if(!strcmp("getk", cmd)) {
        theTree=Matlab2Ptr<metricTreeCPP*>(prhs[1]);
        plhs[0]=unsignedSizeMat2Matlab(&(theTree->k),1,1);
    }else {
        mexErrMsgTxt("Invalid string passed to metricTreeCPPInt.");
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numPolyVertices, numClipVertices; 
    double *convexClipPolygon, *curPolygon, *clippedPolygonNew;
    double *prevClipVertex;
    mxArray *curPolygonMat, *clippedPolygonNewMat;
    size_t curClip,numVertices;
            
    if(nrhs!=2) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Incorrect number of outputs.");
        return;
    }
    
    //Return an empty matrix if an empty polygon is passed.
    if(mxIsEmpty(prhs[0])){
        plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
        return;
    }
    
    if(mxGetM(prhs[0])!=2||mxGetM(prhs[1])!=2) {
        mexErrMsgTxt("The polygons must be two-dimensional.");
        return;
    }
    
    checkRealDoubleArray(prhs[0]);
    numPolyVertices=mxGetN(prhs[0]);
    if(numPolyVertices<3) {
        mexErrMsgTxt("The polygon to be clipped must have at least three vertices.");
        return;
    }

    checkRealDoubleArray(prhs[1]);
    numClipVertices=mxGetN(prhs[1]);
    if(numClipVertices<3) {
        mexErrMsgTxt("The clipping polygon must have at least three vertices.");
        return;
    }
    convexClipPolygon=(double*)mxGetData(prhs[1]);
    
    //The clipping polygon must have its vertices going in a
    //counterclockwise order. Check whether that is the case. If not, then
    //reverse the order.
    if(signedPolygonAreaCPP(convexClipPolygon,numClipVertices)<0) {
        mexErrMsgTxt("The vertices of the clipping polygon should be in a counterclockwise order. Reverse the order of the vertices and try again.");
        return;
    }
    
    //Allocate space for the new polygon and for temporary scratch space.
    {
        //The maximum possible number of vertices in the clipped polygon.
        const size_t maxClippedVertices=(numPolyVertices*3)/2+1;
        size_t i;
        double *inputEls=(double*)mxGetData(prhs[0]);
                
        curPolygonMat=mxCreateDoubleMatrix(2,maxClippedVertices,mxREAL);
        clippedPolygonNewMat=mxCreateDoubleMatrix(2,maxClippedVertices,mxREAL);
        
        curPolygon=(double*)mxGetData(curPolygonMat);
        clippedPolygonNew=(double*)mxGetData(clippedPolygonNewMat);
        
        //Copy the values in prhs[0] into curPolygon.        
        for(i=0;i<2*numPolyVertices;i++) {
            curPolygon[i]=inputEls[i];
        }
        
        //The current number of vertices in curPolygon.
        numVertices=numPolyVertices;
    }
    
    //The first clipping edge will be the one from the end to the
    //beginning.
    prevClipVertex=convexClipPolygon+2*(numClipVertices-1);
    //For each edge, create the reduced polygon by clipping with that edge. 
    for(curClip=0;curClip<numClipVertices;curClip++) {
        double *curClipVertex=convexClipPolygon+2*curClip;
        double *prevVertex;
        //The polygon will be clipped to this edge this iteration.
        const double curClipEdge[2]={curClipVertex[0]-prevClipVertex[0],curClipVertex[1]-prevClipVertex[1]};
        size_t curV, numVerticesNew;
        double *curClippedPolygonNew=clippedPolygonNew;
        
        //Number of vertices that have been added to clippedPolygonNew
        numVerticesNew=0;
        prevVertex=curPolygon+2*(numVertices-1);
        
        for(curV=0;curV<numVertices;curV++) {
            double *curVertex=curPolygon+2*curV;
            
            //Note that the clip edges are infinitely extended so that
            //vertices outside of the clipping region are involved.
            if(vertexIsInsideClipEdge(curVertex,prevClipVertex,curClipEdge)) {
                //If the current vertex is inside of the clipping region,
                //then add it, but if the previous vertex was not in the
                //clipping region, then an extra vertex at the edge of the
                //boundary region needs to be added.
                if(!vertexIsInsideClipEdge(prevVertex,prevClipVertex,curClipEdge)) {
                    //[prevVertex,curVertex]
                    const double line1[4]={prevVertex[0],prevVertex[1],curVertex[0],curVertex[1]};
                    //[curClipVertex,prevClipVertex]
                    const double line2[4]={curClipVertex[0],curClipVertex[1],prevClipVertex[0],prevClipVertex[1]};
                    
                    twoLineIntersectionPoint2DCPP(line1,line2,curClippedPolygonNew);
                    curClippedPolygonNew+=2;
                    numVerticesNew++;
                }

                curClippedPolygonNew[0]=curVertex[0];
                curClippedPolygonNew[1]=curVertex[1];
                curClippedPolygonNew+=2;
                numVerticesNew++;
            }else if(vertexIsInsideClipEdge(prevVertex,prevClipVertex,curClipEdge)) {
                //If the previous vertex was inside of the clipping region
                //and this vertex is not, then add a line segment from the
                //previous vertex to the edge of the clipping region. 
                //[prevVertex,curVertex]
                const double line1[4]={prevVertex[0],prevVertex[1],curVertex[0],curVertex[1]};
                //[curClipVertex,prevClipVertex]
                const double line2[4]={curClipVertex[0],curClipVertex[1],prevClipVertex[0],prevClipVertex[1]};

                twoLineIntersectionPoint2DCPP(line1,line2,curClippedPolygonNew);
                curClippedPolygonNew+=2;
                numVerticesNew++;
            }
            
            prevVertex=curVertex;
        }

        {//Swap the buffers.
            double *temp=curPolygon;
            curPolygon=clippedPolygonNew;
            numVertices=numVerticesNew;
            clippedPolygonNew=temp;
        }
        
        //The object is not in the viewing area at all.
        if(numVertices==0) {
            mxFree(curPolygonMat);
            mxFree(clippedPolygonNewMat);
            plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
            return;
        }
        
        prevClipVertex=curClipVertex;
    }

    //curPolygon is what should be returned. This corresponds to either 
    //curPolygonMat or clippedPolygonNewMat, since the buffers were
    //exchanged during the loops. Determine which is curPolygon and return
    //it, freeing the other. 
    if(curPolygon==(double*)mxGetData(curPolygonMat)) {
        //Resize to fit.
        mxSetN(curPolygonMat,numVertices);
        plhs[0]=curPolygonMat;
        mxDestroyArray(clippedPolygonNewMat);
    } else  {
        mxSetN(clippedPolygonNewMat,numVertices);
        plhs[0]=clippedPolygonNewMat;
        mxDestroyArray(curPolygonMat);
    }
}
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 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(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[]) {
    size_t numRow, numCol;
    mxArray *AMat=NULL;
    double *A,permVal;

    if(nrhs<1) {
        mexErrMsgTxt("Not enough inputs.");
    }

    if(nrhs>3) {
        mexErrMsgTxt("Too many inputs.");
    }

    if(nlhs>1) {
        mexErrMsgTxt("Too many outputs.");
    }

    numRow = mxGetM(prhs[0]);
    numCol = mxGetN(prhs[0]);

    //Empty matrices have a matrix permanent of one by definition.
    if(numRow==0||numCol==0) {
        const double retVal=1;
        plhs[0]=doubleMat2Matlab(&retVal,1,1);
        return;
    }

    checkRealDoubleArray(prhs[0]);

    //If skip lists have bee provided, then use them.
    if(nrhs>1) {
        size_t i, numRowsSkipped,numColsSkipped,numRowsKept,numColsKept;
        size_t arrayLen;
        bool *boolColsSkip, *boolRowsSkip;
        size_t *keptBuffer, *rows2Keep, *cols2Keep;
        bool didAlloc=false;

        if(nrhs<3||mxIsEmpty(prhs[2])) {
            boolColsSkip=reinterpret_cast<bool*>(mxMalloc(numCol*sizeof(bool)));
            //Set all of the entries to false since no column is skipped.
            std::fill_n(boolColsSkip, numCol, false);
            arrayLen=numCol;
        } else {
            boolColsSkip=copyBoolArrayFromMatlab(prhs[2], &arrayLen);
            if(arrayLen!=numCol) {
                mxFree(boolColsSkip);
                mexErrMsgTxt("The column skip list has the wrong length.");
            }
        }

        //Count the number of skipped columns
        numColsSkipped=0;
        for(i=0; i<numCol; i++) {
            numColsSkipped+=boolColsSkip[i];
        }

        if(mxIsEmpty(prhs[1])) {
            boolRowsSkip=reinterpret_cast<bool*>(mxMalloc(numRow*sizeof(bool)));
            //Set all of the entries to false since no column is skipped.
            std::fill_n(boolRowsSkip, numRow, false);
            arrayLen=numRow;
        } else {
            boolRowsSkip=copyBoolArrayFromMatlab(prhs[1], &arrayLen);
            if(arrayLen!=numRow) {
                mxFree(boolRowsSkip);
                mexErrMsgTxt("The row skip list has the wrong length.");
            }
        }

        //Count the number of skipped rows
        numRowsSkipped=0;
        for(i=0; i<arrayLen; i++) {
            numRowsSkipped+=boolRowsSkip[i];
        }

        numRowsKept=numRow-numRowsSkipped;
        numColsKept=numCol-numColsSkipped;

        //Empty matrices have a matrix permanent of one by definition.
        if(numRowsKept==0||numColsKept==0) {
            const double retVal=1;
            plhs[0]=doubleMat2Matlab(&retVal,1,1);
            mxFree(boolColsSkip);
            mxFree(boolRowsSkip);
            return;
        }

        if(numRowsKept<=numColsKept) {
            A=reinterpret_cast<double*>(mxGetData(prhs[0]));
        } else {
            std::swap(numRowsKept, numColsKept);

            //This is freed using mxDestroyArray
            AMat=mxCreateDoubleMatrix(numRowsKept,numColsKept,mxREAL);
            didAlloc=true;
            mexCallMATLAB(1, &AMat, 1,  const_cast<mxArray **>(&prhs[0]), "transpose");
            A=reinterpret_cast<double*>(mxGetData(AMat));
        }

        //Set the mapping of indices of the rows in the submatrix to
        //indices in the full matrix and similarly, set the mapping of
        //columns in the submatrix to columns in the full matrix.
        //The two buffers will be allocated in one go and then freed
        //together in the end.
        keptBuffer=reinterpret_cast<size_t*>(mxMalloc(sizeof(size_t)*(numRowsKept+numColsKept)));
        rows2Keep=keptBuffer;
        cols2Keep=keptBuffer+numRowsKept;
        {   //Do the mapping of the rows.
            size_t cumSkip, curIdx, curRow;
            cumSkip=0;
            curIdx=0;
            for(curRow=0; curRow<numRow; curRow++) {
                if(boolRowsSkip[curRow]==true) {
                    cumSkip++;
                } else {
                    rows2Keep[curIdx]=curIdx+cumSkip;
                    curIdx++;
                }

            }
        }

        {   //Do the mapping of the columns.
            size_t cumSkip, curIdx, curCol;
            cumSkip=0;
            curIdx=0;
            for(curCol=0; curCol<numCol; curCol++) {
                if(boolColsSkip[curCol]==true) {
                    cumSkip++;
                } else {
                    cols2Keep[curIdx]=curIdx+cumSkip;
                    curIdx++;
                }
            }
        }

        {
            size_t* buffer;
            buffer=reinterpret_cast<size_t*>(mxMalloc(numColsKept*sizeof(size_t)));
            permVal=permCPPSkip(A, numRow, rows2Keep, cols2Keep, numRowsKept, numColsKept,buffer);
            mxFree(buffer);
        }

        //Get rid of temporary space.
        if(didAlloc) {
            mxDestroyArray(AMat);
        }

        mxFree(keptBuffer);
        mxFree(boolColsSkip);
        mxFree(boolRowsSkip);

        //Set the return value
        plhs[0]=doubleMat2Matlab(&permVal,1,1);
        return;
    }

    if(numRow==numCol) {
        double *buffer;
        A=reinterpret_cast<double*>(mxGetData(prhs[0]));

        //Allocate temporary scratch space.
        buffer = reinterpret_cast<double*>(mxMalloc((2*numRow+1)*sizeof(double)));
        permVal=permSquareCPP(A,numRow,buffer);
        mxFree(buffer);
    } else {
        bool didAlloc=false;
        size_t *buffer;
        if(numRow<=numCol) {
            A=reinterpret_cast<double*>(mxGetData(prhs[0]));
        } else {
            std::swap(numRow, numCol);

            //This is freed using mxDestroyArray
            AMat=mxCreateDoubleMatrix(numRow,numCol,mxREAL);
            didAlloc=true;
            mexCallMATLAB(1, &AMat, 1,  const_cast<mxArray **>(&prhs[0]), "transpose");
            A=reinterpret_cast<double*>(mxGetData(AMat));
        }

        buffer=reinterpret_cast<size_t*>(mxMalloc(numCol*sizeof(size_t)));
        permVal=permCPP(A,numRow,numCol,buffer);
        mxFree(buffer);
        //Get rid of temporary space.
        if(didAlloc) {
            mxDestroyArray(AMat);
        }
    }

    //Set the return value
    plhs[0]=doubleMat2Matlab(&permVal,1,1);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double gain, *C, CDelta;
    size_t numRow, numCol, i;
    ptrdiff_t *col4row, *row4col;
    mxArray *col4rowMATLAB, *row4colMATLAB, *uMATLAB, *vMATLAB, *CMat;
    bool didFlip=false;
    bool maximize=false;
    
    if(nrhs<1){
        mexErrMsgTxt("Not enough inputs.");
    }
    
    if(nrhs==2){
        maximize=getBoolFromMatlab(prhs[1]);
    }
    
    if(nrhs>2) {
        mexErrMsgTxt("Too many inputs.");
    }
    
    if(nlhs>5) {
        mexErrMsgTxt("Too many outputs.");
    }
    
    /*Verify the validity of the assignment matrix.*/
    checkRealDoubleArray(prhs[0]);
    
    /* Get the dimensions of the input data and the pointer to the matrix.
     * It is assumed that the matrix is not so large in M or N as to cause
     * an overflow when using a SIGNED integer data type.*/
    numRow = mxGetM(prhs[0]);
    numCol = mxGetN(prhs[0]);
    
    /* Transpose the matrix, if necessary, so that the number of rows is
     * >= the number of columns.*/
    if(numRow>=numCol) {
        CMat=mxDuplicateArray(prhs[0]);
    } else {
        size_t temp;
        
        temp=numCol;
        numCol=numRow;
        numRow=temp;
        
        CMat=mxCreateDoubleMatrix(numCol,numRow,mxREAL);
        mexCallMATLAB(1, &CMat, 1, (mxArray **)&prhs[0], "transpose");
        didFlip=true;
    }
    
    C = (double*)mxGetData(CMat);
    
    /* The cost matrix must have all non-negative elements for the
     * assignment algorithm to work. This forces all of the elements to be
     * positive. The delta is added back in when computing the gain in the
     * end.*/
    if(maximize==false) {
        CDelta=INFINITY;
        for(i=0;i<numRow*numCol;i++) {
            if(C[i]<CDelta)
                CDelta=C[i];
        }

        for(i=0;i<numRow*numCol;i++) {
            C[i]=C[i]-CDelta;
        }
    } else {
        CDelta=-INFINITY;
        for(i=0;i<numRow*numCol;i++) {
            if(C[i]>CDelta)
                CDelta=C[i];
        }

        for(i=0;i<numRow*numCol;i++) {
            C[i]=-C[i]+CDelta;
        }
    }
    
    CDelta=CDelta*numCol;
    
   //Allocate space for the return variables to Matlab.
    
    col4rowMATLAB= allocSignedSizeMatInMatlab(numRow, 1);
    row4colMATLAB= allocSignedSizeMatInMatlab(numCol, 1);
    
    /* These will hold the dual variable values. They are all initialized
     * to zero.*/
    uMATLAB = mxCreateNumericMatrix(numCol,1,mxDOUBLE_CLASS,mxREAL);
    vMATLAB = mxCreateNumericMatrix(numRow,1,mxDOUBLE_CLASS,mxREAL);
    
    col4row=(ptrdiff_t*)mxGetData(col4rowMATLAB);
    row4col=(ptrdiff_t*)mxGetData(row4colMATLAB);
    
    gain=shortestPathCFast(C,col4row,row4col, (double*)mxGetData(uMATLAB), (double*)mxGetData(vMATLAB), numRow, numCol);
    
    mxDestroyArray(CMat);
    /* If a transposed array was used */
    if(didFlip==true) {
        size_t temp;
        ptrdiff_t *tempIPtr;
        mxArray *tempMat;

        temp=numCol;
        numCol=numRow;
        numRow=temp;
        
        tempIPtr=row4col;
        row4col=col4row;
        col4row=tempIPtr;
        
        tempMat=row4colMATLAB;
        row4colMATLAB=col4rowMATLAB;
        col4rowMATLAB=tempMat;
        
        tempMat=uMATLAB;
        uMATLAB=vMATLAB;
        vMATLAB=tempMat;
    }
    
    //If there is no feasible solution.
    if(gain==-1){
        mxDestroyArray(col4rowMATLAB);
        mxDestroyArray(row4colMATLAB);
        
        plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
        if(nlhs>1){
            plhs[1]=mxCreateDoubleMatrix(0,0,mxREAL);
            
            if(nlhs>2){
                plhs[2]=mxCreateDoubleScalar(gain);
                
                if(nlhs>3) {
                    plhs[3]=uMATLAB;
                    
                    if(nlhs>4){
                        plhs[4]=vMATLAB;
                    }
                }
                
            }
        }
        return;
    } else {
        
        /* Adjust for shifting that was done to make everything positive.*/
        if(maximize==false) {
            gain=gain+CDelta;

        } else {
            gain=-gain+CDelta;
        }
        
        /* Convert the C indices into indices for MATLAB.*/
        for(i=0;i<numRow;i++){
            col4row[i]=col4row[i]+1;
        }
                
        plhs[0]=col4rowMATLAB;
        if(nlhs>1){
            plhs[1]=row4colMATLAB;
            
            for(i=0;i<numCol;i++){
                row4col[i]=row4col[i]+1;
            }
            
            if(nlhs>2){
                plhs[2]=mxCreateDoubleScalar(gain);
                
                if(nlhs>3) {
                    plhs[3]=uMATLAB;
                    
                    if(nlhs>4){
                        plhs[4]=vMATLAB;
                    }
                }
            }
        }  
    }
    
    /*Free the u and v matrices if they are not returned.*/
    if(nlhs<4){
        mxDestroyArray(uMATLAB);
    }
    if(nlhs<5){
        mxDestroyArray(vMATLAB);   
    }
    
    return;
}
Esempio n. 22
0
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double TT1,TT2,TDB1,TDB2,Jul2,deltaTTUT1,deltaT,Jul1UT1, Jul2UT1,UT1Frac;
    double u, v, elon;
    int retVal;
    
    if(nrhs<2||nrhs>4){
        mexErrMsgTxt("Wrong number of inputs.");
        return;
    }

    if(nlhs>2){
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
    
    TT1=getDoubleFromMatlab(prhs[0]);
    TT2=getDoubleFromMatlab(prhs[1]);

    //If the parameter is given and is not just an empty matrix.
    if(nrhs>2&&!(mxGetM(prhs[2])==0||mxGetN(prhs[2])==0)) {
        deltaTTUT1=getDoubleFromMatlab(prhs[2]);
    } else {
        mxArray *retVals[4];
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        
        //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(4,retVals,2,JulUTCMATLAB,"getEOP");
        //This is TT-UT1
        deltaTTUT1=getDoubleFromMatlab(retVals[3]);
        //Free the returned arrays.
        mxDestroyArray(retVals[0]);
        mxDestroyArray(retVals[1]);
        mxDestroyArray(retVals[2]);
        mxDestroyArray(retVals[3]);
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
    }
    
    if(nrhs>3) {
        double *xyzClock;
        
        if(mxGetM(prhs[3])!=3||mxGetN(prhs[3])!=1) {
            mexErrMsgTxt("The dimensionality of the clock location is incorrect.");
            return;
        }
        checkRealDoubleArray(prhs[3]);
        
        xyzClock=(double*)mxGetData(prhs[3]);
        //Convert from meters to kilometers.
        xyzClock[0]/=1000;xyzClock[1]/=1000;xyzClock[2]/=1000;
        
        u=sqrt(xyzClock[0]*xyzClock[0] + xyzClock[1]*xyzClock[1]);
        v=xyzClock[2];
        elon=atan2(xyzClock[1],xyzClock[0]);
        
    } else {
        u=0;
        v=0;
        elon=0;
    }
    
    //Get UT1 
    retVal=iauTtut1(TT1, TT2, deltaTTUT1, &Jul1UT1, &Jul2UT1);
    switch(retVal) {
        case -1:
            mexErrMsgTxt("Unacceptable date provided.");
            return;
        case 1:
            mexWarnMsgTxt("Dubious year provided\n");
            break;
        default:
            break;
    }
    //Find the fraction of a Julian day in UT1
    UT1Frac=(Jul1UT1-floor(Jul1UT1))+(Jul2UT1-floor(Jul2UT1));
    UT1Frac=UT1Frac-floor(UT1Frac);

    /*Compute TDB-TT. The function iauDtdb takes TDB as an input, but we
     *only have TT. The documentation for iauDtdb says that TT can be
     *substituted within the precision limits of the function. However, an
     *extra iteration is performed here to try to make the result
     *consistent with TDB2TT to a few more digits of precision.*/
    TDB1=TT1;
    TDB2=TT2;
    {
        int curIter;
        for(curIter=0;curIter<2;curIter++) {
            deltaT = iauDtdb(TDB1, TDB2, UT1Frac, elon, u, v);

            //TT -> TDB
            retVal = iauTttdb(TT1, TT2, deltaT, &TDB1, &TDB2);
            if(retVal!=0) {
               mexErrMsgTxt("An error occured during an intermediate conversion to TDB.\n");
               return;
            }
        }
    }
    
    plhs[0]=doubleMat2Matlab(&TDB1,1, 1);
    if(nlhs>1) {
        plhs[1]=doubleMat2Matlab(&TDB2,1, 1);
    }
}
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(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[]) {
    bool diagAugment=false;
    size_t numRow, numCol,numBetaCols;
    mxArray *betaMatlab;
    double *A, *beta;

    if(nrhs<1){
        mexErrMsgTxt("Not enough inputs.");
    }
    
    if(nrhs>2) {
        mexErrMsgTxt("Too many inputs.");
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Too many outputs.");
    }
    
    numRow = mxGetM(prhs[0]);
    numCol = mxGetN(prhs[0]);
    
    //If an empty matrix is passed, then return an empty matrix.
    if(numRow==0||numCol==0) {
        plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
        return;
    }

    checkRealDoubleArray(prhs[0]);

    if(nrhs>1) {
        diagAugment=getBoolFromMatlab(prhs[1]);
    }
    
    //Get the matrix.
    A=(double*)mxGetData(prhs[0]);
    
    //If we are solving the general probability problem.
    if(diagAugment==false) {
        //If we are here, then we just want general assignment probabilities,
        //not specialized to target tracking applications.
        size_t *buffer,*rows2Keep,*cols2Keep;
        size_t *buff4PermFunc;//Buffer for the permanent function.
        const size_t numRowsKept=numRow-1;
        const size_t numColsKept=numCol-1;
        size_t curRow,curCol;
        
        //Allocate the return values.
        numBetaCols=numCol;
        betaMatlab=mxCreateDoubleMatrix(numRow,numBetaCols,mxREAL);
        beta=(double*)mxGetData(betaMatlab);
        
        //Allocate the space for the indices of the rows and columns that
        //are kept in the submatrix to be passed to the permCPPSkip
        //function.
        buffer= new size_t[numRowsKept+2*numColsKept];
        rows2Keep=buffer;
        cols2Keep=rows2Keep+numRowsKept;
        buff4PermFunc=cols2Keep+numColsKept;
        
        for(curRow=0;curRow<numRow;curRow++) {
             size_t i;
             //Fill in the indices of the rows to keep.
             for(i=curRow;i<numRowsKept;i++) {
                rows2Keep[i]=i+1;
             }

             for(curCol=0;curCol<numCol;curCol++){
                 double ati=A[curRow+curCol*numRow];
                 //The A matrix removing the row and column corresponding
                 //to the selected association.
                 //Fill in the indices of the columns to keep.
                 for(i=curCol;i<numColsKept;i++) {
                    cols2Keep[i]=i+1;
                 }

                 beta[curRow+curCol*numRow]=ati*permCPPSkip(A,numRow,rows2Keep, cols2Keep, numRowsKept, numColsKept, buff4PermFunc);
                 cols2Keep[curCol]=curCol;
             }
             rows2Keep[curRow]=curRow;
        }
        
        //Delete the buffers
        delete buffer;
    }else {
        //This is the case where we are solving for target-measurement
        //assignment probabilities with missed detections.
        size_t *buffer,*rows2Keep,*cols2Keep;
        size_t *buff4PermFunc;//Buffer for the permanent function.
        const size_t numRowsKept=numRow-1;
        const size_t numColsKept=numCol-1;
        size_t numTar,numMeas;
        size_t curTar,curMeas;
        
        if(numCol<numRow) {
            mexErrMsgTxt("The number of columns cannot be less than the number of rows when diagAugment is true.");
        }

        numTar=numRow;
        numMeas=numCol-numTar;
        numBetaCols=numMeas+1;

        //Allocate the return values.
        betaMatlab=mxCreateDoubleMatrix(numRow,numBetaCols,mxREAL);
        beta=(double*)mxGetData(betaMatlab);

        //Allocate the space for the indices of the rows and columns
        //that are kept in the submatrix to be passed to the
        //permCPPSkip function.
        buffer= new size_t[numRow+2*numCol];
        rows2Keep=buffer;
        cols2Keep=rows2Keep+numRowsKept;
        buff4PermFunc=cols2Keep+numColsKept;

        for(curTar=0;curTar<numTar;curTar++) {
            size_t i;
            double ati;
            //Fill in the indices of the rows to keep.
            for(i=curTar;i<numRowsKept;i++) {
                rows2Keep[i]=i+1;
            }
            
            for(curMeas=0;curMeas<numMeas;curMeas++) {
                //The measurement hypotheses
                ati=A[curTar+curMeas*numRow];
                //The A matrix removing the row and column corresponding
                //to the selected association.
                //Fill in the indices of the columns to keep.
                for(i=curMeas;i<numColsKept;i++) {
                    cols2Keep[i]=i+1;
                }

                beta[curTar+curMeas*numRow]=ati*permCPPSkip(A,numRow,rows2Keep, cols2Keep, numRowsKept, numColsKept, buff4PermFunc);
                cols2Keep[curMeas]=curMeas;
            }
            //The missed detection hypothesis
            curMeas=numMeas+curTar;
            ati=A[curTar+curMeas*numRow];
            //Fill in the indices of the columns to keep.
            for(i=numMeas;i<curMeas;i++) {
                cols2Keep[i]=i;
            }
            for(i=curMeas;i<numColsKept;i++) {
                cols2Keep[i]=i+1;
            }
            
            beta[curTar+numMeas*numRow]=ati*permCPPSkip(A,numRow,rows2Keep, cols2Keep, numRowsKept, numColsKept, buff4PermFunc);
            rows2Keep[curTar]=curTar;
        }
        //Delete the buffers
        delete buffer;
    }
    
    //Normalize the return values.
    //It is faster to normalize the betas this way then to compute the
    //normalization constant by finding the permanent of the entire A
    //matrix.
    {
        double sumVal;
        size_t curRow,curCol;
        
        for(curRow=0;curRow<numRow;curRow++) {
            sumVal=0;
            //Compute the sum across the columns
            for(curCol=0;curCol<numBetaCols;curCol++) {
                sumVal+=beta[curRow+curCol*numRow];
            }
            //Normalize the value across the columns.
            for(curCol=0;curCol<numBetaCols;curCol++) {
                size_t idx=curRow+curCol*numRow;
                beta[idx]/=sumVal;
            }
        }
    }
 
    //Set the return values.
    plhs[0]=betaMatlab;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double TT1, TT2, dX, dY, *xVec;
    size_t numRow, numVec;
    mxArray *retMat;
    double *retData;
    double GCRS2CIRS[3][3];
    
    if(nrhs<3||nrhs>4){
        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||mxGetM(prhs[3])==0) {
        mxArray *retVals[2];
        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(2,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]);
            mexErrMsgTxt("Error using the getEOP function.");
            return;
        }
        
        dXdY=(double*)mxGetData(retVals[1]);
        dX=dXdY[0];
        dY=dXdY[1];
        
        //Free the returned arrays.
        mxDestroyArray(retVals[1]);
    } else {//Get the celestial pole offsets
        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;
        }
    }
    
    {
    double x, y, s;
    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, GCRS2CIRS);
    }
    
    //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(GCRS2CIRS, xVec+numRow*curVec, retData+numRow*curVec);
            
            //If a velocity vector was given.
            if(numRow>3) {
                double *velGCRS=xVec+numRow*curVec+3;//Velocity in GCRS
                double *retDataVel=retData+numRow*curVec+3;
                
                //Convert velocity from GCRS to CIRS.
                iauRxp(GCRS2CIRS, velGCRS, 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]=GCRS2CIRS[i][j];
            }
        }
    }
}
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;
}