main.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include <igl/read_triangle_mesh.h>
  2. #include <igl/parula.h>
  3. #include <igl/remove_unreferenced.h>
  4. #include <igl/opengl/glfw/Viewer.h>
  5. #include <igl/per_face_normals.h>
  6. #include <igl/orient_halfedges.h>
  7. #include <igl/cr_vector_laplacian.h>
  8. #include <igl/cr_vector_mass.h>
  9. #include <igl/crouzeix_raviart_cotmatrix.h>
  10. #include <igl/crouzeix_raviart_massmatrix.h>
  11. #include <igl/edge_midpoints.h>
  12. #include <igl/edge_vectors.h>
  13. #include <igl/average_from_edges_onto_vertices.h>
  14. #include <igl/min_quad_with_fixed.h>
  15. #include <igl/heat_geodesics.h>
  16. #include <Eigen/Core>
  17. #include <Eigen/SparseCholesky>
  18. #include <Eigen/Geometry>
  19. #include <iostream>
  20. #include <set>
  21. #include <limits>
  22. #include <stdlib.h>
  23. #include "tutorial_shared_path.h"
  24. int main(int argc, char * argv[])
  25. {
  26. typedef Eigen::SparseMatrix<double> SparseMat;
  27. typedef Eigen::Matrix<double, 1, 1> Vector1d;
  28. typedef Eigen::Matrix<int, 1, 1> Vector1i;
  29. //Constants used for smoothing
  30. const double howMuchToSmoothBy = 1e-1;
  31. const int howManySmoothingInterations = 50;
  32. //Read our mesh
  33. Eigen::MatrixXd V;
  34. Eigen::MatrixXi F;
  35. if(!igl::read_triangle_mesh
  36. (argc>1?argv[1]: TUTORIAL_SHARED_PATH "/cheburashka.off",V,F)) {
  37. std::cout << "Failed to load mesh." << std::endl;
  38. }
  39. //Compute vector Laplacian and mass matrix
  40. Eigen::MatrixXi E, oE;//Compute Laplacian and mass matrix
  41. SparseMat vecL, vecM;
  42. igl::cr_vector_mass(V, F, E, oE, vecM);
  43. igl::cr_vector_laplacian(V, F, E, oE, vecL);
  44. const int m = vecL.rows()/2; //The number of edges in the mesh
  45. //Convert the E / oE matrix format to list of edges / EMAP format required
  46. // by the functions constructing scalar Crouzeix-Raviart functions
  47. Eigen::MatrixXi Elist(m,2), EMAP(3*F.rows(),1);
  48. for(int i=0; i<F.rows(); ++i) {
  49. for(int j=0; j<3; ++j) {
  50. const int e = E(i,j);
  51. EMAP(i+j*F.rows()) = e;
  52. if(oE(i,j)>0) {
  53. Elist.row(e) << F(i, (j+1)%3), F(i, (j+2)%3);
  54. }
  55. }
  56. }
  57. SparseMat scalarL, scalarM;
  58. igl::crouzeix_raviart_massmatrix(V, F, Elist, EMAP, scalarM);
  59. igl::crouzeix_raviart_cotmatrix(V, F, Elist, EMAP, scalarL);
  60. //Compute edge midpoints & edge vectors
  61. Eigen::MatrixXd edgeMps, parVec, perpVec;
  62. igl::edge_midpoints(V, F, E, oE, edgeMps);
  63. igl::edge_vectors(V, F, E, oE, parVec, perpVec);
  64. //Perform the vector heat method
  65. const int initialIndex = 14319;
  66. const double initialPara=0.95, initialPerp=0.08;
  67. const double t = 0.01;
  68. SparseMat Aeq;
  69. Eigen::VectorXd Beq;
  70. Eigen::VectorXi known = Eigen::Vector2i(initialIndex, initialIndex+m);
  71. Eigen::VectorXd knownVals = Eigen::Vector2d(initialPara, initialPerp);
  72. Eigen::VectorXd Y0 = Eigen::VectorXd::Zero(2*m), Yt;
  73. Y0(initialIndex) = initialPara; Y0(initialIndex+m) = initialPerp;
  74. igl::min_quad_with_fixed
  75. (SparseMat(vecM+t*vecL), Eigen::VectorXd(-vecM*Y0), known, knownVals,
  76. Aeq, Beq, false, Yt);
  77. Eigen::VectorXd u0 = Eigen::VectorXd::Zero(m), ut;
  78. u0(initialIndex) = sqrt(initialPara*initialPara + initialPerp*initialPerp);
  79. Eigen::VectorXi knownScal = Vector1i(initialIndex);
  80. Eigen::VectorXd knownScalVals = Vector1d(u0(initialIndex));
  81. igl::min_quad_with_fixed
  82. (SparseMat(scalarM+t*scalarL), Eigen::VectorXd(-scalarM*u0), knownScal,
  83. knownScalVals, Aeq, Beq, false, ut);
  84. Eigen::VectorXd phi0 = Eigen::VectorXd::Zero(m), phit;
  85. phi0(initialIndex) = 1;
  86. Eigen::VectorXd knownScalValsPhi = Vector1d(1);
  87. igl::min_quad_with_fixed
  88. (SparseMat(scalarM+t*scalarL), Eigen::VectorXd(-scalarM*phi0), knownScal,
  89. knownScalValsPhi, Aeq, Beq, false, phit);
  90. Eigen::ArrayXd Xtfactor = ut.array() /
  91. (phit.array() * (Yt.array().segment(0,m)*Yt.array().segment(0,m)
  92. + Yt.array().segment(m,m)*Yt.array().segment(m,m)).sqrt());
  93. Eigen::VectorXd Xt(2*m);
  94. Xt.segment(0,m) = Xtfactor * Yt.segment(0,m).array();
  95. Xt.segment(m,m) = Xtfactor * Yt.segment(m,m).array();
  96. //Compute scalar heat colors
  97. igl::HeatGeodesicsData<double> hgData;
  98. igl::heat_geodesics_precompute(V, F, hgData);
  99. Eigen::VectorXd heatColor;
  100. Eigen::VectorXi gamma = Elist.row(initialIndex);
  101. igl::heat_geodesics_solve(hgData, gamma, heatColor);
  102. //Convert vector field for plotting
  103. Eigen::MatrixXd vecs(m, 3);
  104. for(int i=0; i<edgeMps.rows(); ++i) {
  105. vecs.row(i) = Xt(i)*parVec.row(i) + Xt(i+edgeMps.rows())*perpVec.row(i);
  106. }
  107. //Viewer that shows parallel transported vector
  108. igl::opengl::glfw::Viewer viewer;
  109. viewer.data().set_mesh(V,F);
  110. viewer.data().show_lines = false;
  111. viewer.data().set_data(heatColor.maxCoeff()-heatColor.array(), //invert colormap
  112. igl::COLOR_MAP_TYPE_VIRIDIS);
  113. const double s = 0.012; //How much to scale vectors during plotting
  114. Eigen::MatrixXd vecColors(m, 3);
  115. for(int i=0; i<m; ++i) {
  116. vecColors.row(i) << 0.1, 0.1, 0.1;
  117. }
  118. vecColors.row(initialIndex) << 0.9, 0.1, 0.1;
  119. viewer.data().add_edges(edgeMps, edgeMps + s*vecs, vecColors);
  120. std::cout << R"(The red vector is parallel transported to every point on the surface.
  121. The surface is shaded by geodesic distance from the red vector.
  122. )"
  123. << std::endl;
  124. viewer.launch();
  125. return 0;
  126. }