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); } }