text: // 
  //   V2 = [0 0 0;1 0 0;0 1 0;0 1.004 0];
  //   F2 = [1 2 3;3 2 4];
  //   [CF] = collapse_small_triangles(V,F,1e-3);
  // 
  
  #include <igl/collapse_small_triangles.h>
  #include <igl/read_triangle_mesh.h>
  #include <igl/EPS.h>
  #include <igl/pathinfo.h>
  #include <igl/writeOFF.h>
  #include <igl/writeOBJ.h>
  #include <igl/writeDMAT.h>
  #ifdef MEX
  #  define IGL_REDRUM_NOOP
  #endif
  #include <igl/REDRUM.h>
  #ifdef MEX
  #  include <igl/matlab/MexStream.h>
  #  include <igl/matlab/parse_rhs.h>
  #  include <igl/matlab/mexErrMsgTxt.h>
  #endif
  
  #ifdef MEX
  #  include "mex.h"
  #endif
  #include <iostream>
  #include <string>
  
  #ifdef MEX
  void mexFunction(int nlhs, mxArray *plhs[], 
      int nrhs, const mxArray *prhs[])
  {
    //mexPrintf("Compiled at %s on %s\n",__TIME__,__DATE__);
    if(nrhs != 2 && nrhs != 3)
    {
      mexErrMsgTxt("The number of input arguments must be 2 or 3.");
    }
    //mexPrintf("%s %s\n",__TIME__,__DATE__);
    igl::matlab::MexStream mout;
    std::streambuf *outbuf = std::cout.rdbuf(&mout);
  
  #else
  int main(int argc, char * argv[])
  {
  #endif
    using namespace std;
    using namespace Eigen;
    using namespace igl;
    using namespace igl::matlab;
  
    MatrixXd V;
    MatrixXi F;
    VectorXi IM;
  
    string prefix;
    bool use_obj_format = false;
    double eps = FLOAT_EPS;
  #ifdef MEX
    // This parses first two arguements
    parse_rhs_double(prhs,V);
    parse_rhs_index(prhs+1,F);
    igl::matlab::mexErrMsgTxt(V.cols()==3,"V must be #V by 3");
    igl::matlab::mexErrMsgTxt(F.cols()==3,"F must be #F by 3");
  
    if(nrhs==3)
    {
      if(mxGetM(prhs[2]) != 1 || mxGetN(prhs[2]) != 1)
      {
        mexErrMsgTxt("3rd argument should be scalar");
      }
      eps = *mxGetPr(prhs[2]);
    }
  #else
    if(argc <= 1 || argc>3)
    {
      cerr<<"Usage:"<<endl<<
        "  collapse_small_triangles [path to mesh]"<<endl<<
        "or "<<endl<<
        "  collapse_small_triangles [path to mesh] [eps]"<<endl;
      return 1;
    }
    // Load mesh
    string filename(argv[1]);
    if(!read_triangle_mesh(filename,V,F))
    {
      cout<<REDRUM("Reading "<<filename<<" failed.")<<endl;
      return false;
    }
    cout<<GREENGIN("Read "<<filename<<" successfully.")<<endl;
    {
      // dirname, basename, extension and filename
      string dirname,b,ext;
      pathinfo(filename,dirname,b,ext,prefix);
      prefix = dirname + "/" + prefix;
      transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
      use_obj_format = ext == "obj";
    }
    if(argc == 3)
    {
      if(sscanf(argv[2], "%lf", &eps)!=1)
      {
        cout<<REDRUM("Parsing "<<argv[2]<<" failed.")<<endl;
        return 1;
      }else
      {
        cout<<"eps: "<<eps<<endl;
      }
    }else
    {
      cout<<"Default eps: "<<eps<<endl;
    }
  #endif
  
  
    // let's first try to merge small triangles
    {
      MatrixXd tempV;
      MatrixXi tempF;
      collapse_small_triangles(V,F,eps,tempF);
      //if(F.rows() == tempF.rows())
      //{
      //  cout<<GREENGIN("No small triangles detected.")<<endl;
      //}else
      //{
      //  cout<<BLUEGIN("Collapsed all small triangles, reducing "<<F.rows()<<
      //    " input triangles to "<<tempF.rows()<<" triangles.")<<endl;
      //}
      F=tempF;
  #ifndef MEX
      if(use_obj_format)
      {
        cout<<"writing mesh to "<<(prefix+"-collapse.obj")<<endl;
        writeOBJ(prefix+"-collapse.obj",V,F);
      }else
      {
        cout<<"writing mesh to "<<(prefix+"-collapse.off")<<endl;
        writeOFF(prefix+"-collapse.off",V,F);
      }
  #endif
    }
  
  #ifdef MEX
    // Prepare left-hand side
    nlhs = 1;
  
    // Treat indices as reals
    plhs[0] = mxCreateDoubleMatrix(F.rows(),F.cols(), mxREAL);
    double * Fp = mxGetPr(plhs[0]);
    MatrixXd Fd = (F.cast<double>().array()+1).matrix();
    copy(&Fd.data()[0],&Fd.data()[0]+Fd.size(),Fp);
  
    // Restore the std stream buffer Important!
    std::cout.rdbuf(outbuf);
  
  #else
    return 0;
  #endif
  }
  
  
  