main.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #include <igl/pathinfo.h>
  2. #include <igl/readOBJ.h>
  3. #include <igl/readOFF.h>
  4. #include <igl/readMESH.h>
  5. #include <igl/tetgen/mesh_with_skeleton.h>
  6. #include <igl/faces_first.h>
  7. #include <igl/readTGF.h>
  8. #include <igl/launch_medit.h>
  9. #include <igl/boundary_conditions.h>
  10. #include <igl/bbw/bbw.h>
  11. #include <igl/writeDMAT.h>
  12. #include <igl/writeMESH.h>
  13. #include <igl/normalize_row_sums.h>
  14. #include <Eigen/Dense>
  15. #include <iostream>
  16. #include <string>
  17. // Whether medit program is install
  18. //#define WITH_MEDIT
  19. const char * USAGE=
  20. "Usage:\n"
  21. " ./bbw_demo shape{.obj|.off|.mesh} skeleton{.tgf|.bf}\n"
  22. ;
  23. // Read a surface mesh from a {.obj|.off|.mesh} files
  24. // Inputs:
  25. // mesh_filename path to {.obj|.off|.mesh} file
  26. // Outputs:
  27. // V #V by 3 list of mesh vertex positions
  28. // F #F by 3 list of triangle indices
  29. // Returns true only if successfuly able to read file
  30. bool load_mesh_from_file(
  31. const std::string mesh_filename,
  32. Eigen::MatrixXd & V,
  33. Eigen::MatrixXi & F)
  34. {
  35. using namespace std;
  36. using namespace igl;
  37. using namespace Eigen;
  38. string dirname, basename, extension, filename;
  39. pathinfo(mesh_filename,dirname,basename,extension,filename);
  40. transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
  41. bool success = false;
  42. if(extension == "obj")
  43. {
  44. success = readOBJ(mesh_filename,V,F);
  45. }else if(extension == "off")
  46. {
  47. success = readOFF(mesh_filename,V,F);
  48. }else if(extension == "mesh")
  49. {
  50. // Unused Tets read from .mesh file
  51. MatrixXi Tets;
  52. success = readMESH(mesh_filename,V,Tets,F);
  53. // We're not going to use any input tets. Only the surface
  54. if(Tets.size() > 0 && F.size() == 0)
  55. {
  56. // If Tets read, but no faces then use surface of tet volume
  57. }else
  58. {
  59. // Rearrange vertices so that faces come first
  60. VectorXi IM;
  61. faces_first(V,F,IM);
  62. // Dont' bother reordering Tets, but this is how one would:
  63. //Tets =
  64. // Tets.unaryExpr(bind1st(mem_fun( static_cast<VectorXi::Scalar&
  65. // (VectorXi::*)(VectorXi::Index)>(&VectorXi::operator())),
  66. // &IM)).eval();
  67. // Don't throw away any interior vertices, since user may want weights
  68. // there
  69. }
  70. }else
  71. {
  72. cerr<<"Error: Unknown shape file format extension: ."<<extension<<endl;
  73. return false;
  74. }
  75. return success;
  76. }
  77. // Load a skeleton (bones, points and cage edges) from a {.bf|.tgf} file
  78. //
  79. // Inputs:
  80. // skel_filename path to skeleton {.bf|.tgf} file
  81. // Outputs:
  82. // C # vertices by 3 list of vertex positions
  83. // P # point-handles list of point handle indices
  84. // BE # bone-edges by 2 list of bone-edge indices
  85. // CE # cage-edges by 2 list of cage-edge indices
  86. bool load_skeleton_from_file(
  87. const std::string skel_filename,
  88. Eigen::MatrixXd & C,
  89. Eigen::VectorXi & P,
  90. Eigen::MatrixXi & BE,
  91. Eigen::MatrixXi & CE)
  92. {
  93. using namespace std;
  94. using namespace igl;
  95. using namespace Eigen;
  96. string dirname, basename, extension, filename;
  97. pathinfo(skel_filename,dirname,basename,extension,filename);
  98. transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
  99. bool success = false;
  100. if(extension == "tgf")
  101. {
  102. // Phony space for unused all edges and pseudo edges
  103. MatrixXi E;
  104. MatrixXi PE;
  105. success = readTGF(skel_filename,C,E,P,BE,CE,PE);
  106. }else
  107. {
  108. cerr<<"Error: Unknown skeleton file format extension: ."<<extension<<endl;
  109. return false;
  110. }
  111. return success;
  112. }
  113. // Writes output files to /path/to/input/mesh-skeleton.dmat,
  114. // mesh-volume.dmat, mesh-volume.mesh if input mesh was
  115. // located at /path/to/input/mesh.obj and input skeleton was at
  116. // /other/path/to/input/skel.tgf
  117. //
  118. // Writes:
  119. //// mesh.dmat dense weights matrix corresponding to original input
  120. //// vertices V
  121. // mesh-volume.dmat dense weights matrix corresponding to all
  122. // vertices in tet mesh used for computation VV
  123. // mesh-volume.mesh Tet mesh used for computation
  124. //
  125. // Inputs:
  126. // mesh_filename path to {.obj|.off|.mesh} file
  127. // skel_filename path to skeleton {.bf|.tgf} file
  128. // V #V by 3 list of original mesh vertex positions
  129. // F #F by 3 list of original triangle indices
  130. // VV #VV by 3 list of tet-mesh vertex positions
  131. // TT #TT by 4 list of tetrahedra indices
  132. // FF #FF by 3 list of surface triangle indices
  133. // W #VV by #W weights matrix
  134. // Returns true on success
  135. bool save_output(
  136. const std::string mesh_filename,
  137. const std::string /*skel_filename*/,
  138. const Eigen::MatrixXd & V,
  139. const Eigen::MatrixXi & /*F*/,
  140. const Eigen::MatrixXd & VV,
  141. const Eigen::MatrixXi & TT,
  142. const Eigen::MatrixXi & FF,
  143. const Eigen::MatrixXd & W)
  144. {
  145. using namespace std;
  146. using namespace igl;
  147. using namespace Eigen;
  148. // build filename prefix out of input base names
  149. string prefix = "";
  150. {
  151. string dirname, basename, extension, filename;
  152. pathinfo(mesh_filename,dirname,basename,extension,filename);
  153. transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
  154. prefix += dirname + "/" + filename;
  155. }
  156. //{
  157. // string dirname, basename, extension, filename;
  158. // pathinfo(skel_filename,dirname,basename,extension,filename);
  159. // transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
  160. // prefix += "-" + filename;
  161. //}
  162. // Keep track if any fail
  163. bool success = true;
  164. //// Weights matrix for just V. Assumes V prefaces VV
  165. //MatrixXd WV = W.block(0,0,V.rows(),W.cols());
  166. //// write dmat
  167. //success &= writeDMAT(prefix + ".dmat",WV);
  168. // write volume weights dmat
  169. success &= writeDMAT(prefix + "-volume.dmat",W);
  170. // write volume mesh
  171. success &= writeMESH(prefix + "-volume.mesh",VV,TT,FF);
  172. //// write surface OBJ with pseudocolor
  173. return success;
  174. }
  175. int main(int argc, char * argv[])
  176. {
  177. using namespace std;
  178. using namespace Eigen;
  179. using namespace igl;
  180. string mesh_filename = "examples/brick.obj";
  181. string skeleton_filename = "examples/brick.tgf";
  182. if(argc<3)
  183. {
  184. cerr<<USAGE<<endl;
  185. cout<<endl<<"Using defaults..."<<endl;
  186. }else
  187. {
  188. mesh_filename = argv[1];
  189. skeleton_filename = argv[2];
  190. }
  191. // #V by 3 list of mesh vertex positions
  192. MatrixXd V;
  193. // #F by 3 list of triangle indices
  194. MatrixXi F;
  195. // load mesh from .obj, .off or .mesh
  196. if(!load_mesh_from_file(mesh_filename,V,F))
  197. {
  198. return 1;
  199. }
  200. // "Skeleton" (handles) descriptors:
  201. // List of control and joint (bone endpoint) positions
  202. MatrixXd C;
  203. // List of point handles indexing C
  204. VectorXi P;
  205. // List of bone edges indexing C
  206. MatrixXi BE;
  207. // List of cage edges indexing *P*
  208. MatrixXi CE;
  209. // load skeleton (.tgf or .bf)
  210. if(!load_skeleton_from_file(skeleton_filename,C,P,BE,CE))
  211. {
  212. return 1;
  213. }
  214. // Mesh with samples on skeleton
  215. // New vertices of tet mesh, V prefaces VV
  216. MatrixXd VV;
  217. // Tetrahedra
  218. MatrixXi TT;
  219. // New surface faces FF
  220. MatrixXi FF;
  221. if(!mesh_with_skeleton(V,F,C,P,BE,CE,10,VV,TT,FF))
  222. {
  223. return 1;
  224. }
  225. #ifdef WITH_MEDIT
  226. // If you have medit installed then it's convenient to visualize the tet mesh
  227. // at this point
  228. launch_medit(VV,TT,FF,false);
  229. #endif
  230. // Compute boundary conditions (aka fixed value constraints)
  231. // List of boundary indices (aka fixed value indices into VV)
  232. VectorXi b;
  233. // List of boundary conditions of each weight function
  234. MatrixXd bc;
  235. if(!boundary_conditions(VV,TT,C,P,BE,CE,b,bc))
  236. {
  237. return 1;
  238. }
  239. cout<<"b=["<<b<<"];"<<endl;
  240. cout<<"bc=["<<bc<<"];"<<endl;
  241. // compute BBW
  242. // Default bbw data and flags
  243. BBWData bbw_data;
  244. bbw_data.qp_solver = QP_SOLVER_IGL_ACTIVE_SET;
  245. //bbw_data.qp_solver = QP_SOLVER_MOSEK;
  246. // Weights matrix
  247. MatrixXd W;
  248. if(!bbw(VV,TT,b,bc,bbw_data,W))
  249. {
  250. return 1;
  251. }
  252. // Normalize weights to sum to one
  253. normalize_row_sums(W,W);
  254. // Save output
  255. save_output(mesh_filename,skeleton_filename,V,F,VV,TT,FF,W);
  256. return 0;
  257. }