Beispiel #1
0
void test3() {
#ifdef MAKE_TEST3
    std::cout << "Multidimensional test:" << std::endl;
    
    // Construct data for the IVP
    double T = 1;
    // Many dimensions
    int n = 5;
    
    // Multidimensional rhs
    Eigen::VectorXd y0(2*n);
    for(int i = 0; i < n; ++i) {
        y0(i)=(i+1.)/n;
        y0(i+n)=-1;
    }
    
    // Multidimensional rhs
    auto f = [n] (Eigen::VectorXd y) {
        Eigen::VectorXd fy(2*n);
        
        Eigen::VectorXd g(n);
        g(0) = y(0)*(y(1)+y(0));
        g(n-1) = y(n-1)*(y(n-1)+y(n-2));
        for(int i = 1; i < n-1; ++i) {
            g(i) = y(i)*(y(i-1)+y(i+1));
        }
        
        Eigen::SparseMatrix<double> C(n,n);
        C.reserve(3);
        for(int i = 0; i < n; ++i) {
            C.insert(i,i) = 2;
            if(i < n-1) C.insert(i,i+1) = -1;
            if(i >= 1)  C.insert(i,i-1) = -1;
        }
        C.makeCompressed();
        fy.head(n) = y.head(n);
        
        Eigen::SparseLU< Eigen::SparseMatrix<double> >  solver;
        solver.analyzePattern(C);
        solver.compute(C);
        fy.tail(n) = solver.solve(g);
        return fy;
    };
    
    // Constructor:
    ode45<Eigen::VectorXd> O(f);
    
    // Setup options
    O.options.do_statistics = true;
    
    // Solve
    auto sol = O.solve(y0, T);
    
    // Print info
    O.print();

    std::cout << "T = " << sol.back().second << std::endl;
    std::cout << "y(T) = " << std::endl << sol.back().first << std::endl;
#endif
}
Beispiel #2
0
 NatCSI(const std::vector<double> & t, const std::vector<double> & y)
     : t(t), y(y), h(t.size()-1), c(t.size()) {
     // Size check
     assert( ( t.size() == y.size() ) && "Error: mismatched size of t and y!");
     
     // m is the number of conditions (t goes from t_0 to t_n)
     // WARNING: m = n+1
     m = t.size();
     
     // Vector containing increments (from the right)
     for(int i = 0; i < (m - 1); ++i) {
         h(i) = t[i+1] - t[i];
         // Check that t is sorted
         assert( ( h(i) > 0 ) && "Error: array t must be sorted!");
     }
     
     // System matrix and rhs as in 3.5.9, we remove first and last row (known by natural contition)
     Eigen::SparseMatrix<double> A(m,m);
     Eigen::VectorXd b(m);
     
     // WARNING: sparse reserve space
     A.reserve(3);
     
     // Fill in natural conditions 3.5.10 for matrix
     A.coeffRef(0,0) = 2 / h(0);
     A.coeffRef(0,1) = 1 / h(0);
     A.coeffRef(m-1,m-2) = 1 / h(m-2);
     A.coeffRef(m-1,m-1) = 2 / h(m-2);
     
     // Reuse computation for rhs
     double bold = (y[1] - y[0]) / (h(0)*h(0));
     b(0) = 3*bold; // Fill in natural conditions 3.5.10
     // Fill matrix A and rhs b
     for(int i = 1; i < m-1; ++i) {
         // PRecompute b_i
         double hinv = 1./h(i);
         
         // Fill in a
         A.coeffRef(i,i-1) = hinv;
         A.coeffRef(i,i) = 2./h(i) + 2./h(i-1);
         A.coeffRef(i,i+1) = hinv;
         
         // Reuse computation for rhs b
         double bnew = (y[i+1] - y[i]) / (h(i)*h(i));
         b(i) = 3. * (bnew + bold);
         bold = bnew;
     }
     b(m-1) = 3*bold; // Fill in natural conditions 3.5.10
     // Compress the matrix
     A.makeCompressed();
     std::cout << A;
     
     // Factorize A and solve system A*c(1:end) = b
     Eigen::SparseLU<Eigen::SparseMatrix<double>> lu;
     lu.compute(A);
     c = lu.solve(b);
     
 }
Beispiel #3
0
void testEigen(int m, int n, int nnz, std::vector<int>& rows, std::vector<int>& cols,
		std::vector<double>& values, double* matB){

	double start, stop, time_to_solve, time_to_build;
    double tol=1e-9;
    Eigen::SparseMatrix<double> A;

    std::vector< Eigen::Triplet<double> > trips;
    trips.reserve(m * n);

    for (int k = 0; k < nnz; k++){
    	double _val = values[k];
    	int i = rows[k];
    	int j = cols[k];

    	if (fabs(_val) > tol){
    		trips.push_back(Eigen::Triplet<double>(i-1,j-1,_val));
        }
    }



    //NOTE: setFromTriples() accumulates contributions to the same (i,j)!
    A.resize(m, n);
    start = second();
    A.setFromTriplets(trips.begin(), trips.end());
    stop = second();
    time_to_build = stop - start;

	Eigen::SparseLU< Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int> > solverLU;



    Eigen::VectorXd b; b.resize(m);
    for (int i = 0; i < m; i++ ) b(i) = matB[i];

	printf("\nProcessing in Eigen using LU...\n");
	start = second();
	solverLU.compute(A);
	Eigen::VectorXd X = solverLU.solve(b);
	stop = second();
	time_to_solve = stop - start;

    Eigen::VectorXd ax = A * X;
    Eigen::VectorXd bMinusAx = b - ax;

	double h_r[m];
    for (int i=0; i<m; i++) h_r[i]=bMinusAx(i);

    double r_inf = vec_norminf(m, h_r);

    printf("(Eigen) |b - A*x| = %E \n", r_inf);
    printf("(Eigen) Time to build(sec): %f\n", time_to_build);
    printf("(Eigen) Time (sec): %f\n", time_to_solve);
}
Beispiel #4
0
//************************************
// Method:    SolvePFC
// FullName:  PFCal::PFC::SolvePFC
// Access:    public 
// Returns:   PF_RESULT
// Qualifier: 潮流计算模板函数,构造各种方法求解线性方程组
//************************************
PFVoid PFC::Solve(){
	PFDouble opml(0.0);
	Eigen::SparseLU<PFCore::PFSMatrixXD, PFCore::PFCOLAMDOrdering> solver;
	PFCIter = 0;
	//0. 初始化计算矩阵及向量大小
	this->_InitPFCalMatrix();

	do {
		//1. 求解功率失配量
		cout << "QG DISPATCH..." << endl;
		_MakeDPQVector();
		//2. 如果达到收敛条件,退出
		cout << "MAXDISPATCH\t" << PFCIter << "\t" << dPFCPQ.cwiseAbs().maxCoeff() << endl;
		if (dPFCPQ.cwiseAbs().maxCoeff() <  PFCEpsm){
			this->PFCResult = PF_RESULT_CONVERG;
			return;
		}
		//3. 计算雅可比阵
		_MakeJacoMatrix();
		//4. 计算电压偏差
		solver.compute(PFCJaco);
		if (solver.info() != Eigen::Success){
			cout << "Solving<stage_1> Failed!" << endl;
			this->PFCResult = PF_RESULT_DIVERGE_FAILURE;
			return;
		}
		dPFCVA = solver.solve(dPFCPQ);
		if (solver.info() != Eigen::Success){
			cout << "Solving<stage_2> Failed!" << endl;
			this->PFCResult = PF_RESULT_DIVERGE_FAILURE;
			return;
		}
		//5. 检测是否出现NAN
		if(dPFCVA.hasNaN()){
			this->PFCResult = PF_RESULT_DIVERGE_NAN;
			return;
		}
		//6. 更新状态量
		cout << "VOL DISPATCH..." << endl;
		opml = _CalOptimalMultiplier();
		dPFCVA *= opml;
		_UpdateSysState();
		//7. 迭代次数增加
		++PFCIter;
	} while (PFCIter <= PFCMaxIter);
	//迭代次数越限
	if (PFCIter > PFCMaxIter){
		this->PFCResult = PF_RESULT_DIVERGE_OVER_ITER;
		return;
	}
	this->PFCResult = PF_RESULT_DIVERGE;
	return;
}
    Tvector<T> Tsparse_matrix<T>::solve( const Tvector<T>& b ) const
    {
        
        assert( ROWS == b.size() );                                 // Check dimensions are compatible
	    // Convert Tvector to an Eigen matrix
	    Eigen::Matrix<T, -1, 1> B;
	    B.resize(b.size(),1);
	    for (std::size_t i=0; i<b.size(); ++i)
	    {
		    B(i,0) = b.CONTAINER[i];
	    }
        
        // Convert Tsparse_matrix to an Eigen::SparseMatrix
        Eigen::SparseMatrix<T> A(ROWS,COLS);  // Declare Eigen sparse matrix
        std::vector<Eigen::Triplet<T>> triplet_list;                // Declare list of triplets 
        for ( std::size_t i=0; i<ROWS; ++i )
        {
            if ( !S_MATRIX[i].isempty() )                           // Check that the row is not empty 
            {   
                std::vector<std::size_t> index;
                std::vector<T> element;
                index = S_MATRIX[i].index_list();
                element = S_MATRIX[i].element_list();
                std::size_t J = index.size();
                for ( std::size_t j=0; j<J; ++j )
                {
                    triplet_list.push_back( Eigen::Triplet<T>( i, index[j], element[j] ));
                }
            }
        } 
        A.setFromTriplets(triplet_list.begin(), triplet_list.end());
        
        // Setup and solve the system
        Eigen::SparseLU< Eigen::SparseMatrix<T> > solverA;
		//Eigen::BiCGSTAB<Eigen::SparseMatrix<T>> solverA;
		//solverA.analyzePattern(A);
		//solverA.factorize(A);
        solverA.compute(A);

        Eigen::Matrix<T, -1, 1> X;
	    X.resize(b.size(),1);
        X = solverA.solve(B);
        
        // Convert back to a Tvector 
	    Tvector<T> x(COLS,0.0);
	    for (std::size_t i=0; i<COLS; ++i)
	    {
		    x.CONTAINER[i] = X(i,0);
	    }	
	    return x;
    }   
