/* * mexFunction(): entry point for the mex function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // interface to deal with input arguments from Matlab enum InputIndexType {IN_TRI, IN_X, InputIndexType_MAX}; MatlabImportFilter::Pointer matlabImport = MatlabImportFilter::New(); matlabImport->ConnectToMatlabFunctionInput(nrhs, prhs); // check that we have at least a filter name and input image matlabImport->CheckNumberOfArguments(2, InputIndexType_MAX); // register the inputs for this function at the import filter typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inTRI = matlabImport->RegisterInput(IN_TRI, "TRI"); MatlabInputPointer inX = matlabImport->RegisterInput(IN_X, "X"); // interface to deal with outputs to Matlab enum OutputIndexType {OUT_A, OutputIndexType_MAX}; MatlabExportFilter::Pointer matlabExport = MatlabExportFilter::New(); matlabExport->ConnectToMatlabFunctionOutput(nlhs, plhs); // check number of outputs the user is asking for matlabExport->CheckNumberOfArguments(0, OutputIndexType_MAX); // register the outputs for this function at the export filter typedef MatlabExportFilter::MatlabOutputPointer MatlabOutputPointer; MatlabOutputPointer outA = matlabExport->RegisterOutput(OUT_A, "A"); // default coordinates are NaN values, so that the user can spot // whether there was any problem reading them Point def(mxGetNaN(), mxGetNaN(), mxGetNaN()); // if any of the inputs is empty, the output is empty too if (mxIsEmpty(prhs[IN_TRI]) || mxIsEmpty(prhs[IN_X])) { matlabExport->CopyEmptyArrayToMatlab(outA); return; } // get size of input matrix mwSize nrowsTri = mxGetM(prhs[IN_TRI]); mwSize ncolsTri = mxGetN(prhs[IN_TRI]); mwSize ncolsX = mxGetN(prhs[IN_X]); if ((ncolsTri != 3) || (ncolsX != 3)) { mexErrMsgTxt("Both input arguments must have 3 columns"); } // initialise output double *area = matlabExport->AllocateColumnVectorInMatlab<double>(outA, nrowsTri); // read triangular mesh from function Triangle tri; mwIndex v0, v1, v2; // indices of the 3 vertices of each triangle Point x0, x1, x2; // coordinates of the 3 vertices of each triangle for (mwIndex i = 0; i < nrowsTri; ++i) { // exit if user pressed Ctrl+C ctrlcCheckPoint(__FILE__, __LINE__); // get indices of the 3 vertices of each triangle. These indices // follow Matlab's convention v0 = 1, 2, ..., n v0 = matlabImport->ReadScalarFromMatlab<mwIndex>(inTRI, i, 0, mxGetNaN()); v1 = matlabImport->ReadScalarFromMatlab<mwIndex>(inTRI, i, 1, mxGetNaN()); v2 = matlabImport->ReadScalarFromMatlab<mwIndex>(inTRI, i, 2, mxGetNaN()); if (mxIsNaN(v0) || mxIsNaN(v1) || mxIsNaN(v2)) { mexErrMsgTxt("Input TRI: Vertex index is NaN"); } // get coordinates of the 3 vertices (substracting 1 so that // indices follow the C++ convention 0, 1, ..., n-1) x0 = matlabImport->ReadRowVectorFromMatlab<void, Point>(inX, v0 - 1, def); x1 = matlabImport->ReadRowVectorFromMatlab<void, Point>(inX, v1 - 1, def); x2 = matlabImport->ReadRowVectorFromMatlab<void, Point>(inX, v2 - 1, def); // create triangle from the vertices read at the input tri = Triangle(x0, x1, x2); // compute triangle area area[i] = std::sqrt(tri.squared_area()); // // DEBUG // std::cout << x0 << "\t" << x1 << "\t" << x2 << "\t" << std::sqrt(tri.squared_area()) << std::endl; } }
/* * mexFunction(): entry point for the mex function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // interface to deal with input arguments from Matlab MatlabImportFilter::Pointer matlabImport = MatlabImportFilter::New(); matlabImport->ConnectToMatlabFunctionInput(nrhs, prhs); // register all possible inputs for this function at the import filter typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inTRANSFORM = matlabImport->RegisterInput(IN_TRANSFORM, "TRANSFORM"); MatlabInputPointer inX = matlabImport->RegisterInput(IN_X, "X"); MatlabInputPointer inY = matlabImport->RegisterInput(IN_Y, "Y"); MatlabInputPointer inXI = matlabImport->RegisterInput(IN_XI, "XI"); MatlabInputPointer inORDER = matlabImport->RegisterInput(IN_ORDER, "ORDER"); MatlabInputPointer inLEVELS = matlabImport->RegisterInput(IN_LEVELS, "LEVELS"); // interface to deal with output arguments from Matlab MatlabExportFilter::Pointer matlabExport = MatlabExportFilter::New(); matlabExport->ConnectToMatlabFunctionOutput(nlhs, plhs); // register the outputs for this function at the export filter typedef MatlabExportFilter::MatlabOutputPointer MatlabOutputPointer; MatlabOutputPointer outYI = matlabExport->RegisterOutput(OUT_YI, "YI"); // check number of input and output arguments matlabImport->CheckNumberOfArguments(4, InputIndexType_MAX); matlabExport->CheckNumberOfArguments(0, OutputIndexType_MAX); // if there are no points to warp, return empty array if (mxIsEmpty(inXI->pm)) { matlabExport->CopyEmptyArrayToMatlab(outYI); return; } // check size of input arguments mwSize Mx = mxGetM(inX->pm); // number of source points mwSize My = mxGetM(inY->pm); // number of target points mwSize Dimension = mxGetN(inX->pm); // dimension of source points mwSize dimy = mxGetN(inY->pm); // dimension of target points mwSize dimxi = mxGetN(inXI->pm); // dimension of points to be warped // the landmark arrays must have the same number of points // (degenerate case, both are empty) if (Mx != My) { mexErrMsgTxt("X and Y must have the same number of points (i.e. rows)."); } // if there are no landmarks, we apply no transformation to the // points to warp if (mxIsEmpty(inX->pm)) { *outYI->ppm = mxDuplicateArray(inXI->pm); return; } // if there are landmarks and points to warp, all must have the same dimension if (Dimension != dimy || Dimension != dimxi) { mexErrMsgTxt("X, Y and XI must all have the same dimension (i.e. number of columns)."); } // run filter (this function starts a cascade of functions designed // to translate the run-time type variables like inputVoxelClassId // to templates, so that we don't need to nest lots of "switch" or // "if" statements) parseInputTypeToTemplate(matlabImport, matlabExport); // exit successfully return; }
void runKernelTransform(MatlabImportFilter::Pointer matlabImport, MatlabExportFilter::Pointer matlabExport) { // check number of input arguments (the kernel transform syntax // accepts up to 4 arguments only. Thus, we cannot use InputIndexType_MAX) matlabImport->CheckNumberOfArguments(4, 4); // retrieve pointers to the inputs that we are going to need here typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inX = matlabImport->GetRegisteredInput("X"); MatlabInputPointer inY = matlabImport->GetRegisteredInput("Y"); MatlabInputPointer inXI = matlabImport->GetRegisteredInput("XI"); // register the outputs for this function at the export filter typedef MatlabExportFilter::MatlabOutputPointer MatlabOutputPointer; MatlabOutputPointer outYI = matlabExport->RegisterOutput(OUT_YI, "YI"); // get size of input arguments mwSize Mx = mxGetM(inX->pm); // number of source points mwSize Mxi = mxGetM(inXI->pm); // number of points to be warped mwSize ndimxi; // number of dimension of points to be warped const mwSize *dimsxi; // dimensions vector of array of points to be warped // create pointers to input matrices TScalarType *x = (TScalarType *)mxGetData(inX->pm); // source points TScalarType *y = (TScalarType *)mxGetData(inY->pm); // target points TScalarType *xi = (TScalarType *)mxGetData(inXI->pm); // points to be warped if (x == NULL) { mexErrMsgTxt("Cannot get a pointer to input X"); } if (y == NULL) { mexErrMsgTxt("Cannot get a pointer to input Y"); } if (xi == NULL) { mexErrMsgTxt("Cannot get a pointer to input XI"); } // type definitions and variables to store points for the kernel transform typedef typename TransformType::PointSetType PointSetType; typename PointSetType::Pointer fixedPointSet = PointSetType::New(); typename PointSetType::Pointer movingPointSet = PointSetType::New(); typename PointSetType::Pointer toWarpPointSet = PointSetType::New(); typedef typename PointSetType::PointsContainer PointsContainer; typename PointsContainer::Pointer fixedPointContainer = PointsContainer::New(); typename PointsContainer::Pointer movingPointContainer = PointsContainer::New(); typedef typename PointSetType::PointType PointType; PointType fixedPoint; PointType movingPoint; PointType toWarpPoint; PointType warpedPoint; // duplicate the input x and y matrices to PointSet format so that // we can pass it to the ITK function mwSize pointId=0; for (mwSize row=0; row < Mx; ++row) { for (mwSize col=0; col < (mwSize)Dimension; ++col) { fixedPoint[CAST2MWSIZE(col)] = y[Mx * col + row]; movingPoint[CAST2MWSIZE(col)] = x[Mx * col + row]; } fixedPointContainer->InsertElement(pointId, fixedPoint); movingPointContainer->InsertElement(pointId, movingPoint); ++pointId; } fixedPointSet->SetPoints(fixedPointContainer); movingPointSet->SetPoints(movingPointContainer); // compute the transform typename TransformType::Pointer transform; transform = TransformType::New(); transform->SetSourceLandmarks(movingPointSet); transform->SetTargetLandmarks(fixedPointSet); transform->ComputeWMatrix(); // create output vector and pointer to populate it ndimxi = mxGetNumberOfDimensions(inXI->pm); dimsxi = mxGetDimensions(inXI->pm); std::vector<mwSize> size; for (mwIndex i = 0; i < ndimxi; ++i) { size.push_back(dimsxi[i]); } TScalarType *yi = matlabExport->AllocateNDArrayInMatlab<TScalarType>(outYI, size); // transform points for (mwSize row=0; row < Mxi; ++row) { for (mwSize col=0; col < (mwSize)Dimension; ++col) { toWarpPoint[CAST2MWSIZE(col)] = xi[Mxi * col + row]; } warpedPoint = transform->TransformPoint(toWarpPoint); for (mwSize col=0; col < (mwSize)Dimension; ++col) { yi[Mxi * col + row] = warpedPoint[CAST2MWSIZE(col)]; } } // exit function return; }
/* * mexFunction(): entry point for the mex function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // interface to deal with input arguments from Matlab enum InputIndexType {IN_TRI, IN_X, IN_ITRI, InputIndexType_MAX}; MatlabImportFilter::Pointer matlabImport = MatlabImportFilter::New(); matlabImport->ConnectToMatlabFunctionInput(nrhs, prhs); // check the number of input arguments matlabImport->CheckNumberOfArguments(2, InputIndexType_MAX); // register the inputs for this function at the import filter typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inTRI = matlabImport->RegisterInput(IN_TRI, "TRI"); MatlabInputPointer inX = matlabImport->RegisterInput(IN_X, "X"); MatlabInputPointer inITRI = matlabImport->RegisterInput(IN_ITRI, "ITRI"); // interface to deal with outputs to Matlab enum OutputIndexType {OUT_C, OutputIndexType_MAX}; MatlabExportFilter::Pointer matlabExport = MatlabExportFilter::New(); matlabExport->ConnectToMatlabFunctionOutput(nlhs, plhs); // check number of outputs the user is asking for matlabExport->CheckNumberOfArguments(0, OutputIndexType_MAX); // register the outputs for this function at the export filter typedef MatlabExportFilter::MatlabOutputPointer MatlabOutputPointer; MatlabOutputPointer outC = matlabExport->RegisterOutput(OUT_C, "C"); // if any of the inputs is empty, the output is empty too if (mxIsEmpty(prhs[IN_TRI]) || mxIsEmpty(prhs[IN_X])) { matlabExport->CopyEmptyArrayToMatlab(outC); return; } // default coordinates are NaN values, so that the user can spot // whether there was any problem reading them Point def(mxGetNaN(), mxGetNaN(), mxGetNaN()); // get size of input matrix mwSize nrowsTri = mxGetM(prhs[IN_TRI]); mwSize ncolsTri = mxGetN(prhs[IN_TRI]); mwSize ncolsX = mxGetN(prhs[IN_X]); if ((ncolsTri != 3) || (ncolsX != 3)) { mexErrMsgTxt("All input arguments must have 3 columns"); } // get list of triangle indices the user wants to check // intersections for. By default, we check all triangles std::vector<mwIndex> itriDef(nrowsTri); for (mwSize i = 0; i < nrowsTri; ++i) { itriDef[i] = i + 1; } std::vector<mwIndex> itri = matlabImport-> ReadRowVectorFromMatlab<mwIndex, std::vector<mwIndex> >(inITRI, itriDef); // read triangular mesh from function std::vector<Triangle> triangles(nrowsTri); mwIndex v0, v1, v2; // indices of the 3 vertices of each triangle Point x0, x1, x2; // coordinates of the 3 vertices of each triangle Iterator it = triangles.begin(); for (mwIndex i = 0; i < nrowsTri; ++i, ++it) { // exit if user pressed Ctrl+C ctrlcCheckPoint(__FILE__, __LINE__); // get indices of the 3 vertices of each triangle. These indices // follow Matlab's convention v0 = 1, 2, ..., n v0 = matlabImport->ReadScalarFromMatlab<mwIndex>(inTRI, i, 0, mxGetNaN()); v1 = matlabImport->ReadScalarFromMatlab<mwIndex>(inTRI, i, 1, mxGetNaN()); v2 = matlabImport->ReadScalarFromMatlab<mwIndex>(inTRI, i, 2, mxGetNaN()); if (mxIsNaN(v0) || mxIsNaN(v1) || mxIsNaN(v2)) { mexErrMsgTxt("Parameter TRI: Vertex index is NaN"); } // get coordinates of the 3 vertices (substracting 1 so that // indices follow the C++ convention 0, 1, ..., n-1) x0 = matlabImport->ReadRowVectorFromMatlab<void, Point>(inX, v0 - 1, def); x1 = matlabImport->ReadRowVectorFromMatlab<void, Point>(inX, v1 - 1, def); x2 = matlabImport->ReadRowVectorFromMatlab<void, Point>(inX, v2 - 1, def); // add triangle to the vector of triangles in the surface triangles[i] = Triangle(x0, x1, x2); // // debug: show the memory address of each triangle in the std::vector // std::cout << "tri mem address: " << &(triangles[i]) << std::endl; } // // debug: show the memory address of each triangle in the std::vector // for (it = triangles.begin(); it != triangles.end(); ++it) { // std::cout << "tri mem address: " << &(*(it)) << std::endl; // } // construct AABB tree Tree tree(triangles.begin(),triangles.end()); // initialise outputs double *n = matlabExport->AllocateColumnVectorInMatlab<double>(outC, nrowsTri); // // DEBUG: // mwSize triNum = 0; // initialize variable to keep a list of intersections for the // current triangle std::list<Object_and_primitive_id> intersections; // loop every facet to see whether it intersects the mesh for (std::vector<mwIndex>::iterator itri_it = itri.begin(); itri_it != itri.end(); ++itri_it) { // triangle index (converting Matlab index convention 1, 2, 3,... to C++ 0, 1, 2,... mwIndex idx = *itri_it - 1; // iterator pointer to the triangle Iterator it = triangles.begin(); it += idx; // // DEBUG: // std::cout << ++triNum << ": Triangle = " << *it << std::endl; // exit if user pressed Ctrl+C ctrlcCheckPoint(__FILE__, __LINE__); // if the triangle is degenerated, trying to find intersections // will produce a segfault. To avoid it, we just count one // intersection for this triangle and skip to the next one if ( (it->vertex(0) == it->vertex(1)) || (it->vertex(0) == it->vertex(2)) || (it->vertex(1) == it->vertex(2)) ) { // // DEBUG: // mexWarnMsgTxt("Degenerate triangle found, skipping:"); // std::cerr << it->vertex(0) << ", " << it->vertex(1) << ", " << it->vertex(2) << std::endl; // add one to the count of self intersections n[idx] += 1; continue; } // computes all intersections with segment query (as pairs object - primitive_id) intersections.clear(); tree.all_intersections(*it, std::back_inserter(intersections)); // // DEBUG: // std::cout << "\tTotal number of intersections found for current triangle = " // << intersections.size() << std::endl; // loop all intersections for (std::list<Object_and_primitive_id>::iterator itx = intersections.begin(); itx != intersections.end(); ++itx) { // two triangles sharing a vertex or edge are detected by CGAL // as intersecting. Of course, in those case we cannot talk // about triangles overlapping. In this block of code, be // identify what kind of intersection we have. The // self-intersections that will be considered as actual // self-intersections that make the mesh non-topological are: // // 1) all triangle-type intersections: This is the current // triangle being parallel to another triangle, bigger or // smaller. Note that an intersection will always be detected // between the current triangle and itself. But it's easier // to simply count and then discount that intersection than // having to check the validity of each triangle-intersection // // 2) segment-type intersections where a triangle intersects // another triangle. This excludes the intersections that are // simply the triangle sharing an edge with its neighbours // // 3) point-type intersections where the triangle just touches // another triangle. This excludes the intersections that are // simply the triangle sharing a vertex with its neighbours Object_and_primitive_id op = *itx; CGAL::Object object = op.first; Triangle triangle; Segment segment; Point point; // 1) triangle intersection if(CGAL::assign(triangle, object)) { // add one to the count of self intersections n[idx] += 1; // // DEBUG: // std::cout << "\tTriangle: " << triangle << std::endl; // std::cout << "\t\tMesh self-intersection detected" << std::endl; } // end: triangle intersection // 2) segment intersection if(CGAL::assign(segment, object)) { // // DEBUG: // std::cout << "\tSegment: " << segment << std::endl; // for convenience, end points of the segment Point pa = segment[0]; Point pb = segment[1]; // for convenience, the three vertices of the current triangle Point vA = it->vertex(0); Point vB = it->vertex(1); Point vC = it->vertex(2); // for convenience, the three vertices of the intersected triangle Triangle intersectedTrianglePointer = *(op.second); Point vX = intersectedTrianglePointer.vertex(0); Point vY = intersectedTrianglePointer.vertex(1); Point vZ = intersectedTrianglePointer.vertex(2); // CGAL will detect as intersections the edges between the // current triangle and each neighbour. We need to detect and // disregard these cases if ( ((pa == vA) || (pa == vB) || (pa == vC)) && ((pb == vA) || (pb == vB) || (pb == vC)) && ((pa == vX) || (pa == vY) || (pa == vZ)) && ((pb == vX) || (pb == vY) || (pb == vZ)) ) { // // DEBUG: // std::cout << "\t\tDisregarding intersection: it's a valid edge between current triangle and neighbour" << std::endl; } else { // // DEBUG: // std::cout << "\t\tMesh self-intersection detected" << std::endl; // add one to the count of self intersections n[idx] += 1; } } // end: segment intersection // 3) point intersection if(CGAL::assign(point, object)) { // // DEBUG: // std::cout << "\tPoint: " << point << std::endl; // for convenience, the three vertices of the triangle Point vA = it->vertex(0); Point vB = it->vertex(1); Point vC = it->vertex(2); // for convenience, the three vertices of the intersected triangle Triangle intersectedTrianglePointer = *(op.second); Point vX = intersectedTrianglePointer.vertex(0); Point vY = intersectedTrianglePointer.vertex(1); Point vZ = intersectedTrianglePointer.vertex(2); // CGAL will detect as intersections the vertices shared by // the current triangle and each neighbour. We need to detect // and disregard those cases if ( ((point == vA) || (point == vB) || (point == vC)) && ((point == vX) || (point == vY) || (point == vZ)) ){ // // DEBUG: // std::cout << "\t\tDisregarding intersection: it's a valid vertex shared by current triangle and neighbour" << std::endl; } else { // // DEBUG: // std::cout << "\t\tMesh self-intersection detected" << std::endl; // add one to the count of self intersections n[idx] += 1; } } // end: point intersection } // end: loop all intersections // substract one intersection, because each triangle will intersect itself n[idx] -= 1; } }
/* * mexFunction(): entry point for the mex function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // interface to deal with input arguments from Matlab enum InputIndexType {IN_TRI, IN_X, IN_METHOD, IN_ITER, InputIndexType_MAX}; MatlabImportFilter::Pointer matlabImport = MatlabImportFilter::New(); matlabImport->ConnectToMatlabFunctionInput(nrhs, prhs); // check that we have all input arguments matlabImport->CheckNumberOfArguments(2, InputIndexType_MAX); // register the inputs for this function at the import filter MatlabInputPointer inTRI = matlabImport->RegisterInput(IN_TRI, "TRI"); MatlabInputPointer inX = matlabImport->RegisterInput(IN_X, "X"); MatlabInputPointer inMETHOD = matlabImport->RegisterInput(IN_METHOD, "METHOD"); MatlabInputPointer inITER = matlabImport->RegisterInput(IN_ITER, "ITER"); // interface to deal with outputs to Matlab enum OutputIndexType {OUT_TRI, OUT_N, OutputIndexType_MAX}; MatlabExportFilter::Pointer matlabExport = MatlabExportFilter::New(); matlabExport->ConnectToMatlabFunctionOutput(nlhs, plhs); // check number of outputs the user is asking for matlabExport->CheckNumberOfArguments(0, OutputIndexType_MAX); // register the outputs for this function at the export filter typedef MatlabExportFilter::MatlabOutputPointer MatlabOutputPointer; MatlabOutputPointer outTRI = matlabExport->RegisterOutput(OUT_TRI, "TRI"); MatlabOutputPointer outN = matlabExport->RegisterOutput(OUT_N, "N"); // if any of the inputs is empty, the output is empty too if (mxIsEmpty(prhs[IN_TRI]) || mxIsEmpty(prhs[IN_X])) { matlabExport->CopyEmptyArrayToMatlab(outTRI); matlabExport->CopyEmptyArrayToMatlab(outN); return; } // polyhedron to contain the input mesh Polyhedron mesh; PolyhedronBuilder<Polyhedron> builder(matlabImport, inTRI, inX); mesh.delegate(builder); // get size of input matrix with the points mwSize nrowsTri = mxGetM(inTRI->pm); mwSize nrowsX = mxGetM(inX->pm); #ifdef DEBUG std::cout << "Number of facets read = " << mesh.size_of_facets() << std::endl; std::cout << "Number of vertices read = " << mesh.size_of_vertices() << std::endl; #endif if (nrowsTri != mesh.size_of_facets()) { mexErrMsgTxt(("Input " + inTRI->name + ": Number of triangles read into mesh different from triangles provided at the input").c_str()); } if (nrowsX != mesh.size_of_vertices()) { mexErrMsgTxt(("Input " + inX->name + ": Number of vertices read into mesh different from vertices provided at the input").c_str()); } // sort halfedges such that the non-border edges precede the // border edges. We need to do this before any halfedge iterator // operations are valid mesh.normalize_border(); #ifdef DEBUG std::cout << "Number of border halfedges = " << mesh.size_of_border_halfedges() << std::endl; #endif // number of holes we have filled mwIndex n = 0; // a closed mesh with no holes will have no border edges. What we do // is grab a border halfedge and close the associated hole. This // makes the rest of the iterators invalid, so we have to normalize // the mesh again. Then we iterate, looking for a new border // halfedge, filling the hole, etc. // // Note that confusingly, mesh.border_halfedges_begin() gives a // pointer to the halfedge that is NOT a border in a border // edge. The border halfedge is instead // mesh.border_halfedges_begin()->opposite() while (!mesh.is_closed()) { // exit if user pressed Ctrl+C ctrlcCheckPoint(__FILE__, __LINE__); // get the first hole we can find, and close it mesh.fill_hole(mesh.border_halfedges_begin()->opposite()); // increase the counter of number of holes we have filled n++; // renormalize mesh so that halfedge iterators are again valid mesh.normalize_border(); } // split all facets to triangles CGAL::triangulate_polyhedron<Polyhedron>(mesh); // copy output with number of holes filled std::vector<double> nout(1, n); matlabExport->CopyVectorOfScalarsToMatlab<double, std::vector<double> >(outN, nout, 1); // allocate memory for Matlab outputs double *tri = matlabExport->AllocateMatrixInMatlab<double>(outTRI, mesh.size_of_facets(), 3); // extract the triangles of the solution // snippet adapted from CgalMeshSegmentation.cpp // vertices coordinates. Assign indices to the vertices by defining // a map between their handles and the index std::map<Vertex_handle, int> V; int inum = 0; for(Vertex_iterator vit = mesh.vertices_begin(); vit != mesh.vertices_end(); ++vit) { // save to internal list of vertices V[vit] = inum++; } // triangles given as (i,j,k), where each index corresponds to a vertex in x mwIndex row = 0; for (Facet_iterator fit = mesh.facets_begin(); fit != mesh.facets_end(); ++fit, ++row) { if (fit->facet_degree() != 3) { std::cerr << "Facet has " << fit->facet_degree() << " edges" << std::endl; mexErrMsgTxt("Facet does not have 3 edges"); } // go around the half-edges of the facet, to extract the vertices Halfedge_around_facet_circulator heit = fit->facet_begin(); int idx = 0; do { // extract triangle indices and save to Matlab output // note that Matlab indices go like 1, 2, 3..., while C++ indices go like 0, 1, 2... tri[row + idx * mesh.size_of_facets()] = 1 + V[heit->vertex()]; idx++; } while (++heit != fit->facet_begin()); } }
/* * mexFunction(): entry point for the mex function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { // interface to deal with input arguments from Matlab enum InputIndexType {IN_TRI, IN_X, IN_RES, IN_SIZE, IN_ORIGIN, InputIndexType_MAX}; MatlabImportFilter::Pointer matlabImport = MatlabImportFilter::New(); matlabImport->ConnectToMatlabFunctionInput(nrhs, prhs); // check the number of input arguments matlabImport->CheckNumberOfArguments(2, InputIndexType_MAX); // register the inputs for this function at the import filter typedef MatlabImportFilter::MatlabInputPointer MatlabInputPointer; MatlabInputPointer inTRI = matlabImport->RegisterInput(IN_TRI, "TRI"); MatlabInputPointer inX = matlabImport->RegisterInput(IN_X, "X"); // (x, y, z) MatlabInputPointer inRES = matlabImport->RegisterInput(IN_RES, "RES"); // (r, c, s) MatlabInputPointer inSIZE = matlabImport->RegisterInput(IN_SIZE, "SIZE"); // (r, c, s) MatlabInputPointer inORIGIN = matlabImport->RegisterInput(IN_ORIGIN, "ORIGIN"); // (x, y, z) // interface to deal with outputs to Matlab enum OutputIndexType {OUT_IM, OutputIndexType_MAX}; MatlabExportFilter::Pointer matlabExport = MatlabExportFilter::New(); matlabExport->ConnectToMatlabFunctionOutput(nlhs, plhs); // check that the number of outputs the user is asking for is valid matlabExport->CheckNumberOfArguments(0, OutputIndexType_MAX); // register the outputs for this function at the export filter typedef MatlabExportFilter::MatlabOutputPointer MatlabOutputPointer; MatlabOutputPointer outIM = matlabExport->RegisterOutput(OUT_IM, "IM"); // if any input point set is empty, the outputs are empty too if (mxIsEmpty(inTRI->pm) || mxIsEmpty(inX->pm)) { matlabExport->CopyEmptyArrayToMatlab(outIM); return; } // get number of rows in inputs X and TRI mwSize nrowsX = mxGetM(inX->pm); mwSize nrowsTRI = mxGetM(inTRI->pm); // instantiate mesh MeshType::Pointer mesh = MeshType::New(); // read vertices PointSetType::Pointer xDef = PointSetType::New(); // default: empty point set PointSetType::Pointer x = PointSetType::New(); x->GetPoints()->CastToSTLContainer() = matlabImport->ReadVectorOfVectorsFromMatlab<PointType::CoordRepType, PointType> (inX, xDef->GetPoints()->CastToSTLContainer()); #ifdef DEBUG std::cout << "Number of X points read = " << x->GetNumberOfPoints() << std::endl; #endif // assertion check if (nrowsX != x->GetNumberOfPoints()) { mexErrMsgTxt(("Input " + inX->name + ": Number of points read different from number of points provided by user").c_str()); } // swap XY coordinates to make them compliant with ITK convention // (see important programming note at the help header above) matlabImport->SwapXYInVectorOfVectors<PointType::CoordRepType, std::vector<PointType> > (x->GetPoints()->CastToSTLContainer(), x->GetNumberOfPoints()); // populate mesh with vertices mesh->SetPoints(x->GetPoints()); // read triangles PointType triDef; triDef.Fill(mxGetNaN()); for (mwIndex i = 0; i < nrowsTRI; ++i) { PointType triangle = matlabImport->ReadRowVectorFromMatlab<CoordType, PointType>(inTRI, i, triDef); // create a triangle cell to read the vertex indices of the current input triangle CellAutoPointer cell; cell.TakeOwnership(new TriangleType); // assign to the 0, 1, 2 elements in the triangle cell the vertex // indices that we have just read. Note that we have to substract // 1 to convert Matlab's index convention 1, 2, 3, ... to C++ // convention 0, 1, 2, ... cell->SetPointId(0, triangle[0] - 1); cell->SetPointId(1, triangle[1] - 1); cell->SetPointId(2, triangle[2] - 1); // insert cell into the mesh mesh->SetCell(i, cell); } #ifdef DEBUG std::cout << "Number of triangles read = " << mesh->GetNumberOfCells() << std::endl; #endif // assertion check if (nrowsTRI != mesh->GetNumberOfCells()) { mexErrMsgTxt(("Input " + inTRI->name + ": Number of triangles read different from number of triangles provided by user").c_str()); } // get user input parameters for the output rasterization ImageType::SpacingType spacingDef; spacingDef.Fill(1.0); ImageType::SpacingType spacing = matlabImport-> ReadRowVectorFromMatlab<ImageType::SpacingValueType, ImageType::SpacingType>(inRES, spacingDef); ImageType::SizeType sizeDef; sizeDef.Fill(10); ImageType::SizeType size = matlabImport-> ReadRowVectorFromMatlab<ImageType::SizeValueType, ImageType::SizeType>(inSIZE, sizeDef); ImageType::PointType originDef; originDef.Fill(0.0); ImageType::PointType origin = matlabImport-> ReadRowVectorFromMatlab<ImageType::PointType::ValueType, ImageType::PointType>(inORIGIN, originDef); // (see important programming note at the help header above) matlabImport->SwapXYInVector<ImageType::PointType::ValueType, ImageType::PointType>(origin); // instantiate rasterization filter MeshFilterType::Pointer meshFilter = MeshFilterType::New(); // smallest voxel side length ImageType::SpacingValueType minSpacing = spacing[0]; for (mwIndex i = 1; i < Dimension; ++i) { minSpacing = std::min(minSpacing, spacing[i]); } // pass input parameters to the filter meshFilter->SetInput(mesh); meshFilter->SetSpacing(spacing); meshFilter->SetSize(size); meshFilter->SetOrigin(origin); meshFilter->SetTolerance(minSpacing / 10.0); meshFilter->SetInsideValue(1); meshFilter->SetOutsideValue(0); ImageType::IndexType start; start.Fill(0); meshFilter->SetIndex(start); // convert image size from itk::Size format to std::vector<mwSize> // so that we can use it in GraftItkImageOntoMatlab std::vector<mwSize> sizeStdVector(Dimension); for (unsigned int i = 0; i < Dimension; ++i) { sizeStdVector[i] = size[i]; } // graft ITK filter output onto Matlab output matlabExport->GraftItkImageOntoMatlab<PixelType, Dimension> (outIM, meshFilter->GetOutput(), sizeStdVector); #ifdef DEBUG std::cout << "Resolution (spacing) = " << meshFilter->GetSpacing() << std::endl; std::cout << "Size = " << meshFilter->GetSize() << std::endl; std::cout << "Origin = " << meshFilter->GetOrigin() << std::endl; #endif // run rasterization meshFilter->Update(); }