예제 #1
0
int NumExactMatches(const Eigen::MatrixXi& M, const Eigen::MatrixXi& m, int& best_score, int& best_r, int& best_c)
{
    const int border = std::min((int)std::min(m.rows(),m.cols())-2, 2);
    best_score = std::numeric_limits<int>::max();
    const Eigen::Vector2i rcmax( 2*border + M.rows() - m.rows(), 2*border + M.cols() - m.cols());
    int num_zeros = 0;
    for(int r=-border; r < rcmax(0); ++r ) {
        for(int c=-border; c < rcmax(1); ++c) {
            const int hd = HammingDistance(M, m, r,c );
            if(hd < best_score) {
                best_score = hd;
                best_r = r;
                best_c = c;
            }
            if(hd==0) {
                ++num_zeros;
            }
        }
    }

    return num_zeros;
}
예제 #2
0
파일: CSGTree.cpp 프로젝트: hankstag/libigl
TEST(CSGTree, extrusion) {
    Eigen::MatrixXd V;
    Eigen::MatrixXi F;
    test_common::load_mesh("extrusion.obj", V, F);
    igl::copyleft::cgal::CSGTree tree(V, F);
    igl::copyleft::cgal::CSGTree inter(tree, tree, "i"); // returns error

    Eigen::MatrixXd V2 = inter.cast_V<Eigen::MatrixXd>();
    Eigen::MatrixXi F2 = inter.F();

    ASSERT_EQ(V.rows(), V2.rows());
    ASSERT_EQ(F.rows(), F2.rows());
}
예제 #3
0
void PointProjector::project(Eigen::MatrixXi &indexImage, 
			     Eigen::MatrixXf &depthImage, 
			     const HomogeneousPoint3fVector &points) const {
  depthImage.resize(indexImage.rows(), indexImage.cols());
  depthImage.fill(std::numeric_limits<float>::max());
  indexImage.fill(-1);
  const HomogeneousPoint3f* point = &points[0];
  for (size_t i=0; i<points.size(); i++, point++){
    int x, y;
    float d;
    if (!project(x, y, d, *point) ||
	x<0 || x>=indexImage.rows() ||
	y<0 || y>=indexImage.cols()  )
      continue;
    float& otherDistance=depthImage(x,y);
    int&   otherIndex=indexImage(x,y);
    if (otherDistance>d) {
      otherDistance = d;
      otherIndex = i;
    }
  }
}
예제 #4
0
IGL_INLINE void igl::ViewerData::set_edges(
  const Eigen::MatrixXd& P,
  const Eigen::MatrixXi& E,
  const Eigen::MatrixXd& C)
{
  using namespace Eigen;
  lines.resize(E.rows(),9);
  assert(C.cols() == 3);
  for(int e = 0;e<E.rows();e++)
  {
    RowVector3d color;
    if(C.size() == 3)
    {
      color<<C;
    }else if(C.rows() == E.rows())
    {
      color<<C.row(e);
    }
    lines.row(e)<< P.row(E(e,0)), P.row(E(e,1)), color;
  }
  dirty |= DIRTY_OVERLAY_LINES;
}
예제 #5
0
void optimize_index_buffer(
  const Eigen::MatrixXi& F, 
  const bool silent,
  Eigen::MatrixXi& OF)
{
  const int numTris = F.rows();
  std::vector<int> triBuf;
  for (int t=0; t<numTris; t++) 
  {
    triBuf.push_back(F(t,0));
    triBuf.push_back(F(t,1));
    triBuf.push_back(F(t,2));
  }
  VertexCache vertex_cache;
  int misses = vertex_cache.GetCacheMissCount(&triBuf[0], numTris);

  if (!silent)
  {
    printf("*** Before optimization ***\n");
    printf("Cache misses\t: %d\n", misses);
    printf("ACMR\t\t: %f\n", (float)misses / (float)numTris);
  }

  VertexCacheOptimizer vco;
  if(!silent)
  {
    printf("Optimizing ... \n");  
  }
  // vco.draw_list is the new order
  VertexCacheOptimizer::Result res = vco.Optimize(&triBuf[0], numTris);  
  if (res)
  {
    printf("Error in vertex cache optimization...\n");    
  }

  misses = vertex_cache.GetCacheMissCount(&triBuf[0], numTris);

  if (!silent)
  {
    printf("*** After optimization ***\n");
    printf("Cache misses\t: %d\n", misses);
    printf("ACMR\t\t: %f\n", (float)misses / (float)numTris);
  }

  for (int t=0; t<numTris; t++) 
  {
    OF(t,0) = triBuf[3*t];
    OF(t,1) = triBuf[3*t + 1];
    OF(t,2) = triBuf[3*t + 2];
  }
}
예제 #6
0
TEST(copyleft_cgal_peel_outer_hull_layers, TwoCubes) {
    Eigen::MatrixXd V;
    Eigen::MatrixXi F;
    test_common::load_mesh("two-boxes-bad-self-union.ply", V, F);
    ASSERT_EQ(486, V.rows());
    ASSERT_EQ(708, F.rows());

    typedef CGAL::Exact_predicates_exact_constructions_kernel K;
    typedef K::FT Scalar;
    typedef Eigen::Matrix<Scalar,
            Eigen::Dynamic,
            Eigen::Dynamic> MatrixXe;

    MatrixXe Vs;
    Eigen::MatrixXi Fs, IF;
    Eigen::VectorXi J, IM;
    igl::copyleft::cgal::RemeshSelfIntersectionsParam param;
    igl::copyleft::cgal::remesh_self_intersections(V, F, param, Vs, Fs, IF, J, IM);

    std::for_each(Fs.data(),Fs.data()+Fs.size(),
            [&IM](int & a){ a=IM(a); });
    MatrixXe Vt;
    Eigen::MatrixXi Ft;
    igl::remove_unreferenced(Vs,Fs,Vt,Ft,IM);
    const size_t num_faces = Ft.rows();

    Eigen::VectorXi I, flipped;
    size_t num_peels = igl::copyleft::cgal::peel_outer_hull_layers(Vt, Ft, I, flipped);

    Eigen::MatrixXd vertices(Vt.rows(), Vt.cols());
    std::transform(Vt.data(), Vt.data() + Vt.rows() * Vt.cols(),
            vertices.data(), [](Scalar v) { return CGAL::to_double(v); });
    igl::writeOBJ("debug.obj", vertices, Ft);

    ASSERT_EQ(num_faces, I.rows());
    ASSERT_EQ(0, I.minCoeff());
    ASSERT_EQ(1, I.maxCoeff());
}
예제 #7
0
IGL_INLINE void igl::adjacency_matrix(
  const Eigen::MatrixXi & F, 
  Eigen::SparseMatrix<T>& A)
{
  using namespace std;
  using namespace Eigen;

  typedef Triplet<T> IJV;
  vector<IJV > ijv;
  ijv.reserve(F.size()*2);
  // Loop over faces
  for(int i = 0;i<F.rows();i++)
  {
    // Loop over this face
    for(int j = 0;j<F.cols();j++)
    {
      // Get indices of edge: s --> d
      int s = F(i,j);
      int d = F(i,(j+1)%F.cols());
      ijv.push_back(IJV(s,d,1));
      ijv.push_back(IJV(d,s,1));
    }
  }

  const int n = F.maxCoeff()+1;
  A.resize(n,n);
  switch(F.cols())
  {
    case 3:
      A.reserve(6*(F.maxCoeff()+1));
      break;
    case 4:
      A.reserve(26*(F.maxCoeff()+1));
      break;
  }
  A.setFromTriplets(ijv.begin(),ijv.end());

  // Force all non-zeros to be one

  // Iterate over outside
  for(int k=0; k<A.outerSize(); ++k)
  {
    // Iterate over inside
    for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
    {
      assert(it.value() != 0);
      A.coeffRef(it.row(),it.col()) = 1;
    }
  }
}
예제 #8
0
IGL_INLINE void igl::PolyVectorFieldFinder<DerivedV, DerivedF>::getGeneralCoeffConstraints(const Eigen::VectorXi &isConstrained,
                                                       const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> &cfW,
                                                       int k,
                                                       Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic,1> &Ck)
{
  int numConstrained = isConstrained.sum();
  Ck.resize(numConstrained,1);
  int n = cfW.cols()/3;

  Eigen::MatrixXi allCombs;
  {
    Eigen::VectorXi V = Eigen::VectorXi::LinSpaced(n,0,n-1);
    igl::nchoosek(V,k+1,allCombs);
  }


  int ind = 0;
  for (int fi = 0; fi <numF; ++fi)
  {
    const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &b1 = B1.row(fi);
    const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &b2 = B2.row(fi);
    if(isConstrained[fi])
    {
      std::complex<typename DerivedV::Scalar> ck(0);

      for (int j = 0; j < allCombs.rows(); ++j)
      {
        std::complex<typename DerivedV::Scalar> tk(1.);
        //collect products
        for (int i = 0; i < allCombs.cols(); ++i)
        {
          int index = allCombs(j,i);

          const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &w = cfW.block(fi,3*index,1,3);
          typename DerivedV::Scalar w0 = w.dot(b1);
          typename DerivedV::Scalar w1 = w.dot(b2);
          std::complex<typename DerivedV::Scalar> u(w0,w1);
          tk*= u*u;
        }
        //collect sum
        ck += tk;
      }
      Ck(ind) = ck;
      ind ++;
    }
  }


}
예제 #9
0
IGL_INLINE void igl::n_polyvector(const Eigen::MatrixXd &V,
                             const Eigen::MatrixXi &F,
                             const Eigen::VectorXi& b,
                             const Eigen::MatrixXd& bc,
                             Eigen::MatrixXd &output)
{
  Eigen::VectorXi isConstrained = Eigen::VectorXi::Constant(F.rows(),0);
  Eigen::MatrixXd cfW = Eigen::MatrixXd::Constant(F.rows(),bc.cols(),0);

  for(unsigned i=0; i<b.size();++i)
  {
    isConstrained(b(i)) = 1;
    cfW.row(b(i)) << bc.row(i);
  }
  if (b.size() == F.rows())
  {
    output = cfW;
    return;
  }

  int n = cfW.cols()/3;
  igl::PolyVectorFieldFinder<Eigen::MatrixXd, Eigen::MatrixXi> pvff(V,F,n);
  pvff.solve(isConstrained, cfW, output);
}
예제 #10
0
IGL_INLINE void igl::triangle_fan(
  const Eigen::MatrixXi & E,
  Eigen::MatrixXi & cap)
{
  using namespace std;
  using namespace Eigen;

  // Handle lame base case
  if(E.size() == 0)
  {
    cap.resize(0,E.cols()+1);
    return;
  }
  // "Triangulate" aka "close" the E trivially with facets
  // Note: in 2D we need to know if E endpoints are incoming or
  // outgoing (left or right). Thus this will not work.
  assert(E.cols() == 2);
  // Arbitrary starting vertex
  //int s = E(int(((double)rand() / RAND_MAX)*E.rows()),0);
  int s = E(rand()%E.rows(),0);
  vector<vector<int> >  lcap;
  for(int i = 0;i<E.rows();i++)
  {
    // Skip edges incident on s (they would be zero-area)
    if(E(i,0) == s || E(i,1) == s)
    {
      continue;
    }
    vector<int> e(3);
    e[0] = s;
    e[1] = E(i,0);
    e[2] = E(i,1);
    lcap.push_back(e);
  }
  list_to_matrix(lcap,cap);
}
예제 #11
0
int main(int argc, char * argv[])
{
  using namespace Eigen;
  using namespace igl;
  using namespace std;

  // init mesh
  string filename = "../shared/decimated-knight.obj";
  if(argc < 2)
  {
    cerr<<"Usage:"<<endl<<"    ./example input.obj"<<endl;
    cout<<endl<<"Opening default mesh..."<<endl;
  }else
  {
    // Read and prepare mesh
    filename = argv[1];
  }
  if(!read_triangle_mesh(filename,V,F))
  {
    return 1;
  }
  // Compute normals, centroid, colors, bounding box diagonal
  per_face_normals(V,F,N);
  normalize_row_lengths(N,N);
  mean = V.colwise().mean();
  C.resize(F.rows(),3);
  init_C();
  bbd =
    (V.colwise().maxCoeff() -
    V.colwise().minCoeff()).maxCoeff();

  // Init embree
  ei.init(V.cast<float>(),F.cast<int>());

  // Init glut
  glutInit(&argc,argv);
  glutInitDisplayString( "rgba depth double samples>=8 ");
  glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT));
  glutCreateWindow("embree");
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(key);
  glutMouseFunc(mouse);
  glutMotionFunc(mouse_drag);
  glutPassiveMotionFunc(mouse_move);
  glutMainLoop();
  return 0;
}
예제 #12
0
int ComputationGraph::matrix(Eigen::MatrixXi matrix) {
    std::vector<int> output;
    for (int i = 0; i < matrix.rows(); i++) {
        for (int j = 0; j < matrix.cols(); j++) {
            output.push_back(matrix(i, j));
        }
    }

    nodes.push_back({
        -1,
        {},
        output
    });

    return nodes.size() - 1;
}
예제 #13
0
IGL_INLINE std::vector<int> igl::circulation(
  const int e,
  const bool ccw,
  const Eigen::MatrixXi & F,
  const Eigen::MatrixXi & E,
  const Eigen::VectorXi & EMAP,
  const Eigen::MatrixXi & EF,
  const Eigen::MatrixXi & EI)
{
  // prepare output
  std::vector<int> N;
  N.reserve(6);
  const int m = F.rows();
  const auto & step = [&](
    const int e, 
    const int ff,
    int & ne, 
    int & nf)
  {
    assert((EF(e,1) == ff || EF(e,0) == ff) && "e should touch ff");
    //const int fside = EF(e,1)==ff?1:0;
    const int nside = EF(e,0)==ff?1:0;
    const int nv = EI(e,nside);
    // get next face
    nf = EF(e,nside);
    // get next edge 
    const int dir = ccw?-1:1;
    ne = EMAP(nf+m*((nv+dir+3)%3));
  };
  // Always start with first face (ccw in step will be sure to turn right
  // direction)
  const int f0 = EF(e,0);
  int fi = f0;
  int ei = e;
  while(true)
  {
    step(ei,fi,ei,fi);
    N.push_back(fi);
    // back to start?
    if(fi == f0)
    {
      assert(ei == e);
      break;
    }
  }
  return N;
}
예제 #14
0
파일: main.cpp 프로젝트: Codermay/libigl
void drawCuts(igl::viewer::Viewer& viewer,
              const Eigen::MatrixXi &cuts)
{
  int maxCutNum = cuts.sum();
  Eigen::MatrixXd start(maxCutNum,3);
  Eigen::MatrixXd end(maxCutNum,3);
  int ind = 0;
  for (unsigned int i=0;i<F.rows();i++)
    for (int j=0;j<3;j++)
      if (cuts(i,j))
      {
        start.row(ind) = V.row(F(i,j));
        end.row(ind) = V.row(F(i,(j+1)%3));
        ind++;
      }
  viewer.data.add_edges(start, end , Eigen::RowVector3d(1.,0,1.));
}
예제 #15
0
파일: main.cpp 프로젝트: Codermay/libigl
// Plots the mesh with an N-RoSy field and its singularities on top
// The constrained faces (b) are colored in red.
void plot_mesh_nrosy(
    igl::viewer::Viewer& viewer,
    Eigen::MatrixXd& V,
    Eigen::MatrixXi& F,
    int N,
    Eigen::MatrixXd& PD1,
    Eigen::VectorXd& S,
    Eigen::VectorXi& b)
{
    using namespace Eigen;
    using namespace std;
    // Clear the mesh
    viewer.data.clear();
    viewer.data.set_mesh(V,F);

    // Expand the representative vectors in the full vector set and plot them as lines
    double avg = igl::avg_edge_length(V, F);
    MatrixXd Y;
    representative_to_nrosy(V, F, PD1, N, Y);

    MatrixXd B;
    igl::barycenter(V,F,B);

    MatrixXd Be(B.rows()*N,3);
    for(unsigned i=0; i<B.rows(); ++i)
        for(unsigned j=0; j<N; ++j)
            Be.row(i*N+j) = B.row(i);

    viewer.data.add_edges(Be,Be+Y*(avg/2),RowVector3d(0,0,1));

    // Plot the singularities as colored dots (red for negative, blue for positive)
    for (unsigned i=0; i<S.size(); ++i)
    {
        if (S(i) < -0.001)
            viewer.data.add_points(V.row(i),RowVector3d(1,0,0));
        else if (S(i) > 0.001)
            viewer.data.add_points(V.row(i),RowVector3d(0,1,0));
    }

    // Highlight in red the constrained faces
    MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
    for (unsigned i=0; i<b.size(); ++i)
        C.row(b(i)) << 1, 0, 0;
    viewer.data.set_colors(C);
}
예제 #16
0
int main(int argc, char * argv[])
{
  using namespace Eigen;
  using namespace igl;
  using namespace std;

  // init mesh
  string filename = "/usr/local/igl/libigl/examples/shared/decimated-knight.obj" ;
  if(argc > 1)
  {
    filename = argv[1];
  }

  if(!read_triangle_mesh(filename,V,F))
  {
    return 1;
  }
  // Compute normals, centroid, colors, bounding box diagonal
  per_face_normals(V,F,N);
  normalize_row_lengths(N,N);
  mean = V.colwise().mean();
  C.resize(F.rows(),3);
  init_C();
  bbd =
    (V.colwise().maxCoeff() -
    V.colwise().minCoeff()).maxCoeff();


  // Init viewports
  init_viewports();

  // Init glut
  glutInit(&argc,argv);
  glutInitDisplayString( "rgba depth double samples>=8 ");
  glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT));
  glutCreateWindow("multi-viewport");
  glutDisplayFunc(display);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(key);
  glutMouseFunc(mouse);
  glutMotionFunc(mouse_drag);
  glutPassiveMotionFunc(mouse_move);
  glutMainLoop();
  return 0;
}
예제 #17
0
IGL_INLINE void igl::forward_kinematics(
  const Eigen::MatrixXd & C,
  const Eigen::MatrixXi & BE,
  const Eigen::VectorXi & P,
  const std::vector<
    Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
  std::vector<
    Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ,
  std::vector<Eigen::Vector3d> & vT)
{
  using namespace std;
  using namespace Eigen;
  const int m = BE.rows(); 
  assert(m == P.rows());
  assert(m == (int)dQ.size());
  vector<bool> computed(m,false);
  vQ.resize(m);
  vT.resize(m);
  function<void (int) > fk_helper = [&] (int b)
  {
    if(!computed[b])
    {
      if(P(b) < 0)
      {
        // base case for roots
        vQ[b] = dQ[b];
        const Vector3d r = C.row(BE(b,0)).transpose();
        vT[b] = r-dQ[b]*r;
      }else
      {
        // Otherwise first compute parent's
        const int p = P(b);
        fk_helper(p);
        vQ[b] = vQ[p] * dQ[b];
        const Vector3d r = C.row(BE(b,0)).transpose();
        vT[b] = vT[p] - vQ[b]*r + vQ[p]*r;
      }
      computed[b] = true;
    }
  };
  for(int b = 0;b<m;b++)
  {
    fk_helper(b);
  }
}
예제 #18
0
  /*
  Train the classifier with the dataset of breastcancer patients from the
  LibSVM Libary
  */
  void TrainSVMClassifier_BreastCancerDataSet_shouldReturnTrue()
  {
    /* Declarating an featurematrixdataset, the first matrix
    of the matrixpair is the trainingmatrix and the second one is the testmatrix.*/
    std::pair<MatrixDoubleType,MatrixDoubleType> matrixDouble;
    matrixDouble = convertCSVToMatrix<double>(GetTestDataFilePath("Classification/FeaturematrixBreastcancer.csv"),';',0.5,true);
    m_TrainingMatrixX = matrixDouble.first;
    m_TestXPredict = matrixDouble.second;

    /* The declaration of the labelmatrixdataset is equivalent to the declaration
    of the featurematrixdataset.*/
    std::pair<MatrixIntType,MatrixIntType> matrixInt;
    matrixInt = convertCSVToMatrix<int>(GetTestDataFilePath("Classification/LabelmatrixBreastcancer.csv"),';',0.5,false);
    m_TrainingLabelMatrixY = matrixInt.first;
    m_TestYPredict = matrixInt.second;

    /* Setting of the SVM-Parameters*/
    classifier = mitk::LibSVMClassifier::New();
    classifier->SetGamma(1/(double)(m_TrainingMatrixX.cols()));
    classifier->SetSvmType(0);
    classifier->SetKernelType(2);

    /* Train the classifier, by giving trainingdataset for the labels and features.
    The result in an colunmvector of the labels.*/
    classifier->Train(m_TrainingMatrixX,m_TrainingLabelMatrixY);
    Eigen::MatrixXi classes = classifier->Predict(m_TestXPredict);

    /* Testing the matching between the calculated colunmvector and the result
    of the SVM */
    unsigned int maxrows = classes.rows();

    bool isYPredictVector = false;
    int count = 0;

    for(int i= 0; i < maxrows; i++){
      if(classes(i,0) == m_TestYPredict(i,0)){
        isYPredictVector = true;
        count++;
      }
    }
    MITK_INFO << 100*count/(double)(maxrows) << "%";
    MITK_TEST_CONDITION(isIntervall<int>(m_TestYPredict,classes,75,100),"Testvalue is in range.");
  }
