readMSH.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. //
  9. #include "readMSH.h"
  10. #include <iostream>
  11. #include <sstream>
  12. #include <fstream>
  13. #include <vector>
  14. #include <map>
  15. template <
  16. typename DerivedV,
  17. typename DerivedT>
  18. IGL_INLINE bool igl::readMSH(
  19. const std::string & filename,
  20. Eigen::PlainObjectBase<DerivedV> & V,
  21. Eigen::PlainObjectBase<DerivedT> & T)
  22. {
  23. // https://github.com/Yixin-Hu/TetWild/blob/master/pymesh/MshSaver.cpp
  24. // Original copyright: /* This file is part of PyMesh. Copyright (c) 2015 by Qingnan Zhou */
  25. typedef typename DerivedV::Scalar Float;
  26. typedef Eigen::Matrix<Float,Eigen::Dynamic,1> VectorF;
  27. typedef Eigen::Matrix<int,Eigen::Dynamic,1> VectorI;
  28. typedef std::map<std::string, VectorF> FieldMap;
  29. typedef std::vector<std::string> FieldNames;
  30. VectorF m_nodes;
  31. VectorI m_elements;
  32. FieldMap m_node_fields;
  33. FieldMap m_element_fields;
  34. bool m_binary;
  35. size_t m_data_size;
  36. size_t m_nodes_per_element;
  37. size_t m_element_type;
  38. std::ifstream fin(filename.c_str(), std::ios::in | std::ios::binary);
  39. if (!fin.is_open())
  40. {
  41. std::stringstream err_msg;
  42. err_msg << "failed to open file \"" << filename << "\"";
  43. return false;
  44. }
  45. // Parse header
  46. std::string buf;
  47. double version;
  48. int type;
  49. fin >> buf;
  50. const auto invalid_format = []()->bool
  51. {
  52. assert(false && "Invalid format");
  53. return false;
  54. };
  55. const auto not_implemented = []()->bool
  56. {
  57. assert(false && "Not implemented");
  58. return false;
  59. };
  60. if (buf != "$MeshFormat") { return invalid_format(); }
  61. fin >> version >> type >> m_data_size;
  62. m_binary = (type == 1);
  63. // Some sanity check.
  64. if (m_data_size != 8) {
  65. std::cerr << "Error: data size must be 8 bytes." << std::endl;
  66. return not_implemented();
  67. }
  68. if (sizeof(int) != 4) {
  69. std::cerr << "Error: code must be compiled with int size 4 bytes." << std::endl;
  70. return not_implemented();
  71. }
  72. const auto eat_white_space = [](std::ifstream& fin)
  73. {
  74. char next = fin.peek();
  75. while (next == '\n' || next == ' ' || next == '\t' || next == '\r')
  76. {
  77. fin.get();
  78. next = fin.peek();
  79. }
  80. };
  81. // Read in extra info from binary header.
  82. if (m_binary) {
  83. int one;
  84. eat_white_space(fin);
  85. fin.read(reinterpret_cast<char*>(&one), sizeof(int));
  86. if (one != 1) {
  87. std::cerr << "Warning: binary msh file " << filename
  88. << " is saved with different endianness than this machine."
  89. << std::endl;
  90. return not_implemented();
  91. }
  92. }
  93. fin >> buf;
  94. if (buf != "$EndMeshFormat") { return not_implemented(); }
  95. const auto num_nodes_per_elem_type = [](int elem_type)->int
  96. {
  97. size_t nodes_per_element = 0;
  98. switch (elem_type) {
  99. case 2:
  100. nodes_per_element = 3; // Triangle
  101. break;
  102. case 3:
  103. nodes_per_element = 4; // Quad
  104. break;
  105. case 4:
  106. nodes_per_element = 4; // Tet
  107. break;
  108. case 5:
  109. nodes_per_element = 8; // hexahedron
  110. break;
  111. default:
  112. assert(false && "not implemented");
  113. nodes_per_element = -1;
  114. break;
  115. }
  116. return nodes_per_element;
  117. };
  118. const auto parse_nodes = [&](std::ifstream& fin)
  119. {
  120. size_t num_nodes;
  121. fin >> num_nodes;
  122. m_nodes.resize(num_nodes*3);
  123. if (m_binary) {
  124. size_t num_bytes = (4+3*m_data_size) * num_nodes;
  125. char* data = new char[num_bytes];
  126. eat_white_space(fin);
  127. fin.read(data, num_bytes);
  128. for (size_t i=0; i<num_nodes; i++) {
  129. int node_idx = *reinterpret_cast<int*> (&data[i*(4+3*m_data_size)]) - 1;
  130. m_nodes[node_idx*3] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4]);
  131. m_nodes[node_idx*3+1] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4 + m_data_size]);
  132. m_nodes[node_idx*3+2] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4 + 2*m_data_size]);
  133. }
  134. delete [] data;
  135. } else {
  136. int node_idx;
  137. for (size_t i=0; i<num_nodes; i++) {
  138. fin >> node_idx;
  139. node_idx -= 1;
  140. fin >> m_nodes[node_idx*3]
  141. >> m_nodes[node_idx*3+1]
  142. >> m_nodes[node_idx*3+2];
  143. }
  144. }
  145. };
  146. const auto parse_elements = [&](std::ifstream& fin)
  147. {
  148. size_t num_elements;
  149. fin >> num_elements;
  150. // Tmp storage of elements;
  151. std::vector<int> triangle_element_idx;
  152. std::vector<int> triangle_elements;
  153. std::vector<int> quad_element_idx;
  154. std::vector<int> quad_elements;
  155. std::vector<int> tet_element_idx;
  156. std::vector<int> tet_elements;
  157. std::vector<int> hex_element_idx;
  158. std::vector<int> hex_elements;
  159. auto get_element_storage = [&](int elem_type) -> std::vector<int>* {
  160. switch (elem_type) {
  161. default:
  162. assert(false && "Unsupported element type encountered");
  163. case 2:
  164. return &triangle_elements;
  165. case 3:
  166. return &quad_elements;
  167. case 4:
  168. return &tet_elements;
  169. case 5:
  170. return &hex_elements;
  171. };
  172. };
  173. auto get_element_idx_storage = [&](int elem_type) -> std::vector<int>* {
  174. switch (elem_type) {
  175. default:
  176. assert(false && "Unsupported element type encountered");
  177. case 2:
  178. return &triangle_element_idx;
  179. case 3:
  180. return &quad_element_idx;
  181. case 4:
  182. return &tet_element_idx;
  183. case 5:
  184. return &hex_element_idx;
  185. };
  186. };
  187. size_t nodes_per_element;
  188. int glob_elem_type = -1;
  189. if (m_binary)
  190. {
  191. eat_white_space(fin);
  192. int elem_read = 0;
  193. while (elem_read < num_elements) {
  194. // Parse element header.
  195. int elem_type, num_elems, num_tags;
  196. fin.read((char*)&elem_type, sizeof(int));
  197. fin.read((char*)&num_elems, sizeof(int));
  198. fin.read((char*)&num_tags, sizeof(int));
  199. nodes_per_element = num_nodes_per_elem_type(elem_type);
  200. std::vector<int>& elements = *get_element_storage(elem_type);
  201. std::vector<int>& element_idx = *get_element_idx_storage(elem_type);
  202. for (size_t i=0; i<num_elems; i++) {
  203. int elem_idx;
  204. fin.read((char*)&elem_idx, sizeof(int));
  205. elem_idx -= 1;
  206. element_idx.push_back(elem_idx);
  207. // Eat up tags.
  208. for (size_t j=0; j<num_tags; j++) {
  209. int tag;
  210. fin.read((char*)&tag, sizeof(int));
  211. }
  212. // Element values.
  213. for (size_t j=0; j<nodes_per_element; j++) {
  214. int idx;
  215. fin.read((char*)&idx, sizeof(int));
  216. elements.push_back(idx-1);
  217. }
  218. }
  219. elem_read += num_elems;
  220. }
  221. } else
  222. {
  223. for (size_t i=0; i<num_elements; i++) {
  224. // Parse per element header
  225. int elem_num, elem_type, num_tags;
  226. fin >> elem_num >> elem_type >> num_tags;
  227. for (size_t j=0; j<num_tags; j++) {
  228. int tag;
  229. fin >> tag;
  230. }
  231. nodes_per_element = num_nodes_per_elem_type(elem_type);
  232. std::vector<int>& elements = *get_element_storage(elem_type);
  233. std::vector<int>& element_idx = *get_element_idx_storage(elem_type);
  234. elem_num -= 1;
  235. element_idx.push_back(elem_num);
  236. // Parse node idx.
  237. for (size_t j=0; j<nodes_per_element; j++) {
  238. int idx;
  239. fin >> idx;
  240. elements.push_back(idx-1); // msh index starts from 1.
  241. }
  242. }
  243. }
  244. auto copy_to_array = [&](
  245. const std::vector<int>& elements,
  246. const int nodes_per_element) {
  247. const size_t num_elements = elements.size() / nodes_per_element;
  248. if (elements.size() % nodes_per_element != 0) {
  249. assert(false && "parsing element failed");
  250. return;
  251. }
  252. m_elements.resize(elements.size());
  253. std::copy(elements.begin(), elements.end(), m_elements.data());
  254. m_nodes_per_element = nodes_per_element;
  255. };
  256. if (!tet_elements.empty()) {
  257. copy_to_array(tet_elements, 4);
  258. m_element_type = 4;
  259. } else if (!hex_elements.empty()) {
  260. copy_to_array(hex_elements, 8);
  261. m_element_type = 5;
  262. } else if (!triangle_elements.empty()) {
  263. copy_to_array(triangle_elements, 3);
  264. m_element_type = 2;
  265. } else if (!quad_elements.empty()) {
  266. copy_to_array(quad_elements, 4);
  267. m_element_type = 3;
  268. } else {
  269. // 0 elements, use triangle by default.
  270. m_element_type = 2;
  271. }
  272. };
  273. const auto parse_element_field = [&](std::ifstream& fin)
  274. {
  275. size_t num_string_tags;
  276. size_t num_real_tags;
  277. size_t num_int_tags;
  278. fin >> num_string_tags;
  279. std::string* str_tags = new std::string[num_string_tags];
  280. for (size_t i=0; i<num_string_tags; i++) {
  281. eat_white_space(fin);
  282. if (fin.peek() == '\"') {
  283. // Handle field name between quoates.
  284. char buf[128];
  285. fin.get(); // remove the quote at the beginning.
  286. fin.getline(buf, 128, '\"');
  287. str_tags[i] = std::string(buf);
  288. } else {
  289. fin >> str_tags[i];
  290. }
  291. }
  292. fin >> num_real_tags;
  293. Float* real_tags = new Float[num_real_tags];
  294. for (size_t i=0; i<num_real_tags; i++)
  295. fin >> real_tags[i];
  296. fin >> num_int_tags;
  297. int* int_tags = new int[num_int_tags];
  298. for (size_t i=0; i<num_int_tags; i++)
  299. fin >> int_tags[i];
  300. if (num_string_tags <= 0 || num_int_tags <= 2) { assert(false && "invalid format"); return; }
  301. std::string fieldname = str_tags[0];
  302. int num_components = int_tags[1];
  303. int num_entries = int_tags[2];
  304. VectorF field(num_entries * num_components);
  305. delete [] str_tags;
  306. delete [] real_tags;
  307. delete [] int_tags;
  308. if (m_binary) {
  309. size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
  310. char* data = new char[num_bytes];
  311. eat_white_space(fin);
  312. fin.read(data, num_bytes);
  313. for (size_t i=0; i<num_entries; i++) {
  314. int elem_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
  315. elem_idx -= 1;
  316. size_t base_idx = i*(4+num_components*m_data_size) + 4;
  317. for (size_t j=0; j<num_components; j++) {
  318. field[elem_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
  319. }
  320. }
  321. delete [] data;
  322. } else {
  323. int elem_idx;
  324. for (size_t i=0; i<num_entries; i++) {
  325. fin >> elem_idx;
  326. elem_idx -= 1;
  327. for (size_t j=0; j<num_components; j++) {
  328. fin >> field[elem_idx * num_components + j];
  329. }
  330. }
  331. }
  332. m_element_fields[fieldname] = field;
  333. };
  334. const auto parse_node_field = [&](std::ifstream& fin)
  335. {
  336. size_t num_string_tags;
  337. size_t num_real_tags;
  338. size_t num_int_tags;
  339. fin >> num_string_tags;
  340. std::string* str_tags = new std::string[num_string_tags];
  341. for (size_t i=0; i<num_string_tags; i++) {
  342. eat_white_space(fin);
  343. if (fin.peek() == '\"') {
  344. // Handle field name between quoates.
  345. char buf[128];
  346. fin.get(); // remove the quote at the beginning.
  347. fin.getline(buf, 128, '\"');
  348. str_tags[i] = std::string(buf);
  349. } else {
  350. fin >> str_tags[i];
  351. }
  352. }
  353. fin >> num_real_tags;
  354. Float* real_tags = new Float[num_real_tags];
  355. for (size_t i=0; i<num_real_tags; i++)
  356. fin >> real_tags[i];
  357. fin >> num_int_tags;
  358. int* int_tags = new int[num_int_tags];
  359. for (size_t i=0; i<num_int_tags; i++)
  360. fin >> int_tags[i];
  361. if (num_string_tags <= 0 || num_int_tags <= 2) { assert(false && "invalid format"); return; }
  362. std::string fieldname = str_tags[0];
  363. int num_components = int_tags[1];
  364. int num_entries = int_tags[2];
  365. VectorF field(num_entries * num_components);
  366. delete [] str_tags;
  367. delete [] real_tags;
  368. delete [] int_tags;
  369. if (m_binary) {
  370. size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
  371. char* data = new char[num_bytes];
  372. eat_white_space(fin);
  373. fin.read(data, num_bytes);
  374. for (size_t i=0; i<num_entries; i++) {
  375. int node_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
  376. node_idx -= 1;
  377. size_t base_idx = i*(4+num_components*m_data_size) + 4;
  378. for (size_t j=0; j<num_components; j++) {
  379. field[node_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
  380. }
  381. }
  382. delete [] data;
  383. } else {
  384. int node_idx;
  385. for (size_t i=0; i<num_entries; i++) {
  386. fin >> node_idx;
  387. node_idx -= 1;
  388. for (size_t j=0; j<num_components; j++) {
  389. fin >> field[node_idx * num_components + j];
  390. }
  391. }
  392. }
  393. m_node_fields[fieldname] = field;
  394. };
  395. const auto parse_unknown_field = [](std::ifstream& fin,
  396. const std::string& fieldname)
  397. {
  398. std::cerr << "Warning: \"" << fieldname << "\" not supported yet. Ignored." << std::endl;
  399. std::string endmark = fieldname.substr(0,1) + "End"
  400. + fieldname.substr(1,fieldname.size()-1);
  401. std::string buf("");
  402. while (buf != endmark && !fin.eof()) {
  403. fin >> buf;
  404. }
  405. };
  406. while (!fin.eof()) {
  407. buf.clear();
  408. fin >> buf;
  409. if (buf == "$Nodes") {
  410. parse_nodes(fin);
  411. fin >> buf;
  412. if (buf != "$EndNodes") { return invalid_format(); }
  413. } else if (buf == "$Elements") {
  414. parse_elements(fin);
  415. fin >> buf;
  416. if (buf != "$EndElements") { return invalid_format(); }
  417. } else if (buf == "$NodeData") {
  418. parse_node_field(fin);
  419. fin >> buf;
  420. if (buf != "$EndNodeData") { return invalid_format(); }
  421. } else if (buf == "$ElementData") {
  422. parse_element_field(fin);
  423. fin >> buf;
  424. if (buf != "$EndElementData") { return invalid_format(); }
  425. } else if (fin.eof()) {
  426. break;
  427. } else {
  428. parse_unknown_field(fin, buf);
  429. }
  430. }
  431. fin.close();
  432. V.resize(m_nodes.rows()/3,3);
  433. for (int i = 0; i < m_nodes.rows() / 3; i++)
  434. {
  435. for (int j = 0; j < 3; j++)
  436. {
  437. V(i,j) = m_nodes(i * 3 + j);
  438. }
  439. }
  440. int ss = num_nodes_per_elem_type(m_element_type);
  441. T.resize(m_elements.rows()/ss,ss);
  442. for (int i = 0; i < m_elements.rows() / ss; i++)
  443. {
  444. for (int j = 0; j < ss; j++)
  445. {
  446. T(i, j) = m_elements(i * ss + j);
  447. }
  448. }
  449. return true;
  450. }
  451. #ifdef IGL_STATIC_LIBRARY
  452. // Explicit template instantiation
  453. #endif