Example #1
0
int main(int argc, char *argv[])
{
  using namespace Eigen;
  using namespace std;

  // Load a quad mesh generated by a conjugate field
  igl::readOFF(TUTORIAL_SHARED_PATH "/inspired_mesh_quads_Conjugate.off", VQC, FQC);

  // Convert it in a triangle mesh
  FQCtri.resize(2*FQC.rows(), 3);
  FQCtri <<  FQC.col(0),FQC.col(1),FQC.col(2),
             FQC.col(2),FQC.col(3),FQC.col(0);
  igl::slice( VQC, FQC.col(0).eval(), 1, PQC0);
  igl::slice( VQC, FQC.col(1).eval(), 1, PQC1);
  igl::slice( VQC, FQC.col(2).eval(), 1, PQC2);
  igl::slice( VQC, FQC.col(3).eval(), 1, PQC3);

  // Planarize it
  igl::planarize_quad_mesh(VQC, FQC, 100, 0.005, VQCplan);

  // Convert the planarized mesh to triangles
  igl::slice( VQCplan, FQC.col(0).eval(), 1, PQC0plan);
  igl::slice( VQCplan, FQC.col(1).eval(), 1, PQC1plan);
  igl::slice( VQCplan, FQC.col(2).eval(), 1, PQC2plan);
  igl::slice( VQCplan, FQC.col(3).eval(), 1, PQC3plan);

  // Launch the viewer
  igl::viewer::Viewer viewer;
  key_down(viewer,'2',0);
  viewer.data.invert_normals = true;
  viewer.data.show_lines = false;
  viewer.callback_key_down = &key_down;
  viewer.launch();
}
Example #2
0
void PixelMapper::mergeProjections(Eigen::MatrixXf& depthImage, Eigen::MatrixXi& indexImage,
				   Eigen::MatrixXf* depths, Eigen::MatrixXi* indices, int numImages){
  assert (numImages>0);
  int rows=depths[0].rows();
  int cols=depths[0].cols();
  depthImage.resize(indexImage.rows(), indexImage.cols());
  depthImage.fill(std::numeric_limits<float>::max());
  indexImage.resize(rows, cols);
  indexImage.fill(-1);

  #pragma omp parallel for
  for (int c=0; c<cols; c++){
    int* destIndexPtr = &indexImage.coeffRef(0,c);
    float* destDepthPtr = &depthImage.coeffRef(0,c);
    int* srcIndexPtr[numImages];
    float* srcDepthPtr[numImages];
    for (int i=0; i<numImages; i++){
      srcIndexPtr[i] = &indices[i].coeffRef(0,c);
      srcDepthPtr[i] = &depths[i].coeffRef(0,c);
    }
    for (int r=0; r<rows; r++){
      for (int i=0; i<numImages; i++){
	if (*destDepthPtr>*srcDepthPtr[i]){
	  *destDepthPtr = *srcDepthPtr[i];
	  *destIndexPtr = *srcIndexPtr[i];
	}
	srcDepthPtr[i]++;
	srcIndexPtr[i]++;
      }
      destDepthPtr++;
      destIndexPtr++;
    }
  }

}
Example #3
0
int main(int argc, char *argv[])
{
  using namespace Eigen;
  using namespace std;

  // Create the boundary of a square
  V.resize(8,2);
  E.resize(8,2);
  H.resize(1,2);

  V << -1,-1, 1,-1, 1,1, -1, 1,
       -2,-2, 2,-2, 2,2, -2, 2;

  E << 0,1, 1,2, 2,3, 3,0,
       4,5, 5,6, 6,7, 7,4;

  H << 0,0;

  // Triangulate the interior
  igl::triangle::triangulate(V,E,H,"a0.005q",V2,F2);

  // Plot the generated mesh
  igl::viewer::Viewer viewer;
  viewer.data.set_mesh(V2,F2);
  viewer.launch();
}
Example #4
0
//=============================================================================
int readMatrixXi(Eigen::MatrixXi &_matrix, const char* _filename)
{
	std::ifstream ifs(_filename);

	int rows;
	ifs >> rows;

	int cols;
	ifs >> cols;

	if (rows < 1 || cols < 1)
	{
		std::cout << "Invalid matrix size: (" << rows << ", " << cols << ")." 
			<< std::endl;

		return -1;
	}

	_matrix.resize(rows, cols);

	for (int i = 0; i < rows; i++) {
		for (int j = 0; j < cols; j++)
		{
			ifs >> _matrix(i, j);
		}
	}

	return 0;
}
// Parse right hand side arguments for a matlab mex function.
//
// Inputs:
//   nrhs  number of right hand side arguments
//   prhs  pointer to right hand side arguments
// Outputs:
//   V  n by dim list of mesh vertex positions
//   F  m by dim list of mesh face indices
//   s  1 by dim bone source vertex position
//   d  1 by dim bone dest vertex position
// "Throws" matlab errors if dimensions are not sane.
void parse_rhs(
  const int nrhs, 
  const mxArray *prhs[], 
  Eigen::MatrixXd & V,
  Eigen::MatrixXi & F,
  Eigen::VectorXd & s,
  Eigen::VectorXd & d)
{
  using namespace std;
  if(nrhs < 4)
  {
    mexErrMsgTxt("nrhs < 4");
  }
  const int dim = mxGetN(prhs[0]);
  if(dim != 3)
  {
    mexErrMsgTxt("Mesh vertex list must be #V by 3 list of vertex positions");
  }
  if(dim != (int)mxGetN(prhs[1]))
  {
   mexErrMsgTxt("Mesh facet size must equal dimension");
  }
  if(dim != (int)mxGetN(prhs[2]))
  {
   mexErrMsgTxt("Source dim must equal vertex dimension");
  }
  if(dim != (int)mxGetN(prhs[3]))
  {
   mexErrMsgTxt("Dest dim must equal vertex dimension");
  }
  // set number of mesh vertices
  const int n = mxGetM(prhs[0]);
  // set vertex position pointers
  double * Vp = mxGetPr(prhs[0]);
  // set number of faces
  const int m = mxGetM(prhs[1]);
  // set face index list pointer
  double * Fp = mxGetPr(prhs[1]);
  // set source and dest pointers
  double * sp = mxGetPr(prhs[2]);
  double * dp = mxGetPr(prhs[3]);
  // resize output to transpose
  V.resize(n,dim);
  copy(Vp,Vp+n*dim,V.data());
  // resize output to transpose
  F.resize(m,dim);
  // Q: Is this doing a cast?
  // A: Yes.
  copy(Fp,Fp+m*dim,F.data());
  // http://stackoverflow.com/a/4461466/148668
  transform(F.data(),F.data()+m*dim,F.data(),
    bind2nd(std::plus<double>(),-1.0));
  // resize output to transpose
  s.resize(dim);
  copy(sp,sp+dim,s.data());
  d.resize(dim);
  copy(dp,dp+dim,d.data());
}
Example #6
0
IGL_INLINE void igl::exterior_edges(
  const Eigen::MatrixXi & F,
  Eigen::MatrixXi & E)
{
  using namespace Eigen;
  using namespace std;
  assert(F.cols() == 3);
  const size_t m = F.rows();
  MatrixXi all_E,sall_E,sort_order;
  // Sort each edge by index
  all_edges(F,all_E);
  sort(all_E,2,true,sall_E,sort_order);
  // Find unique edges
  MatrixXi uE;
  VectorXi IA,EMAP;
  unique_rows(sall_E,uE,IA,EMAP);
  VectorXi counts = VectorXi::Zero(uE.rows());
  for(size_t a = 0;a<3*m;a++)
  {
    counts(EMAP(a)) += (sort_order(a)==0?1:-1);
  }

  E.resize(all_E.rows(),2);
  {
    int e = 0;
    const size_t nue = uE.rows();
    // Append each unique edge with a non-zero amount of signed occurances
    for(size_t ue = 0; ue<nue; ue++)
    {
      const int count = counts(ue);
      size_t i,j;
      if(count == 0)
      {
        continue;
      }else if(count < 0)
      {
        i = uE(ue,1);
        j = uE(ue,0);
      }else if(count > 0)
      {
        i = uE(ue,0);
        j = uE(ue,1);
      }
      // Append edge for every repeated entry
      const int abs_count = abs(count);
      for(size_t k = 0;k<abs_count;k++)
      {
        E(e,0) = i;
        E(e,1) = j;
        e++;
      }
    }
    E.conservativeResize(e,2);
  }
}
Example #7
0
 // construct
 WorldParamsPrior(const std::vector<distrib::MultiGaussian>& ctrlpts_, const std::vector<Eigen::MatrixXi>& ctrlptMasks_,
                  const std::vector<Eigen::MatrixXd>& ctrlptMins_, const std::vector<Eigen::MatrixXd>& ctrlptMaxs_,
                  const Eigen::VectorXd& ctrlptCoupledSds_, const Eigen::VectorXd& ctrlptUncoupledSds_,
                  const std::vector<distrib::MultiGaussian>& properties_, const std::vector<Eigen::VectorXi>& propMasks_,
                  const std::vector<Eigen::VectorXd>& propMins_, const std::vector<Eigen::VectorXd>& propMaxs_,
                  const std::vector<BoundaryClass>& classes_)
     : ctrlptMasks(ctrlptMasks_),
       ctrlptMins(ctrlptMins_),
       ctrlptMaxs(ctrlptMaxs_),
       ctrlptCoupledSds(ctrlptCoupledSds_),
       ctrlptUncoupledSds(ctrlptUncoupledSds_),
       ctrlptPrior(ctrlpts_),
       propMasks(propMasks_),
       propMins(propMins_),
       propMaxs(propMaxs_),
       propertyPrior(properties_),
       classes(classes_)
 {
   for (uint l = 0; l < propMasks.size(); l++)
   {
     for (uint p = 0; p < propMasks_[l].size(); p++)
     {
       if (!propMasks_[l](p))
       {
         propertyPrior[l].sigma.row(p).setZero();
         propertyPrior[l].sigma.col(p).setZero();
         propertyPrior[l].sigma(p, p) = 1;
       }
     }
   }
   for (uint l = 0; l < ctrlptMasks_.size(); l++)
   {
     Eigen::MatrixXi masks = ctrlptMasks_[l];
     masks.resize(masks.rows() * masks.cols(), 1);
     for (uint p = 0; p < masks.rows(); p++)
     {
       if (!masks(p))
       {
         ctrlptPrior[l].sigma.row(p).setZero();
         ctrlptPrior[l].sigma.col(p).setZero();
         ctrlptPrior[l].sigma(p, p) = 1;
       }
     }
   }
   WorldParams minParams; 
   WorldParams maxParams;
   minParams.rockProperties = propMins;
   maxParams.rockProperties = propMaxs;
   minParams.controlPoints = ctrlptMins;
   maxParams.controlPoints = ctrlptMaxs;
   thetaMin = deconstruct(minParams);
   thetaMax = deconstruct(maxParams);
   VLOG(1) << "Theta min:" << thetaMin.transpose();
   VLOG(1) << "Theta max:" << thetaMax.transpose();
 }