예제 #19
0
IGL_INLINE void igl::viewer::ViewerCore::get_scale_and_shift_to_fit_mesh(
  const Eigen::MatrixXd& V,
  const Eigen::MatrixXi& F,
  float& zoom,
  Eigen::Vector3f& shift)
{
  if (V.rows() == 0)
    return;

  Eigen::MatrixXd BC;
  if (F.rows() <= 1)
  {
    BC = V;
  } else
  {
    igl::barycenter(V,F,BC);
  }
  return get_scale_and_shift_to_fit_mesh(BC,zoom,shift);
}
예제 #20
0
IGL_INLINE bool igl::copyleft::progressive_hulls(
  const Eigen::MatrixXd & V,
  const Eigen::MatrixXi & F,
  const size_t max_m,
  Eigen::MatrixXd & U,
  Eigen::MatrixXi & G,
  Eigen::VectorXi & J)
{
  int m = F.rows();
  Eigen::VectorXi I;
  return decimate(
    V,
    F,
    progressive_hulls_cost_and_placement,
    max_faces_stopping_condition(m,max_m),
    U,
    G,
    J,
    I);
}
예제 #21
0
void triangle_tree(
  const Eigen::MatrixXd & V,
  const Eigen::MatrixXi & F,
  TriTree & tree,
  TriangleList & tlist)
{
  assert(F.cols() == 3);
  tlist.clear();

  // Loop over facets
  for(int f = 0;f<F.rows();f++)
  {
    Point3 a(V(F(f,0),0), V(F(f,0),1), V(F(f,0),2));
    Point3 b(V(F(f,1),0), V(F(f,1),1), V(F(f,1),2));
    Point3 c(V(F(f,2),0), V(F(f,2),1), V(F(f,2),2));
    tlist.push_back(Triangle3( a,b,c));
  }
  // constructs AABB tree
  tree.clear();
  tree.insert(tlist.begin(),tlist.end());
}
예제 #22
0
파일: main.cpp 프로젝트: Codermay/libigl
int main(int argc, char *argv[])
{
  // Mesh with per-face color
  Eigen::MatrixXd V, C;
  Eigen::MatrixXi F;

  // Load a mesh in OFF format
  igl::readOFF(TUTORIAL_SHARED_PATH "/fertility.off", V, F);

  // Initialize white
  C = Eigen::MatrixXd::Constant(F.rows(),3,1);
  igl::viewer::Viewer viewer;
  viewer.callback_mouse_down = 
    [&V,&F,&C](igl::viewer::Viewer& viewer, int, int)->bool
  {
    int fid;
    Eigen::Vector3f bc;
    // Cast a ray in the view direction starting from the mouse position
    double x = viewer.current_mouse_x;
    double y = viewer.core.viewport(3) - viewer.current_mouse_y;
    if(igl::unproject_onto_mesh(Eigen::Vector2f(x,y), viewer.core.view * viewer.core.model,
      viewer.core.proj, viewer.core.viewport, V, F, fid, bc))
    {
      // paint hit red
      C.row(fid)<<1,0,0;
      viewer.data.set_colors(C);
      return true;
    }
    return false;
  };
  std::cout<<R"(Usage:
  [click]  Pick face on shape

)";
  // Show mesh
  viewer.data.set_mesh(V, F);
  viewer.data.set_colors(C);
  viewer.core.show_lines = false;
  viewer.launch();
}
예제 #23
0
// Helpers that draws the most common meshes
IGL_INLINE void igl::ViewerData::set_mesh(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F)
{
  using namespace std;

  Eigen::MatrixXd V_temp;

  // If V only has two columns, pad with a column of zeros
  if (_V.cols() == 2)
  {
    V_temp = Eigen::MatrixXd::Zero(_V.rows(),3);
    V_temp.block(0,0,_V.rows(),2) = _V;
  }
  else
    V_temp = _V;

  if (V.rows() == 0 && F.rows() == 0)
  {
    clear();
    V = V_temp;
    F = _F;

    compute_normals();
    uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
                   Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
                   Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));

    grid_texture();
  }
  else
  {
    if (_V.rows() == V.rows() && _F.rows() == F.rows())
    {
      V = V_temp;
      F = _F;
    }
    else
      cerr << "ERROR (set_mesh): The new mesh has a different number of vertices/faces. Please clear the mesh before plotting.";
  }
  dirty |= DIRTY_FACE | DIRTY_POSITION;
}
예제 #24
0
// IF THIS IS EVER TEMPLATED BE SURE THAT V IS COLMAJOR
IGL_INLINE void igl::winding_number(
    const Eigen::MatrixXd & V,
    const Eigen::MatrixXi & F,
    const Eigen::MatrixXd & O,
    Eigen::VectorXd & W)
{
    using namespace Eigen;
    // make room for output
    W.resize(O.rows(),1);
    switch(F.cols())
    {
    case 2:
        return winding_number_2(
                   V.data(),
                   V.rows(),
                   F.data(),
                   F.rows(),
                   O.data(),
                   O.rows(),
                   W.data());
    case 3:
    {
        WindingNumberAABB<Vector3d> hier(V,F);
        hier.grow();
        // loop over origins
        const int no = O.rows();
        #   pragma omp parallel for if (no>IGL_WINDING_NUMBER_OMP_MIN_VALUE)
        for(int o = 0; o<no; o++)
        {
            Vector3d p = O.row(o);
            W(o) = hier.winding_number(p);
        }
        break;
    }
    default:
        assert(false && "Bad simplex size");
        break;
    }
}
예제 #25
0
void shortest_edge_and_midpoint6(const int e, const Eigen::MatrixXd &V,
                                 const Eigen::MatrixXi &F,
                                 const Eigen::MatrixXi &E,
                                 const Eigen::VectorXi &EMAP,
                                 const Eigen::MatrixXi &EF,
                                 const Eigen::MatrixXi &EI, double &cost,
                                 RowVectorXd &p) {
    // circulation angle sum
    p = 0.5 * (V.row(E(e, 0)) + V.row(E(e, 1)));
    const vector<int> c1 = igl::circulation(e, false, F, E, EMAP, EF, EI);
    const vector<int> c2 = igl::circulation(e, true, F, E, EMAP, EF, EI);
    unordered_set<int> circ;
    circ.insert(c1.begin(), c1.end());
    circ.insert(c2.begin(), c2.end());
    cost = 0.0;
    for (int face : circ) {
        for (int j = 0; j < 3; j++) {
            int edge = EMAP(face + j * F.rows());
            cost +=
                acos(normals.row(EF(edge, 0)).dot(normals.row(EF(edge, 1))));
        }
    }
}
예제 #26
0
IGL_INLINE bool igl::tetgen::mesh_with_skeleton(
  const Eigen::MatrixXd & V,
  const Eigen::MatrixXi & F,
  const Eigen::MatrixXd & C,
  const Eigen::VectorXi & /*P*/,
  const Eigen::MatrixXi & BE,
  const Eigen::MatrixXi & CE,
  const int samples_per_bone,
  const std::string & tetgen_flags,
  Eigen::MatrixXd & VV,
  Eigen::MatrixXi & TT,
  Eigen::MatrixXi & FF)
{
  using namespace Eigen;
  using namespace igl;
  using namespace std;
  const string eff_tetgen_flags = 
    (tetgen_flags.length() == 0?DEFAULT_TETGEN_FLAGS:tetgen_flags);
  // Collect all edges that need samples:
  MatrixXi BECE = cat(1,BE,CE);
  MatrixXd S;
  // Sample each edge with 10 samples. (Choice of 10 doesn't seem to matter so
  // much, but could under some circumstances)
  sample_edges(C,BECE,samples_per_bone,S);
  // Vertices we'll constrain tet mesh to meet
  MatrixXd VS = cat(1,V,S);
  // Use tetgen to mesh the interior of surface, this assumes surface:
  //   * has no holes
  //   * has no non-manifold edges or vertices
  //   * has consistent orientation
  //   * has no self-intersections
  //   * has no 0-volume pieces
  //writeOBJ("mesh_with_skeleton.obj",VS,F);
  cerr<<"tetgen begin()"<<endl;
  int status = tetrahedralize( VS,F,eff_tetgen_flags,VV,TT,FF);
  cerr<<"tetgen end()"<<endl;
  if(FF.rows() != F.rows())
  {
    // Issue a warning if the surface has changed
    cerr<<"mesh_with_skeleton: Warning: boundary faces != input faces"<<endl;
  }
  if(status != 0)
  {
    cerr<<
      "***************************************************************"<<endl<<
      "***************************************************************"<<endl<<
      "***************************************************************"<<endl<<
      "***************************************************************"<<endl<<
      "* mesh_with_skeleton: tetgen failed. Just meshing convex hull *"<<endl<<
      "***************************************************************"<<endl<<
      "***************************************************************"<<endl<<
      "***************************************************************"<<endl<<
      "***************************************************************"<<endl;
    // If meshing convex hull then use more regular mesh
    status = tetrahedralize(VS,F,"q1.414",VV,TT,FF);
    // I suppose this will fail if the skeleton is outside the mesh
    assert(FF.maxCoeff() < VV.rows());
    if(status != 0)
    {
      cerr<<"mesh_with_skeleton: tetgen failed again."<<endl;
      return false;
    }
  }

  return true;
}
예제 #27
0
파일: main.cpp 프로젝트: nixz/libigl
bool key_down(igl::viewer::Viewer& viewer, unsigned char key, int modifier)
{
  using namespace std;
  using namespace Eigen;

  if (key <'1' || key >'6')
    return false;

  viewer.data.clear();
  viewer.core.show_lines = false;
  viewer.core.show_texture = false;

  if (key == '1')
  {
    // Frame field constraints
    viewer.data.set_mesh(V, F);

    MatrixXd F1_t = MatrixXd::Zero(FF1.rows(),FF1.cols());
    MatrixXd F2_t = MatrixXd::Zero(FF2.rows(),FF2.cols());
    // Highlight in red the constrained faces
    MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
    for (unsigned i=0; i<b.size();++i)
    {
      C.row(b(i)) << 1, 0, 0;
      F1_t.row(b(i)) = bc1.row(i);
      F2_t.row(b(i)) = bc2.row(i);
    }

    viewer.data.set_colors(C);

    MatrixXd C1,C2;
    VectorXd K1 = F1_t.rowwise().norm();
    VectorXd K2 = F2_t.rowwise().norm();
    igl::jet(K1,true,C1);
    igl::jet(K2,true,C2);

    viewer.data.add_edges(B - global_scale*F1_t, B + global_scale*F1_t ,C1);
    viewer.data.add_edges(B - global_scale*F2_t, B + global_scale*F2_t ,C2);
  }

  if (key == '2')
  {
    // Frame field
    viewer.data.set_mesh(V, F);
    MatrixXd C1,C2;
    VectorXd K1 = FF1.rowwise().norm();
    VectorXd K2 = FF2.rowwise().norm();
    igl::jet(K1,true,C1);
    igl::jet(K2,true,C2);

    viewer.data.add_edges(B - global_scale*FF1, B + global_scale*FF1 ,C1);
    viewer.data.add_edges(B - global_scale*FF2, B + global_scale*FF2 ,C2);

    // Highlight in red the constrained faces
    MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
    for (unsigned i=0; i<b.size();++i)
      C.row(b(i)) << 1, 0, 0;
    viewer.data.set_colors(C);

  }

  if (key == '3')
  {
    // Deformed with frame field
    viewer.data.set_mesh(V_deformed, F);
    viewer.data.add_edges(B_deformed - global_scale*FF1_deformed, B_deformed + global_scale*FF1_deformed ,Eigen::RowVector3d(1,0,0));
    viewer.data.add_edges(B_deformed - global_scale*FF2_deformed, B_deformed + global_scale*FF2_deformed ,Eigen::RowVector3d(0,0,1));
    viewer.data.set_colors(RowVector3d(1,1,1));
  }

  if (key == '4')
  {
    // Deformed with cross field
    viewer.data.set_mesh(V_deformed, F);
    viewer.data.add_edges(B_deformed - global_scale*X1_deformed, B_deformed + global_scale*X1_deformed ,Eigen::RowVector3d(0,0,1));
    viewer.data.add_edges(B_deformed - global_scale*X2_deformed, B_deformed + global_scale*X2_deformed ,Eigen::RowVector3d(0,0,1));
    viewer.data.set_colors(RowVector3d(1,1,1));
  }

  if (key == '5')
  {
    // Deformed with quad texture
    viewer.data.set_mesh(V_deformed, F);
    viewer.data.set_uv(V_uv,F_uv);
    viewer.data.set_colors(RowVector3d(1,1,1));
    viewer.core.show_texture = true;
  }

  if (key == '6')
  {
    // Deformed with quad texture
    viewer.data.set_mesh(V, F);
    viewer.data.set_uv(V_uv,F_uv);
    viewer.data.set_colors(RowVector3d(1,1,1));
    viewer.core.show_texture = true;
  }

  // Replace the standard texture with an integer shift invariant texture
  Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_R, texture_G, texture_B;
  line_texture(texture_R, texture_G, texture_B);
  viewer.data.set_texture(texture_R, texture_B, texture_G);
  viewer.core.align_camera_center(viewer.data.V,viewer.data.F);

  return false;
}
예제 #28
0
IGL_INLINE void igl::triangle::triangulate(
  const Eigen::MatrixXd& V,
  const Eigen::MatrixXi& E,
  const Eigen::MatrixXd& H,
  const std::string flags,
  Eigen::MatrixXd& V2,
  Eigen::MatrixXi& F2)
{
  using namespace std;
  using namespace Eigen;

  // Prepare the flags
  string full_flags = flags + "pzB";

  // Prepare the input struct
  triangulateio in;

  assert(V.cols() == 2);

  in.numberofpoints = V.rows();
  in.pointlist = (double*)calloc(V.rows()*2,sizeof(double));
  for (unsigned i=0;i<V.rows();++i)
    for (unsigned j=0;j<2;++j)
      in.pointlist[i*2+j] = V(i,j);

  in.numberofpointattributes = 0;
  in.pointmarkerlist = (int*)calloc(V.rows(),sizeof(int));
   for (unsigned i=0;i<V.rows();++i)
     in.pointmarkerlist[i] = 1;

  in.trianglelist = NULL;
  in.numberoftriangles = 0;
  in.numberofcorners = 0;
  in.numberoftriangleattributes = 0;
  in.triangleattributelist = NULL;

  in.numberofsegments = E.rows();
  in.segmentlist = (int*)calloc(E.rows()*2,sizeof(int));
  for (unsigned i=0;i<E.rows();++i)
    for (unsigned j=0;j<2;++j)
      in.segmentlist[i*2+j] = E(i,j);
  in.segmentmarkerlist = (int*)calloc(E.rows(),sizeof(int));
  for (unsigned i=0;i<E.rows();++i)
    in.segmentmarkerlist[i] = 1;

  in.numberofholes = H.rows();
  in.holelist = (double*)calloc(H.rows()*2,sizeof(double));
  for (unsigned i=0;i<H.rows();++i)
    for (unsigned j=0;j<2;++j)
      in.holelist[i*2+j] = H(i,j);
  in.numberofregions = 0;

  // Prepare the output struct
  triangulateio out;

  out.pointlist = NULL;
  out.trianglelist = NULL;
  out.segmentlist = NULL;

  // Call triangle
  ::triangulate(const_cast<char*>(full_flags.c_str()), &in, &out, 0);

  // Return the mesh
  V2.resize(out.numberofpoints,2);
  for (unsigned i=0;i<V2.rows();++i)
    for (unsigned j=0;j<2;++j)
      V2(i,j) = out.pointlist[i*2+j];

  F2.resize(out.numberoftriangles,3);
  for (unsigned i=0;i<F2.rows();++i)
    for (unsigned j=0;j<3;++j)
      F2(i,j) = out.trianglelist[i*3+j];

  // Cleanup in
  free(in.pointlist);
  free(in.pointmarkerlist);
  free(in.segmentlist);
  free(in.segmentmarkerlist);
  free(in.holelist);

  // Cleanup out
  free(out.pointlist);
  free(out.trianglelist);
  free(out.segmentlist);

}
예제 #29
0
IGL_INLINE bool igl::collapse_edge(
  const std::function<void(
    const int,
    const Eigen::MatrixXd &,
    const Eigen::MatrixXi &,
    const Eigen::MatrixXi &,
    const Eigen::VectorXi &,
    const Eigen::MatrixXi &,
    const Eigen::MatrixXi &,
    double &,
    Eigen::RowVectorXd &)> & cost_and_placement,
  Eigen::MatrixXd & V,
  Eigen::MatrixXi & F,
  Eigen::MatrixXi & E,
  Eigen::VectorXi & EMAP,
  Eigen::MatrixXi & EF,
  Eigen::MatrixXi & EI,
  std::set<std::pair<double,int> > & Q,
  std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
  Eigen::MatrixXd & C,
  int & e,
  int & e1,
  int & e2,
  int & f1,
  int & f2)
{
  using namespace Eigen;
  if(Q.empty())
  {
    // no edges to collapse
    return false;
  }
  std::pair<double,int> p = *(Q.begin());
  if(p.first == std::numeric_limits<double>::infinity())
  {
    // min cost edge is infinite cost
    return false;
  }
  Q.erase(Q.begin());
  e = p.second;
  Qit[e] = Q.end();
  std::vector<int> N  = circulation(e, true,F,E,EMAP,EF,EI);
  std::vector<int> Nd = circulation(e,false,F,E,EMAP,EF,EI);
  N.insert(N.begin(),Nd.begin(),Nd.end());
  const bool collapsed =
    collapse_edge(e,C.row(e),V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
  if(collapsed)
  {
    // Erase the two, other collapsed edges
    Q.erase(Qit[e1]);
    Qit[e1] = Q.end();
    Q.erase(Qit[e2]);
    Qit[e2] = Q.end();
    // update local neighbors
    // loop over original face neighbors
    for(auto n : N)
    {
      if(F(n,0) != IGL_COLLAPSE_EDGE_NULL ||
          F(n,1) != IGL_COLLAPSE_EDGE_NULL ||
          F(n,2) != IGL_COLLAPSE_EDGE_NULL)
      {
        for(int v = 0;v<3;v++)
        {
          // get edge id
          const int ei = EMAP(v*F.rows()+n);
          // erase old entry
          Q.erase(Qit[ei]);
          // compute cost and potential placement
          double cost;
          RowVectorXd place;
          cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
          // Replace in queue
          Qit[ei] = Q.insert(std::pair<double,int>(cost,ei)).first;
          C.row(ei) = place;
        }
      }
    }
  }else
  {
    // reinsert with infinite weight (the provided cost function must **not**
    // have given this un-collapsable edge inf cost already)
    p.first = std::numeric_limits<double>::infinity();
    Qit[e] = Q.insert(p).first;
  }
  return collapsed;
}
예제 #30
0
IGL_INLINE bool igl::collapse_edge(
  const int e,
  const Eigen::RowVectorXd & p,
  Eigen::MatrixXd & V,
  Eigen::MatrixXi & F,
  Eigen::MatrixXi & E,
  Eigen::VectorXi & EMAP,
  Eigen::MatrixXi & EF,
  Eigen::MatrixXi & EI,
  int & a_e1,
  int & a_e2,
  int & a_f1,
  int & a_f2)
{
  // Assign this to 0 rather than, say, -1 so that deleted elements will get
  // draw as degenerate elements at vertex 0 (which should always exist and
  // never get collapsed to anything else since it is the smallest index)
  using namespace Eigen;
  using namespace std;
  const int eflip = E(e,0)>E(e,1);
  // source and destination
  const int s = eflip?E(e,1):E(e,0);
  const int d = eflip?E(e,0):E(e,1);

  if(!edge_collapse_is_valid(e,F,E,EMAP,EF,EI))
  {
    return false;
  }

  // Important to grab neighbors of d before monkeying with edges
  const std::vector<int> nV2Fd = circulation(e,!eflip,F,E,EMAP,EF,EI);

  // The following implementation strongly relies on s<d
  assert(s<d && "s should be less than d");
  // move source and destination to midpoint
  V.row(s) = p;
  V.row(d) = p;

  // Helper function to replace edge and associate information with NULL
  const auto & kill_edge = [&E,&EI,&EF](const int e)
  {
    E(e,0) = IGL_COLLAPSE_EDGE_NULL;
    E(e,1) = IGL_COLLAPSE_EDGE_NULL;
    EF(e,0) = IGL_COLLAPSE_EDGE_NULL;
    EF(e,1) = IGL_COLLAPSE_EDGE_NULL;
    EI(e,0) = IGL_COLLAPSE_EDGE_NULL;
    EI(e,1) = IGL_COLLAPSE_EDGE_NULL;
  };

  // update edge info
  // for each flap
  const int m = F.rows();
  for(int side = 0;side<2;side++)
  {
    const int f = EF(e,side);
    const int v = EI(e,side);
    const int sign = (eflip==0?1:-1)*(1-2*side);
    // next edge emanating from d
    const int e1 = EMAP(f+m*((v+sign*1+3)%3));
    // prev edge pointing to s
    const int e2 = EMAP(f+m*((v+sign*2+3)%3));
    assert(E(e1,0) == d || E(e1,1) == d);
    assert(E(e2,0) == s || E(e2,1) == s);
    // face adjacent to f on e1, also incident on d
    const bool flip1 = EF(e1,1)==f;
    const int f1 = flip1 ? EF(e1,0) : EF(e1,1);
    assert(f1!=f);
    assert(F(f1,0)==d || F(f1,1)==d || F(f1,2) == d);
    // across from which vertex of f1 does e1 appear?
    const int v1 = flip1 ? EI(e1,0) : EI(e1,1);
    // Kill e1
    kill_edge(e1);
    // Kill f
    F(f,0) = IGL_COLLAPSE_EDGE_NULL;
    F(f,1) = IGL_COLLAPSE_EDGE_NULL;
    F(f,2) = IGL_COLLAPSE_EDGE_NULL;
    // map f1's edge on e1 to e2
    assert(EMAP(f1+m*v1) == e1);
    EMAP(f1+m*v1) = e2;
    // side opposite f2, the face adjacent to f on e2, also incident on s
    const int opp2 = (EF(e2,0)==f?0:1);
    assert(EF(e2,opp2) == f);
    EF(e2,opp2) = f1;
    EI(e2,opp2) = v1;
    // remap e2 from d to s
    E(e2,0) = E(e2,0)==d ? s : E(e2,0);
    E(e2,1) = E(e2,1)==d ? s : E(e2,1);
    if(side==0)
    {
      a_e1 = e1;
      a_f1 = f;
    }else
    {
      a_e2 = e1;
      a_f2 = f;
    }
  }

  // finally, reindex faces and edges incident on d. Do this last so asserts
  // make sense.
  //
  // Could actually skip first and last, since those are always the two
  // collpased faces.
  for(auto f : nV2Fd)
  {
    for(int v = 0;v<3;v++)
    {
      if(F(f,v) == d)
      {
        const int flip1 = (EF(EMAP(f+m*((v+1)%3)),0)==f)?1:0;
        const int flip2 = (EF(EMAP(f+m*((v+2)%3)),0)==f)?0:1;
        assert(
          E(EMAP(f+m*((v+1)%3)),flip1) == d ||
          E(EMAP(f+m*((v+1)%3)),flip1) == s);
        E(EMAP(f+m*((v+1)%3)),flip1) = s;
        assert(
          E(EMAP(f+m*((v+2)%3)),flip2) == d ||
          E(EMAP(f+m*((v+2)%3)),flip2) == s);
        E(EMAP(f+m*((v+2)%3)),flip2) = s;
        F(f,v) = s;
        break;
      }
    }
  }
  // Finally, "remove" this edge and its information
  kill_edge(e);

  return true;
}