Beispiel #6
0
int main() {
    
    // Construct data for RK order 4
    MatrixXd A = MatrixXd::Zero(4,4);
    A(1,0) = .5;
    A(2,1) = .5;
    A(3,2) = 1;
    VectorXd b(4);
    b << 1./6, 1./3, 1./3, 1./6;
    
    // Construct data for the IVP
    double T = 1;
    int n = 5;
    VectorXd y0(2*n);
    for(int i = 0; i < n; ++i) {
        y0(i)=(i+1.)/n;
        y0(i+n)=-1;
    }

    auto f = [n] (VectorXd y) {
        VectorXd fy(2*n);
        
        VectorXd g(n);
        g(0) = y(0)*(y(1)+y(0));
        g(n-1) = y(n-1)*(y(n-1)+y(n-2));
        for(int i = 1; i < n-1; ++i) {
            g(i) = y(i)*(y(i-1)+y(i+1));
        }
        
        Eigen::SparseMatrix<double> C(n,n);
        C.reserve(3);
        for(int i = 0; i < n; ++i) {
            C.insert(i,i) = 2;
            if(i < n-1) C.insert(i,i+1) = -1;
            if(i >= 1)  C.insert(i,i-1) = -1;
        }
        C.makeCompressed();
        fy.head(n) = y.head(n);
        
        Eigen::SparseLU< Eigen::SparseMatrix<double> >  solver;
        solver.analyzePattern(C);
        solver.compute(C);
        fy.tail(n) = solver.solve(g);
        return fy;
    };

    errors(f, T, y0, A, b);
}
Beispiel #7
0
    void ReliefGeneration::CompressHeightField(std::vector<double>& heightField, int resX, int resY)
    {
        double bbScale = 2;
        double alpha = bbScale * 300.0;
        double threthold = bbScale * 0.05;
        int vertNum = (resX + 1) * (resY + 1);
        std::vector<MagicMath::Vector3> DeltaVector(vertNum);
        for (int xid = 0; xid < resX; xid++)
        {
            for (int yid = 0; yid < resY; yid++)
            {
                int index = xid * (resY + 1) + yid;
                MagicMath::Vector3 deltaT(0, 0, 0);
                deltaT[0] = heightField.at(index + resY + 1) - heightField.at(index);
                deltaT[1] = heightField.at(index + 1) - heightField.at(index);
                double deltaMag = deltaT.Normalise();
                if (deltaMag > threthold)
                {
                    deltaMag = 0;
                }
                else
                {
                    deltaMag = log(1 + alpha * deltaMag) / alpha;
                }
                DeltaVector.at(index) = deltaT * deltaMag;
            }
        }
        std::vector<double> LaplaceField(vertNum);
        for (int xid = 1; xid < resX; xid++)
        {
            for (int yid = 1; yid < resY; yid++)
            {
                int index = xid * (resY + 1) + yid;
                LaplaceField.at(index) = DeltaVector.at(index)[0] - DeltaVector.at(index - resY - 1)[0] + 
                    DeltaVector.at(index)[1] - DeltaVector.at(index - 1)[1];

            }
        }
        DebugLog << "Relief: Construct Matrix" << std::endl;
        std::vector< Eigen::Triplet<double> > tripletList;
        Eigen::VectorXd b(vertNum, 1);
        for (int xid = 0; xid < resX + 1; xid++)
        {
            for (int yid = 0; yid < resY + 1; yid++)
            {
                int index = xid * (resY + 1) + yid;
                if (xid == 0 || xid == resX || yid == 0 || yid == resY)
                {
                    tripletList.push_back( Eigen::Triplet<double>(index, index, 1) );
                    b(index) = 0;
                }
                else
                {
                    tripletList.push_back( Eigen::Triplet<double>(index, index, -4.0) );
                    tripletList.push_back( Eigen::Triplet<double>(index, index + 1, 1.0) );
                    tripletList.push_back( Eigen::Triplet<double>(index, index - 1, 1.0) );
                    tripletList.push_back( Eigen::Triplet<double>(index, index + resY + 1, 1.0) );
                    tripletList.push_back( Eigen::Triplet<double>(index, index - resY - 1, 1.0) );
                    b(index) = LaplaceField.at(index);
                }
            }
        }
        DebugLog << "Relief: Solve Matrix" << std::endl;
        Eigen::SparseMatrix<double, Eigen::ColMajor> matA(vertNum,vertNum);
        matA.setFromTriplets(tripletList.begin(), tripletList.end());
        Eigen::SparseLU<Eigen::SparseMatrix<double, Eigen::ColMajor> > solver;
        solver.compute(matA);
        if(solver.info()!= Eigen::Success) 
        {
            DebugLog << "Relief: SuperLU Failed" << std::endl;
        }
        Eigen::VectorXd res = solver.solve(b);
        //Copy results
        for (int i = 0; i < vertNum; i++)
        {
            heightField.at(i) = res(i);
        }
    }
