MshSaver.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. // based on MSH writer from PyMesh
  2. // Copyright (c) 2015 Qingnan Zhou <[email protected]>
  3. // Copyright (C) 2020 Vladimir Fonov <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla
  6. // Public License v. 2.0. If a copy of the MPL was not distributed
  7. // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "MshSaver.h"
  9. #include <cassert>
  10. #include <iostream>
  11. #include <sstream>
  12. #include <exception>
  13. IGL_INLINE igl::MshSaver::MshSaver(const std::string& filename, bool binary) :
  14. m_binary(binary), m_num_nodes(0), m_num_elements(0) {
  15. if (!m_binary) {
  16. fout.open(filename.c_str(), std::fstream::out);
  17. } else {
  18. fout.open(filename.c_str(), std::fstream::binary);
  19. }
  20. if (!fout) {
  21. std::stringstream err_msg;
  22. err_msg << "Error opening " << filename << " to write msh file." << std::endl;
  23. throw std::ios_base::failure(err_msg.str());
  24. }
  25. }
  26. IGL_INLINE igl::MshSaver::~MshSaver() {
  27. fout.close();
  28. }
  29. IGL_INLINE void igl::MshSaver::save_mesh(
  30. const FloatVector& nodes,
  31. const IndexVector& elements,
  32. const IntVector& element_lengths,
  33. const IntVector& element_types,
  34. const IntVector& element_tags
  35. ) {
  36. save_header();
  37. save_nodes(nodes);
  38. save_elements(elements, element_lengths, element_types, element_tags );
  39. }
  40. IGL_INLINE void igl::MshSaver::save_header() {
  41. if (!m_binary) {
  42. fout << "$MeshFormat" << std::endl;
  43. fout << "2.2 0 " << sizeof(double) << std::endl;
  44. fout << "$EndMeshFormat" << std::endl;
  45. fout.precision(17);
  46. } else {
  47. fout << "$MeshFormat" << std::endl;
  48. fout << "2.2 1 " << sizeof(double) << std::endl;
  49. int one = 1;
  50. fout.write((char*)&one, sizeof(int));
  51. fout << "\n$EndMeshFormat" << std::endl;
  52. }
  53. fout.flush();
  54. }
  55. IGL_INLINE void igl::MshSaver::save_nodes(const FloatVector& nodes) {
  56. // Save nodes.
  57. // 3D hadrcoded
  58. m_num_nodes = nodes.size() / 3;
  59. fout << "$Nodes" << std::endl;
  60. fout << m_num_nodes << std::endl;
  61. if (!m_binary) {
  62. for (size_t i=0; i<nodes.size(); i+=3) {
  63. //const VectorF& v = nodes.segment(i,m_dim);
  64. int node_idx = i/3 + 1;
  65. fout << node_idx << " " << nodes[i] << " " << nodes[i+1] << " " << nodes[i+2] << std::endl;
  66. }
  67. } else {
  68. for (size_t i=0; i<nodes.size(); i+=3) {
  69. //const VectorF& v = nodes.segment(i,m_dim);
  70. int node_idx = i/3 + 1;
  71. fout.write((const char*)&node_idx, sizeof(int));
  72. fout.write((const char*)&nodes[i], sizeof(Float)*3);
  73. }
  74. }
  75. fout << "$EndNodes" << std::endl;
  76. fout.flush();
  77. }
  78. IGL_INLINE void igl::MshSaver::save_elements(const IndexVector& elements,
  79. const IntVector& element_lengths,
  80. const IntVector& element_types,
  81. const IntVector& element_tags)
  82. {
  83. m_num_elements = element_tags.size();
  84. assert(element_lengths.size() == element_types.size() );
  85. assert(element_lengths.size() == element_tags.size() );
  86. // TODO: sum up all lengths
  87. // Save elements.
  88. // node inxes are 1-based
  89. fout << "$Elements" << std::endl;
  90. fout << m_num_elements << std::endl;
  91. if (m_num_elements > 0) {
  92. //int elem_type = el_type;
  93. //int tags = 0;
  94. if (!m_binary) {
  95. size_t el_ptr=0;
  96. for (size_t i=0;i<m_num_elements;++i) {
  97. int elem_num = (int) i + 1;
  98. ///VectorI elem = elements.segment(i, nodes_per_element) + VectorI::Ones(nodes_per_element);
  99. // hardcoded: duplicate tags (I don't know why)
  100. fout << elem_num << " " << element_types[i] << " " << 2 << " "<< element_tags[i] << " "<< element_tags[i] << " ";
  101. for (size_t j=0; j<element_lengths[i]; j++) {
  102. fout << elements[el_ptr + j] + 1 << " ";
  103. }
  104. fout << std::endl;
  105. el_ptr+=element_lengths[i];
  106. }
  107. } else {
  108. size_t el_ptr=0,i=0;
  109. while(i<m_num_elements) {
  110. // write elements in consistent chunks
  111. // TODO: refactor this code to be able to specify different elements
  112. // more effeciently
  113. int elem_type=-1;
  114. int elem_len=-1;
  115. size_t j=i;
  116. for(;j<m_num_elements;++j)
  117. {
  118. if( elem_type==-1 )
  119. {
  120. elem_type=element_types[j];
  121. elem_len=element_lengths[j];
  122. } else if( elem_type!=element_types[j] ||
  123. elem_len!=element_lengths[j]) {
  124. break; // found the edge of the segment
  125. }
  126. }
  127. //hardcoded: 2 tags
  128. int num_elems=j-i, num_tags=2;
  129. fout.write((const char*)& elem_type, sizeof(int));
  130. fout.write((const char*)& num_elems, sizeof(int));
  131. fout.write((const char*)& num_tags, sizeof(int));
  132. for(int k=0;k<num_elems; ++k,++i){
  133. int elem_num = (int )i + 1;
  134. fout.write((const char*)&elem_num, sizeof(int));
  135. // HACK: hardcoded 2 tags
  136. fout.write((const char*)& element_tags[i], sizeof(int));
  137. fout.write((const char*)& element_tags[i], sizeof(int));
  138. for (size_t e=0; e<elem_len; e++) {
  139. int _elem = static_cast<int>( elements[el_ptr + e] )+1;
  140. fout.write((const char*)&_elem, sizeof(int));
  141. }
  142. el_ptr+=elem_len;
  143. }
  144. }
  145. }
  146. }
  147. fout << "$EndElements" << std::endl;
  148. fout.flush();
  149. }
  150. IGL_INLINE void igl::MshSaver::save_scalar_field(const std::string& fieldname, const FloatVector& field) {
  151. assert(field.size() == m_num_nodes);
  152. fout << "$NodeData" << std::endl;
  153. fout << "1" << std::endl; // num string tags.
  154. fout << "\"" << fieldname << "\"" << std::endl;
  155. fout << "1" << std::endl; // num real tags.
  156. fout << "0.0" << std::endl; // time value.
  157. fout << "3" << std::endl; // num int tags.
  158. fout << "0" << std::endl; // the time step
  159. fout << "1" << std::endl; // 1-component scalar field.
  160. fout << m_num_nodes << std::endl; // number of nodes
  161. if (m_binary) {
  162. for (size_t i=0; i<m_num_nodes; i++) {
  163. int node_idx = i+1;
  164. fout.write((char*)&node_idx, sizeof(int));
  165. fout.write((char*)&field[i], sizeof(Float));
  166. }
  167. } else {
  168. for (size_t i=0; i<m_num_nodes; i++) {
  169. int node_idx = i+1;
  170. fout << node_idx << " " << field[i] << std::endl;
  171. }
  172. }
  173. fout << "$EndNodeData" << std::endl;
  174. fout.flush();
  175. }
  176. IGL_INLINE void igl::MshSaver::save_vector_field(const std::string& fieldname, const FloatVector& field) {
  177. assert(field.size() == 3 * m_num_nodes);
  178. fout << "$NodeData" << std::endl;
  179. fout << "1" << std::endl; // num string tags.
  180. fout << "\"" << fieldname << "\"" << std::endl;
  181. fout << "1" << std::endl; // num real tags.
  182. fout << "0.0" << std::endl; // time value.
  183. fout << "3" << std::endl; // num int tags.
  184. fout << "0" << std::endl; // the time step
  185. fout << "3" << std::endl; // 3-component vector field.
  186. fout << m_num_nodes << std::endl; // number of nodes
  187. if (m_binary) {
  188. for (size_t i=0; i<m_num_nodes; i++) {
  189. int node_idx = i+1;
  190. fout.write((const char*)&node_idx, sizeof(int));
  191. fout.write((const char*)&field[i*3], sizeof(Float)*3);
  192. }
  193. } else {
  194. for (size_t i=0; i<m_num_nodes; i++) {
  195. int node_idx = i+1;
  196. fout << node_idx
  197. << " " << field[i*3]
  198. << " " << field[i*3+1]
  199. << " " << field[i*3+2]
  200. << std::endl;
  201. }
  202. }
  203. fout << "$EndNodeData" << std::endl;
  204. fout.flush();
  205. }
  206. IGL_INLINE void igl::MshSaver::save_elem_scalar_field(const std::string& fieldname, const FloatVector& field) {
  207. assert(field.size() == m_num_elements);
  208. fout << "$ElementData" << std::endl;
  209. fout << 1 << std::endl; // num string tags.
  210. fout << "\"" << fieldname << "\"" << std::endl;
  211. fout << "1" << std::endl; // num real tags.
  212. fout << "0.0" << std::endl; // time value.
  213. fout << "3" << std::endl; // num int tags.
  214. fout << "0" << std::endl; // the time step
  215. fout << "1" << std::endl; // 1-component scalar field.
  216. fout << m_num_elements << std::endl; // number of elements
  217. if (m_binary) {
  218. for (size_t i=0; i<m_num_elements; i++) {
  219. int elem_idx = i+1;
  220. fout.write((const char*)&elem_idx, sizeof(int));
  221. fout.write((const char*)&field[i], sizeof(Float));
  222. }
  223. } else {
  224. for (size_t i=0; i<m_num_elements; i++) {
  225. int elem_idx = i+1;
  226. fout << elem_idx << " " << field[i] << std::endl;
  227. }
  228. }
  229. fout << "$EndElementData" << std::endl;
  230. fout.flush();
  231. }
  232. IGL_INLINE void igl::MshSaver::save_elem_vector_field(const std::string& fieldname, const FloatVector& field) {
  233. assert(field.size() == m_num_elements * 3);
  234. fout << "$ElementData" << std::endl;
  235. fout << 1 << std::endl; // num string tags.
  236. fout << "\"" << fieldname << "\"" << std::endl;
  237. fout << "1" << std::endl; // num real tags.
  238. fout << "0.0" << std::endl; // time value.
  239. fout << "3" << std::endl; // num int tags.
  240. fout << "0" << std::endl; // the time step
  241. fout << "3" << std::endl; // 3-component vector field.
  242. fout << m_num_elements << std::endl; // number of elements
  243. if (m_binary) {
  244. for (size_t i=0; i<m_num_elements; ++i) {
  245. int elem_idx = i+1;
  246. fout.write((const char*)&elem_idx, sizeof(int));
  247. fout.write((const char*)&field[i*3], sizeof(Float) * 3);
  248. }
  249. } else {
  250. for (size_t i=0; i<m_num_elements; ++i) {
  251. int elem_idx = i+1;
  252. fout << elem_idx
  253. << " " << field[i*3]
  254. << " " << field[i*3+1]
  255. << " " << field[i*3+2]
  256. << std::endl;
  257. }
  258. }
  259. fout << "$EndElementData" << std::endl;
  260. fout.flush();
  261. }
  262. IGL_INLINE void igl::MshSaver::save_elem_tensor_field(const std::string& fieldname, const FloatVector& field) {
  263. assert(field.size() == m_num_elements * 3 * (3 + 1) / 2);
  264. fout << "$ElementData" << std::endl;
  265. fout << 1 << std::endl; // num string tags.
  266. fout << "\"" << fieldname << "\"" << std::endl;
  267. fout << "1" << std::endl; // num real tags.
  268. fout << "0.0" << std::endl; // time value.
  269. fout << "3" << std::endl; // num int tags.
  270. fout << "0" << std::endl; // the time step
  271. fout << "9" << std::endl; // 9-component tensor field.
  272. fout << m_num_elements << std::endl; // number of elements
  273. if (m_binary) {
  274. for (size_t i=0; i<m_num_elements; i++) {
  275. int elem_idx = i+1;
  276. fout.write((char*)&elem_idx, sizeof(int));
  277. //const VectorF& val = field.segment(i*6, 6);
  278. const Float* val = &field[i*6];
  279. Float tensor[9] = {
  280. val[0], val[5], val[4],
  281. val[5], val[1], val[3],
  282. val[4], val[3], val[2] };
  283. fout.write((char*)tensor, sizeof(Float) * 9);
  284. }
  285. } else {
  286. for (size_t i=0; i<m_num_elements; i++) {
  287. int elem_idx = i+1;
  288. const Float* val = &field[i*6];
  289. fout << elem_idx
  290. << " " << val[0]
  291. << " " << val[5]
  292. << " " << val[4]
  293. << " " << val[5]
  294. << " " << val[1]
  295. << " " << val[3]
  296. << " " << val[4]
  297. << " " << val[3]
  298. << " " << val[2]
  299. << std::endl;
  300. }
  301. }
  302. fout << "$EndElementData" << std::endl;
  303. fout.flush();
  304. }