readMSH.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  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) {
  301. delete[] str_tags;
  302. delete[] real_tags;
  303. delete[] int_tags;
  304. assert(false && "invalid format");
  305. return;
  306. }
  307. std::string fieldname = str_tags[0];
  308. int num_components = int_tags[1];
  309. int num_entries = int_tags[2];
  310. VectorF field(num_entries * num_components);
  311. delete [] str_tags;
  312. delete [] real_tags;
  313. delete [] int_tags;
  314. if (m_binary) {
  315. size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
  316. char* data = new char[num_bytes];
  317. eat_white_space(fin);
  318. fin.read(data, num_bytes);
  319. for (size_t i=0; i<num_entries; i++) {
  320. int elem_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
  321. elem_idx -= 1;
  322. size_t base_idx = i*(4+num_components*m_data_size) + 4;
  323. for (size_t j=0; j<num_components; j++) {
  324. field[elem_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
  325. }
  326. }
  327. delete [] data;
  328. } else {
  329. int elem_idx;
  330. for (size_t i=0; i<num_entries; i++) {
  331. fin >> elem_idx;
  332. elem_idx -= 1;
  333. for (size_t j=0; j<num_components; j++) {
  334. fin >> field[elem_idx * num_components + j];
  335. }
  336. }
  337. }
  338. m_element_fields[fieldname] = field;
  339. };
  340. const auto parse_node_field = [&](std::ifstream& fin)
  341. {
  342. size_t num_string_tags;
  343. size_t num_real_tags;
  344. size_t num_int_tags;
  345. fin >> num_string_tags;
  346. std::string* str_tags = new std::string[num_string_tags];
  347. for (size_t i=0; i<num_string_tags; i++) {
  348. eat_white_space(fin);
  349. if (fin.peek() == '\"') {
  350. // Handle field name between quoates.
  351. char buf[128];
  352. fin.get(); // remove the quote at the beginning.
  353. fin.getline(buf, 128, '\"');
  354. str_tags[i] = std::string(buf);
  355. } else {
  356. fin >> str_tags[i];
  357. }
  358. }
  359. fin >> num_real_tags;
  360. Float* real_tags = new Float[num_real_tags];
  361. for (size_t i=0; i<num_real_tags; i++)
  362. fin >> real_tags[i];
  363. fin >> num_int_tags;
  364. int* int_tags = new int[num_int_tags];
  365. for (size_t i=0; i<num_int_tags; i++)
  366. fin >> int_tags[i];
  367. if (num_string_tags <= 0 || num_int_tags <= 2) {
  368. delete[] str_tags;
  369. delete[] real_tags;
  370. delete[] int_tags;
  371. assert(false && "invalid format");
  372. return;
  373. }
  374. std::string fieldname = str_tags[0];
  375. int num_components = int_tags[1];
  376. int num_entries = int_tags[2];
  377. VectorF field(num_entries * num_components);
  378. delete [] str_tags;
  379. delete [] real_tags;
  380. delete [] int_tags;
  381. if (m_binary) {
  382. size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
  383. char* data = new char[num_bytes];
  384. eat_white_space(fin);
  385. fin.read(data, num_bytes);
  386. for (size_t i=0; i<num_entries; i++) {
  387. int node_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
  388. node_idx -= 1;
  389. size_t base_idx = i*(4+num_components*m_data_size) + 4;
  390. for (size_t j=0; j<num_components; j++) {
  391. field[node_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
  392. }
  393. }
  394. delete [] data;
  395. } else {
  396. int node_idx;
  397. for (size_t i=0; i<num_entries; i++) {
  398. fin >> node_idx;
  399. node_idx -= 1;
  400. for (size_t j=0; j<num_components; j++) {
  401. fin >> field[node_idx * num_components + j];
  402. }
  403. }
  404. }
  405. m_node_fields[fieldname] = field;
  406. };
  407. const auto parse_unknown_field = [](std::ifstream& fin,
  408. const std::string& fieldname)
  409. {
  410. std::cerr << "Warning: \"" << fieldname << "\" not supported yet. Ignored." << std::endl;
  411. std::string endmark = fieldname.substr(0,1) + "End"
  412. + fieldname.substr(1,fieldname.size()-1);
  413. std::string buf("");
  414. while (buf != endmark && !fin.eof()) {
  415. fin >> buf;
  416. }
  417. };
  418. while (!fin.eof()) {
  419. buf.clear();
  420. fin >> buf;
  421. if (buf == "$Nodes") {
  422. parse_nodes(fin);
  423. fin >> buf;
  424. if (buf != "$EndNodes") { return invalid_format(); }
  425. } else if (buf == "$Elements") {
  426. parse_elements(fin);
  427. fin >> buf;
  428. if (buf != "$EndElements") { return invalid_format(); }
  429. } else if (buf == "$NodeData") {
  430. parse_node_field(fin);
  431. fin >> buf;
  432. if (buf != "$EndNodeData") { return invalid_format(); }
  433. } else if (buf == "$ElementData") {
  434. parse_element_field(fin);
  435. fin >> buf;
  436. if (buf != "$EndElementData") { return invalid_format(); }
  437. } else if (fin.eof()) {
  438. break;
  439. } else {
  440. parse_unknown_field(fin, buf);
  441. }
  442. }
  443. fin.close();
  444. V.resize(m_nodes.rows()/3,3);
  445. for (int i = 0; i < m_nodes.rows() / 3; i++)
  446. {
  447. for (int j = 0; j < 3; j++)
  448. {
  449. V(i,j) = m_nodes(i * 3 + j);
  450. }
  451. }
  452. int ss = num_nodes_per_elem_type(m_element_type);
  453. T.resize(m_elements.rows()/ss,ss);
  454. for (int i = 0; i < m_elements.rows() / ss; i++)
  455. {
  456. for (int j = 0; j < ss; j++)
  457. {
  458. T(i, j) = m_elements(i * ss + j);
  459. }
  460. }
  461. return true;
  462. }
  463. #ifdef IGL_STATIC_LIBRARY
  464. // Explicit template instantiation
  465. #endif