int main(int argc, char *argv[]) { using namespace Eigen; using namespace std; igl::readOBJ(TUTORIAL_SHARED_PATH "/bump-domain.obj",V,F); U=V; // Find boundary vertices outside annulus typedef Matrix<bool,Dynamic,1> VectorXb; VectorXb is_outer = (V.rowwise().norm().array()-1.0)>-1e-15; VectorXb is_inner = (V.rowwise().norm().array()-0.15)<1e-15; VectorXb in_b = is_outer.array() || is_inner.array(); igl::colon<int>(0,V.rows()-1,b); b.conservativeResize(stable_partition( b.data(), b.data()+b.size(), [&in_b](int i)->bool{return in_b(i);})-b.data()); bc.resize(b.size(),1); for(int bi = 0;bi<b.size();bi++) { bc(bi) = (is_outer(b(bi))?0.0:1.0); } // Pseudo-color based on selection MatrixXd C(F.rows(),3); RowVector3d purple(80.0/255.0,64.0/255.0,255.0/255.0); RowVector3d gold(255.0/255.0,228.0/255.0,58.0/255.0); for(int f = 0;f<F.rows();f++) { if( in_b(F(f,0)) && in_b(F(f,1)) && in_b(F(f,2))) { C.row(f) = purple; }else { C.row(f) = gold; } } // Plot the mesh with pseudocolors igl::viewer::Viewer viewer; viewer.data.set_mesh(U, F); viewer.core.show_lines = false; viewer.data.set_colors(C); viewer.core.trackball_angle = Eigen::Quaternionf(0.81,-0.58,-0.03,-0.03); viewer.core.trackball_angle.normalize(); viewer.callback_pre_draw = &pre_draw; viewer.callback_key_down = &key_down; viewer.core.is_animating = true; viewer.core.animation_max_fps = 30.; cout<< "Press [space] to toggle animation."<<endl<< "Press '.' to increase k."<<endl<< "Press ',' to decrease k."<<endl; viewer.launch(); }
int main(int argc, char *argv[]) { using namespace Eigen; using namespace std; igl::readOFF("../shared/decimated-knight.off",V,F); U=V; igl::readDMAT("../shared/decimated-knight-selection.dmat",S); // vertices in selection igl::colon<int>(0,V.rows()-1,b); b.conservativeResize(stable_partition( b.data(), b.data()+b.size(), [](int i)->bool{return S(i)>=0;})-b.data()); // Centroid mid = 0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff()); // Precomputation arap_data.max_iter = 100; igl::arap_precomputation(V,F,V.cols(),b,arap_data); // Set color based on selection MatrixXd C(F.rows(),3); RowVector3d purple(80.0/255.0,64.0/255.0,255.0/255.0); RowVector3d gold(255.0/255.0,228.0/255.0,58.0/255.0); for(int f = 0;f<F.rows();f++) { if( S(F(f,0))>=0 && S(F(f,1))>=0 && S(F(f,2))>=0) { C.row(f) = purple; }else { C.row(f) = gold; } } // Plot the mesh with pseudocolors igl::viewer::Viewer viewer; viewer.data.set_mesh(U, F); viewer.data.set_colors(C); viewer.callback_pre_draw = &pre_draw; viewer.callback_key_down = &key_down; viewer.core.is_animating = false; viewer.core.animation_max_fps = 30.; cout<< "Press [space] to toggle animation"<<endl; viewer.launch(); }
void place::removeMinimumConnectedComponents(cv::Mat &image) { std::list<std::pair<int, int>> toLabel; Eigen::RowMatrixXi labeledImage = Eigen::RowMatrixXi::Zero(image.rows, image.cols); int currentLabel = 1; for (int j = 0; j < image.rows; ++j) { const uchar *src = image.ptr<uchar>(j); for (int i = 0; i < image.cols; ++i) { if (src[i] != 255 && labeledImage(j, i) == 0) { labeledImage(j, i) = currentLabel; toLabel.emplace_front(j, i); labelNeighbours(image, currentLabel, labeledImage, toLabel); ++currentLabel; } } } Eigen::VectorXi countPerLabel = Eigen::VectorXi::Zero(currentLabel); const int *labeledImagePtr = labeledImage.data(); for (int i = 0; i < labeledImage.size(); ++i) ++countPerLabel[*(labeledImagePtr + i)]; double average = 0.0, sigma = 0.0; const int *countPerLabelPtr = countPerLabel.data(); std::tie(average, sigma) = place::aveAndStdev( countPerLabelPtr + 1, countPerLabelPtr + countPerLabel.size()); double threshHold = average; for (int j = 0; j < image.rows; ++j) { uchar *src = image.ptr<uchar>(j); for (int i = 0; i < image.cols; ++i) { if (src[i] != 255) { const int label = labeledImage(j, i); const int count = countPerLabel[label]; if (count < threshHold) src[i] = 255; } } } }
IGL_INLINE void igl::sort_new( const Eigen::PlainObjectBase<DerivedX>& X, const int dim, const bool ascending, Eigen::PlainObjectBase<DerivedY>& Y, Eigen::PlainObjectBase<DerivedIX>& IX) { // get number of rows (or columns) int num_inner = (dim == 1 ? X.rows() : X.cols() ); // Special case for swapping if(num_inner == 2) { return igl::sort2(X,dim,ascending,Y,IX); } using namespace Eigen; // get number of columns (or rows) int num_outer = (dim == 1 ? X.cols() : X.rows() ); // dim must be 2 or 1 assert(dim == 1 || dim == 2); // Resize output Y.resize(X.rows(),X.cols()); IX.resize(X.rows(),X.cols()); // idea is to process each column (or row) as a std vector // loop over columns (or rows) for(int i = 0; i<num_outer;i++) { Eigen::VectorXi ix; colon(0,num_inner-1,ix); // Sort the index map, using unsorted for comparison if(dim == 1) { std::sort( ix.data(), ix.data()+ix.size(), igl::IndexVectorLessThan<const typename DerivedX::ConstColXpr >(X.col(i))); }else { std::sort( ix.data(), ix.data()+ix.size(), igl::IndexVectorLessThan<const typename DerivedX::ConstRowXpr >(X.row(i))); } // if not ascending then reverse if(!ascending) { std::reverse(ix.data(),ix.data()+ix.size()); } for(int j = 0;j<num_inner;j++) { if(dim == 1) { Y(j,i) = X(ix[j],i); IX(j,i) = ix[j]; }else { Y(i,j) = X(i,ix[j]); IX(i,j) = ix[j]; } } } }
IGL_INLINE void igl::lexicographic_triangulation( const Eigen::PlainObjectBase<DerivedP>& P, Orient2D orient2D, Eigen::PlainObjectBase<DerivedF>& F) { typedef typename DerivedP::Scalar Scalar; const size_t num_pts = P.rows(); if (num_pts < 3) { throw "At least 3 points are required for triangulation!"; } // Sort points in lexicographic order. DerivedP ordered_P; Eigen::VectorXi order; igl::sortrows(P, true, ordered_P, order); std::vector<Eigen::Vector3i> faces; std::list<int> boundary; const Scalar p0[] = {ordered_P(0, 0), ordered_P(0, 1)}; const Scalar p1[] = {ordered_P(1, 0), ordered_P(1, 1)}; for (size_t i=2; i<num_pts; i++) { const Scalar curr_p[] = {ordered_P(i, 0), ordered_P(i, 1)}; if (faces.size() == 0) { // All points processed so far are collinear. // Check if the current point is collinear with every points before it. auto orientation = orient2D(p0, p1, curr_p); if (orientation != 0) { // Add a fan of triangles eminating from curr_p. if (orientation > 0) { for (size_t j=0; j<=i-2; j++) { faces.push_back({order[j], order[j+1], order[i]}); } } else if (orientation < 0) { for (size_t j=0; j<=i-2; j++) { faces.push_back({order[j+1], order[j], order[i]}); } } // Initialize current boundary. boundary.insert(boundary.end(), order.data(), order.data()+i+1); if (orientation < 0) { boundary.reverse(); } } } else { const size_t bd_size = boundary.size(); assert(bd_size >= 3); std::vector<short> orientations; for (auto itr=boundary.begin(); itr!=boundary.end(); itr++) { auto next_itr = std::next(itr, 1); if (next_itr == boundary.end()) { next_itr = boundary.begin(); } const Scalar bd_p0[] = {P(*itr, 0), P(*itr, 1)}; const Scalar bd_p1[] = {P(*next_itr, 0), P(*next_itr, 1)}; auto orientation = orient2D(bd_p0, bd_p1, curr_p); if (orientation < 0) { faces.push_back({*next_itr, *itr, order[i]}); } orientations.push_back(orientation); } auto left_itr = boundary.begin(); auto right_itr = boundary.begin(); auto curr_itr = boundary.begin(); for (size_t j=0; j<bd_size; j++, curr_itr++) { size_t prev = (j+bd_size-1) % bd_size; if (orientations[j] >= 0 && orientations[prev] < 0) { right_itr = curr_itr; } else if (orientations[j] < 0 && orientations[prev] >= 0) { left_itr = curr_itr; } } assert(left_itr != right_itr); for (auto itr=left_itr; itr!=right_itr; itr++) { if (itr == boundary.end()) itr = boundary.begin(); if (itr == right_itr) break; if (itr == left_itr || itr == right_itr) continue; itr = boundary.erase(itr); if (itr == boundary.begin()) { itr = boundary.end(); } else { itr--; } } if (right_itr == boundary.begin()) { assert(std::next(left_itr, 1) == boundary.end()); boundary.insert(boundary.end(), order[i]); } else { assert(std::next(left_itr, 1) == right_itr); boundary.insert(right_itr, order[i]); } } } const size_t num_faces = faces.size(); if (num_faces == 0) { // All input points are collinear. // Do nothing here. } else { F.resize(num_faces, 3); for (size_t i=0; i<num_faces; i++) { F.row(i) = faces[i]; } } }
int main(int argc, char * argv[]) { using namespace Eigen; using namespace std; using namespace igl; if(!readMESH("../shared/octopus-low.mesh",low.V,low.T,low.F)) { cout<<"failed to load mesh"<<endl; } if(!readMESH("../shared/octopus-high.mesh",high.V,high.T,high.F)) { cout<<"failed to load mesh"<<endl; } // Precomputation { Eigen::VectorXi b; { Eigen::VectorXi J = Eigen::VectorXi::LinSpaced(high.V.rows(),0,high.V.rows()-1); Eigen::VectorXd sqrD; Eigen::MatrixXd _2; cout<<"Finding closest points..."<<endl; igl::point_mesh_squared_distance(low.V,high.V,J,sqrD,b,_2); assert(sqrD.minCoeff() < 1e-7 && "low.V should exist in high.V"); } // force perfect positioning, rather have popping in low-res than high-res. // The correct/elaborate thing to do is express original low.V in terms of // linear interpolation (or extrapolation) via elements in (high.V,high.F) igl::slice(high.V,b,1,low.V); // list of points --> list of singleton lists std::vector<std::vector<int> > S; igl::matrix_to_list(b,S); cout<<"Computing weights for "<<b.size()<< " handles at "<<high.V.rows()<<" vertices..."<<endl; // Technically k should equal 3 for smooth interpolation in 3d, but 2 is // faster and looks OK const int k = 2; igl::biharmonic_coordinates(high.V,high.T,S,k,W); cout<<"Reindexing..."<<endl; // Throw away interior tet-vertices, keep weights and indices of boundary VectorXi I,J; igl::remove_unreferenced(high.V.rows(),high.F,I,J); for_each(high.F.data(),high.F.data()+high.F.size(),[&I](int & a){a=I(a);}); for_each(b.data(),b.data()+b.size(),[&I](int & a){a=I(a);}); igl::slice(MatrixXd(high.V),J,1,high.V); igl::slice(MatrixXd(W),J,1,W); } // Resize low res (high res will also be resized by affine precision of W) low.V.rowwise() -= low.V.colwise().mean(); low.V /= (low.V.maxCoeff()-low.V.minCoeff()); low.V.rowwise() += RowVector3d(0,1,0); low.U = low.V; high.U = high.V; arap_data.with_dynamics = true; arap_data.max_iter = 10; arap_data.energy = ARAP_ENERGY_TYPE_DEFAULT; arap_data.h = 0.01; arap_data.ym = 0.001; if(!arap_precomputation(low.V,low.T,3,VectorXi(),arap_data)) { cerr<<"arap_precomputation failed."<<endl; return EXIT_FAILURE; } // Constant gravitational force Eigen::SparseMatrix<double> M; igl::massmatrix(low.V,low.T,igl::MASSMATRIX_TYPE_DEFAULT,M); const size_t n = low.V.rows(); arap_data.f_ext = M * RowVector3d(0,-9.8,0).replicate(n,1); // Random initial velocities to wiggle things arap_data.vel = MatrixXd::Random(n,3); igl::viewer::Viewer viewer; // Create one huge mesh containing both meshes igl::cat(1,low.U,high.U,scene.U); igl::cat(1,low.F,MatrixXi(high.F.array()+low.V.rows()),scene.F); // Color each mesh viewer.data.set_mesh(scene.U,scene.F); MatrixXd C(scene.F.rows(),3); C<< RowVector3d(0.8,0.5,0.2).replicate(low.F.rows(),1), RowVector3d(0.3,0.4,1.0).replicate(high.F.rows(),1); viewer.data.set_colors(C); viewer.callback_key_pressed = [&](igl::viewer::Viewer & viewer,unsigned int key,int mods)->bool { switch(key) { default: return false; case ' ': viewer.core.is_animating = !viewer.core.is_animating; return true; case 'r': low.U = low.V; return true; } }; viewer.callback_pre_draw = [&](igl::viewer::Viewer & viewer)->bool { glEnable(GL_CULL_FACE); if(viewer.core.is_animating) { arap_solve(MatrixXd(0,3),arap_data,low.U); for(int v = 0;v<low.U.rows();v++) { // collide with y=0 plane const int y = 1; if(low.U(v,y) < 0) { low.U(v,y) = -low.U(v,y); // ~ coefficient of restitution const double cr = 1.1; arap_data.vel(v,y) = - arap_data.vel(v,y) / cr; } } scene.U.block(0,0,low.U.rows(),low.U.cols()) = low.U; high.U = W * (low.U.rowwise() + RowVector3d(1,0,0)); scene.U.block(low.U.rows(),0,high.U.rows(),high.U.cols()) = high.U; viewer.data.set_vertices(scene.U); viewer.data.compute_normals(); } return false; }; viewer.core.show_lines = false; viewer.core.is_animating = true; viewer.core.animation_max_fps = 30.; viewer.data.set_face_based(true); cout<<R"( [space] to toggle animation 'r' to reset positions )"; viewer.core.rotation_type = igl::viewer::ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP; viewer.launch(); }
int main(int argc, char *argv[]) { using namespace Eigen; using namespace std; igl::readOBJ(TUTORIAL_SHARED_PATH "/decimated-max.obj",V,F); U=V; // S(i) = j: j<0 (vertex i not in handle), j >= 0 (vertex i in handle j) VectorXi S; igl::readDMAT(TUTORIAL_SHARED_PATH "/decimated-max-selection.dmat",S); igl::colon<int>(0,V.rows()-1,b); b.conservativeResize(stable_partition( b.data(), b.data()+b.size(), [&S](int i)->bool{return S(i)>=0;})-b.data()); // Boundary conditions directly on deformed positions U_bc.resize(b.size(),V.cols()); V_bc.resize(b.size(),V.cols()); for(int bi = 0;bi<b.size();bi++) { V_bc.row(bi) = V.row(b(bi)); switch(S(b(bi))) { case 0: // Don't move handle 0 U_bc.row(bi) = V.row(b(bi)); break; case 1: // move handle 1 down U_bc.row(bi) = V.row(b(bi)) + RowVector3d(0,-50,0); break; case 2: default: // move other handles forward U_bc.row(bi) = V.row(b(bi)) + RowVector3d(0,0,-25); break; } } // Pseudo-color based on selection MatrixXd C(F.rows(),3); RowVector3d purple(80.0/255.0,64.0/255.0,255.0/255.0); RowVector3d gold(255.0/255.0,228.0/255.0,58.0/255.0); for(int f = 0;f<F.rows();f++) { if( S(F(f,0))>=0 && S(F(f,1))>=0 && S(F(f,2))>=0) { C.row(f) = purple; }else { C.row(f) = gold; } } // Plot the mesh with pseudocolors igl::opengl::glfw::Viewer viewer; viewer.data().set_mesh(U, F); viewer.data().show_lines = false; viewer.data().set_colors(C); viewer.core().trackball_angle = Eigen::Quaternionf(sqrt(2.0),0,sqrt(2.0),0); viewer.core().trackball_angle.normalize(); viewer.callback_pre_draw = &pre_draw; viewer.callback_key_down = &key_down; //viewer.core().is_animating = true; viewer.core().animation_max_fps = 30.; cout<< "Press [space] to toggle deformation."<<endl<< "Press 'd' to toggle between biharmonic surface or displacements."<<endl; viewer.launch(); }