MEPP2 Project
MshFileWriter.h
Go to the documentation of this file.
1 // Copyright (c) 2012-2019 University of Lyon and CNRS (France).
2 // All rights reserved.
3 //
4 // This file is part of MEPP2; you can redistribute it and/or modify
5 // it under the terms of the GNU Lesser General Public License as
6 // published by the Free Software Foundation; either version 3 of
7 // the License, or (at your option) any later version.
8 //
9 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
10 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 #pragma once
12 
13 #include <iostream>
14 #include <cstdio>
15 #include <cstring>
16 
19 
20 namespace FEVV {
21 namespace IO {
22 
23 
24 using namespace StrUtils;
25 using namespace FileUtils;
26 
27 template< typename IndexType >
28  inline IndexType get_type(const IndexType size, const IndexType dim)
29  {
30  switch(size)
31  {
32  case 3:
33  return 2;
34  case 4:
35  return (dim==2)?3:4;
36  case 6:
37  return 9;
38  case 8:
39  return 5;
40  }
41  return 0;
42  }
43 
47 template< typename CoordType,
48  typename CoordNType,
49  typename CoordCType,
50  typename IndexType >
51  bool write_gmsh_file( const std::string &file_path,
52  const std::vector< std::vector<CoordType> >& points_coords,
53  const std::vector< std::vector<CoordNType> >& normals_coords,
54  const std::vector< std::vector<CoordCType> >& vertex_color_coords,
55  const std::vector< std::vector<IndexType> >& line_indices,
56  const std::vector< std::vector<CoordCType> >& lines_color_coords,
57  const std::vector< std::vector<IndexType> >& face_indices,
58  const std::vector< std::vector<CoordCType> >& face_color_coords,
59  const std::vector< std::vector< std::vector<double> > >& field_attributes,
60  const std::vector< std::string >& field_names)
61  {
62  //We check that the file path has the correct extension
63  if(!(FileUtils::has_extension(file_path, ".msh")))
64  {
65  std::cerr << "MSH Writer: file extension is inappropriate" << std::endl;
66  return false;
67  }
68 
69  //We check that no node is colored or that every node are colored
70  if (vertex_color_coords.size()!=0 && vertex_color_coords.size()!=points_coords.size())
71  {
72  std::cerr << "MSH Writer: Not every node are colored" << std::endl;
73  return false;
74  }
75 
76  //We check that no node has normal or that every node has normal
77  if (normals_coords.size()>0 && normals_coords.size()!=points_coords.size())
78  {
79  std::cerr << "MSH Writer: Not every node are normalized" << std::endl;
80  return false;
81  }
82 
83  //We check that no element is colored or that every element is colored
84  if (face_color_coords.size()!=0 && face_color_coords.size()!=face_indices.size())
85  {
86  std::cerr << "MSH Writer: Not every 2D element are colored" << std::endl;
87  return false;
88  }
89 
90  //We check that there is not 3D elements combined with 2D elements
91  if (line_indices.size()!=0 && face_indices.size()!=0)
92  {
93  std::cerr << "MSH Writer: It is impossible to have 2D elements with 3D elements" << std::endl;
94  return false;
95  }
96  std::vector<std::string> names;
97  if (field_names.size() != field_attributes.size())
98  {
99  names.resize(field_attributes.size());
100  // When data field names need to be set, we assume that nD (n>=2)
101  // fields associated with positions are displacement fields while others
102  // are understood as physical laws.
103  for (unsigned long i(0); i<field_attributes.size(); ++i){
104  if( (points_coords.size() == field_attributes[i].size()) &&
105  ((points_coords.size() != face_indices.size()) || (field_attributes[i][0].size()>1)))
106  names[i] = std::string("Shifting_") + convert(i);
107  else
108  names[i] = std::string("cell_law_")+ convert(i);
109  }
110  }
111  else
112  names = field_names;
114  //If there is elements in the vector face_indices so it is the 2D vectors that we should use
115  //Otherwise we should use the 3D vectors
116  IndexType dim = (face_indices.size()) ? 2 : 3;
117  const std::vector< std::vector<IndexType> >& elem = (face_indices.size()) ? face_indices : line_indices;
118  const std::vector< std::vector<CoordCType> >& color = (face_indices.size()) ? face_color_coords : lines_color_coords;
119 
120  //We open the file
121  FILE* file = fopen(file_path.c_str(), "w");
122  if (file==NULL)
123  {
124  std::cerr << "MSH Reader: Unable to open file : " << file_path << std::endl;
125  return false;
126  }
127 
128  //We write the beginning of the file
129  fprintf(file, "$MeshFormat\n2.2 0 %zd\n$EndMeshFormat\n$Nodes\n%zd\n", sizeof(double), points_coords.size());
130 
131  //If there is some points to write
132  if (points_coords.size()!=0)
133  {
134  //We write every point while not forgetting the fact that index starts at 1 in msh file
135  for(unsigned long i(0); i<points_coords.size(); i++)
136  {
137  fprintf(file, "%ld %.10g %.10g %.10g\n", i+1, static_cast<double>(points_coords[i][0]), static_cast<double>(points_coords[i][1]), static_cast<double>(points_coords[i][2]));
138  }
139  fprintf(file, "$EndNodes\n");
140 
141  //Then we write the element (at least points, msh file must at least have one Elements block)
142  fprintf(file, "$Elements\n");
143  //If there is elements different from points
144  if (elem.size()!=0)
145  {
146  //Then we write the number of elements
147  fprintf(file, "%zd\n", elem.size());
148  //And we write all their attributes
149  IndexType type;
150  for(unsigned long i(0); i<elem.size(); i++)
151  {
152  type = get_type(static_cast<IndexType>(elem[i].size()), dim);
153  //If we found an unknown element
154  if (type==0)
155  {
156  std::cerr << "MSH Writer: Type of element is unknown" << std::endl;
157  fclose(file);
158  return false;
159  }
160  fprintf(file, "%ld %ld 2 99 2", i+1, static_cast<long>(type));
161  for(unsigned long j(0); j<elem[i].size(); j++)
162  {
163  fprintf(file, " %s", convert(elem[i][j]+1).c_str());
164  }
165  fprintf(file, "\n");
166  }
167  fprintf(file, "$EndElements");
168  }
169  //If there is no element we write the points as elements
170  else
171  {
172  fprintf(file, "%zd\n", points_coords.size());
173  for(unsigned long i(0); i<points_coords.size(); i++)
174  {
175  fprintf(file, "%lu 15 2 99 2 %lu\n", i+1, i+1);
176  }
177  fprintf(file, "$EndElements");
178  }
179 
180  //If there is point colors we write it
181  if (vertex_color_coords.size()!=0)
182  {
183  fprintf(file, "\n$NodeData\n1\n\"Color\"\n0\n1\n%zd\n", vertex_color_coords.size());
184  for(unsigned long i(0); i<vertex_color_coords.size(); i++)
185  {
186  if (vertex_color_coords[i].size()!=3)
187  {
188  std::cerr << "MSH Writer: Wrong number of values for declaration of colors" << std::endl;
189  fclose(file);
190  return false;
191  }
192  fprintf(file, "%ld %.10g %.10g %.10g\n", i+1, static_cast<double>(vertex_color_coords[i][0]), static_cast<double>(vertex_color_coords[i][1]), static_cast<double>(vertex_color_coords[i][2]));
193  }
194  fprintf(file, "$EndNodeData");
195  }
196 
197  //If there is point normal we write it
198  if (normals_coords.size()!=0)
199  {
200  fprintf(file, "\n$NodeData\n1\n\"Normal\"\n0\n1\n%zd\n", normals_coords.size());
201  for(unsigned long i(0); i<normals_coords.size(); i++)
202  {
203  if (normals_coords[i].size()!=3)
204  {
205  std::cerr << "MSH Writer: Wrong number of values for declaration of normals" << std::endl;
206  fclose(file);
207  return false;
208  }
209  fprintf(file, "%ld %.10g %.10g %.10g\n", i+1, static_cast<double>(normals_coords[i][0]), static_cast<double>(normals_coords[i][1]), static_cast<double>(normals_coords[i][2]));
210  }
211  fprintf(file, "$EndNodeData");
212  }
213 
214  //If there is element color we write it
215  if (color.size()!=0)
216  {
217  fprintf(file, "\n$ElementData\n1\n\"Color\"\n0\n1\n%zd\n", color.size());
218  for(unsigned long i(0); i<color.size(); i++)
219  {
220  if (color[i].size()!=3)
221  {
222  std::cerr << "MSH Writer: Wrong number of values for declaration of colors" << std::endl;
223  fclose(file);
224  return false;
225  }
226  fprintf(file, "%ld %.10g %.10g %.10g\n", i+1, static_cast<double>(color[i][0]), static_cast<double>(color[i][1]), static_cast<double>(color[i][2]));
227  }
228  fprintf(file, "$EndElementData");
229  }
230 
231  if (names.size()>0)
232  {
233  bool isnode = true;
234  for(unsigned long i(0); i<names.size(); ++i)
235  {
236  fprintf(file, "\n");
237  if ( names[i].find("POINT_DATA_") != std::string::npos )
238  {
239  isnode = true;
240  fprintf(file, "$NodeData\n1\n\"%s\"\n0\n1\n%zd\n", names[i].substr(11).c_str(), field_attributes[i].size());
241  }
242  else if ( (points_coords.size()==field_attributes[i].size()) && ( (points_coords.size()!=face_indices.size()) || (field_attributes[i][0].size()>1)) ) // the case of points_coords.size()=face_indices.size() is not well tackled, but for the time being we assume that in that case the attribute is a face attribute if only one value... [temporary solution; try to use the name of the field to decide?]
243  {
244  isnode = true;
245  fprintf(file, "$NodeData\n1\n\"%s\"\n0\n1\n%zd\n", names[i].c_str(), field_attributes[i].size());
246  }
247  else if (names[i].find("ELEMENT_DATA_") != std::string::npos)
248  {
249  isnode = false;
250  fprintf(file, "$ElementData\n1\n\"%s\"\n0\n1\n%zd\n", names[i].substr(13).c_str(), field_attributes[i].size());
251  }
252  else if (names[i].find("CELL_DATA_") != std::string::npos)
253  {
254  isnode = false;
255  fprintf(file, "$ElementData\n1\n\"%s\"\n0\n1\n%zd\n", names[i].substr(10).c_str(), field_attributes[i].size());
256  }
257  else
258  {
259  isnode = false;
260  fprintf(file, "$ElementData\n1\n\"%s\"\n0\n1\n%zd\n", names[i].c_str(), field_attributes[i].size());
261  }
262  for(unsigned long j(0); j<field_attributes[i].size(); ++j)
263  {
264  fprintf(file, "%lu", j+1);
265  for(unsigned long k(0); k<field_attributes[i][j].size(); ++k)
266  {
267  fprintf(file, " %.10g", field_attributes[i][j][k]);
268  }
269  fprintf(file, "\n");
270  }
271  if (isnode)
272  fprintf(file, "$EndNodeData");
273  else
274  fprintf(file, "$EndElementData");
275  }
276  }
277  }
278  //If there is no point we write that there is nothing
279  else
280  {
281  fprintf(file, "$EndNodes\n$Elements\n0\n$EndElements");
282  }
283 
284  fclose(file);
285  return true;
286  }
287 
288 }
289 }
FEVV::StrUtils::convert
void convert(const std::string &str, ConvertType &elem)
Definition: StringUtilities.hpp:81
FEVV
Interfaces for plugins These interfaces will be used for different plugins.
Definition: Assert.h:16
FEVV::IO::write_gmsh_file
bool write_gmsh_file(const std::string &file_path, const std::vector< std::vector< CoordType > > &points_coords, const std::vector< std::vector< CoordNType > > &normals_coords, const std::vector< std::vector< CoordCType > > &vertex_color_coords, const std::vector< std::vector< IndexType > > &line_indices, const std::vector< std::vector< CoordCType > > &lines_color_coords, const std::vector< std::vector< IndexType > > &face_indices, const std::vector< std::vector< CoordCType > > &face_color_coords, const std::vector< std::vector< std::vector< double > > > &field_attributes, const std::vector< std::string > &field_names)
Definition: MshFileWriter.h:51
StringUtilities.hpp
FEVV::FileUtils::has_extension
bool has_extension(const std::string &file_name)
Definition: FileUtilities.hpp:58
FileUtilities.hpp
FEVV::IO::get_type
IndexType get_type(const IndexType size, const IndexType dim)
Definition: MshFileWriter.h:28