Example #8
0
void parse_rhs(
  const int nrhs, 
  const mxArray *prhs[], 
  Eigen::MatrixXd & V,
  Eigen::MatrixXi & F,
  Eigen::MatrixXd & P,
  Eigen::MatrixXd & N,
  int & num_samples)
{
  using namespace std;
  if(nrhs < 5)
  {
    mexErrMsgTxt("nrhs < 5");
  }

  const int dim = mxGetN(prhs[0]);
  if(dim != 3)
  {
    mexErrMsgTxt("Mesh vertex list must be #V by 3 list of vertex positions");
  }
  if(dim != (int)mxGetN(prhs[1]))
  {
   mexErrMsgTxt("Mesh facet size must be 3");
  }
  if(mxGetN(prhs[2]) != dim)
  {
    mexErrMsgTxt("Point list must be #P by 3 list of origin locations");
  }
  if(mxGetN(prhs[3]) != dim)
  {
    mexErrMsgTxt("Normal list must be #P by 3 list of origin normals");
  }
  if(mxGetN(prhs[4]) != 1 || mxGetM(prhs[4]) != 1)
  {
    mexErrMsgTxt("Number of samples must be scalar.");
  }


  V.resize(mxGetM(prhs[0]),mxGetN(prhs[0]));
  copy(mxGetPr(prhs[0]),mxGetPr(prhs[0])+V.size(),V.data());
  F.resize(mxGetM(prhs[1]),mxGetN(prhs[1]));
  copy(mxGetPr(prhs[1]),mxGetPr(prhs[1])+F.size(),F.data());
  F.array() -= 1;
  P.resize(mxGetM(prhs[2]),mxGetN(prhs[2]));
  copy(mxGetPr(prhs[2]),mxGetPr(prhs[2])+P.size(),P.data());
  N.resize(mxGetM(prhs[3]),mxGetN(prhs[3]));
  copy(mxGetPr(prhs[3]),mxGetPr(prhs[3])+N.size(),N.data());
  if(*mxGetPr(prhs[4]) != (int)*mxGetPr(prhs[4]))
  {
    mexErrMsgTxt("Number of samples should be non negative integer.");
  }
  num_samples = (int) *mxGetPr(prhs[4]);
}
Example #9
0
void PointProjector::projectIntervals(Eigen::MatrixXi &intervalImage, 
				      const Eigen::MatrixXf &depthImage, 
				      const float worldRadius) const{
  intervalImage.resize(depthImage.rows(), depthImage.cols());
  int cpix=0;
  for (int c=0; c<depthImage.cols(); c++){
    const float* f = &depthImage(0,c);
    int* i =&intervalImage(0,c);
    for (int r=0; r<depthImage.rows(); r++, f++, i++){
      *i=projectInterval(r,c,*f, worldRadius);
      cpix++;
    }
  }
}
IGL_INLINE void igl::copyleft::cgal::polyhedron_to_mesh(
  const Polyhedron & poly,
  Eigen::MatrixXd & V,
  Eigen::MatrixXi & F)
{
  using namespace std;
  V.resize(poly.size_of_vertices(),3);
  F.resize(poly.size_of_facets(),3);
  typedef typename Polyhedron::Vertex_const_iterator Vertex_iterator;
  std::map<Vertex_iterator,size_t> vertex_to_index;
  {
    size_t v = 0;
    for(
      typename Polyhedron::Vertex_const_iterator p = poly.vertices_begin();
      p != poly.vertices_end();
      p++)
    {
      V(v,0) = p->point().x();
      V(v,1) = p->point().y();
      V(v,2) = p->point().z();
      vertex_to_index[p] = v;
      v++;
    }
  }
  {
    size_t f = 0;
    for(
      typename Polyhedron::Facet_const_iterator facet = poly.facets_begin();
      facet != poly.facets_end();
      ++facet)
    {
      typename Polyhedron::Halfedge_around_facet_const_circulator he = 
        facet->facet_begin();
      // Facets in polyhedral surfaces are at least triangles.
      assert(CGAL::circulator_size(he) == 3 && "Facets should be triangles");
      size_t c = 0;
      do {
        //// This is stooopidly slow
        // F(f,c) = std::distance(poly.vertices_begin(), he->vertex());
        F(f,c) = vertex_to_index[he->vertex()];
        c++;
      } while ( ++he != facet->facet_begin());
      f++;
    }
  }
}
/**
 * @brief Searches in the graph closest points to origin and target
 * 
 * @param origin ...
 * @param target ...
 * @param originVertex to return selected vertex
 * @param targetVertex ...
 * @return void
 */
