IGL_INLINE void igl::vertex_triangle_adjacency( const Eigen::MatrixBase<DerivedF> & F, const int n, Eigen::PlainObjectBase<DerivedVF> & VF, Eigen::PlainObjectBase<DerivedNI> & NI) { typedef Eigen::Matrix<typename DerivedVF::Scalar,Eigen::Dynamic,1> VectorXI; // vfd #V list so that vfd(i) contains the vertex-face degree (number of // faces incident on vertex i) VectorXI vfd = VectorXI::Zero(n); for (int i = 0; i < F.rows(); i++) { for (int j = 0; j < 3; j++) { vfd[F(i,j)]++; } } igl::cumsum(vfd,1,NI); // Prepend a zero NI = (DerivedNI(n+1)<<0,NI).finished(); // vfd now acts as a counter vfd = NI; VF.derived()= Eigen::VectorXi(3*F.rows()); for (int i = 0; i < F.rows(); i++) { for (int j = 0; j < 3; j++) { VF[vfd[F(i,j)]] = i; vfd[F(i,j)]++; } } }
IGL_INLINE bool igl::bbw( const Eigen::PlainObjectBase<DerivedV> & V, const Eigen::PlainObjectBase<DerivedEle> & Ele, const Eigen::PlainObjectBase<Derivedb> & b, const Eigen::PlainObjectBase<Derivedbc> & bc, igl::BBWData & data, Eigen::PlainObjectBase<DerivedW> & W ) { using namespace igl; using namespace std; using namespace Eigen; // number of domain vertices int n = V.rows(); // number of handles int m = bc.cols(); SparseMatrix<typename DerivedW::Scalar> L; cotmatrix(V,Ele,L); MassMatrixType mmtype = MASSMATRIX_VORONOI; if(Ele.cols() == 4) { mmtype = MASSMATRIX_BARYCENTRIC; } SparseMatrix<typename DerivedW::Scalar> M; SparseMatrix<typename DerivedW::Scalar> Mi; massmatrix(V,Ele,mmtype,M); invert_diag(M,Mi); // Biharmonic operator SparseMatrix<typename DerivedW::Scalar> Q = L.transpose() * Mi * L; W.derived().resize(n,m); if(data.partition_unity) { // Not yet implemented assert(false); }else { // No linear terms VectorXd c = VectorXd::Zero(n); // No linear constraints SparseMatrix<typename DerivedW::Scalar> A(0,n),Aeq(0,n),Aieq(0,n); VectorXd uc(0,1),Beq(0,1),Bieq(0,1),lc(0,1); // Upper and lower box constraints (Constant bounds) VectorXd ux = VectorXd::Ones(n); VectorXd lx = VectorXd::Zero(n); active_set_params eff_params = data.active_set_params; switch(data.qp_solver) { case QP_SOLVER_IGL_ACTIVE_SET: { //if(data.verbosity >= 1) //{ cout<<"BBW: max_iter: "<<eff_params.max_iter<<endl; //} if(data.verbosity >= 1) { cout<<"BBW: Computing initial weights for "<<m<<" handle"<< (m!=1?"s":"")<<"."<<endl; } min_quad_with_fixed_data<typename DerivedW::Scalar > mqwf; min_quad_with_fixed_precompute(Q,b,Aeq,true,mqwf); min_quad_with_fixed_solve(mqwf,c,bc,Beq,W); // decrement eff_params.max_iter--; bool error = false; // Loop over handles #pragma omp parallel for for(int i = 0;i<m;i++) { // Quicker exit for openmp if(error) { continue; } if(data.verbosity >= 1) { #pragma omp critical cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<< "."<<endl; } VectorXd bci = bc.col(i); VectorXd Wi; // use initial guess Wi = W.col(i); SolverStatus ret = active_set( Q,c,b,bci,Aeq,Beq,Aieq,Bieq,lx,ux,eff_params,Wi); switch(ret) { case SOLVER_STATUS_CONVERGED: break; case SOLVER_STATUS_MAX_ITER: cerr<<"active_set: max iter without convergence."<<endl; break; case SOLVER_STATUS_ERROR: default: cerr<<"active_set error."<<endl; error = true; } W.col(i) = Wi; } if(error) { return false; } break; } case QP_SOLVER_MOSEK: { #ifdef IGL_NO_MOSEK assert(false && "Use another QPSolver. Recompile without IGL_NO_MOSEK defined."); cerr<<"Use another QPSolver. Recompile without IGL_NO_MOSEK defined."<<endl; return false; #else // Loop over handles for(int i = 0;i<m;i++) { if(data.verbosity >= 1) { cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<< "."<<endl; } VectorXd bci = bc.col(i); VectorXd Wi; // impose boundary conditions via bounds slice_into(bci,b,ux); slice_into(bci,b,lx); bool r = mosek_quadprog(Q,c,0,A,lc,uc,lx,ux,data.mosek_data,Wi); if(!r) { return false; } W.col(i) = Wi; } #endif break; } default: { assert(false && "Unknown qp_solver"); return false; } } #ifndef NDEBUG const double min_rowsum = W.rowwise().sum().array().abs().minCoeff(); if(min_rowsum < 0.1) { cerr<<"bbw.cpp: Warning, minimum row sum is very low. Consider more " "active set iterations or enforcing partition of unity."<<endl; } #endif } return true; }