main.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #undef IGL_STATIC_LIBRARY
  2. #include <igl/readOBJ.h>
  3. #include <igl/readDMAT.h>
  4. #include <igl/viewer/Viewer.h>
  5. #include <igl/barycenter.h>
  6. #include <igl/avg_edge_length.h>
  7. #include <vector>
  8. #include <igl/n_polyvector.h>
  9. #include <igl/angle_bound_frame_fields.h>
  10. #include <stdlib.h>
  11. #include <igl/jet.h>
  12. // Input mesh
  13. Eigen::MatrixXd V;
  14. Eigen::MatrixXi F;
  15. // Face barycenters
  16. Eigen::MatrixXd B;
  17. // Quad mesh generated from smooth field
  18. Eigen::MatrixXd VQS;
  19. Eigen::MatrixXi FQS;
  20. Eigen::MatrixXi FQStri;
  21. Eigen::MatrixXd PQS0, PQS1, PQS2, PQS3;
  22. // Quad mesh generated from conjugate field
  23. Eigen::MatrixXd VQC;
  24. Eigen::MatrixXi FQC;
  25. Eigen::MatrixXi FQCtri;
  26. Eigen::MatrixXd PQC0, PQC1, PQC2, PQC3;
  27. // Scale for visualizing the fields
  28. double global_scale;
  29. // Input constraints
  30. Eigen::VectorXi isConstrained;
  31. Eigen::MatrixXd constraints;
  32. Eigen::MatrixXd smooth_pvf;
  33. Eigen::MatrixXd angle_bound_pvf;
  34. igl::AngleBoundFFSolverData<Eigen::MatrixXd, Eigen::MatrixXi> *csdata;
  35. int conjIter = 2;
  36. int totalConjIter = 0;
  37. double lambdaOrtho = .1;
  38. double lambdaInit = 100;
  39. double lambdaMultFactor = 1.5;
  40. bool doHardConstraints = false;
  41. bool showAngles = true;
  42. int curr_key = 0;
  43. void computeAngles(const Eigen::MatrixXd &ff, Eigen::VectorXd &angles)
  44. {
  45. angles.resize(ff.rows(),1);
  46. int num =0;
  47. for (int i =0; i<ff.rows(); ++i)
  48. {
  49. Eigen::RowVector3d u = (ff.block(i,0,1,3)); u.normalize();
  50. Eigen::RowVector3d v = (ff.block(i,3,1,3)); v.normalize();
  51. double s = (u.cross(v)).norm();
  52. double c = fabs(u.dot(v));
  53. angles[i] = atan2(s,c);
  54. num += (angles[i]<70*M_PI/180);
  55. }
  56. std::cerr<<"out of bound:"<<num<<std::endl;
  57. }
  58. void getAngleColor(const Eigen::MatrixXd &ff, Eigen::MatrixXd &C)
  59. {
  60. Eigen::VectorXd angles;
  61. computeAngles(ff, angles);
  62. Eigen::VectorXd val = 0.5*M_PI*Eigen::VectorXd::Ones(angles.rows(),1)-angles;
  63. igl::jet(val, 0, 20*M_PI/180., C);
  64. }
  65. bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
  66. {
  67. using namespace std;
  68. using namespace Eigen;
  69. // Highlight in red the constrained faces
  70. MatrixXd CC = MatrixXd::Constant(F.rows(),3,1);
  71. for (unsigned i=0; i<F.rows();++i)
  72. if (isConstrained[i])
  73. CC.row(i) << 1, 0, 0;
  74. if (key == 'c' || key == 'C')
  75. {
  76. showAngles = !showAngles;
  77. if (curr_key == 2)
  78. {
  79. MatrixXd C = CC;
  80. if (showAngles)
  81. getAngleColor(smooth_pvf, C);
  82. viewer.set_colors(C);
  83. }
  84. else if (curr_key == 3)
  85. {
  86. MatrixXd C = CC;
  87. if (showAngles)
  88. getAngleColor(angle_bound_pvf, C);
  89. viewer.set_colors(C);
  90. }
  91. return false;
  92. }
  93. if (key <'1' || key >'5')
  94. {
  95. return false;
  96. }
  97. viewer.clear();
  98. viewer.core.show_lines = false;
  99. viewer.core.show_texture = false;
  100. if (key == '1')
  101. {
  102. viewer.set_mesh(V, F);
  103. viewer.set_colors(CC);
  104. // Frame field constraints
  105. MatrixXd F1_t = MatrixXd::Zero(F.rows(),3);
  106. MatrixXd F2_t = MatrixXd::Zero(F.rows(),3);
  107. for (unsigned i=0; i<F.rows();++i)
  108. if (isConstrained[i])
  109. {
  110. F1_t.row(i) = constraints.block(i,0,1,3);
  111. F2_t.row(i) = constraints.block(i,3,1,3);
  112. }
  113. viewer.add_edges (B - global_scale*F1_t, B + global_scale*F1_t , Eigen::RowVector3d(0,0,1));
  114. viewer.add_edges (B - global_scale*F2_t, B + global_scale*F2_t , Eigen::RowVector3d(0,0,1));
  115. curr_key = 1;
  116. }
  117. if (key == '2')
  118. {
  119. viewer.set_mesh(V, F);
  120. viewer.add_edges (B - global_scale*smooth_pvf.block(0,0,F.rows(),3),
  121. B + global_scale*smooth_pvf.block(0,0,F.rows(),3),
  122. Eigen::RowVector3d(0,1,0));
  123. viewer.add_edges (B - global_scale*smooth_pvf.block(0,3,F.rows(),3),
  124. B + global_scale*smooth_pvf.block(0,3,F.rows(),3),
  125. Eigen::RowVector3d(0,1,0));
  126. MatrixXd C = CC;
  127. if (showAngles)
  128. getAngleColor(smooth_pvf, C);
  129. viewer.set_colors(C);
  130. curr_key = 2;
  131. }
  132. if (key == '3')
  133. {
  134. viewer.set_mesh(V, F);
  135. if (totalConjIter <50)
  136. {
  137. double lambdaOut;
  138. igl::angle_bound_frame_fields(*csdata,
  139. 70,
  140. isConstrained,
  141. angle_bound_pvf,
  142. angle_bound_pvf,
  143. conjIter,
  144. lambdaInit,
  145. lambdaMultFactor,
  146. doHardConstraints,
  147. &lambdaOut);
  148. totalConjIter += conjIter;
  149. lambdaInit = lambdaOut;
  150. }
  151. viewer.add_edges (B - global_scale*angle_bound_pvf.block(0,0,F.rows(),3),
  152. B + global_scale*angle_bound_pvf.block(0,0,F.rows(),3),
  153. Eigen::RowVector3d(0,1,0));
  154. viewer.add_edges (B - global_scale*angle_bound_pvf.block(0,3,F.rows(),3),
  155. B + global_scale*angle_bound_pvf.block(0,3,F.rows(),3),
  156. Eigen::RowVector3d(0,1,0));
  157. MatrixXd C = CC;
  158. if (showAngles)
  159. getAngleColor(angle_bound_pvf, C);
  160. viewer.set_colors(C);
  161. curr_key = 3;
  162. }
  163. if (key == '4')
  164. {
  165. viewer.set_mesh(VQS, FQStri);
  166. viewer.add_edges (PQS0, PQS1, Eigen::RowVector3d(0,0,0));
  167. viewer.add_edges (PQS1, PQS2, Eigen::RowVector3d(0,0,0));
  168. viewer.add_edges (PQS2, PQS3, Eigen::RowVector3d(0,0,0));
  169. viewer.add_edges (PQS3, PQS0, Eigen::RowVector3d(0,0,0));
  170. curr_key = 4;
  171. }
  172. if (key == '5')
  173. {
  174. viewer.set_mesh(VQC, FQCtri);
  175. viewer.add_edges (PQC0, PQC1, Eigen::RowVector3d(0,0,0));
  176. viewer.add_edges (PQC1, PQC2, Eigen::RowVector3d(0,0,0));
  177. viewer.add_edges (PQC2, PQC3, Eigen::RowVector3d(0,0,0));
  178. viewer.add_edges (PQC3, PQC0, Eigen::RowVector3d(0,0,0));
  179. curr_key = 5;
  180. }
  181. return false;
  182. }
  183. int main(int argc, char *argv[])
  184. {
  185. using namespace Eigen;
  186. using namespace std;
  187. // Load a mesh in OBJ format
  188. igl::readOBJ("../shared/teddy.obj", V, F);
  189. // Compute face barycenters
  190. igl::barycenter(V, F, B);
  191. // Compute scale for visualizing fields
  192. global_scale = .2*igl::avg_edge_length(V, F);
  193. // Load constraints
  194. MatrixXd temp;
  195. igl::readDMAT("../shared/teddy.dmat",temp);
  196. isConstrained = temp.block(0,0,temp.rows(),1).cast<int>();
  197. constraints = temp.block(0,1,temp.rows(),temp.cols()-1);
  198. // Interpolate to get a smooth field
  199. igl::n_polyvector(V, F, isConstrained, constraints, smooth_pvf);
  200. // Initialize conjugate field with smooth field
  201. csdata = new igl::AngleBoundFFSolverData<Eigen::MatrixXd,Eigen::MatrixXi>(V,F);
  202. angle_bound_pvf = smooth_pvf;
  203. // Load quad mesh generated by smooth field
  204. igl::readOBJ("../shared/teddy_smooth_remeshed.obj", VQS, FQS);
  205. FQStri.resize(2*FQS.rows(), 3);
  206. FQStri << FQS.col(0),FQS.col(1),FQS.col(2),
  207. FQS.col(2),FQS.col(3),FQS.col(0);
  208. // Load quad mesh generated by conjugate field
  209. igl::readOBJ("../shared/teddy_angle_bound_remeshed.obj", VQC, FQC);
  210. FQCtri.resize(2*FQC.rows(), 3);
  211. FQCtri << FQC.col(0),FQC.col(1),FQC.col(2),
  212. FQC.col(2),FQC.col(3),FQC.col(0);
  213. igl::slice( VQS, FQS.col(0), 1, PQS0);
  214. igl::slice( VQS, FQS.col(1), 1, PQS1);
  215. igl::slice( VQS, FQS.col(2), 1, PQS2);
  216. igl::slice( VQS, FQS.col(3), 1, PQS3);
  217. igl::slice( VQC, FQC.col(0), 1, PQC0);
  218. igl::slice( VQC, FQC.col(1), 1, PQC1);
  219. igl::slice( VQC, FQC.col(2), 1, PQC2);
  220. igl::slice( VQC, FQC.col(3), 1, PQC3);
  221. igl::Viewer viewer;
  222. // Plot the original mesh with a texture parametrization
  223. key_down(viewer,'1',0);
  224. // Launch the viewer
  225. viewer.callback_key_down = &key_down;
  226. viewer.launch();
  227. }