Beispiel #1
0
GTEST_TEST(TestConvexHull, testRandomConvexCombinations) {
  // Generate a set of points, then find a random convex combination of those
  // points, and verify that it's correctly reported as being inside the
  // convex hull
  for (int i = 2; i < 50; ++i) {
    for (int j = 0; j < 500; ++j) {
      MatrixXd pts = MatrixXd::Random(2, i);
      VectorXd weights = VectorXd::Random(i);
      if (weights.minCoeff() < 0) {
        weights = weights.array() -
                  weights.minCoeff();  // make sure they're all nonnegative
      }
      weights = weights.array() / weights.sum();
      Vector2d q = pts * weights;
      EXPECT_TRUE(inConvexHull(pts, q, 1e-8));
    }
  }
}
Beispiel #2
0
Matrix<bool, Dynamic, 1> getActiveSupportMask(
    const RigidBodyTree &r, VectorXd q, VectorXd qd,
    std::vector<SupportStateElement,
                Eigen::aligned_allocator<SupportStateElement>> &
        available_supports,
    const Ref<const Matrix<bool, Dynamic, 1>> &contact_force_detected,
    double contact_threshold) {
  KinematicsCache<double> cache = r.doKinematics(q, qd);

  size_t nsupp = available_supports.size();
  Matrix<bool, Dynamic, 1> active_supp_mask =
      Matrix<bool, Dynamic, 1>::Zero(nsupp);
  VectorXd phi;
  SupportStateElement se;
  bool needs_kin_check;
  bool kin_contact;
  bool force_contact;

  for (size_t i = 0; i < nsupp; i++) {
    // mexPrintf("evaluating support: %d\n", i);
    se = available_supports[i];

    force_contact = (contact_force_detected(se.body_idx) != 0);
    // Determine if the body needs to be checked for kinematic contact. We only
    // need to check for kin contact if the logic map indicates that the
    // presence or absence of such contact would  affect the decision about
    // whether to use that body as a support.
    needs_kin_check = (((se.support_logic_map[1] != se.support_logic_map[0]) &&
                        (contact_force_detected(se.body_idx) == 0)) ||
                       ((se.support_logic_map[3] != se.support_logic_map[2]) &&
                        (contact_force_detected(se.body_idx) == 1)));

    if (needs_kin_check) {
      if (contact_threshold == -1) {
        kin_contact = true;
      } else {
        contactPhi(r, cache, se, phi);
        kin_contact = (phi.minCoeff() <= contact_threshold);
      }
    } else {
      kin_contact = false;  // we've determined already that kin contact doesn't
                            // matter for this support element
    }

    active_supp_mask(i) =
        isSupportElementActive(&se, force_contact, kin_contact);
    // mexPrintf("needs check: %d force contact: %d kin_contact: %d is_active:
    // %d\n", needs_kin_check, force_contact, kin_contact, active_supp_mask(i));
  }
  return active_supp_mask;
}
Beispiel #3
0
void  UpdaterMean::costsToWeights(const VectorXd& costs, string weighting_method, double eliteness, VectorXd& weights) const
{
  weights.resize(costs.size());
  if (weighting_method.compare("PI-BB")==0)
  {
    // PI^2 style weighting: continuous, cost exponention
    double h = eliteness; // In PI^2, eliteness parameter is known as "h"
    double range = costs.maxCoeff()-costs.minCoeff();
    if (range==0)
      weights.fill(1);
    else
      weights = (-h*(costs.array()-costs.minCoeff())/range).exp();
  } 
  else if (weighting_method.compare("CMA-ES")==0 || weighting_method.compare("CEM")==0 )
  {
    // CMA-ES and CEM are rank-based, so we must first sort the costs, and the assign a weight to 
    // each rank.
    VectorXd costs_sorted = costs; 
    std::sort(costs_sorted.data(), costs_sorted.data()+costs_sorted.size());
    // In Python this is more elegant because we have argsort.
    // indices = np.argsort(costs)
    // It is possible to do this with fancy lambda functions or std::pair in C++ too, but  I don't
    // mind writing two for loops instead ;-)
    
    weights.fill(0.0);
    int mu = eliteness; // In CMA-ES, eliteness parameter is known as "mu"
    assert(mu<costs.size());
    for (int ii=0; ii<mu; ii++)
    {
      double cur_cost = costs_sorted[ii];
      for (int jj=0; jj<costs.size(); jj++)
      {
        if (costs[jj] == cur_cost)
        {
          if (weighting_method.compare("CEM")==0)
            weights[jj] = 1.0/mu; // CEM
          else
            weights[jj] = log(mu+0.5) - log(ii+1); // CMA-ES
          break;
        }
      }
      
    }
    // For debugging
    //MatrixXd print_mat(3,costs.size());
    //print_mat.row(0) = costs_sorted;
    //print_mat.row(1) = costs;
    //print_mat.row(2) = weights;
    //cout << print_mat << endl;
  }
  else
  {
    cout << __FILE__ << ":" << __LINE__ << ":WARNING: Unknown weighting method '" << weighting_method << "'. Calling with PI-BB weighting." << endl; 
    costsToWeights(costs, "PI-BB", eliteness, weights);
    return;
  }
  
  // Relative standard deviation of total costs
  double mean = weights.mean();
  double std = sqrt((weights.array()-mean).pow(2).mean());
  double rel_std = std/mean;
  if (rel_std<1e-10)
  {
      // Special case: all costs are the same
      // Set same weights for all.
      weights.fill(1);
  }

  // Normalize weights
  weights = weights/weights.sum();

}
Beispiel #4
0
int main(int argc, char* argv[])
{
  //Misc. initialization
  StartTime = (unsigned)time(0); //Time the program starts
  cout.precision(12);
  cout << fixed;
  //End of section

  //Initialize local variables
  fstream vcidata,spectfile; //File streams for the input and output files
  MatrixXd VCIHam; //Full Hamiltonian matrix
  MatrixXd CIVec; //CI eigenvectors (wavefunction)
  VectorXd CIFreq; //CI eigenvalues (frequencies
  double Ezpe = 0; //CI zero-point energy
  double RunTime; //Run time for the calculations
  string TimeUnits; //Seconds, minutes, or hours for RunTime
  //End of section

  //Print title and compile date
  PrintFancyTitle();
  cout << "Last modification: ";
  cout << __TIME__ << " on ";
  cout << __DATE__ << '\n';
  cout << '\n';
  cout.flush();
  //End of section

  //Gather input and check for errors
  cout << "Reading input..." << '\n';
  ReadCIArgs(argc,argv,vcidata,spectfile); //Read arguments
  ReadCIInput(VCIHam,vcidata); //Read input files
  //End of section

  //Adjust force constants
  ScaleFC();
  //End of section

  //Calculate spectrum
  cout << "Constructing the CI Hamiltonian...";
  cout << '\n';
  cout << "  Zeroth-order Hamiltionian";
  cout.flush(); //Print progress
  ZerothHam(VCIHam); //Harmonic terms
  cout << "; Done." << '\n';
  cout << "  Adding anharmonic potential";
  cout.flush(); //Print progress
  AnharmHam(VCIHam); //Anharmonic terms
  cout << "; Done." << '\n';
  cout << '\n';
  cout << "Diagonalizing the Hamiltonian...";
  cout << '\n' << '\n';
  cout.flush(); //Print progress
  VCIDiagonalize(VCIHam,CIVec,CIFreq); //Diagonalization wrapper
  //End of section

  //Free memory
  VCIHam = MatrixXd(1,1);
  //End of section

  //Calculate and remove ZPE
  VectorXd UnitVec(BasisSet.size()); //Create a unit vector
  UnitVec.setOnes(); //Subtracting a constant requires a vector
  Ezpe = CIFreq.minCoeff(); //Find ZPE
  if (Ezpe < 0)
  {
    //Print error
    cout << "Error: The zero-point energy is negative.";
    cout << " Something is wrong.";
    cout << '\n';
    cout << "Try reducing the number of quanta or removing";
    cout << " large anharmonic";
    cout << '\n';
    cout << "force constants.";
    cout << '\n' << '\n';
    cout.flush();
    //Quit
    exit(0);
  }
  CIFreq -= (Ezpe*UnitVec); //Remove ZPE from all frequencies
  //End of section

  //Free memory
  UnitVec = VectorXd(1);
  //End of section

  //Print results
  cout << "Printing the spectrum...";
  cout << '\n' << '\n';
  cout << "Results:" << '\n';
  cout << "  Zero-point energy: ";
  cout.precision(2); //Truncate energy
  cout << Ezpe << " (1/cm)"; //Print energy
  cout.precision(12); //Replace settings
  cout << '\n';
  cout.flush(); //Print progress
  PrintSpectrum(CIFreq,CIVec,spectfile); //Convert the frequencies to a spectrum
  EndTime = (unsigned)time(0); //Time the calculation stops
  RunTime = (double)(EndTime-StartTime); //Total run time
  if (RunTime >= 3600)
  {
    //Switch to hours
    RunTime /= 3600;
    TimeUnits = "hours";
  }
  else if (RunTime >= 60)
  {
    //Switch to minutes
    RunTime /= 60;
    TimeUnits = "minutes";
  }
  else
  {
    //Stick with seconds
    TimeUnits = "seconds";
  }
  cout.precision(2); //Truncate time
  cout << "  Run time: " << RunTime;
  cout.precision(12); //Replace settings
  cout << " " << TimeUnits;
  cout << '\n' << '\n';
  cout << "Done.";
  cout << '\n' << '\n';
  cout.flush(); //Print progress
  //End of section

  //Empty memory and delete junk files
  vcidata.close();
  spectfile.close();
  //End of section

  //Quit
  return 0;
};
void mexFunction(int nlhs, mxArray *plhs[], 
    int nrhs, const mxArray *prhs[])
{
  // This is useful for debugging whether Matlab is caching the mex binary
  //mexPrintf("%s %s\n",__TIME__,__DATE__);
  igl::matlab::MexStream mout;
  std::streambuf *outbuf = std::cout.rdbuf(&mout);

  using namespace std;
  using namespace Eigen;
  using namespace igl;
  using namespace igl::matlab;
  using namespace igl::copyleft::cgal;

  MatrixXd V;
  MatrixXi F;
  igl::copyleft::cgal::RemeshSelfIntersectionsParam params;

  string prefix;
  bool use_obj_format = false;
  if(nrhs < 2)
  {
    mexErrMsgTxt("nrhs < 2");
  }
  parse_rhs_double(prhs,V);
  parse_rhs_index(prhs+1,F);
  mexErrMsgTxt(V.cols()==3,"V must be #V by 3");
  mexErrMsgTxt(F.cols()==3,"F must be #F by 3");

  if(nrhs>2)
  {
    int i = 2;
    while(i<nrhs)
    {
      if(!mxIsChar(prhs[i]))
      {
        mexErrMsgTxt("Parameter names should be char strings");
      }
      // Cast to char
      const char * name = mxArrayToString(prhs[i]);
      if(strcmp("DetectOnly",name) == 0)
      {
        validate_arg_scalar(i,nrhs,prhs,name);
        validate_arg_logical(i,nrhs,prhs,name);
        mxLogical * v = (mxLogical *)mxGetData(prhs[++i]);
        params.detect_only = *v;
      }else if(strcmp("FirstOnly",name) == 0)
      {
        validate_arg_scalar(i,nrhs,prhs,name);
        validate_arg_logical(i,nrhs,prhs,name);
        mxLogical * v = (mxLogical *)mxGetData(prhs[++i]);
        params.first_only = *v;
      }else if(strcmp("StitchAll",name) == 0)
      {
        validate_arg_scalar(i,nrhs,prhs,name);
        validate_arg_logical(i,nrhs,prhs,name);
        mxLogical * v = (mxLogical *)mxGetData(prhs[++i]);
        params.stitch_all = *v;
      }else
      {
        mexErrMsgTxt(C_STR("Unsupported parameter: "<<name));
      }
      i++;
    }
  }
  MatrixXi IF;
  VectorXi J,IM;
  if(F.rows()>0)
  {
    // Check that there aren't any combinatorially or geometrically degenerate triangles
    VectorXd A;
    doublearea(V,F,A);
    if(A.minCoeff()<=0)
    {
      mexErrMsgTxt("Geometrically degenerate face found.");
    }
    if(
       (F.array().col(0) == F.array().col(1)).any() ||
       (F.array().col(1) == F.array().col(2)).any() ||
       (F.array().col(2) == F.array().col(0)).any())
    {
      mexErrMsgTxt("Combinatorially degenerate face found.");
    }

    // Now mesh self intersections
    {
      MatrixXd tempV;
      MatrixXi tempF;
      remesh_self_intersections(V,F,params,tempV,tempF,IF,J,IM);
      //cout<<BLUEGIN("Found and meshed "<<IF.rows()<<" pair"<<(IF.rows()==1?"":"s")
      //  <<" of self-intersecting triangles.")<<endl;
      V=tempV;
      F=tempF;
    }

  // Double-check output

#ifdef DEBUG
    // There should be *no* combinatorial duplicates
    {
      MatrixXi tempF;
      unique_simplices(F,tempF);
      if(tempF.rows() < F.rows())
      {
        cout<<REDRUM("Error: selfintersect created "<<
          F.rows()-tempF.rows()<<" combinatorially duplicate faces")<<endl;
      }else
      {
        assert(tempF.rows() == F.rows());
        cout<<GREENGIN("selfintersect created no duplicate faces")<<endl;
      }
      F = tempF;
    }
#endif
  }

  // Prepare left-hand side
  switch(nlhs)
  {
    case 5:
    {
      // Treat indices as reals
      plhs[4] = mxCreateDoubleMatrix(IM.rows(),IM.cols(), mxREAL);
      double * IMp = mxGetPr(plhs[4]);
      VectorXd IMd = (IM.cast<double>().array()+1).matrix();
      copy(&IMd.data()[0],&IMd.data()[0]+IMd.size(),IMp);
      // Fallthrough
    }
    case 4:
    {
      // Treat indices as reals
      plhs[3] = mxCreateDoubleMatrix(J.rows(),J.cols(), mxREAL);
      double * Jp = mxGetPr(plhs[3]);
      VectorXd Jd = (J.cast<double>().array()+1).matrix();
      copy(&Jd.data()[0],&Jd.data()[0]+Jd.size(),Jp);
      // Fallthrough
    }
    case 3:
    {
      // Treat indices as reals
      plhs[2] = mxCreateDoubleMatrix(IF.rows(),IF.cols(), mxREAL);
      double * IFp = mxGetPr(plhs[2]);
      MatrixXd IFd = (IF.cast<double>().array()+1).matrix();
      copy(&IFd.data()[0],&IFd.data()[0]+IFd.size(),IFp);
      // Fallthrough
    }
    case 2:
    {
      // Treat indices as reals
      plhs[1] = mxCreateDoubleMatrix(F.rows(),F.cols(), mxREAL);
      double * Fp = mxGetPr(plhs[1]);
      MatrixXd Fd = (F.cast<double>().array()+1).matrix();
      copy(&Fd.data()[0],&Fd.data()[0]+Fd.size(),Fp);
      // Fallthrough
    }
    case 1:
    {
      plhs[0] = mxCreateDoubleMatrix(V.rows(),V.cols(), mxREAL);
      double * Vp = mxGetPr(plhs[0]);
      copy(&V.data()[0],&V.data()[0]+V.size(),Vp);
      break;
    }
    default:break;
  }

  // Restore the std stream buffer Important!
  std::cout.rdbuf(outbuf);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  if (nrhs<1) mexErrMsgTxt("usage: ptr = supportDetectmex(0,robot_obj,...); alpha=supportDetectmex(ptr,...,...)");
  if (nlhs<1) mexErrMsgTxt("take at least one output... please.");
  
  struct SupportDetectData* pdata;
//   mxArray* pm;
  double* pr;
  int i,j;

  if (mxGetScalar(prhs[0])==0) { // then construct the data object and return
    pdata = new struct SupportDetectData;
    
    // get robot mex model ptr
    if (!mxIsNumeric(prhs[1]) || mxGetNumberOfElements(prhs[1])!=1)
      mexErrMsgIdAndTxt("DRC:supportDetectmex:BadInputs","the second argument should be the robot mex ptr");
    memcpy(&(pdata->r),mxGetData(prhs[1]),sizeof(pdata->r));
        
     // get the map ptr back from matlab
     if (!mxIsNumeric(prhs[2]) || mxGetNumberOfElements(prhs[2])!=1)
     mexErrMsgIdAndTxt("DRC:supportDetectmex:BadInputs","the third argument should be the map ptr");
     memcpy(&(pdata->map_ptr),mxGetPr(prhs[2]),sizeof(pdata->map_ptr));
    
    if (!pdata->map_ptr)
      mexWarnMsgTxt("Map ptr is NULL.  Assuming flat terrain at z=0");
   
     
    mxClassID cid;
    if (sizeof(pdata)==4) cid = mxUINT32_CLASS;
    else if (sizeof(pdata)==8) cid = mxUINT64_CLASS;
    else mexErrMsgIdAndTxt("Drake:supportDetectmex:PointerSize","Are you on a 32-bit machine or 64-bit machine??");
     
    plhs[0] = mxCreateNumericMatrix(1,1,cid,mxREAL);
    memcpy(mxGetData(plhs[0]),&pdata,sizeof(pdata));
     
    return;
  }
  
  // first get the ptr back from matlab
  if (!mxIsNumeric(prhs[0]) || mxGetNumberOfElements(prhs[0])!=1)
    mexErrMsgIdAndTxt("DRC:supportDetectmex:BadInputs","the first argument should be the ptr");
  memcpy(&pdata,mxGetData(prhs[0]),sizeof(pdata));

  int nq = pdata->r->num_positions;
  int nv = pdata->r->num_velocities;

  int narg=1;  
  double *q = mxGetPr(prhs[narg++]);
  double *qd = &q[nq];
  
  Map<VectorXd> qvec(q,nq);
  Map<VectorXd> qdvec(qd, nv);

  int desired_support_argid = narg++;

  double* double_contact_sensor = mxGetPr(prhs[narg]); int len = static_cast<int>(mxGetNumberOfElements(prhs[narg++]));
  VectorXi contact_sensor(len);  
  for (i=0; i<len; i++)
    contact_sensor(i)=(int)double_contact_sensor[i];
  double contact_threshold = mxGetScalar(prhs[narg++]);
  double terrain_height = mxGetScalar(prhs[narg++]); // nonzero if we're using DRCFlatTerrainMap
  
  int contact_logic_AND = (int) mxGetScalar(prhs[narg++]); // true if we should AND plan and sensor, false if we should OR them

  KinematicsCache<double> cache = pdata->r->doKinematics(qvec, qdvec); // FIXME: pass this into the function.

  //---------------------------------------------------------------------
  // Compute active support from desired supports -----------------------
  vector<SupportStateElement,Eigen::aligned_allocator<SupportStateElement>> active_supports;
  set<int> contact_bodies; // redundant, clean up later
  int num_active_contact_pts=0;
  if (!mxIsEmpty(prhs[desired_support_argid])) {
    VectorXd phi;
    mxArray* mxBodies;
    mxBodies = mxGetProperty(prhs[desired_support_argid],0,"bodies");
    if (!mxBodies) mxBodies = mxGetField(prhs[desired_support_argid],0,"bodies");
    if (!mxBodies) mexErrMsgTxt("couldn't get bodies");
    double* pBodies = mxGetPr(mxBodies);

    mxArray* mxContactPts;
    // We may have gotten a RigidBodySupportState object (in which case we need mxGetProperty...
    mxContactPts = mxGetProperty(prhs[desired_support_argid],0,"contact_pts");
    // ...or a struct array, in which case we need mxGetField
    if (!mxContactPts) mxContactPts = mxGetField(prhs[desired_support_argid],0,"contact_pts");
    if (!mxContactPts) mexErrMsgTxt("couldn't get contact points");
    
    for (i=0; i<mxGetNumberOfElements(mxBodies);i++) {
      mxArray* mxBodyContactPts = mxGetCell(mxContactPts,i);
      assert(mxGetM(mxBodyContactPts) == 3);
      int nc = static_cast<int>(mxGetN(mxBodyContactPts));
      if (nc<1) continue;
      
      Map<MatrixXd> all_body_contact_pts(mxGetPr(mxBodyContactPts), mxGetM(mxBodyContactPts), mxGetN(mxBodyContactPts));

      SupportStateElement se;
      se.body_idx = (int) pBodies[i]-1;
      for (j=0; j<nc; j++) {
        se.contact_pts.push_back(all_body_contact_pts.col(j));
      }
      
      if (contact_threshold == -1) { // ignore terrain
        if (contact_sensor(i)!=0) { // no sensor info, or sensor says yes contact
          active_supports.push_back(se);
          num_active_contact_pts += nc;
          contact_bodies.insert((int)se.body_idx); 
        }
      } 
      else {
        contactPhi(pdata->r, cache, se, pdata->map_ptr, phi, terrain_height);
        bool in_contact = true;
        if (contact_logic_AND) { // plan is true, now check contact sensor/kinematics
          in_contact =  (phi.minCoeff()<=contact_threshold || contact_sensor(i)==1); // any contact below threshold (kinematically) OR contact sensor says yes contact
        }
        // else: (plan) OR (sensor), so in_contact = true

        if (in_contact) { 
          active_supports.push_back(se);
          num_active_contact_pts += nc;
          contact_bodies.insert((int)se.body_idx);
        }
      }
    }
  }

  if (nlhs>0) {
    plhs[0] = mxCreateDoubleMatrix(1,static_cast<int>(active_supports.size()),mxREAL);
    pr = mxGetPr(plhs[0]);
    int i=0;
    for (vector<SupportStateElement,Eigen::aligned_allocator<SupportStateElement>>::iterator iter = active_supports.begin(); iter!=active_supports.end(); iter++) {
      pr[i++] = (double) (iter->body_idx + 1);
    }
  }
} 
Beispiel #7
0
void mexFunction(int nlhs, mxArray *plhs[], 
    int nrhs, const mxArray *prhs[])
{
  // This is useful for debugging whether Matlab is caching the mex binary
  //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;
  using namespace igl::cgal;

  MatrixXd V;
  MatrixXi F;
  igl::cgal::RemeshSelfIntersectionsParam params;

  string prefix;
  bool use_obj_format = false;
#ifdef MEX
  if(nrhs < 2)
  {
    mexErrMsgTxt("nrhs < 2");
  }
  parse_rhs_double(prhs,V);
  parse_rhs_index(prhs+1,F);
  mexErrMsgTxt(V.cols()==3,"V must be #V by 3");
  mexErrMsgTxt(F.cols()==3,"F must be #F by 3");

  if(nrhs>2)
  {
    int i = 2;
    while(i<nrhs)
    {
      if(!mxIsChar(prhs[i]))
      {
        mexErrMsgTxt("Parameter names should be char strings");
      }
      // Cast to char
      const char * name = mxArrayToString(prhs[i]);
      if(strcmp("DetectOnly",name) == 0)
      {
        validate_arg_scalar(i,nrhs,prhs,name);
        validate_arg_logical(i,nrhs,prhs,name);
        mxLogical * v = (mxLogical *)mxGetData(prhs[++i]);
        params.detect_only = *v;
      }else if(strcmp("FirstOnly",name) == 0)
      {
        validate_arg_scalar(i,nrhs,prhs,name);
        validate_arg_logical(i,nrhs,prhs,name);
        mxLogical * v = (mxLogical *)mxGetData(prhs[++i]);
        params.first_only = *v;
      }else
      {
        mexErrMsgTxt(C_STR("Unsupported parameter: "<<name));
      }
      i++;
    }
  }
#else
  if(argc <= 1)
  {
    cerr<<"Usage:"<<endl<<"  selfintersect [path to .off/.obj mesh] "
      "[0 or 1 for detect only]"<<endl;
    return 1;
  }
  // Apparently CGAL doesn't have a good data structure triangle soup. Their
  // own examples use (V,F):
  // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/AABB_tree/Chapter_main.html#Subsection_64.3.7
  //
  // 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>2)
  {
    //http://stackoverflow.com/a/9748431/148668
    char *p;
    long d = strtol(argv[2], &p, 10);
    if (errno != 0 || *p != '\0')
    {
      cerr<<"detect only param should be 0 or 1"<<endl;
    }else
    {
      params.detect_only = d!=0;
    }
  }
#endif
  MatrixXi IF;
  VectorXi J,IM;
  if(F.rows()>0)
  {
    // Check that there aren't any combinatorially or geometrically degenerate triangles
    VectorXd A;
    doublearea(V,F,A);
    if(A.minCoeff()<=0)
    {
#ifdef MEX
      mexErrMsgTxt("Geometrically degenerate face found.");
#else
      cerr<<"Geometrically degenerate face found."<<endl;
      return 1;
#endif
    }
    VectorXi F12,F23,F31;
    F12 = F.col(0)-F.col(1);
    F23 = F.col(1)-F.col(2);
    F31 = F.col(2)-F.col(0);
    if(
      F12.minCoeff() == 0 || 
      F23.minCoeff() == 0 || 
      F31.minCoeff() == 0)
    {
#ifdef MEX
      mexErrMsgTxt("Combinatorially degenerate face found.");
#else
      cerr<<"Geometrically degenerate face found."<<endl;
      return 1;
#endif
    }

    // Now mesh self intersections
    {
      MatrixXd tempV;
      MatrixXi tempF;
      remesh_self_intersections(V,F,params,tempV,tempF,IF,J,IM);
      //cout<<BLUEGIN("Found and meshed "<<IF.rows()<<" pair"<<(IF.rows()==1?"":"s")
      //  <<" of self-intersecting triangles.")<<endl;
      V=tempV;
      F=tempF;
#ifndef MEX
      cout<<"writing pair list to "<<(prefix+"-IF.dmat")<<endl;
      writeDMAT((prefix+"-IF.dmat").c_str(),IF);
      cout<<"writing map to F list to "<<(prefix+"-J.dmat")<<endl;
      writeDMAT((prefix+"-J.dmat").c_str(),J);
      cout<<"writing duplicat index map to "<<(prefix+"-IM.dmat")<<endl;
      writeDMAT((prefix+"-IM.dmat").c_str(),IM);
      if(!params.detect_only)
      {
        if(use_obj_format)
        {
          cout<<"writing mesh to "<<(prefix+"-selfintersect.obj")<<endl;
          writeOBJ(prefix+"-selfintersect.obj",V,F);
        }else
        {
          cout<<"writing mesh to "<<(prefix+"-selfintersect.off")<<endl;
          writeOFF(prefix+"-selfintersect.off",V,F);
        }
      }
#endif
    }

  // Double-check output

#ifdef DEBUG
    // There should be *no* combinatorial duplicates
    {
      MatrixXi tempF;
      unique_simplices(F,tempF);
      if(tempF.rows() < F.rows())
      {
        cout<<REDRUM("Error: selfintersect created "<<
          F.rows()-tempF.rows()<<" combinatorially duplicate faces")<<endl;
      }else
      {
        assert(tempF.rows() == F.rows());
        cout<<GREENGIN("selfintersect created no duplicate faces")<<endl;
      }
      F = tempF;
    }
#endif
  }

#ifdef MEX
  // Prepare left-hand side
  switch(nlhs)
  {
    case 5:
    {
      // Treat indices as reals
      plhs[4] = mxCreateDoubleMatrix(IM.rows(),IM.cols(), mxREAL);
      double * IMp = mxGetPr(plhs[4]);
      VectorXd IMd = (IM.cast<double>().array()+1).matrix();
      copy(&IMd.data()[0],&IMd.data()[0]+IMd.size(),IMp);
      // Fallthrough
    }
    case 4:
    {
      // Treat indices as reals
      plhs[3] = mxCreateDoubleMatrix(J.rows(),J.cols(), mxREAL);
      double * Jp = mxGetPr(plhs[3]);
      VectorXd Jd = (J.cast<double>().array()+1).matrix();
      copy(&Jd.data()[0],&Jd.data()[0]+Jd.size(),Jp);
      // Fallthrough
    }
    case 3:
    {
      // Treat indices as reals
      plhs[2] = mxCreateDoubleMatrix(IF.rows(),IF.cols(), mxREAL);
      double * IFp = mxGetPr(plhs[2]);
      MatrixXd IFd = (IF.cast<double>().array()+1).matrix();
      copy(&IFd.data()[0],&IFd.data()[0]+IFd.size(),IFp);
      // Fallthrough
    }
    case 2:
    {
      // Treat indices as reals
      plhs[1] = mxCreateDoubleMatrix(F.rows(),F.cols(), mxREAL);
      double * Fp = mxGetPr(plhs[1]);
      MatrixXd Fd = (F.cast<double>().array()+1).matrix();
      copy(&Fd.data()[0],&Fd.data()[0]+Fd.size(),Fp);
      // Fallthrough
    }
    case 1:
    {
      plhs[0] = mxCreateDoubleMatrix(V.rows(),V.cols(), mxREAL);
      double * Vp = mxGetPr(plhs[0]);
      copy(&V.data()[0],&V.data()[0]+V.size(),Vp);
      break;
    }
    default:break;
  }

  // Restore the std stream buffer Important!
  std::cout.rdbuf(outbuf);

#else
  return 0;
#endif
}
Beispiel #8
0
//#define IGL_LINPROG_VERBOSE
IGL_INLINE bool igl::linprog(
  const Eigen::VectorXd & c,
  const Eigen::MatrixXd & _A,
  const Eigen::VectorXd & b,
  const int k,
  Eigen::VectorXd & x)
{
  // This is a very literal translation of
  // http://www.mathworks.com/matlabcentral/fileexchange/2166-introduction-to-linear-algebra/content/strang/linprog.m
  using namespace Eigen;
  using namespace std;
  bool success = true;
  // number of constraints
  const int m = _A.rows();
  // number of original variables
  const int n = _A.cols();
  // number of iterations
  int it = 0;
  // maximum number of iterations
  //const int MAXIT = 10*m;
  const int MAXIT = 100*m;
  // residual tolerance
  const double tol = 1e-10;
  const auto & sign = [](const Eigen::VectorXd & B) -> Eigen::VectorXd
  {
    Eigen::VectorXd Bsign(B.size());
    for(int i = 0;i<B.size();i++)
    {
      Bsign(i) = B(i)>0?1:(B(i)<0?-1:0);
    }
    return Bsign;
  };
  // initial (inverse) basis matrix
  VectorXd Dv = sign(sign(b).array()+0.5);
  Dv.head(k).setConstant(1.);
  MatrixXd D = Dv.asDiagonal();
  // Incorporate slack variables
  MatrixXd A(_A.rows(),_A.cols()+D.cols());
  A<<_A,D;
  // Initial basis
  VectorXi B = igl::colon<int>(n,n+m-1);
  // non-basis, may turn out that vector<> would be better here
  VectorXi N = igl::colon<int>(0,n-1);
  int j;
  double bmin = b.minCoeff(&j);
  int phase;
  VectorXd xb;
  VectorXd s;
  VectorXi J;
  if(k>0 && bmin<0)
  {
    phase = 1;
    xb = VectorXd::Ones(m);
    // super cost
    s.resize(n+m+1);
    s<<VectorXd::Zero(n+k),VectorXd::Ones(m-k+1);
    N.resize(n+1);
    N<<igl::colon<int>(0,n-1),B(j);
    J.resize(B.size()-1);
    // [0 1 2 3 4]
    //      ^
    // [0 1]
    //      [3 4]
    J.head(j) = B.head(j);
    J.tail(B.size()-j-1) = B.tail(B.size()-j-1);
    B(j) = n+m;
    MatrixXd AJ;
    igl::slice(A,J,2,AJ);
    const VectorXd a = b - AJ.rowwise().sum();
    {
      MatrixXd old_A = A;
      A.resize(A.rows(),A.cols()+a.cols());
      A<<old_A,a;
    }
    D.col(j) = -a/a(j);
    D(j,j) = 1./a(j);
  }else if(k==m)
  {
    phase = 2;
    xb = b;
    s.resize(c.size()+m);
    // cost function
    s<<c,VectorXd::Zero(m);
  }else //k = 0 or bmin >=0
  {
    phase = 1;
    xb = b.array().abs();
    s.resize(n+m);
    // super cost
    s<<VectorXd::Zero(n+k),VectorXd::Ones(m-k);
  }
  while(phase<3)
  {
    double df = -1;
    int t = std::numeric_limits<int>::max();
    // Lagrange mutipliers fro Ax=b
    VectorXd yb = D.transpose() * igl::slice(s,B);
    while(true)
    {
      if(MAXIT>0 && it>=MAXIT)
      {
#ifdef IGL_LINPROG_VERBOSE
        cerr<<"linprog: warning! maximum iterations without convergence."<<endl;
#endif
        success = false;
        break;
      }
      // no freedom for minimization
      if(N.size() == 0)
      {
        break;
      }
      // reduced costs
      VectorXd sN = igl::slice(s,N);
      MatrixXd AN = igl::slice(A,N,2);
      VectorXd r = sN - AN.transpose() * yb;
      int q;
      // determine new basic variable
      double rmin = r.minCoeff(&q);
      // optimal! infinity norm
      if(rmin>=-tol*(sN.array().abs().maxCoeff()+1))
      {
        break;
      }
      // increment iteration count
      it++;
      // apply Bland's rule to avoid cycling
      if(df>=0)
      {
        if(MAXIT == -1)
        {
#ifdef IGL_LINPROG_VERBOSE
          cerr<<"linprog: warning! degenerate vertex"<<endl;
#endif
          success = false;
        }
        igl::find((r.array()<0).eval(),J);
        double Nq = igl::slice(N,J).minCoeff();
        // again seems like q is assumed to be a scalar though matlab code
        // could produce a vector for multiple matches
        (N.array()==Nq).cast<int>().maxCoeff(&q);
      }
      VectorXd d = D*A.col(N(q));
      VectorXi I;
      igl::find((d.array()>tol).eval(),I);
      if(I.size() == 0)
      {
#ifdef IGL_LINPROG_VERBOSE
        cerr<<"linprog: warning! solution is unbounded"<<endl;
#endif
        // This seems dubious:
        it=-it;
        success = false;
        break;
      }
      VectorXd xbd = igl::slice(xb,I).array()/igl::slice(d,I).array();
      // new use of r
      int p;
      {
        double r;
        r = xbd.minCoeff(&p);
        p = I(p);
        // apply Bland's rule to avoid cycling
        if(df>=0)
        {
          igl::find((xbd.array()==r).eval(),J);
          double Bp = igl::slice(B,igl::slice(I,J)).minCoeff();
          // idiotic way of finding index in B of Bp
          // code down the line seems to assume p is a scalar though the matlab
          // code could find a vector of matches)
          (B.array()==Bp).cast<int>().maxCoeff(&p);
        }
        // update x
        xb -= r*d;
        xb(p) = r;
        // change in f
        df = r*rmin;
      }
      // row vector
      RowVectorXd v = D.row(p)/d(p);
      yb += v.transpose() * (s(N(q)) - d.transpose()*igl::slice(s,B));
      d(p)-=1;
      // update inverse basis matrix
      D = D - d*v;
      t = B(p);
      B(p) = N(q);
      if(t>(n+k-1))
      {
        // remove qth entry from N
        VectorXi old_N = N;
        N.resize(N.size()-1);
        N.head(q) = old_N.head(q);
        N.head(q) = old_N.head(q);
        N.tail(old_N.size()-q-1) = old_N.tail(old_N.size()-q-1);
      }else
      {
        N(q) = t;
      }
    }
    // iterative refinement
    xb = (xb+D*(b-igl::slice(A,B,2)*xb)).eval();
    // must be due to rounding
    VectorXi I;
    igl::find((xb.array()<0).eval(),I);
    if(I.size()>0)
    {
      // so correct
      VectorXd Z = VectorXd::Zero(I.size(),1);
      igl::slice_into(Z,I,xb);
    }
    // B, xb,n,m,res=A(:,B)*xb-b
    if(phase == 2 || it<0)
    {
      break;
    }
    if(xb.transpose()*igl::slice(s,B) > tol)
    {
      it = -it;
#ifdef IGL_LINPROG_VERBOSE
      cerr<<"linprog: warning, no feasible solution"<<endl;
#endif
      success = false;
      break;
    }
    // re-initialize for Phase 2
    phase = phase+1;
    s*=1e6*c.array().abs().maxCoeff();
    s.head(n) = c;
  }
  x.resize(std::max(B.maxCoeff()+1,n));
  igl::slice_into(xb,B,x);
  x = x.head(n).eval();
  return success;
}
Beispiel #9
0
bool ClassLayouter::computeNormally()
{
    FuzzyDependAttr::Ptr fuzzyAttr = m_parent->getAttr<FuzzyDependAttr>();
    if (!fuzzyAttr)
        return false;

    Graph G;
    GraphAttributes GA(G,
                       GraphAttributes::nodeGraphics | GraphAttributes::edgeGraphics |
                       GraphAttributes::nodeLabel    | GraphAttributes::nodeTemplate |
                       GraphAttributes::edgeDoubleWeight);

    SparseMatrix& veMat = fuzzyAttr->vtxEdgeMatrix();
    VectorXd	  edgeWeight	= fuzzyAttr->edgeWeightVector();
    if (edgeWeight.size() != veMat.cols())
    {
        m_status |= WARNING_USE_DEFAULT_EDGE_WEIGHT;
        edgeWeight.setOnes(veMat.cols());
    }
    const int nNodes = veMat.rows();
    const int nEdges = veMat.cols();
    if (nNodes <= 0 || nNodes != m_childList.size() || nEdges < 1)
    {
        m_status |= WARNING_NO_EDGE;
        return false;
    }

    bool isUseOrthoLayout = nEdges < 50;

    vector<node> nodeArray;
    vector<edge> edgeArray;
    NodeArray<float> nodeSize(G);
    EdgeArray<double> edgeLength(G);
    for (int i = 0; i < nNodes; ++i)
    {
        nodeArray.push_back(G.newNode());
        float r = m_nodeRadius[i];
        GA.width(nodeArray.back()) = r*2;
        GA.height(nodeArray.back()) = r*2;
        nodeSize[nodeArray.back()] = r * 2;
    }

    float maxEdgeWeight = edgeWeight.maxCoeff();
    float minEdgeWeight = edgeWeight.minCoeff();
    for (int ithEdge = 0; ithEdge < nEdges; ++ithEdge)
    {
        int src, dst;
        GraphUtility::getVtxFromEdge(veMat, ithEdge, src, dst);
        edgeArray.push_back(G.newEdge(nodeArray[src], nodeArray[dst]));
        //GA.doubleWeight(edgeArray.back()) = edgeWeight[ithEdge];
        edgeLength[edgeArray.back()] = 1;//log(edgeWeight[ithEdge] + 1);
    }


    // add dummy vertices and edges in order to merge parallel edge segments attached to the same node
    VectorXi compVec;
    int nComp = 1;
    const float dummyNodeRadius = 0.01;
    if(m_isMergeEdgeEnd && isUseOrthoLayout && GraphUtility::findConnectedComponentsVE(	veMat, compVec, nComp ))
    {
        bool* isCompSet = new bool[nComp];
        for (int i = 0; i < nComp; ++i)
            isCompSet[i] = false;

        // add a dummy node and edge for each connect component
        for (int ithVtx = 0; ithVtx < compVec.size(); ++ithVtx)
        {
            int ithCmp = compVec[ithVtx];
            if (isCompSet[ithCmp] == false)
            {
                // add dummy node and set its radius
                nodeArray.push_back(G.newNode());
                GA.width(nodeArray.back()) = dummyNodeRadius;
                GA.height(nodeArray.back()) = dummyNodeRadius;
                // add dummy edge
                edgeArray.push_back(G.newEdge(nodeArray[ithVtx], nodeArray.back()));
                isCompSet[ithCmp] = true;
            }
        }
        delete[] isCompSet;
    }


    MatrixXd pos;
    pos.resize(nNodes, 2);
    try
    {
        if (isUseOrthoLayout)
        {
            PlanarizationLayout layouter;
            OrthoLayout *ol = new OrthoLayout;
            float sep = max(m_nodeRadius.sum() / nNodes, LayoutSetting::s_baseRadius * 12);
            ol->separation(sep);
            ol->cOverhang(0.1);
            ol->setOptions(1+4);
            layouter.setPlanarLayouter(ol);
            layouter.call(GA);
            for (int v = 0; v < nNodes; ++v)
            {
                double x = GA.x(nodeArray[v]);
                double y = GA.y(nodeArray[v]);
                pos(v,0) = x;
                pos(v,1) = y;
            }
        }
        else
        {
            FMMMLayout layouter;
            //CircularLayout layouter;
            float avgRadius = m_nodeRadius.sum();
            layouter.unitEdgeLength(avgRadius * 4);
            //layouter.call(GA, edgeLength);
            layouter.call(GA);
            // 	layouter.resizeDrawing(true);
            // 	layouter.resizingScalar(3);

            for (int v = 0; v < nNodes; ++v)
            {
                double x = GA.x(nodeArray[v]);
                double y = GA.y(nodeArray[v]);
                pos(v,0) = x;
                pos(v,1) = y;
            }

            MDSPostProcesser m_postProcessor(5000, 1, 1.0, 1.0, LayoutSetting::s_baseRadius * 2);
            m_postProcessor.set2DPos(pos, m_nodeRadius.cast<double>());
            m_postProcessor.compute();
            m_postProcessor.getFinalPos(pos);
        }
    }
    catch(...)//AlgorithmFailureException e
    {
        return false;
    }

    VectorXd halfSize,offset;
    GeometryUtility::moveToOrigin(pos, m_nodeRadius.cast<double>(), halfSize, &offset);
    m_nodePos = pos.cast<float>();

    // postprocessing, and set edges
    float edgeBound[2] = {halfSize[0], halfSize[1]};
    if (isUseOrthoLayout)
    {
        for(int ithEdge = 0; ithEdge < nEdges; ++ithEdge)
        {
            DPolyline& p = GA.bends(edgeArray[ithEdge]);
            int nPoints = p.size();

            BSpline splineBuilder(5, BSpline::BSPLINE_OPEN_UNIFORM, true);
            int ithPnt = 0;
            for (DPolyline::iterator pLine = p.begin(); pLine != p.end(); ++pLine, ++ithPnt)
            {
                float px = (*pLine).m_x + offset[0];
                float py = (*pLine).m_y + offset[1];
                splineBuilder.addPoint(px,py);
                splineBuilder.addPoint(px,py);
            }
            splineBuilder.computeLine((nPoints) * 5);
            const QList<QPointF>& curve = splineBuilder.getCurvePnts();

            m_edgeParam.push_back(EdgeParam());
            EdgeParam& ep = m_edgeParam.back();
            ep.m_points.resize(curve.size(),2);
            for (int i = 0; i < curve.size(); ++i)
            {
                ep.m_points(i, 0) = curve[i].x();
                ep.m_points(i, 1) = curve[i].y();

                edgeBound[0] = qMax(edgeBound[0], (float)qAbs(curve[i].x()));
                edgeBound[1] = qMax(edgeBound[1], (float)qAbs(curve[i].y()));
            }
            ep.m_weight = edgeWeight[ithEdge];
        }
    }
    else
    {
        DelaunayCore::DelaunayRouter router;
        router.setLaneWidthRatio(2);
        router.setSmoothParam(0.5,2);
        router.setEndPointNormalRatio(0.8);
        computeEdgeRoute(router);
    }

    m_totalRadius = qSqrt(edgeBound[0]*edgeBound[0] + edgeBound[1]*edgeBound[1]);
    return true;
}
void
AutoSeg::autoSegment()
{
  // Total timing
  double last = getTime ();

  // Step 1: filter the input cloud
  //double last_f = pcl::getTime ();
  SampleFilter filter (input_cloud_);
  filter.setMaxPtLimit (input_task_->getMaxPatchDistance());
  filter.filter();
  filtered_cloud_ = filter.cloud_filtered_;
  //double now_f = pcl::getTime ();
  //cerr << "Time for filter: " << now_f-last_f << endl;

  // Return if no points are valid
  if (!AutoSeg::numValidPoints(filtered_cloud_))
    return;
  
  // Update the viewer
  if (do_vis_ && show_filtered_ && viewer_)
    AutoSeg::showFilteredCloud();

  // Decimation ratio
  float dec_ratio = static_cast<float> (nd) / 
                    (2.0*static_cast<float> (filtered_cloud_->points.size ()));

  // Step 2: find salient points on the filtered cloud
  //double last_sal = pcl::getTime ();
  sal_ = new SampleSaliency;
  
  sal_->setInputCloud (filtered_cloud_);
  sal_->setNNSize (2.0f*radius_, 580.0f/dec_ratio);
  sal_->setNNCAThres (MAX_DON_COS_ANGLE);
  if (use_gravity_) {sal_->setG (g_);}
  if (use_gravity_) {sal_->setNGCAThres (MAX_DONG_COS_ANGLE);}
  sal_->setNMS(do_nms_);
  
  sal_->extractSalientPoints ();
  
  // Keep only MAX_SAL_POINTS random points
  // TBD: do it in sal_
  if ((sal_->getIndxSalient())->size() > MAX_SAL_POINTS)
  {
    random_shuffle((sal_->getIndxSalient())->begin(), (sal_->getIndxSalient())->end());
    (sal_->getIndxSalient())->resize (MAX_SAL_POINTS);
  }
  
  //double now_sal = pcl::getTime ();
  //cerr << "Time for sal: " << now_sal-last_sal << endl;

  // Update viewer with normals
  if (do_vis_ && viewer_)
  {
    sal_->setViewer (viewer_);
    if (show_sal_filtered_) sal_->showDtFPCloud ();
    if (show_fixation_) sal_->showFixation ();
    if (show_salient_) sal_->showSalPoints (true);
    if (show_sal_curvatures_) sal_->showCurvature (true);
    if (show_sal_normals_) sal_->showNormals (true);
  }

  if (do_vis_ && show_patches_ && viewer_) removePatchPlots();

  // Create nn object
  search::OrganizedNeighbor<PointXYZ> search;
  search.setInputCloud(filtered_cloud_);
  
  // For each seed point
  ns = 0; // set number of current seeds to zero
  int num_patches = 0;
  for (int si=0; si<(sal_->getIndxSalient())->size (); si++)
  {
    // generate seeds until some termination condition holds
    //if (AutoSeg::terminate())
    //  break;

    // Step 3: generate and validate a new seed
    seed = (sal_->getIndxSalient())->at(si);
    if (!isSeedValid())
      continue;
    seeds.push_back(seed);
    ns++;

    // Step 4: fetch and validate neighborhood
    //double last_nn = pcl::getTime ();
    search.radiusSearch(filtered_cloud_->points[seed], radius_, nn_indices, nn_sqr_distances);
    nn_cloud_->points.resize (0);
    for (int i=0; i<nn_indices.size(); i++)
      nn_cloud_->points.push_back(filtered_cloud_->points[nn_indices[i]]);
    //double now_nn = pcl::getTime ();
    //cerr << "Time for nn: " << now_nn-last_nn << endl;
   
    if (do_vis_ && show_nn_ && viewer_)
      AutoSeg::showNN();

    // Step 5: fit the patch
    //double last_pf = pcl::getTime ();
    PatchFit *patchFit;
    patchFit = new PatchFit(nn_cloud_);
    patchFit->setSSmax (50);
    patchFit->fit();
    //double now_pf = pcl::getTime ();
    //cerr << "Time for fitting " << nn_cloud_->points.size() <<
    //        " points: " << now_pf-last_pf << endl;
  

    // Step 6: validate patch
    //double last_val = pcl::getTime ();
    if (do_validation_)
    {
      (*patchFit->p_).computeResidual (nn_cloud_);
      if ((*patchFit->p_).getResidual() > t_residual_)
        continue;

      VectorXd k;
      k = (*patchFit->p_).getK ();
      if (k.minCoeff () < t_min_curv_ || k.maxCoeff ()>t_max_curv_)
        continue;
    }
    num_patches++;
    //double now_val = pcl::getTime ();
    //cerr << "Time for validation: " << now_val-last_val << endl;

    // Visualize patch
    //double last_pp = pcl::getTime ();
    if (do_vis_ && show_patches_ && viewer_)
    {
      PatchPlot *patch_plot;
      (*patchFit->p_).setID (ns);
      (*patchFit->p_).setSS (0.025);
      (*patchFit->p_).infer_params();
      (*patchFit->p_).gs();

      //PatchPlot patch_plot (*patchFit->p_);
      patch_plot = new PatchPlot (*patchFit->p_);
    
      patch_plot->showPatch (viewer_, 0, 1, 0, boost::to_string(ns) + "_patch");
    
      delete (patch_plot);
    }
    //double now_pp = pcl::getTime ();
    //cerr << "Time for ploting patch: " << now_pp-last_pp << endl;

    if (!no_stats_)
    {
      // Save normal vector
      (*patchFit->p_).setCnn (sal_->getNormalNormalAngle (seed));
      if (use_gravity_)
        (*patchFit->p_).setCng (sal_->getNormalGravityAngle (seed));

      // Step 7: save statistics
      AutoSeg::saveStat (*patchFit->p_);
    
      // Step 8: print statistics
      Vector2d sk = (*patchFit->p_).getSK();
      cout << "patch stats" << " "
           << sk (0) << " "
           << sk (1) << " "
           << (*patchFit->p_).getCnn () << " "
           << (*patchFit->p_).getCng () << endl;
    }
    // delete objects
    delete (patchFit);

  } // for each seed

  if(do_vis_ && show_patches_) max_patch_plot_id_ = ns-1;
  else max_patch_plot_id_ = 0;

  // Total timing
  double now = getTime();
  cerr << "Total autoseg for " << num_patches << " patches out of " << ns <<
          " seed points: " << now-last << " sec." << endl;

  // destroy objects
  delete (sal_);
}
double DataGenerator::evaluate(MatrixXd estimate) {
    
    if (estimate.rows()!=mCenters.rows()) {
        cout << endl <<"ERROR:DataGenerator evaluate"<< endl;
        cout << "resultEvaluation dimension mismatch "<< endl;
        return 0;
    }
    
    //MatrixXd finalEstimate(mPara.dimension(),   mPara.cluster());
    unsigned long nEstimate = estimate.cols();
    
    //cout << "finalEstimate row:"<< finalEstimate.rows() << endl;
    //cout << "estimate row:"<< estimate.rows() << endl;
    //cout << "nEstimate:"<< nEstimate <<"      mPara.cluster():"<<  mPara.cluster() << endl;
    
    
    //finalEstimate.leftCols(nEstimate) = estimate;
    
    MatrixXd finalEstimate = estimate;
    
    /*
     if (nEstimate !=   mPara.cluster()) {
     unsigned long sizeDiff =   mPara.cluster() - nEstimate;
     
     if (sizeDiff>0) {
     finalEstimate.rightCols(sizeDiff) = MatrixXd::Zero(mPara.dimension(), sizeDiff);
     cout << "# of decomposed element is less than expected!! expect:" <<   mPara.cluster() << "  only:" << nEstimate << endl;
     nEstimate = nEstimate + sizeDiff;
     } else {
     cout << endl << "ERROR:DataGenerator evaluate" << endl;
     cout <<"Decompsed center is more than expected. We already pick dominant centers!!" << endl;
     
     }
     }
     */
    
    // Assign all the real center to the nearest estimater center
    
    MatrixXd bestMatch(mPara.dimension(),   mPara.cluster());
    
    double error = 0;
    
    for (unsigned long i=0; i<  mPara.cluster(); i++) {
        MatrixXd currentRep = mCenters.col(i).replicate(1,nEstimate);
        MatrixXd diff = finalEstimate - currentRep;
        diff = diff.array().pow(2);
        VectorXd dist = diff.colwise().sum();
        
        MatrixXf::Index minRow, minCol;
        error += pow(dist.minCoeff(&minRow, &minCol),0.5);
        bestMatch.col(i) = finalEstimate.col(minRow);
    }
    
    //cout << endl <<" ===== Best match ===== " << endl;
    //cout << bestMatch << endl;
    //cout << " ===== Original ===== " << endl;
    //cout << mCenters << endl;
    // cout << endl << "Avg RMSE=" << error/  mPara.cluster() << endl;
    
    return (error/  mPara.cluster());
}