void PlannerPRM::searchClosestPoints(const QVec& origin, const QVec& target, Vertex& originVertex, Vertex& targetVertex)
{
	qDebug() << __FUNCTION__ << "Searching from " << origin << "and " << target;

	//prepare the query
	Eigen::MatrixXi indices;
	Eigen::MatrixXf distsTo;
	Eigen::MatrixXf query(3,2);
	indices.resize(1, query.cols());
	distsTo.resize(1, query.cols());
	query(0,0) = origin.x();query(1,0) = origin.y();query(2,0) = origin.z();
	query(0,1) = target.x();query(1,1) = target.y();query(2,1) = target.z();

	nabo->knn(query, indices, distsTo, 1);

	originVertex = vertexMap.value(indices(0,0));
	targetVertex = vertexMap.value(indices(0,1));

 	qDebug() << __FUNCTION__ << "Closest point to origin is at" << data(0,indices(0,0)) << data(1,indices(0,0)) << data(2,indices(0,0)) << " and corresponds to " << graph[originVertex].pose;
 	qDebug() << __FUNCTION__ << "Closest point to target is at" << data(0,indices(0,1)) << data(1,indices(0,1)) << data(2,indices(0,1)) << " and corresponds to " << graph[targetVertex].pose;

}
Example #12
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);
}
Example #13
0
void PointProjector::unProject(HomogeneousPoint3fVector &points,
			       Eigen::MatrixXi &indexImage,
			       const Eigen::MatrixXf &depthImage) const {
  points.resize(depthImage.rows()*depthImage.cols());
  int count = 0;
  indexImage.resize(depthImage.rows(), depthImage.cols());
  HomogeneousPoint3f* point = &points[0];
  int cpix=0;
  for (int c=0; c<depthImage.cols(); c++){
    const float* f = &depthImage(0,c);
    int* i =&indexImage(0,c);
    for (int r=0; r<depthImage.rows(); r++, f++, i++){
      if (!unProject(*point, r,c,*f)){
	*i=-1;
	continue;
      }
      point++;
      cpix++;
      *i=count;
      count++;
    }
  }
  points.resize(count);
}
void igl::collapse_small_triangles(
  const Eigen::MatrixXd & V,
  const Eigen::MatrixXi & F,
  const double eps,
  Eigen::MatrixXi & FF)
{
  using namespace Eigen;
  using namespace std;

  // Compute bounding box diagonal length
  double bbd = bounding_box_diagonal(V);
  MatrixXd l;
  edge_lengths(V,F,l);
  VectorXd dblA;
  doublearea(l,dblA);

  // Minimum area tolerance
  const double min_dblarea = 2.0*eps*bbd*bbd;

  Eigen::VectorXi FIM = colon<int>(0,V.rows()-1);
  int num_edge_collapses = 0;
  // Loop over triangles
  for(int f = 0;f<F.rows();f++)
  {
    if(dblA(f) < min_dblarea)
    {
      double minl = 0;
      int minli = -1;
      // Find shortest edge
      for(int e = 0;e<3;e++)
      {
        if(minli==-1 || l(f,e)<minl)
        {
          minli = e;
          minl = l(f,e);
        }
      }
      double maxl = 0;
      int maxli = -1;
      // Find longest edge
      for(int e = 0;e<3;e++)
      {
        if(maxli==-1 || l(f,e)>maxl)
        {
          maxli = e;
          maxl = l(f,e);
        }
      }
      // Be sure that min and max aren't the same
      maxli = (minli==maxli?(minli+1)%3:maxli);

      // Collapse min edge maintaining max edge: i-->j
      // Q: Why this direction?
      int i = maxli;
      int j = ((minli+1)%3 == maxli ? (minli+2)%3: (minli+1)%3);
      assert(i != minli);
      assert(j != minli);
      assert(i != j);
      FIM(F(f,i)) = FIM(F(f,j));
      num_edge_collapses++;
    }
  }

  // Reindex faces
  MatrixXi rF = F;
  // Loop over triangles
  for(int f = 0;f<rF.rows();f++)
  {
    for(int i = 0;i<rF.cols();i++)
    {
      rF(f,i) = FIM(rF(f,i));
    }
  }

  FF.resize(rF.rows(),rF.cols());
  int num_face_collapses=0;
  // Only keep uncollapsed faces
  {
    int ff = 0;
    // Loop over triangles
    for(int f = 0;f<rF.rows();f++)
    {
      bool collapsed = false;
      // Check if any indices are the same
      for(int i = 0;i<rF.cols();i++)
      {
        for(int j = i+1;j<rF.cols();j++)
        {
          if(rF(f,i)==rF(f,j))
          {
            collapsed = true;
            num_face_collapses++;
            break;
          }
        }
      }
      if(!collapsed)
      {
        FF.row(ff++) = rF.row(f);
      }
    }
    // Use conservative resize
    FF.conservativeResize(ff,FF.cols());
  }
  //cout<<"num_edge_collapses: "<<num_edge_collapses<<endl;
  //cout<<"num_face_collapses: "<<num_face_collapses<<endl;
  if(num_edge_collapses == 0)
  {
    // There must have been a "collapsed edge" in the input
    assert(num_face_collapses==0);
    // Base case
    return;
  }

  //// force base case
  //return;

  MatrixXi recFF = FF;
  return collapse_small_triangles(V,recFF,eps,FF);
}
Example #15
0
// A tet is organized in the following fashion:
//
//       0
//       
//       3       (3 is in the background; 1 and 2 are in the foreground)
//  2        1
//
// So the faces (with counterclockwise normals) are:
// (0 1 3)
// (0 2 1)
// (3 2 0)
// (1 2 3)
//
//
// This method will perform three steps:
// 1. Add all faces, duplicating ones on the interior
// 2. Remove all duplicate verts (might have been caused during #1)
// 3. Remove all duplicate faces
void marching_tets(
  const Eigen::MatrixXd& V,
  const Eigen::MatrixXi& T,
  const Eigen::VectorXd& H,
  double offset,
  Eigen::MatrixXd& NV,
  Eigen::MatrixXi& NF,
  Eigen::VectorXi& I)
{
  min_how_much = 1;
  max_how_much = 0;
  using namespace Eigen;
  using namespace std;

  // Count the faces.
  std::map<std::vector<int>, int> face_counts;
  for (int i = 0; i < T.rows(); ++i) {
    std::vector<std::vector<int> > fs;
    fs.push_back({T(i, 0), T(i, 1), T(i, 3)});
    fs.push_back({T(i, 0), T(i, 2), T(i, 1)});
    fs.push_back({T(i, 3), T(i, 2), T(i, 0)});
    fs.push_back({T(i, 1), T(i, 2), T(i, 3)});
    for (auto &f : fs) {
      std::sort(f.begin(), f.end());
      // Add it to the map.
      face_counts[f]++;
    }
  }

  vector<Eigen::RowVector3i> faces;
  vector<int> faces_markers;
  vector<Eigen::RowVector3d> new_verts;
  int times[6];
  for (int i = 0; i < 6; i++) {
    times[i] = 0;
  }

  // Create data structure.
  MarchingTetsDat dd(V, H, faces, faces_markers, face_counts, new_verts, offset);

  int numEq = 0;

  // Check each tet face, add as needed.
  for (int i = 0; i < T.rows(); ++i) {
    // See if the tet is entirely inside.
    vector<int> inside, outside, inside_t, outside_t, identical;
    for (int j = 0; j < T.cols(); ++j) {
      //if (H(T(i, j)) > offset + 1e-4) {
      if (H(T(i, j)) > offset) {
        outside.push_back(j);
      } else if (H(T(i, j)) < offset) {
        inside.push_back(j);
      } else {
        numEq++;
        identical.push_back(j);
      }

      if (H(T(i, j)) == GLOBAL::outside_temp) {
        outside_t.push_back(j);
      } else if (H(T(i, j)) == GLOBAL::inside_temp) {
        inside_t.push_back(j);
      }
    }

    // Ignore this tet if it's entirely outside.
    if (outside.size() == 4) {
      continue;
    }


    if (outside.size() == 0 && inside.size() == 0) {
      // degenerate, ignore.
      printf("WARNING: degenerate tet face found!!\n");
    } else if (inside.size() == 0 && identical.size() < 3) {
      // Nothing to add.
    } else if (identical.size() == 3) {
      //addOrig(T.row(i), 7, dd.faces, dd.faces_markers);
      // Ignore it if there's only one on the outside.
      //if (inside.size() == 0) continue;
      if (outside.size() == 0) continue;
      times[1]++;
      // Add just a single face (always)
      int i1 = T(i,identical[0]), i2 = T(i,identical[1]), i3 = T(i,identical[2]);
      Eigen::RowVector3i f({i1, i2, i3});
      dd.faces.push_back(f);
      dd.faces_markers.push_back(1);
    } else if (outside.size() == 0) {
      // (these are colored blue)
      times[0]++;
      // (A) Takes care of:
      //   inside: 1, identical: 3 (remove three duplicated faces later)
      //   inside: 2, identical: 2 (remove all four duplicated faces later)
      //   inside: 3, identical: 1 (remove all four duplicated faces later)
      //   inside: 4, identical: 0 (remove all four duplicated faces later)
      case0Out(dd, T.row(i), inside, outside, identical, inside_t, outside_t);
    } else if (inside.size() == 1) {
      // (these are colored green)
      times[2]++;
      // (B) Takes care of:
      //   inside: 1 outside: 3
      //   inside: 1 outside: 2 identical: 1
      //   inside: 1 outside: 1 identical: 2
      //
      case1In(dd, T.row(i), inside, outside, identical, inside_t, outside_t);
    } else if (inside.size() == 3 && outside.size() == 1) {
      // (these are colored orange)
      times[3]++;
      // (C) takes care of:
      //   inside: 3 outside: 1
      //
      case3In1Out(dd, T.row(i), inside, outside, identical, inside_t, outside_t);
    } else if (inside.size() == 2 && outside.size() >= 1) {
      // (these are colored red)
      times[4]++;
      // (D) takes care of:
      //   inside: 2 outside: 1 identical: 1
      //   inside: 2 outside: 2 identical: 0
      //
      case2In2Out(dd, T.row(i), inside, outside, identical, inside_t, outside_t);
    } else {
      times[5]++;
      fprintf(stderr, "WARN: marching tets found something weird, with in:%lu out:%lu\n",
              inside.size(), outside.size());
    }
  }

  printf("Finished marching tets with usages:\n");
  for (int i = 0; i < 6; ++i) {
    printf("  %d: %d\n", i, times[i]);
  }
  printf("how_much is %lf and EPS is %lf\n", min_how_much, GLOBAL::EPS);
  printf("     max is %lf\n", max_how_much);
  printf("Num equal is %d\n", numEq);

  // Copy verts
  NV.resize(V.rows() + new_verts.size(), 3);
  for (int i = 0; i < V.rows(); ++i) {
    NV.row(i) = V.row(i);
  }
  for (int i = 0; i < new_verts.size(); ++i) {
    NV.row(i + V.rows()) = new_verts[i];
  }
  // Set I
  I.resize(NV.rows());
  for (int i = 0; i < I.rows(); ++i) {
    if (i < V.rows()) {
      I(i) = i;
    } else {
      I(i) = -1;
    }
  }
  Eigen::VectorXi facesMarkers;
  facesMarkers.resize(faces.size());
  // Copy faces
  NF.resize(faces.size(), 3);
  for (int i = 0; i < faces.size(); ++i) {
    NF.row(i) = faces[i];
    facesMarkers(i) = faces_markers[i];
  }
  
  Eigen::MatrixXd newV;
  Eigen::MatrixXi newF;
  Eigen::VectorXi SVJ, SVI, I2;
  // Helpers::viewTriMesh(NV, NF, facesMarkers);
  //igl::writeOFF("offset_mesh.off", NV, NF)
  Helpers::writeMeshWithMarkers("offset_mesh", NV, NF, facesMarkers);

  /*
  igl::collapse_small_triangles(NV, NF, 1e-8, newF);
  printf("Collapsed %d small triangles\n", NF.rows() - newF.rows());
  NF = newF;
  */

  ///*
  igl::remove_duplicate_vertices(NV, NF, 1e-20, newV, SVI, SVJ, newF);
  I2.resize(newV.rows());
  I2.setConstant(-1);
  for (int i = 0; i < NV.rows(); ++i) {
    if (I2(SVJ(i)) == -1) {
      I2(SVJ(i)) = I(i);
    } else {
      I2(SVJ(i)) = std::min(I2(SVJ(i)), I(i));
    }
  }
  NF = newF;
  NV = newV;
  I = I2;

  // Now see if we have duplicated faces.
  //igl::resolve_duplicated_faces(NF, newF, SVJ);
  //NF = newF;
  //*/

  // Other option is to do these two:
  // These are bad because sometimes the "small" triangles are not area zero,
  // and doing the removeDuplicates will delete these triangles and make the
  // mesh non-manifold. Better to wait for remeshing later.
  //Helpers::removeDuplicates(NV, NF, I);
  //Helpers::collapseSmallTriangles(NV, NF);

  igl::remove_unreferenced(NV, NF, newV, newF, SVI, SVJ);
  I2.resize(newV.rows());
  I2.setConstant(-1);
  for (int i = 0; i < I2.rows(); ++i) {
    I2(i) = I(SVJ(i));
  }
  I = I2;
  NV = newV;
  NF = newF;


  // orient everything correctly.
  Eigen::VectorXi C;
  igl::orientable_patches(NF, C);
  igl::bfs_orient(NF, newF, C);
  NF = newF;
  igl::orient_outward(NV, NF, C, newF, SVJ);
  NF = newF;
  //igl::writeOFF("offset_mesh_normals.off", NV, NF);

#ifdef DEBUG_MESH
  if (!Helpers::isMeshOkay(NV, NF)) {
    printf("Error: Mesh is not okay at first...\n");
  }
  if (!Helpers::isManifold(NV, NF, I)) {
    printf("Error: Mesh from marching tets not manifold!\n");
    Eigen::VectorXi temp;
    temp.resize(I.rows());
    temp.setZero();
    Helpers::isManifold(NV, NF, temp, true);
    Helpers::viewTriMesh(NV, NF, temp);
    Helpers::writeMeshWithMarkers("marching_tets_manifold", NV, NF, temp);
    cout << "See marching_tets_manifold.off for problems.\n";
    exit(1);
  }
#endif
}
Example #16
0
IGL_INLINE bool igl::copyleft::boolean::mesh_boolean(
    const Eigen::PlainObjectBase<DerivedVA> & VA,
    const Eigen::PlainObjectBase<DerivedFA> & FA,
    const Eigen::PlainObjectBase<DerivedVB> & VB,
    const Eigen::PlainObjectBase<DerivedFB> & FB,
    const WindingNumberOp& wind_num_op,
    const KeepFunc& keep,
    const ResolveFunc& resolve_fun,
    Eigen::PlainObjectBase<DerivedVC > & VC,
    Eigen::PlainObjectBase<DerivedFC > & FC,
    Eigen::PlainObjectBase<DerivedJ > & J) 
{

#ifdef MESH_BOOLEAN_TIMING
  const auto & tictoc = []() -> double
  {
    static double t_start = igl::get_seconds();
    double diff = igl::get_seconds()-t_start;
    t_start += diff;
    return diff;
  };
  const auto log_time = [&](const std::string& label) -> void {
    std::cout << "mesh_boolean." << label << ": "
      << tictoc() << std::endl;
  };
  tictoc();
#endif

  typedef typename DerivedVC::Scalar Scalar;
  //typedef typename DerivedFC::Scalar Index;
  typedef CGAL::Epeck Kernel;
  typedef Kernel::FT ExactScalar;
  typedef Eigen::Matrix<Scalar,Eigen::Dynamic,3> MatrixX3S;
  //typedef Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> MatrixXI;
  typedef Eigen::Matrix<typename DerivedJ::Scalar,Eigen::Dynamic,1> VectorXJ;

  // Generate combined mesh.
  typedef Eigen::Matrix<
    ExactScalar,
    Eigen::Dynamic,
    Eigen::Dynamic,
    DerivedVC::IsRowMajor> MatrixXES;
  MatrixXES V;
  DerivedFC F;
  VectorXJ  CJ;
  {
      DerivedVA VV(VA.rows() + VB.rows(), 3);
      DerivedFC FF(FA.rows() + FB.rows(), 3);
      VV << VA, VB;
      FF << FA, FB.array() + VA.rows();
      //// Handle annoying empty cases
      //if(VA.size()>0)
      //{
      //  VV<<VA;
      //}
      //if(VB.size()>0)
      //{
      //  VV<<VB;
      //}
      //if(FA.size()>0)
      //{
      //  FF<<FA;
      //}
      //if(FB.size()>0)
      //{
      //  FF<<FB.array()+VA.rows();
      //}
      resolve_fun(VV, FF, V, F, CJ);
  }
#ifdef MESH_BOOLEAN_TIMING
  log_time("resolve_self_intersection");
#endif

  // Compute winding numbers on each side of each facet.
  const size_t num_faces = F.rows();
  Eigen::MatrixXi W;
  Eigen::VectorXi labels(num_faces);
  std::transform(CJ.data(), CJ.data()+CJ.size(), labels.data(),
      [&](int i) { return i<FA.rows() ? 0:1; });
  bool valid = true;
  if (num_faces > 0) 
  {
    valid = valid & 
      igl::copyleft::cgal::propagate_winding_numbers(V, F, labels, W);
  } else 
  {
    W.resize(0, 4);
  }
  assert((size_t)W.rows() == num_faces);
  if (W.cols() == 2) 
  {
    assert(FB.rows() == 0);
    Eigen::MatrixXi W_tmp(num_faces, 4);
    W_tmp << W, Eigen::MatrixXi::Zero(num_faces, 2);
    W = W_tmp;
  } else {
    assert(W.cols() == 4);
  }
#ifdef MESH_BOOLEAN_TIMING
  log_time("propagate_input_winding_number");
#endif

  // Compute resulting winding number.
  Eigen::MatrixXi Wr(num_faces, 2);
  for (size_t i=0; i<num_faces; i++) 
  {
    Eigen::MatrixXi w_out(1,2), w_in(1,2);
    w_out << W(i,0), W(i,2);
    w_in  << W(i,1), W(i,3);
    Wr(i,0) = wind_num_op(w_out);
    Wr(i,1) = wind_num_op(w_in);
  }
#ifdef MESH_BOOLEAN_TIMING
  log_time("compute_output_winding_number");
#endif

  // Extract boundary separating inside from outside.
  auto index_to_signed_index = [&](size_t i, bool ori) -> int
  {
    return (i+1)*(ori?1:-1);
  };
  //auto signed_index_to_index = [&](int i) -> size_t {
  //    return abs(i) - 1;
  //};
  std::vector<int> selected;
  for(size_t i=0; i<num_faces; i++) 
  {
    auto should_keep = keep(Wr(i,0), Wr(i,1));
    if (should_keep > 0) 
    {
      selected.push_back(index_to_signed_index(i, true));
    } else if (should_keep < 0) 
    {
      selected.push_back(index_to_signed_index(i, false));
    }
  }

  const size_t num_selected = selected.size();
  DerivedFC kept_faces(num_selected, 3);
  DerivedJ  kept_face_indices(num_selected, 1);
  for (size_t i=0; i<num_selected; i++) 
  {
    size_t idx = abs(selected[i]) - 1;
    if (selected[i] > 0) 
    {
      kept_faces.row(i) = F.row(idx);
    } else 
    {
      kept_faces.row(i) = F.row(idx).reverse();
    }
    kept_face_indices(i, 0) = CJ[idx];
  }
#ifdef MESH_BOOLEAN_TIMING
  log_time("extract_output");
#endif

  // Finally, remove duplicated faces and unreferenced vertices.
  {
    DerivedFC G;
    DerivedJ JJ;
    igl::resolve_duplicated_faces(kept_faces, G, JJ);
    igl::slice(kept_face_indices, JJ, 1, J);

#ifdef DOUBLE_CHECK_EXACT_OUTPUT
    {
      // Sanity check on exact output.
      igl::copyleft::cgal::RemeshSelfIntersectionsParam params;
      params.detect_only = true;
      params.first_only = true;
      MatrixXES dummy_VV;
      DerivedFC dummy_FF, dummy_IF;
      Eigen::VectorXi dummy_J, dummy_IM;
      igl::copyleft::cgal::SelfIntersectMesh<
        Kernel,
        MatrixXES, DerivedFC,
        MatrixXES, DerivedFC,
        DerivedFC,
        Eigen::VectorXi,
        Eigen::VectorXi
      > checker(V, G, params,
          dummy_VV, dummy_FF, dummy_IF, dummy_J, dummy_IM);
      if (checker.count != 0) 
      {
        throw "Self-intersection not fully resolved.";
      }
    }
#endif

    MatrixX3S Vs(V.rows(), V.cols());
    for (size_t i=0; i<(size_t)V.rows(); i++)
    {
      for (size_t j=0; j<(size_t)V.cols(); j++)
      {
        igl::copyleft::cgal::assign_scalar(V(i,j), Vs(i,j));
      }
    }
    Eigen::VectorXi newIM;
    igl::remove_unreferenced(Vs,G,VC,FC,newIM);
  }
#ifdef MESH_BOOLEAN_TIMING
  log_time("clean_up");
#endif
  return valid;
}
Example #17
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);

}
void igl::polyvector_field_one_ring_matchings(const Eigen::PlainObjectBase<DerivedV> &V,
                                              const Eigen::PlainObjectBase<DerivedF> &F,
                                              const std::vector<std::vector<VFType> >& VF,
                                              const Eigen::MatrixXi& E2F,
                                              const Eigen::MatrixXi& F2E,
                                              const Eigen::PlainObjectBase<DerivedTT>& TT,
                                              const Eigen::PlainObjectBase<DerivedM> &match_ab,
                                              const Eigen::PlainObjectBase<DerivedM> &match_ba,
                                              const int vi,
                                              Eigen::MatrixXi &mvi,
                                              Eigen::VectorXi &fi)
{
  int half_degree = match_ab.cols();
  mvi.resize(VF[vi].size()+1,half_degree);
  fi.resize(VF[vi].size()+1,1);
  //start from one face
  //first, check if the vertex is on a boundary
  //then there must be two faces that are on the boundary
  //(other cases not supported)

  int fstart = -1;
  int ind = 0;
  for (int i =0; i<VF[vi].size(); ++i)
  {
    int fi = VF[vi][i];
    for (int  j=0; j<3; ++j)
      if (F(fi,j)==vi && TT(fi,j) == -1)
      {
        ind ++;
        fstart = fi;
        //        break;
      }
  }
  if (ind >1 )
  {
    std::cerr<<"igl::polyvector_field_one_ring_matchings -- vertex "<<vi<< " is on an unusual boundary"<<std::endl;
    exit(1);
  }
  if (fstart == -1)
    fstart = VF[vi][0];
  int current_face = fstart;
  int i =0;
  fi[i] = current_face;
  for (int j=0; j<half_degree; ++j)
    mvi(i,j) = j;

  int next_face = -1;
  while (next_face != fstart && current_face!=-1)
  {
    // look for the vertex
    int j=-1;
    for (unsigned z=0; z<3; ++z)
      if (F(current_face,(z+1)%3) == vi)
      {
        j=z;
        break;
      }
    assert(j!=-1);

    next_face = TT(current_face, j);
    ++i;

    if (next_face == -1)
      mvi.row(i).setConstant(-1);
    else
    {
      // look at the edge between the two faces
      const int &current_edge = F2E(current_face,j);

      for (int k=0; k<half_degree; ++k)
      {
        // check its orientation to determine whether match_ab or match_ba should be used
        if ((E2F(current_edge,0) == current_face) &&
            (E2F(current_edge,1) == next_face) )
        {
          //look at match_ab
          mvi(i,k) = match_ab(current_edge,(mvi(i-1,k))%half_degree);
        }
        else
        {
          assert((E2F(current_edge,1) == current_face) &&
                 (E2F(current_edge,0) == next_face));
          //look at match_ba
          mvi(i,k) = match_ba(current_edge,(mvi(i-1,k))%half_degree);
        }
        if (mvi(i-1,k)>=half_degree)
          mvi(i,k) = (mvi(i,k)+half_degree)%(2*half_degree);
      }
    }
    current_face = next_face;
    fi[i] = current_face;
  }
}