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[]) {
    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);
    }
}