Beispiel #8
0
IGL_INLINE void igl::PolyVectorFieldFinder<DerivedV, DerivedF>::
minQuadWithKnownMini(const Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &Q,
                          const Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &f,
                     const Eigen::VectorXi isConstrained,
                          const Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &xknown,
                          Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &x)
{
  int N = Q.rows();

  int nc = xknown.rows();
  Eigen::VectorXi known; known.setZero(nc,1);
  Eigen::VectorXi unknown; unknown.setZero(N-nc,1);

  int indk = 0, indu = 0;
  for (int i = 0; i<N; ++i)
    if (isConstrained[i])
    {
      known[indk] = i;
      indk++;
    }
    else
    {
      unknown[indu] = i;
      indu++;
    }

  Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>> Quu, Quk;

  igl::slice(Q,unknown, unknown, Quu);
  igl::slice(Q,unknown, known, Quk);


  std::vector<typename Eigen::Triplet<std::complex<typename DerivedV::Scalar> > > tripletList;

  Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > fu(N-nc,1);

  igl::slice(f,unknown, Eigen::VectorXi::Zero(1,1), fu);

  Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > rhs = (Quk*xknown).sparseView()+.5*fu;

  Eigen::SparseLU< Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>>> solver;
  solver.compute(-Quu);
  if(solver.info()!=Eigen::Success)
  {
    std::cerr<<"Decomposition failed!"<<std::endl;
    return;
  }
  Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>>  b  = solver.solve(rhs);
  if(solver.info()!=Eigen::Success)
  {
    std::cerr<<"Solving failed!"<<std::endl;
    return;
  }

  indk = 0, indu = 0;
  x.setZero(N,1);
  for (int i = 0; i<N; ++i)
    if (isConstrained[i])
      x[i] = xknown[indk++];
    else
      x[i] = b.coeff(indu++,0);

}
Beispiel #9
0
void smooth(VectorField<float> &VF, const vector<int> &v_indices, const int n_unknowns )
{
	typedef float T;
	int nUnknowns = n_unknowns;
	if (nUnknowns == 0)
		for (const auto flag : v_indices)
			if (flag < 0) nUnknowns++;

	//2. build linear system	

	const int channels = VF.VF.cols();
	std::vector< Eigen::Triplet<float> > lhsTriplets;
	lhsTriplets.reserve(nUnknowns * 5);

	Eigen::Matrix<T, -1, -1> rhs(nUnknowns, channels); //Eigen::MatrixXf rhs(nUnknowns, channels);
	rhs.setZero();

	for (int i = 0; i < v_indices.size(); i++) {
		const int varible_id = v_indices[i];
		if (varible_id == -1)
			continue;
		vector<int> neightbors = VF.VV[i];
#if 0
		vector<int> weights = Vf.VVW[i];
		T weight = 0;
		for (int j = 0; j < weights.size(); j++)
			weight += weights[j];
#else  //uniform weights
		vector<T> weights(neightbors.size(), -1);
		T weight = neightbors.size();
#endif

		for (int j = 0; j < neightbors.size(); j++) {
			int neighbor_v = neightbors[j];
			if (v_indices[neighbor_v] == -1) { //boundary
				rhs.row(varible_id) -= weights[j] * VF.VF.row(neighbor_v);
			}
			else {
				lhsTriplets.push_back(Eigen::Triplet<float>(
					varible_id, v_indices[neighbor_v], weights[j]));
			}
		}
		lhsTriplets.push_back(Eigen::Triplet<float>(
			varible_id, varible_id, weight));
		// Add f to rhs.
		//rhs.row(pid) += VF.VF.row();
	}

	//3.  Solve the sparse linear system of equations

	Eigen::SparseMatrix<T> A(nUnknowns, nUnknowns);
	A.setFromTriplets(lhsTriplets.begin(), lhsTriplets.end());

	Eigen::SparseLU< Eigen::SparseMatrix<T> > solver;
	solver.analyzePattern(A);
	solver.factorize(A);

	Eigen::Matrix<T, -1, -1>result(nUnknowns, channels);
	//	Eigen::MatrixXf result(nUnknowns, channels);
	for (int c = 0; c < channels; ++c)
		result.col(c) = solver.solve(rhs.col(c));

	//4. Copy results back
	for (int i = 0; i < v_indices.size(); i++) {
		const int varible_id = v_indices[i];
		if (varible_id == -1)
			continue;
		VF.VF.row(i) = result.row(varible_id);
	}
}
void
poisson_blend(mve::FloatImage::ConstPtr src, mve::ByteImage::ConstPtr mask,
    mve::FloatImage::Ptr dest, float alpha) {

    assert(src->width() == mask->width() && mask->width() == dest->width());
    assert(src->height() == mask->height() && mask->height() == dest->height());
    assert(src->channels() == 3 && dest->channels() == 3);
    assert(mask->channels() == 1);
    assert(valid_mask(mask));

    const int n = dest->get_pixel_amount();
    const int width = dest->width();
    const int height = dest->height();
    const int channels = dest->channels();

    mve::Image<int>::Ptr indices = mve::Image<int>::create(width, height, 1);
    indices->fill(-1);
    int index = 0;
    for (int i = 0; i < n; ++i) {
        if (mask->at(i) != 0) {
            indices->at(i) = index;
            index++;
        }
    }
    const int nnz = index;

    std::vector<math::Vec3f> coefficients_b;
    coefficients_b.resize(nnz);

    std::vector<Eigen::Triplet<float, int> > coefficients_A;
    coefficients_A.reserve(nnz); //TODO better estimate...

    for (int i = 0; i < n; ++i) {
        const int row = indices->at(i);
        if (mask->at(i) == 126 || mask->at(i) == 128) {
            Eigen::Triplet<float, int> t(row, row, 1.0f);
            coefficients_A.push_back(t);

            coefficients_b[row] = math::Vec3f(&dest->at(i, 0));
        }

        if (mask->at(i) == 255) {
            const int i01 = indices->at(i - width);
            const int i10 = indices->at(i - 1);
            const int i11 = indices->at(i);
            const int i12 = indices->at(i + 1);
            const int i21 = indices->at(i + width);

            /* All neighbours should be eighter border conditions or part of the optimization. */
            assert(i01 != -1 && i10 != -1 && i11 != -1 && i12 != -1 && i21 != -1);

            Eigen::Triplet<float, int> t01(row, i01, 1.0f);

            Eigen::Triplet<float, int> t10(row, i10, 1.0f);
            Eigen::Triplet<float, int> t11(row, i11, -4.0f);
            Eigen::Triplet<float, int> t12(row, i12, 1.0f);

            Eigen::Triplet<float, int> t21(row, i21, 1.0f);

            Eigen::Triplet<float, int> triplets[] = {t01, t10, t11, t12, t21};

            coefficients_A.insert(coefficients_A.end(), triplets, triplets + 5);

            math::Vec3f l_d = simple_laplacian(i, dest);
            math::Vec3f l_s = simple_laplacian(i, src);

            coefficients_b[row] = (alpha * l_s + (1.0f - alpha) * l_d);
        }
    }

    SpMat A(nnz, nnz);
    A.setFromTriplets(coefficients_A.begin(), coefficients_A.end());

    Eigen::SparseLU<SpMat, Eigen::COLAMDOrdering<int> > solver;
    solver.compute(A);

    for (int channel = 0; channel < channels; ++channel) {
        Eigen::VectorXf b(nnz);
        for (std::size_t i = 0; i < coefficients_b.size(); ++i)
            b[i] = coefficients_b[i][channel];

        Eigen::VectorXf x(n);
        x = solver.solve(b);

        for (int i = 0; i < n; ++i) {
            int index = indices->at(i);
            if (index != -1) dest->at(i, channel) = x[index];
        }
    }
}
void MeshDenoisingViaL0Minimization::solveVertices(TriMesh &mesh, Eigen::MatrixXd &initial_vertices_matrix,
                                                   std::vector< std::vector<TriMesh::VertexHandle> > &edge_vertex_handle,
                                                   std::vector< std::vector<double> > &coef, std::vector<TriMesh::Point> &delta,
                                                   double alpha, double beta)
{
    Eigen::MatrixXd right_term = initial_vertices_matrix;
    Eigen::SparseMatrix<double> coef_matrix((int)mesh.n_vertices(), (int)mesh.n_vertices());

    std::vector< Eigen::Triplet<double> > triple; triple.clear();

    std::map<TriMesh::VertexHandle, double> vertex_coef;
    std::set<TriMesh::EdgeHandle> edge_handle;;
    for(TriMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); v_it++)
    {
        edge_handle.clear();
        vertex_coef.clear();
        vertex_coef[*v_it] = 1.0;
        for(TriMesh::VertexFaceIter vf_it = mesh.vf_iter(*v_it); vf_it.is_valid(); vf_it++)
        {
            for(TriMesh::FaceEdgeIter fe_it = mesh.fe_iter(*vf_it); fe_it.is_valid(); fe_it++)
            {
                edge_handle.insert(*fe_it);
            }
        }

        TriMesh::Point right(0.0, 0.0, 0.0);
        for(std::set<TriMesh::EdgeHandle>::iterator s_it = edge_handle.begin(); s_it != edge_handle.end(); s_it++)
        {
            if(!mesh.is_boundary(*s_it))
            {
                int index = (*s_it).idx();
                TriMesh::VertexHandle v1 = edge_vertex_handle[index][0],
                        v2 = edge_vertex_handle[index][1],
                        v3 = edge_vertex_handle[index][2],
                        v4 = edge_vertex_handle[index][3];
                double coe1 = coef[index][0],
                        coe2 = coef[index][1],
                        coe3 = coef[index][2],
                        coe4 = coef[index][3];
                TriMesh::Point temp_delta = delta[index];
                if(v1 == *v_it)
                {
                    vertex_coef[v1] = vertex_coef[v1] + alpha + beta * coe1 * coe1;
                    vertex_coef[v2] = vertex_coef[v2] - alpha + beta * coe1 * coe2;
                    vertex_coef[v3] = vertex_coef[v3] + alpha + beta * coe1 * coe3;
                    vertex_coef[v4] = vertex_coef[v4] - alpha + beta * coe1 * coe4;
                    right += temp_delta * beta * coe1;
                }
                else if(v2 == *v_it)
                {
                    vertex_coef[v1] = vertex_coef[v1] - alpha + beta * coe2 * coe1;
                    vertex_coef[v2] = vertex_coef[v2] + alpha + beta * coe2 * coe2;
                    vertex_coef[v3] = vertex_coef[v3] - alpha + beta * coe2 * coe3;
                    vertex_coef[v4] = vertex_coef[v4] + alpha + beta * coe2 * coe4;
                    right += temp_delta * beta * coe2;
                }
                else if(v3 == *v_it)
                {
                    vertex_coef[v1] = vertex_coef[v1] + alpha + beta * coe3 * coe1;
                    vertex_coef[v2] = vertex_coef[v2] - alpha + beta * coe3 * coe2;
                    vertex_coef[v3] = vertex_coef[v3] + alpha + beta * coe3 * coe3;
                    vertex_coef[v4] = vertex_coef[v4] - alpha + beta * coe3 * coe4;
                    right += temp_delta * beta * coe3;
                }
                else if(v4 == *v_it)
                {
                    vertex_coef[v1] = vertex_coef[v1] - alpha + beta * coe4 * coe1;
                    vertex_coef[v2] = vertex_coef[v2] + alpha + beta * coe4 * coe2;
                    vertex_coef[v3] = vertex_coef[v3] - alpha + beta * coe4 * coe3;
                    vertex_coef[v4] = vertex_coef[v4] + alpha + beta * coe4 * coe4;
                    right += temp_delta * beta * coe4;
                }
            }
        }
        right_term(v_it->idx(), 0) += right[0];
        right_term(v_it->idx(), 1) += right[1];
        right_term(v_it->idx(), 2) += right[2];

        for(std::map<TriMesh::VertexHandle, double>::iterator m_it = vertex_coef.begin(); m_it != vertex_coef.end(); m_it++)
        {
            triple.push_back(Eigen::Triplet<double>(v_it->idx(), m_it->first.idx(), m_it->second));
        }
    }
    coef_matrix.setFromTriplets(triple.begin(), triple.end());

    Eigen::SparseLU<Eigen::SparseMatrix<double> > solver;
    solver.analyzePattern(coef_matrix);
    solver.factorize(coef_matrix);
    Eigen::MatrixXd vertices_term = solver.solve(right_term);

    for(TriMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); v_it++)
    {
        int index = v_it->idx();
        TriMesh::Point pt = TriMesh::Point(vertices_term(index,0), vertices_term(index,1), vertices_term(index,2));
        mesh.set_point(*v_it, pt);
    }
}
Beispiel #12
0
int main (int argc, char **argv)
{

  GetPot cl (argc, argv);

  if (cl.search (2, "-h", "--help"))
    {
      std::cerr << help_text << std::endl;
      return 0;
    }

  const double a =
    cl.follow (0.0, "-a");

  const double b =
    cl.follow (1.0, "-b");

  const unsigned int nnodes =
    cl.follow (100, 2, "-n", "--nnodes");

  const std::string diffusion =
    cl.follow ("1.0", 2, "-d", "--diffusion");

  const std::string forcing =
    cl.follow ("1.0", 2, "-f", "--forcing");
  
  coeff f_coeff (forcing);
  coeff a_coeff (diffusion);

  const std::string quadrature =
    cl.follow ("trapezoidal.so",
               2, "-q", "--quadrature-rule");

  std::function <void ()> r_r;
  
  void * handle = dlopen (quadrature.c_str (), RTLD_NOW);
  if (! handle)
    {
      std::cerr << "fem1d: cannot load dynamic object!"
                << std::endl;
      std::cerr << dlerror ()
                << std::endl;
      return (-1);
    }

  void * sym = dlsym (handle, "register_rules");
  if (! sym)
    {
      std::cerr << "fem1d: cannot load symbol!"
                << std::endl;
      std::cerr << dlerror ()
                << std::endl;
      return (-1);
    }


  r_r = reinterpret_cast <void (*) ()> (sym);
  r_r ();

  auto & the_factory = quadrature_factory::instance (); 
  auto integrate = the_factory.create ("trapezoidal");
  if (! integrate)
    {
      std::cerr << "rule name unknown" << std::endl;
      return (-1);
    }
    
  mesh m (a, b, nnodes);
  Eigen::SparseMatrix<double> A(nnodes, nnodes);
  
  Eigen::Matrix2d mloc;
  mloc << 0, 0, 0, 0;
  for (unsigned int iel = 0; iel < m.nels; ++iel)
    {

      mloc << 0, 0, 0, 0;      
      for (unsigned int inode = 0; inode < 2; ++inode)
        {

          auto igrad = [=, &m] (double x) -> double
            {
              return basisfungrad
              (x, m.nodes[m.elements[iel][0]],
               m.nodes[m.elements[iel][1]],
               inode == 0 ? 1.0 : 0.0, 
               inode == 1 ? 1.0 : 0.0);
            };

          
          for (unsigned int jnode = 0; jnode < 2; ++jnode)
            {

              auto jgrad = [=, &m] (double x) -> double
                {
                  return basisfungrad
                  (x, m.nodes[m.elements[iel][0]],
                   m.nodes[m.elements[iel][1]],
                   jnode == 0 ? 1.0 : 0.0, 
                   jnode == 1 ? 1.0 : 0.0);
                };
              
              mloc(inode,jnode) +=
                (*integrate) ([=, &m, &igrad, &jgrad, &a_coeff]
                           (double x) -> double
                           {
                             return (igrad (x) *
                                     jgrad (x) *
                                     a_coeff (x));
                           },
                           m.nodes[m.elements[iel][0]],
                           m.nodes[m.elements[iel][1]]);

              
              A.coeffRef(m.elements[iel][inode],
                         m.elements[iel][jnode]) += 
                mloc(inode,jnode);
              
            }
        }
    }

  Eigen::VectorXd f(nnodes);
  for (unsigned int ii = 0; ii < nnodes; ++ii)
    f(ii) = 0.0;
    
  Eigen::Vector2d vloc;

  for (unsigned int iel = 0; iel < m.nels; ++iel)
    {
      vloc << 0, 0;
      
      for (unsigned int inode = 0; inode < 2; ++inode)
        {

          auto ifun = [=, &m] (double x) -> double
            {
              return basisfun
              (x, m.nodes[m.elements[iel][0]],
               m.nodes[m.elements[iel][1]],
               inode == 0 ? 1.0 : 0.0,
               inode == 1 ? 1.0 : 0.0);
            };
          
            vloc(inode) +=
              (*integrate) ([=, &m, &ifun, &f_coeff]
                         (double x) -> double
                         {
                           return (ifun (x) *
                                   f_coeff (x));
                         },
                         m.nodes[m.elements[iel][0]],
                         m.nodes[m.elements[iel][1]]);

              
          f(m.elements[iel][inode]) += vloc(inode);
        }
    }

  f(0) = 0;
  f(nnodes - 1) = 0;

  A.coeffRef(0,0) = 1.0e10;
  A.coeffRef(nnodes-1,nnodes-1) = 1.0e10;
  for (unsigned int ii = 1; ii < nnodes; ++ii)
    {
      A.coeffRef(0, ii) = 0.0;
      A.coeffRef(nnodes-1, nnodes-1-ii) = 0.0;
    }
    
  Eigen::SparseLU<Eigen::SparseMatrix<double>> solver;
  A.makeCompressed ();
  solver.analyzePattern(A); 
  solver.factorize(A);
  
  Eigen::VectorXd uh = solver.solve (f);

  for (unsigned int ii = 0; ii < nnodes; ++ii)
    std::cout << m.nodes[ii] << " "
              << uh(ii, 0)
              << std:: endl;
      
  return 0;
};
bool fill_hole(std::vector<std::size_t> const & hole, UniGraph const & graph,
    mve::TriangleMesh::ConstPtr mesh, mve::MeshInfo const & mesh_info,
    std::vector<std::vector<VertexProjectionInfo> > * vertex_projection_infos,
    std::vector<TexturePatch::Ptr> * texture_patches) {

    mve::TriangleMesh::FaceList const & mesh_faces = mesh->get_faces();
    mve::TriangleMesh::VertexList const & vertices = mesh->get_vertices();

    std::map<std::size_t, std::set<std::size_t> > tmp;
    for (std::size_t const face_id : hole) {
        std::size_t const v0 = mesh_faces[face_id * 3];
        std::size_t const v1 = mesh_faces[face_id * 3 + 1];
        std::size_t const v2 = mesh_faces[face_id * 3 + 2];

        tmp[v0].insert(face_id);
        tmp[v1].insert(face_id);
        tmp[v2].insert(face_id);
    }

    std::size_t const num_vertices = tmp.size();
    /* Only fill small holes. */
    if (num_vertices > MAX_HOLE_NUM_FACES) return false;

    /* Calculate 2D parameterization using the technique from libremesh/patch2d,
     * which was published as sourcecode accompanying the following paper:
     *
     * Isotropic Surface Remeshing
     * Simon Fuhrmann, Jens Ackermann, Thomas Kalbe, Michael Goesele
     */

    std::size_t seed = -1;
    std::vector<bool> is_border(num_vertices, false);
    std::vector<std::vector<std::size_t> > adj_verts_via_border(num_vertices);
    /* Index structures to map from local <-> global vertex id. */
    std::map<std::size_t, std::size_t> g2l;
    std::vector<std::size_t> l2g(num_vertices);
    /* Index structure to determine column in matrix/vector. */
    std::vector<std::size_t> idx(num_vertices);

    std::size_t num_border_vertices = 0;

    bool disk_topology = true;
    std::map<std::size_t, std::set<std::size_t> >::iterator it = tmp.begin();
    for (std::size_t j = 0; j < num_vertices; ++j, ++it) {
        std::size_t vertex_id = it->first;
        g2l[vertex_id] = j;
        l2g[j] = vertex_id;

        /* Check topology in original mesh. */
        if (mesh_info[vertex_id].vclass != mve::MeshInfo::VERTEX_CLASS_SIMPLE) {
            /* Complex/Border vertex in original mesh */
            disk_topology = false;
            break;
        }

        /* Check new topology and determine if vertex is now at the border. */
        std::vector<std::size_t> const & adj_faces = mesh_info[vertex_id].faces;
        std::set<std::size_t> const & adj_hole_faces = it->second;
        std::vector<std::pair<std::size_t, std::size_t> > fan;
        for (std::size_t k = 0; k < adj_faces.size(); ++k) {
            std::size_t adj_face = adj_faces[k];
            if (graph.get_label(adj_faces[k]) == 0 &&
                adj_hole_faces.find(adj_face) != adj_hole_faces.end()) {
                std::size_t curr = adj_faces[k];
                std::size_t next = adj_faces[(k + 1) % adj_faces.size()];
                std::pair<std::size_t, std::size_t> pair(curr, next);
                fan.push_back(pair);
            }
        }

        std::size_t gaps = 0;
        for (std::size_t k = 0; k < fan.size(); k++) {
            std::size_t curr = fan[k].first;
            std::size_t next = fan[(k + 1) % fan.size()].first;
            if (fan[k].second != next) {
                ++gaps;

                for (std::size_t l = 0; l < 3; ++l) {
                    if(mesh_faces[curr * 3 + l] == vertex_id) {
                        std::size_t second = mesh_faces[curr * 3 + (l + 2) % 3];
                        adj_verts_via_border[j].push_back(second);
                    }
                    if(mesh_faces[next * 3 + l] == vertex_id) {
                        std::size_t first = mesh_faces[next * 3 + (l + 1) % 3];
                        adj_verts_via_border[j].push_back(first);
                    }
                }
            }
        }

        is_border[j] = gaps == 1;

        /* Check if vertex is now complex. */
        if (gaps > 1) {
            /* Complex vertex in hole */
            disk_topology = false;
            break;
        }

        if (is_border[j]) {
            idx[j] = num_border_vertices++;
            seed = vertex_id;
        } else {
            idx[j] = j - num_border_vertices;
        }
    }
    tmp.clear();

    /* No disk or genus zero topology */
    if (!disk_topology || num_border_vertices == 0) return false;

    std::vector<std::size_t> border; border.reserve(num_border_vertices);
    std::size_t prev = seed;
    std::size_t curr = seed;
    while (prev == seed || curr != seed) {
        std::size_t next = std::numeric_limits<std::size_t>::max();
        std::vector<std::size_t> const & adj_verts = adj_verts_via_border[g2l[curr]];
        for (std::size_t adj_vert : adj_verts) {
            assert(is_border[g2l[adj_vert]]);
            if (adj_vert != prev && adj_vert != curr) {
                next = adj_vert;
                break;
            }
        }
        if (next != std::numeric_limits<std::size_t>::max()) {
            prev = curr;
            curr = next;
            border.push_back(next);
        } else {
            /* No new border vertex */
            border.clear();
            break;
        }

        /* Loop within border */
        if (border.size() > num_border_vertices) break;
    }

    if (border.size() != num_border_vertices) return false;

    float total_length = 0.0f;
    float total_projection_length = 0.0f;
    for (std::size_t j = 0; j < border.size(); ++j) {
        std::size_t vi0 = border[j];
        std::size_t vi1 = border[(j + 1) % border.size()];
        std::vector<VertexProjectionInfo> const & vpi0 = vertex_projection_infos->at(vi0);
        std::vector<VertexProjectionInfo> const & vpi1 = vertex_projection_infos->at(vi0);
        /* According to the previous checks (vertex class within the origial
         * mesh and boundary) there already has to be at least one projection
         * of each border vertex. */
        assert(!vpi0.empty() && !vpi1.empty());
        math::Vec2f vp0(0.0f), vp1(0.0f);
        for (VertexProjectionInfo const & info0 : vpi0) {
            for (VertexProjectionInfo const & info1 : vpi1) {
                if (info0.texture_patch_id == info1.texture_patch_id) {
                    vp0 = info0.projection;
                    vp1 = info1.projection;
                    break;
                }
            }
        }
        total_projection_length += (vp0 - vp1).norm();
        math::Vec3f const & v0 = vertices[vi0];
        math::Vec3f const & v1 = vertices[vi1];
        total_length += (v0 - v1).norm();
    }
    float radius = total_projection_length / (2.0f * MATH_PI);

    if (total_length < std::numeric_limits<float>::epsilon()) return false;

    float length = 0.0f;
    std::vector<math::Vec2f> projections(num_vertices);
    for (std::size_t j = 0; j < border.size(); ++j) {
        float angle = 2.0f * MATH_PI * (length / total_length);
        projections[g2l[border[j]]] = math::Vec2f(std::cos(angle), std::sin(angle));
        math::Vec3f const & v0 = vertices[border[j]];
        math::Vec3f const & v1 = vertices[border[(j + 1) % border.size()]];
        length += (v0 - v1).norm();
    }

    typedef Eigen::Triplet<float, int> Triplet;
    std::vector<Triplet> coeff;
    std::size_t matrix_size = num_vertices - border.size();

    Eigen::VectorXf xx(matrix_size), xy(matrix_size);

    if (matrix_size != 0) {
        Eigen::VectorXf bx(matrix_size);
        Eigen::VectorXf by(matrix_size);
        for (std::size_t j = 0; j < num_vertices; ++j) {
            if (is_border[j]) continue;

            std::size_t const vertex_id = l2g[j];

            /* Calculate "Mean Value Coordinates" as proposed by Michael S. Floater */
            std::map<std::size_t, float> weights;
            std::vector<std::size_t> const & adj_faces = mesh_info[vertex_id].faces;
            for (std::size_t adj_face : adj_faces) {
                std::size_t v0 = mesh_faces[adj_face * 3];
                std::size_t v1 = mesh_faces[adj_face * 3 + 1];
                std::size_t v2 = mesh_faces[adj_face * 3 + 2];
                if (v1 == vertex_id) std::swap(v1, v0);
                if (v2 == vertex_id) std::swap(v2, v0);

                math::Vec3f v01 = vertices[v1] - vertices[v0];
                float v01n = v01.norm();
                math::Vec3f v02 = vertices[v2] - vertices[v0];
                float v02n = v02.norm();

                /* Ensure numerical stability */
                if (v01n * v02n < std::numeric_limits<float>::epsilon()) return false;

                float alpha = std::acos(v01.dot(v02) / (v01n * v02n));
                weights[g2l[v1]] += std::tan(alpha / 2.0f) / v01n;
                weights[g2l[v2]] += std::tan(alpha / 2.0f) / v02n;
            }

            std::map<std::size_t, float>::iterator it;
            float sum = 0.0f;
            for (it = weights.begin(); it != weights.end(); ++it)
                sum += it->second;
            assert(sum > 0.0f);
            for (it = weights.begin(); it != weights.end(); ++it)
                it->second /= sum;

            bx[idx[j]] = 0.0f;
            by[idx[j]] = 0.0f;
            for (it = weights.begin(); it != weights.end(); ++it) {
                if (is_border[it->first]) {
                    std::size_t border_vertex_id = border[idx[it->first]];
                    bx[idx[j]] += projections[g2l[border_vertex_id]][0] * it->second;
                    by[idx[j]] += projections[g2l[border_vertex_id]][1] * it->second;
                } else {
                    coeff.push_back(Triplet(idx[j], idx[it->first], -it->second));
                }
            }
        }

        for (std::size_t j = 0; j < matrix_size; ++j) {
            coeff.push_back(Triplet(j, j, 1.0f));
        }

        typedef Eigen::SparseMatrix<float> SpMat;
        SpMat A(matrix_size, matrix_size);
        A.setFromTriplets(coeff.begin(), coeff.end());

        Eigen::SparseLU<SpMat> solver;
        solver.analyzePattern(A);
        solver.factorize(A);
        xx = solver.solve(bx);
        xy = solver.solve(by);
    }

    float const max_hole_patch_size = MAX_HOLE_PATCH_SIZE;
    int image_size = std::min(std::floor(radius * 1.1f) * 2.0f, max_hole_patch_size);
    /* Ensure a minimum scale of one */
    image_size += 2 * (1 + texture_patch_border);
    int scale = image_size / 2 - texture_patch_border;
    for (std::size_t j = 0, k = 0; j < num_vertices; ++j) {
        if (is_border[j]) {
            projections[j] = projections[j] * scale + image_size / 2;
        } else {
            projections[j] = math::Vec2f(xx[k], xy[k]) * scale + image_size / 2;
            ++k;
        }
    }

    mve::ByteImage::Ptr image = mve::ByteImage::create(image_size, image_size, 3);
    //DEBUG image->fill_color(*math::Vec4uc(0, 255, 0, 255));
    std::vector<math::Vec2f> texcoords; texcoords.reserve(hole.size());
    for (std::size_t const face_id : hole) {
        for (std::size_t j = 0; j < 3; ++j) {
            std::size_t const vertex_id = mesh_faces[face_id * 3 + j];
            math::Vec2f const & projection = projections[g2l[vertex_id]];
            texcoords.push_back(projection);
        }
    }
    TexturePatch::Ptr texture_patch = TexturePatch::create(0, hole, texcoords, image);
    std::size_t texture_patch_id;
    #pragma omp critical
    {
        texture_patches->push_back(texture_patch);
        texture_patch_id = texture_patches->size() - 1;
    }

    for (std::size_t j = 0; j < num_vertices; ++j) {
        std::size_t const vertex_id = l2g[j];
        std::vector<std::size_t> const & adj_faces = mesh_info[vertex_id].faces;
        std::vector<std::size_t> faces; faces.reserve(adj_faces.size());
        for (std::size_t adj_face : adj_faces) {
            if (graph.get_label(adj_face) == 0) {
                faces.push_back(adj_face);
            }
        }
        VertexProjectionInfo info = {texture_patch_id, projections[j], faces};
        #pragma omp critical
        vertex_projection_infos->at(vertex_id).push_back(info);
    }

    return true;
}
void
generate_texture_patches(UniGraph const & graph, std::vector<TextureView> const & texture_views,
    mve::TriangleMesh::ConstPtr mesh, mve::VertexInfoList::ConstPtr vertex_infos,
    std::vector<std::vector<VertexProjectionInfo> > * vertex_projection_infos,
    std::vector<TexturePatch> * texture_patches) {

    util::WallTimer timer;

    mve::TriangleMesh::FaceList const & mesh_faces = mesh->get_faces();
    mve::TriangleMesh::VertexList const & vertices = mesh->get_vertices();
    vertex_projection_infos->resize(vertices.size());

    std::size_t num_patches = 0;

    std::cout << "\tRunning... " << std::flush;
    #pragma omp parallel for schedule(dynamic)
    for (std::size_t i = 0; i < texture_views.size(); ++i) {

        std::vector<std::vector<std::size_t> > subgraphs;
        int const label = i + 1;
        graph.get_subgraphs(label, &subgraphs);

        std::list<TexturePatchCandidate> candidates;
        for (std::size_t j = 0; j < subgraphs.size(); ++j) {
            candidates.push_back(generate_candidate(label, texture_views[i], subgraphs[j], mesh));
        }

        /* Merge candidates which contain the same image content. */
        std::list<TexturePatchCandidate>::iterator it, sit;
        for (it = candidates.begin(); it != candidates.end(); ++it) {
            for (sit = candidates.begin(); sit != candidates.end();) {
                Rect<int> bounding_box = sit->bounding_box;
                if (it != sit && bounding_box.is_inside(&it->bounding_box)) {
                    TexturePatch::Faces & faces = it->texture_patch.get_faces();
                    TexturePatch::Faces & ofaces = sit->texture_patch.get_faces();
                    faces.insert(faces.end(), ofaces.begin(), ofaces.end());

                    TexturePatch::Texcoords & texcoords = it->texture_patch.get_texcoords();
                    TexturePatch::Texcoords & otexcoords = sit->texture_patch.get_texcoords();
                    math::Vec2f offset;
                    offset[0] = sit->bounding_box.min_x - it->bounding_box.min_x;
                    offset[1] = sit->bounding_box.min_y - it->bounding_box.min_y;
                    for (std::size_t i = 0; i < otexcoords.size(); ++i) {
                        texcoords.push_back(otexcoords[i] + offset);
                    }

                    sit = candidates.erase(sit);
                } else {
                    ++sit;
                }
            }
        }

        it = candidates.begin();
        for (; it != candidates.end(); ++it) {
            std::size_t texture_patch_id;

            #pragma omp critical
            {
                texture_patches->push_back(it->texture_patch);
                texture_patch_id = num_patches++;
            }

            std::vector<std::size_t> const & faces = it->texture_patch.get_faces();
            std::vector<math::Vec2f> const & texcoords = it->texture_patch.get_texcoords();
            for (std::size_t i = 0; i < faces.size(); ++i) {
                std::size_t const face_id = faces[i];
                std::size_t const face_pos = face_id * 3;
                for (std::size_t j = 0; j < 3; ++j) {
                    std::size_t const vertex_id = mesh_faces[face_pos  + j];
                    math::Vec2f const projection = texcoords[i * 3 + j];

                    VertexProjectionInfo info = {texture_patch_id, projection, {face_id}};

                    #pragma omp critical
                    vertex_projection_infos->at(vertex_id).push_back(info);
                }
            }
        }
    }

    merge_vertex_projection_infos(vertex_projection_infos);

    std::size_t num_holes = 0;
    std::size_t num_hole_faces = 0;

    //if (!settings.skip_hole_filling) {
    {
        std::vector<std::vector<std::size_t> > subgraphs;
        graph.get_subgraphs(0, &subgraphs);

        #pragma omp parallel for schedule(dynamic)
        for (std::size_t i = 0; i < subgraphs.size(); ++i) {
            std::vector<std::size_t> const & subgraph = subgraphs[i];

            std::map<std::size_t, std::set<std::size_t> > tmp;
            for (std::size_t const face_id : subgraph) {
                std::size_t const v0 = mesh_faces[face_id * 3];
                std::size_t const v1 = mesh_faces[face_id * 3 + 1];
                std::size_t const v2 = mesh_faces[face_id * 3 + 2];
                tmp[v0].insert(face_id);
                tmp[v1].insert(face_id);
                tmp[v2].insert(face_id);
            }

            std::size_t const num_vertices = tmp.size();
            /* Only fill small holes. */
            if (num_vertices > 100) {
                //std::cerr << "Hole to large" << std::endl;
                continue;
            }


            /* Calculate 2D parameterization using the technique from libremesh/patch2d,
             * which was published as sourcecode accompanying the following paper:
             *
             * Isotropic Surface Remeshing
             * Simon Fuhrmann, Jens Ackermann, Thomas Kalbe, Michael Goesele
             */

            std::size_t seed = -1;
            std::vector<bool> is_border(num_vertices, false);
            std::vector<std::vector<std::size_t> > adj_verts_via_border(num_vertices);
            /* Index structures to map from local <-> global vertex id. */
            std::map<std::size_t, std::size_t> g2l;
            std::vector<std::size_t> l2g(num_vertices);
            /* Index structure to determine column in matrix/vector. */
            std::vector<std::size_t> idx(num_vertices);

            std::size_t num_border_vertices = 0;

            bool disk_topology = true;
            std::map<std::size_t, std::set<std::size_t> >::iterator it = tmp.begin();
            for (std::size_t j = 0; j < num_vertices; ++j, ++it) {
                std::size_t vertex_id = it->first;
                g2l[vertex_id] = j;
                l2g[j] = vertex_id;

                /* Check topology in original mesh. */
                if (vertex_infos->at(vertex_id).vclass != mve::VERTEX_CLASS_SIMPLE) {
                    //std::cerr << "Complex/Border vertex in original mesh" << std::endl;
                    disk_topology = false;
                    break;
                }

                /* Check new topology and determine if vertex is now at the border. */
                std::vector<std::size_t> const & adj_faces = vertex_infos->at(vertex_id).faces;
                std::set<std::size_t> const & adj_hole_faces = it->second;
                std::vector<std::pair<std::size_t, std::size_t> > fan;
                for (std::size_t k = 0; k < adj_faces.size(); ++k) {
                    std::size_t adj_face = adj_faces[k];
                    if (graph.get_label(adj_faces[k]) == 0 &&
                        adj_hole_faces.find(adj_face) != adj_hole_faces.end()) {
                        std::size_t curr = adj_faces[k];
                        std::size_t next = adj_faces[(k + 1) % adj_faces.size()];
                        std::pair<std::size_t, std::size_t> pair(curr, next);
                        fan.push_back(pair);
                    }
                }

                std::size_t gaps = 0;
                for (std::size_t k = 0; k < fan.size(); k++) {
                    std::size_t curr = fan[k].first;
                    std::size_t next = fan[(k + 1) % fan.size()].first;
                    if (fan[k].second != next) {
                        ++gaps;

                        for (std::size_t l = 0; l < 3; ++l) {
                            if(mesh_faces[curr * 3 + l] == vertex_id) {
                                std::size_t second = mesh_faces[curr * 3 + (l + 2) % 3];
                                adj_verts_via_border[j].push_back(second);
                            }
                            if(mesh_faces[next * 3 + l] == vertex_id) {
                                std::size_t first = mesh_faces[next * 3 + (l + 1) % 3];
                                adj_verts_via_border[j].push_back(first);
                            }
                        }
                    }
                }

                is_border[j] = gaps == 1;

                /* Check if vertex is now complex. */
                if (gaps > 1) {
                    //std::cerr << "Complex vertex in hole" << std::endl;
                    disk_topology = false;
                    break;
                }

                if (is_border[j]) {
                    idx[j] = num_border_vertices++;
                    seed = vertex_id;
                } else {
                    idx[j] = j - num_border_vertices;
                }
            }
            tmp.clear();

            if (!disk_topology) continue;
            if (num_border_vertices == 0) {
                //std::cerr << "Genus zero topology" << std::endl;
                continue;
            }

            std::vector<std::size_t> border; border.reserve(num_border_vertices);
            std::size_t prev = seed;
            std::size_t curr = seed;
            while (prev == seed || curr != seed) {
                std::size_t next = std::numeric_limits<std::size_t>::max();
                std::vector<std::size_t> const & adj_verts = adj_verts_via_border[g2l[curr]];
                for (std::size_t adj_vert : adj_verts) {
                    assert(is_border[g2l[adj_vert]]);
                    if (adj_vert != prev && adj_vert != curr) {
                        next = adj_vert;
                        break;
                    }
                }
                if (next != std::numeric_limits<std::size_t>::max()) {
                    prev = curr;
                    curr = next;
                    border.push_back(next);
                } else {
                    //std::cerr << "No new border vertex" << std::endl;
                    border.clear();
                    break;
                }

                if (border.size() > num_border_vertices) {
                    //std::cerr << "Loop within border" << std::endl;
                    break;
                }
            }

            if (border.size() != num_border_vertices) {
                continue;
            }

            float total_length = 0.0f;
            float total_projection_length = 0.0f;
            for (std::size_t j = 0; j < border.size(); ++j) {
                std::size_t vi0 = border[j];
                std::size_t vi1 = border[(j + 1) % border.size()];
                std::vector<VertexProjectionInfo> const & vpi0 = vertex_projection_infos->at(vi0);
                std::vector<VertexProjectionInfo> const & vpi1 = vertex_projection_infos->at(vi0);
                /* According to the previous checks (vertex class within the origial
                 * mesh and boundary) there already has to be at least one projection
                 * of each border vertex. */
                assert(!vpi0.empty() && !vpi1.empty());
                math::Vec2f vp0(0.0f), vp1(0.0f);
                for (VertexProjectionInfo const & info0 : vpi0) {
                    for (VertexProjectionInfo const & info1 : vpi1) {
                        if (info0.texture_patch_id == info1.texture_patch_id) {
                            vp0 = info0.projection;
                            vp1 = info1.projection;
                            break;
                        }
                    }
                }
                total_projection_length += (vp0 - vp1).norm();
                math::Vec3f const & v0 = vertices[vi0];
                math::Vec3f const & v1 = vertices[vi1];
                total_length += (v0 - v1).norm();
            }
            float radius = total_projection_length / (2.0f * MATH_PI);

            float length = 0.0f;
            std::vector<math::Vec2f> projections(num_vertices);
            for (std::size_t j = 0; j < border.size(); ++j) {
                float angle = 2.0f * MATH_PI * (length / total_length);
                projections[g2l[border[j]]] = math::Vec2f(std::cos(angle), std::sin(angle));
                math::Vec3f const & v0 = vertices[border[j]];
                math::Vec3f const & v1 = vertices[border[(j + 1) % border.size()]];
                length += (v0 - v1).norm();
            }

            typedef Eigen::Triplet<float, int> Triplet;
            std::vector<Triplet> coeff;
            std::size_t matrix_size = num_vertices - border.size();

            Eigen::VectorXf xx(matrix_size), xy(matrix_size);

            if (matrix_size != 0) {
                Eigen::VectorXf bx(matrix_size);
                Eigen::VectorXf by(matrix_size);
                for (std::size_t j = 0; j < num_vertices; ++j) {
                    if (is_border[j]) continue;

                    std::size_t const vertex_id = l2g[j];

                    /* Calculate "Mean Value Coordinates" as proposed by Michael S. Floater */
                    std::map<std::size_t, float> weights;
                    std::vector<std::size_t> const & adj_faces = vertex_infos->at(vertex_id).faces;
                    for (std::size_t adj_face : adj_faces) {
                        std::size_t v0 = mesh_faces[adj_face * 3];
                        std::size_t v1 = mesh_faces[adj_face * 3 + 1];
                        std::size_t v2 = mesh_faces[adj_face * 3 + 2];
                        if (v1 == vertex_id) std::swap(v1, v0);
                        if (v2 == vertex_id) std::swap(v2, v0);

                        math::Vec3f v01 = vertices[v1] - vertices[v0];
                        float v01n = v01.norm();
                        math::Vec3f v02 = vertices[v2] - vertices[v0];
                        float v02n = v02.norm();
                        float alpha = std::acos(v01.dot(v02) / (v01n * v02n));
                        weights[g2l[v1]] += std::tan(alpha / 2.0f) / v01n;
                        weights[g2l[v2]] += std::tan(alpha / 2.0f) / v02n;
                    }

                    std::map<std::size_t, float>::iterator it;
                    float sum = 0.0f;
                    for (it = weights.begin(); it != weights.end(); ++it)
                        sum += it->second;
                    for (it = weights.begin(); it != weights.end(); ++it)
                        it->second /= sum;

                    bx[idx[j]] = 0.0f;
                    by[idx[j]] = 0.0f;
                    for (it = weights.begin(); it != weights.end(); ++it) {
                        if (is_border[it->first]) {
                            std::size_t border_vertex_id = border[idx[it->first]];
                            bx[idx[j]] += projections[g2l[border_vertex_id]][0] * it->second;
                            by[idx[j]] += projections[g2l[border_vertex_id]][1] * it->second;
                        } else {
                            coeff.push_back(Triplet(idx[j], idx[it->first], -it->second));
                        }
                    }
                }
                for (std::size_t j = 0; j < matrix_size; ++j) {
                    coeff.push_back(Triplet(j, j, 1.0f));
                }

                typedef Eigen::SparseMatrix<float> SpMat;
                SpMat A(matrix_size, matrix_size);
                A.setFromTriplets(coeff.begin(), coeff.end());

                Eigen::SparseLU<SpMat> solver;
                solver.analyzePattern(A);
                solver.factorize(A);
                xx = solver.solve(bx);
                xy = solver.solve(by);
            }

            int image_size = std::floor(radius * 1.1f) * 2 + 4;
            int scale = image_size / 2 - texture_patch_border;
            for (std::size_t j = 0, k = 0; j < num_vertices; ++j) {
                if (!is_border[j]) {
                    projections[j] = math::Vec2f(xx[k], xy[k]) * scale + image_size / 2;
                    ++k;
                } else {
                    projections[j] = projections[j] * scale + image_size / 2;
                }
            }

            mve::ByteImage::Ptr image = mve::ByteImage::create(image_size, image_size, 3);
            //DEBUG image->fill_color(*math::Vec4uc(0, 255, 0, 255));
            std::vector<math::Vec2f> texcoords; texcoords.reserve(subgraph.size());
            for (std::size_t const face_id : subgraph) {
                for (std::size_t j = 0; j < 3; ++j) {
                    std::size_t const vertex_id = mesh_faces[face_id * 3 + j];
                    math::Vec2f const & projection = projections[g2l[vertex_id]];
                    texcoords.push_back(projection);
                }
            }
            TexturePatch texture_patch(0, subgraph, texcoords, image);
            std::size_t texture_patch_id;
            #pragma omp critical
            {
                texture_patches->push_back(texture_patch);
                texture_patch_id = num_patches++;

                num_hole_faces += subgraph.size();
                ++num_holes;
            }

            for (std::size_t j = 0; j < num_vertices; ++j) {
                std::size_t const vertex_id = l2g[j];
                std::vector<std::size_t> const & adj_faces = vertex_infos->at(vertex_id).faces;
                std::vector<std::size_t> faces; faces.reserve(adj_faces.size());
                for (std::size_t adj_face : adj_faces) {
                    if (graph.get_label(adj_face) == 0) {
                        faces.push_back(adj_face);
                    }
                }
                VertexProjectionInfo info = {texture_patch_id, projections[j], faces};
                #pragma omp critical
                vertex_projection_infos->at(vertex_id).push_back(info);
            }
        }
    }

    merge_vertex_projection_infos(vertex_projection_infos);

    std::cout << "done. (Took " << timer.get_elapsed_sec() << "s)" << std::endl;
    std::cout << "\t" << num_patches << " texture patches." << std::endl;
    std::cout << "\t" << num_holes << " holes (" << num_hole_faces << " faces)." << std::endl;
}