Example #1
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;
    }
  }
}
IGL_INLINE void igl::covariance_scatter_matrix(
  const Eigen::MatrixXd & V, 
  const Eigen::MatrixXi & F,
  const ARAPEnergyType energy,
  Eigen::SparseMatrix<double>& CSM)
{
  using namespace igl;
  using namespace Eigen;
  // number of mesh vertices
  int n = V.rows();
  assert(n > F.maxCoeff());
  // dimension of mesh
  int dim = V.cols();
  // Number of mesh elements
  int m = F.rows();

  // number of rotations
  int nr;
  switch(energy)
  {
    case ARAP_ENERGY_TYPE_SPOKES:
      nr = n;
      break;
    case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS:
      nr = n;
      break;
    case ARAP_ENERGY_TYPE_ELEMENTS:
      nr = m;
      break;
    default:
      fprintf(
        stderr,
        "covariance_scatter_matrix.h: Error: Unsupported arap energy %d\n",
        energy);
      return;
  }

  SparseMatrix<double> KX,KY,KZ;
  arap_linear_block(V,F,0,energy,KX);
  arap_linear_block(V,F,1,energy,KY);
  SparseMatrix<double> Z(n,nr);
  if(dim == 2)
  {
    CSM = cat(1,cat(2,KX,Z),cat(2,Z,KY)).transpose();
  }else if(dim == 3)
  {
    arap_linear_block(V,F,2,energy,KZ);
    SparseMatrix<double>ZZ(n,nr*2);
    CSM = 
      cat(1,cat(1,cat(2,KX,ZZ),cat(2,cat(2,Z,KY),Z)),cat(2,ZZ,KZ)).transpose();
  }else
  {
    fprintf(
     stderr,
     "covariance_scatter_matrix.h: Error: Unsupported dimension %d\n",
     dim);
    return;
  }

}
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;
}
Example #4
0
IGL_INLINE void igl::draw_mesh(
  const Eigen::MatrixXd & V,
  const Eigen::MatrixXi & F,
  const Eigen::MatrixXd & N,
  const Eigen::MatrixXi & NF,
  const Eigen::MatrixXd & C,
  const Eigen::MatrixXd & TC,
  const Eigen::MatrixXi & TF,
  const Eigen::MatrixXd & W,
  const GLuint W_index,
  const Eigen::MatrixXi & WI,
  const GLuint WI_index)
{
  using namespace std;
  using namespace Eigen;
  const int rF = F.rows();
  const int cF = F.cols();
  const int cC = C.cols();
  const int rC = C.rows();
  const int cW = W.cols();
  const int rW = W.rows();
  const int rV = V.rows();
  const int rTC = TC.rows();
  const int rTF = TF.rows();
  const int rNF = NF.rows();
  const int rN = N.rows();

  if(F.size() > 0)
  {
    assert(F.maxCoeff() < V.rows());
    assert(V.cols() == 3);
    assert(rC == rV || rC == rF || rC == rF*3 || rC==1 || C.size() == 0);
    assert(C.cols() == 3 || C.size() == 0);
    assert(N.cols() == 3 || N.size() == 0);
    assert(TC.cols() == 2 || TC.size() == 0);
    assert(cF == 3 || cF == 4);
    assert(TF.size() == 0 || TF.cols() == F.cols());
    assert(NF.size() == 0 || NF.cols() == NF.cols());
  }
  if(W.size()>0)
  {
    assert(W.rows() == V.rows());
    assert(WI.rows() == V.rows());
    assert(W.cols() == WI.cols());
  }

  switch(F.cols())
  {
    default:
    case 3:
      glBegin(GL_TRIANGLES);
      break;
    case 4:
      glBegin(GL_QUADS);
      break;
  }
  // loop over faces
  for(int i = 0; i<rF;i++)
  {
    // loop over corners of triangle
    for(int j = 0;j<cF;j++)
    {

      int tc = -1;
      if(rTF != 0)
      {
        tc = TF(i,j);
      } else if(rTC == 1)
      {
        tc = 0;
      }else if(rTC == rV)
      {
        tc = F(i,j);
      }else if(rTC == rF*cF)
      {
        tc = i*cF + j;
      }else if(rTC == rF)
      {
        tc = i;
      }else
      {
        assert(TC.size() == 0);
      }

      // RGB(A)
      Matrix<MatrixXd::Scalar,1,Dynamic> color;
      if(rC == 1)
      {
        color = C.row(0);
      }else if(rC == rV)
      {
        color = C.row(F(i,j));
      }else if(rC == rF*cF)
      {
        color = C.row(i*cF+j);
      }else if(rC == rF)
      {
        color = C.row(i);
      }else
      {
        assert(C.size() == 0);
      }

      int n = -1;
      if(rNF != 0)
      {
        n = NF(i,j); // indexed normals
      } else if(rN == 1) 
      {
        n = 0; // uniform normals
      }else if(rN == rF)
      {
        n = i; // face normals
      }else if(rN == rV)
      {
        n = F(i,j); // vertex normals
      }else if(rN == rF*cF)
      {
        n = i*cF + j; // corner normals
      }else
      {
        assert(N.size() == 0);
      }

      {
        if(rW>0 && W_index !=0 && WI_index != 0)
        {
          int weights_left = cW;
          while(weights_left != 0)
          {
            int pass_size = std::min(4,weights_left);
            int weights_already_passed = cW-weights_left;
            // Get attribute location of next 4 weights
            int pass_W_index = W_index + weights_already_passed/4;
            int pass_WI_index = WI_index + weights_already_passed/4;
            switch(pass_size)
            {
              case 1:
                glVertexAttrib1d(
                  pass_W_index,
                  W(F(i,j),0+weights_already_passed));
                glVertexAttrib1d(
                  pass_WI_index,
                  WI(F(i,j),0+weights_already_passed));
                break;
              case 2:
                glVertexAttrib2d(
                  pass_W_index,
                  W(F(i,j),0+weights_already_passed),
                  W(F(i,j),1+weights_already_passed));
                glVertexAttrib2d(
                  pass_WI_index,
                  WI(F(i,j),0+weights_already_passed),
                  WI(F(i,j),1+weights_already_passed));
                break;
              case 3:
                glVertexAttrib3d(
                  pass_W_index,
                  W(F(i,j),0+weights_already_passed),
                  W(F(i,j),1+weights_already_passed),
                  W(F(i,j),2+weights_already_passed));
                glVertexAttrib3d(
                  pass_WI_index,
                  WI(F(i,j),0+weights_already_passed),
                  WI(F(i,j),1+weights_already_passed),
                  WI(F(i,j),2+weights_already_passed));
                break;
              default:
                glVertexAttrib4d(
                  pass_W_index,
                  W(F(i,j),0+weights_already_passed),
                  W(F(i,j),1+weights_already_passed),
                  W(F(i,j),2+weights_already_passed),
                  W(F(i,j),3+weights_already_passed));
                glVertexAttrib4d(
                  pass_WI_index,
                  WI(F(i,j),0+weights_already_passed),
                  WI(F(i,j),1+weights_already_passed),
                  WI(F(i,j),2+weights_already_passed),
                  WI(F(i,j),3+weights_already_passed));
                break;
            }
            weights_left -= pass_size;
          }
        }
        if(tc != -1)
        {
          glTexCoord2d(TC(tc,0),TC(tc,1));
        }
        if(rC>0)
        {
          switch(cC)
          {
            case 3:
              glColor3dv(color.data());
              break;
            case 4:
              glColor4dv(color.data());
              break;
            default:
              break;
          }
        }
        if(n != -1)
        {
          glNormal3d(N(n,0),N(n,1),N(n,2));
        }
        glVertex3d(V(F(i,j),0),V(F(i,j),1),V(F(i,j),2));
      }
    }
  }
  glEnd();
}
Example #5
0
bool BF3PointCircle::getRobustCircle(const cvb::CvContourChainCode& contour, const unsigned int maxVotes, const unsigned int maxAccu, const int maxInvalidVotesInSeries, BFCircle& circle) {

	cvb::CvChainCodes::const_iterator it 		= contour.chainCode.begin();
	cvb::CvChainCodes::const_iterator it_beg	= contour.chainCode.begin();
	cvb::CvChainCodes::const_iterator it_end 	= contour.chainCode.end();

	unsigned int x = contour.startingPoint.x;
	unsigned int y = contour.startingPoint.y;

	BFContour bfContour;
	while(it != it_end) {

		bfContour.add(BFCoordinate<int>(static_cast<int>(x),static_cast<int>(y)));

		x += cvb::cvChainCodeMoves[*it][0];
		y += cvb::cvChainCodeMoves[*it][1];

		it++;
	}
	const unsigned int nContourPoints = bfContour.getPixelCount();

	BFRectangle rect = bfContour.getBounds();
	int nRows = bfRound(rect.getHeight());
	int nCols = bfRound(rect.getWidth());
	int x0 = bfRound(rect.getX0());
	int y0 = bfRound(rect.getY0());
	BFCoordinate<int> topLeft(x0,y0);

	// generate 2d histogram for circle center estimation
	Eigen::MatrixXi H = Eigen::MatrixXi::Zero(nRows, nCols);

	unsigned int votes = 0;
	int invalidVotesInSeries = 0;
	while(votes < maxVotes) {

		unsigned int randIndex1 = (rand() % nContourPoints);
		unsigned int randIndex2 = (rand() % nContourPoints);
		while(randIndex2 == randIndex1)
			randIndex2 = (rand() % nContourPoints);
		unsigned int randIndex3 = (rand() % nContourPoints);
		while(randIndex3 == randIndex2 || randIndex3 == randIndex1)
			randIndex3 = (rand() % nContourPoints);

		BFCoordinate<int> c1 = bfContour.getCoordinate(randIndex1) - topLeft;
		BFCoordinate<int> c2 = bfContour.getCoordinate(randIndex2) - topLeft;
		BFCoordinate<int> c3 = bfContour.getCoordinate(randIndex3) - topLeft;

		BFCoordinate<double> center;
		bool validCenter = getCenter(c1,c2,c3,center);

		if(!validCenter) {
			votes--;
			invalidVotesInSeries++;

			if(invalidVotesInSeries > maxInvalidVotesInSeries) {
				return false;
			}
			continue;
		}
		invalidVotesInSeries = 0;

		double cxD = center.getX();
		double cyD = center.getY();

		int cx = bfRound(cxD);
		int cy = bfRound(cyD);

		if(cx < 0 || cy < 0 || cx >= nRows || cy >= nCols) {
			continue;
		}
		else {
			H(cx,cy) += 1;

			if(H(cx,cy) >= static_cast<int>(maxAccu)) {
				break;
			}
		}

		votes++;
	}

	int finalX = 0;
	int finalY = 0;
	H.maxCoeff(&finalX,&finalY);
	finalX += bfRound(x0);
	finalY += bfRound(y0);

	// generate 1d histogram for circle radius estimation
	Eigen::VectorXi K = Eigen::VectorXi::Zero(bfMax(nRows,nCols));

	it = it_beg;
	x = contour.startingPoint.x;
	y = contour.startingPoint.y;

	while(it != it_end) {

		int r = bfRound(sqrt(pow(static_cast<double>(static_cast<int>(x)-finalX),2.0) + pow(static_cast<double>(static_cast<int>(y)-finalY),2.0)));

		if(r < K.rows()) {
			K(r) += 1;
		}

		x += cvb::cvChainCodeMoves[*it][0];
		y += cvb::cvChainCodeMoves[*it][1];

		it++;
	}

	int finalR = 0;
	K.maxCoeff(&finalR);
	circle.set(finalX,finalY,finalR);

	return true;
}
Example #6
0
bool BF3PointCircle::getRobustCircle(const BFContour& contour, const unsigned int maxVotes, const unsigned int maxAccu, const int maxInvalidVotesInSeries, BFCircle& circle) {

	unsigned int nContourPoints = contour.getPixelCount();
	BFRectangle rect = contour.getBounds();

	BFRectangle zeroRect;
	if(rect.equals(zeroRect)) {
		return false;
	}

	int nRows = bfRound(rect.getHeight());
	int nCols = bfRound(rect.getWidth());

	int x0 = bfRound(rect.getX0());
	int y0 = bfRound(rect.getY0());
	BFCoordinate<int> topLeft(x0,y0);

	int invalidVotesInSeries = 0;

	// generate 2d histogram for circle center estimation
	Eigen::MatrixXi H = Eigen::MatrixXi::Zero(nRows, nCols);
	unsigned int votes = 0;
	for(votes; votes <= maxVotes; ++votes) {
		// random index number in range [0,nContourPoints-1]
		unsigned int randIndex1 = (rand() % nContourPoints);
		unsigned int randIndex2 = (rand() % nContourPoints);
		while(randIndex2 == randIndex1)
			randIndex2 = (rand() % nContourPoints);
		unsigned int randIndex3 = (rand() % nContourPoints);
		while(randIndex3 == randIndex2 || randIndex3 == randIndex1)
			randIndex3 = (rand() % nContourPoints);

		BFCoordinate<int> c1 = contour.getCoordinate(randIndex1) - topLeft;
		BFCoordinate<int> c2 = contour.getCoordinate(randIndex2) - topLeft;
		BFCoordinate<int> c3 = contour.getCoordinate(randIndex3) - topLeft;

		BFCoordinate<double> center;
		bool validCenter = getCenter(c1,c2,c3,center);

		if(!validCenter) {
			votes--;
			invalidVotesInSeries++;

			if(invalidVotesInSeries > maxInvalidVotesInSeries) {
				return false;
			}
			continue;
		}

		invalidVotesInSeries = 0;

		double cxD = center.getX();
		double cyD = center.getY();

		int cx = bfRound(cxD);
		int cy = bfRound(cyD);

		if(cx < 0 || cy < 0 || cx >= nRows || cy >= nCols) {
			votes--;
			continue;
		}
		else {
			H(cx,cy) += 1;

			if(H(cx,cy) >= static_cast<int>(maxAccu)) {
				break;
			}
		}
	}

	int finalX = 0;
	int finalY = 0;
	H.maxCoeff(&finalX,&finalY);
	finalX += bfRound(x0);
	finalY += bfRound(y0);

	// generate 1d histogram for circle radius estimation
	Eigen::VectorXi K = Eigen::VectorXi::Zero(bfMax(nRows,nCols));
	const std::vector<BFCoordinate<int> >& cont = contour.getContour();
	std::vector<BFCoordinate<int> >::const_iterator iter = cont.begin();

	int x;
	int y;

	while(iter != cont.end()) {

		x = bfRound((*iter).getX());
		y = bfRound((*iter).getY());

		int r = bfRound(sqrt(pow(static_cast<double>(x-finalX),2) + pow(static_cast<double>(y-finalY),2)));

		if(r < K.rows()) {
			K(r) += 1;
		}

		iter++;
	}

	int finalR = 0;
	K.maxCoeff(&finalR);

	// return result
	circle.set(finalX,finalY,finalR);
	return true;
}
Example #7
0
void mexFunction(
  int nlhs, mxArray *plhs[], 
  int nrhs, const mxArray *prhs[])
{
  const auto mexErrMsgTxt = [](const bool v ,const char * msg)
  {
    igl::matlab::mexErrMsgTxt(v,msg);
  };
  igl::matlab::MexStream mout;        
  std::streambuf *outbuf = std::cout.rdbuf(&mout);
  mexErrMsgTxt(nrhs >= 4,"Four arguments expected");
  Eigen::MatrixXd V,U0,U,bc;
  Eigen::MatrixXi F;
  Eigen::VectorXi b;
  int iters = 100;
  bool align_guess = true;
  double p = 1e5;

  igl::matlab::parse_rhs_double(prhs+0,V);
  igl::matlab::parse_rhs_index(prhs+1,F);
  igl::matlab::parse_rhs_index(prhs+2,b);
  igl::matlab::parse_rhs_double(prhs+3,bc);

  {
    int i = 4;
    while(i<nrhs)
    {
      mexErrMsgTxt(mxIsChar(prhs[i]),"Parameter names should be strings");
      // Cast to char
      const char * name = mxArrayToString(prhs[i]);
      if(strcmp("P",name) == 0)
      {
        igl::matlab::validate_arg_scalar(i,nrhs,prhs,name);
        igl::matlab::validate_arg_double(i,nrhs,prhs,name);
        p = (double)*mxGetPr(prhs[++i]);
      }else if(strcmp("AlignGuess",name) == 0)
      {
        igl::matlab::validate_arg_scalar(i,nrhs,prhs,name);
        igl::matlab::validate_arg_logical(i,nrhs,prhs,name);
        align_guess = (bool)*mxGetLogicals(prhs[++i]);
      }else if(strcmp("Iters",name) == 0)
      {
        igl::matlab::validate_arg_scalar(i,nrhs,prhs,name);
        igl::matlab::validate_arg_double(i,nrhs,prhs,name);
        iters = (double)*mxGetPr(prhs[++i]);
      }else
      {
        mexErrMsgTxt(false,C_STR("Unknown parameter: "<<name));
      }
      i++;
    }
  }


  {
    Eigen::MatrixXi C;
    igl::vertex_components(F, C);
    mexErrMsgTxt(
      C.maxCoeff() == 0,
      "(V,F) should have exactly 1 connected component");
    const int ec = igl::euler_characteristic(F);
    mexErrMsgTxt(
      ec == 1,
      C_STR("(V,F) should have disk topology (euler characteristic = "<<ec));
    mexErrMsgTxt(
      igl::is_edge_manifold(F),
      "(V,F) should be edge-manifold");
    Eigen::VectorXd A;
    igl::doublearea(V,F,A);
    mexErrMsgTxt(
      (A.array().abs() > igl::EPS<double>()).all(),
      "(V,F) should have non-zero face areas");
  }


  // Initialize with Tutte embedding to disk
  Eigen::VectorXi bnd; 
  Eigen::MatrixXd bnd_uv;
  igl::boundary_loop(F,bnd);
  igl::map_vertices_to_circle(V,bnd,bnd_uv);
  igl::harmonic(V,F,bnd,bnd_uv,1,U0);
  if (igl::flipped_triangles(U0,F).size() != 0) 
  {
    // use uniform laplacian
    igl::harmonic(F,bnd,bnd_uv,1,U0);
  }

  if(align_guess)
  {
    Eigen::MatrixXd X,X0,Y,Y0;
    igl::slice(U0,b,1,X);
    Y = bc;
    Eigen::RowVectorXd Xmean = X.colwise().mean();
    Eigen::RowVectorXd Ymean = Y.colwise().mean();
    Y0 = Y.rowwise()-Ymean;
    X0 = X.rowwise()-Xmean;
    Eigen::MatrixXd I = Eigen::MatrixXd::Identity(X0.cols(),X0.cols())*1e-5;
    Eigen::MatrixXd T = (X0.transpose()*X0+I).inverse()*(X0.transpose()*Y0);
    U0.rowwise() -= Xmean;
    U0 = (U0*T).eval();
    U0.rowwise() += Ymean;
  }

  if(igl::flipped_triangles(U0,F).size() == F.rows())
  {
    F = F.array().rowwise().reverse().eval();
  }

  mexErrMsgTxt(
    igl::flipped_triangles(U0,F).size() == 0,
    "Failed to initialize to feasible guess");

  igl::SLIMData slim;
  slim.energy = igl::SYMMETRIC_DIRICHLET;
  igl::slim_precompute(V,F,U0,slim,igl::SYMMETRIC_DIRICHLET,b,bc,p);
  igl::slim_solve(slim,iters);
  U = slim.V_o;

  switch(nlhs)
  {
    default:
    {
      mexErrMsgTxt(false,"Too many output parameters.");
    }
    case 2:
    {
      igl::matlab::prepare_lhs_double(U0,plhs+1);
      // Fall through
    }
    case 1:
    {
      igl::matlab::prepare_lhs_double(U,plhs+0);
      // Fall through
    }
    case 0: break;
  }
  // Restore the std stream buffer Important!
  std::cout.rdbuf(outbuf);
}