Пример #1
0
/*
 * 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;
  }


  
}
Пример #2
0
/*
 * 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;

}
Пример #3
0
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;

  }
  
}
Пример #5
0
/*
 * 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());
    
  }
}
Пример #6
0
/*
 * 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();

}