Salome HOME
[bos #40653][CEA] New mesh import export formats with meshio.
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_Meshio.cxx
1 // Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // SMESH SMESHGUI : support of import / export with meshio library
24 // File   : SMESHGUI_Meshio.h
25 // Author : Konstantin Leontev, Open CASCADE S.A.S.
26 //
27 #include "SMESHGUI_Meshio.h"
28 #include "SMESH_Meshio.h"
29
30 // SMESH includes
31 #include "SMESHGUI.h"
32 #include "SMESHGUI_FieldSelectorWdg.h"
33
34 // SALOME GUI includes
35 #include <SUIT_Desktop.h>
36 #include <SUIT_FileDlg.h>
37 #include <SUIT_MessageBox.h>
38
39 // SALOME KERNEL includes
40 #include <utilities.h>
41
42 // Qt
43 #include <QStringList>
44
45
46 /*!
47   Constructor
48 */
49 SMESHGUI_Meshio::SMESHGUI_Meshio()
50 {
51 }
52
53 /*!
54   Destructor
55 */
56 SMESHGUI_Meshio::~SMESHGUI_Meshio()
57 {
58 }
59
60 /*!
61   Check and warn about exporting many shapes 
62 */
63 bool SMESHGUI_Meshio::CheckMeshCount(const meshList& aMeshList)
64 {
65   if (aMeshList.size() == 1)
66   {
67     return true;
68   }
69   else if (!aMeshList.size())
70   {
71     // We shouldn't get here, but...
72     MESSAGE("Error: empty mesh list. Export canceled.");
73     return false;
74   }
75
76   const bool isOk = SUIT_MessageBox::warning(
77     SMESHGUI::desktop(),
78     QObject::tr("SMESH_WARNING"),
79     QObject::tr("SMESH_EXPORT_MESHIO_ONLY_MESH"),
80     SUIT_MessageBox::Yes |
81     SUIT_MessageBox::No,
82     SUIT_MessageBox::No) == SUIT_MessageBox::Yes;
83
84   return isOk;
85 }
86
87 /*!
88   Import mesh through an intermediate MED file
89 */
90 SMESH::mesh_array_var SMESHGUI_Meshio::ImportMesh(
91   SMESH::SMESH_Gen_ptr theComponentMesh, const QString& filename, QStringList& errors)
92 {
93   SMESH::DriverMED_ReadStatus res;
94   SMESH::mesh_array_var aMeshes = theComponentMesh->CreateMeshesFromMESHIO(filename.toUtf8().constData(), res);
95   if (res != SMESH::DRS_OK)
96   {
97     errors.append(QString("%1 :\n\t%2").arg(filename).arg(
98       QObject::tr(QString("SMESH_DRS_%1").arg(res).toLatin1().data())));
99   }
100
101   return aMeshes;
102 }
103
104 /*!
105   Returns a filter for Import File dialog
106 */
107 const QStringList& SMESHGUI_Meshio::GetImportFileFilter()
108 {
109   auto addAllFiles = []() -> QStringList
110   {
111     QStringList filter = GetExportFileFilter();
112
113     // Remove SVG because it works only for export
114     const int svgIndex = filter.indexOf(QRegExp("^SVG.+"));
115     if (svgIndex >= 0)
116     {
117       filter.removeAt(svgIndex);
118     }
119
120     filter << QObject::tr("ALL_FILES_FILTER") + " (*)";
121
122     return filter;
123   };
124
125   static const QStringList filter = addAllFiles();
126   return filter;
127 }
128
129 /*!
130   Returns a filter for Export File dialog
131 */
132 const QStringList& SMESHGUI_Meshio::GetExportFileFilter()
133 {
134   static const QStringList filter = {
135     "Abaqus (*.inp)",
136     "ANSYS msh (*.msh)",
137     "AVS-UCD (*.avs)",
138     "CGNS (*.cgns)",
139     "DOLFIN XML (*.xml)",
140 #if !defined(WIN32)
141     "Exodus (*.e *.exo)",
142 #endif
143     "FLAC3D (*.f3grid)",
144     "Gmsh 2.2 (*.msh)",
145     "Gmsh 4.0, and 4.1 (*.msh)",
146     "H5M (*.h5m)",
147     "Kratos/MDPA (*.mdpa)",
148     "MED/Salome (*.med)",
149     "Medit (*.mesh *.meshb)",
150     "Nastran (*.bdf *fem *.nas)",
151     "Netgen(*.vol *.vol.gz)",
152     "OBJ (*.obj)",
153     "OFF (*.off)",
154     "PERMAS (*.post *.post.gz *.dato *.dato.gz)",
155     "PLY (*.ply)",
156     "STL (*.stl)",
157     "SU2 (*.su2)",
158     "SVG, 2D output only (*.svg)",
159     "Tecplot (*.dat)",
160     "TetGen (*.node *.ele)",
161     "UGRID (*.ugrid)",
162     "VTK (*.vtk)",
163     "VTU (*.vtu)",
164     "WKT, TIN (*.wkt)",
165     "XDMF (*.xdmf *.xmf)"
166   };
167
168   return filter;
169 }
170
171 /*!
172   Export mesh through an intermediate MED file
173 */
174 void SMESHGUI_Meshio::ExportMesh(const meshList& aMeshList, const QString& targetFileName, const QString& selectedFilter)
175 {
176   // Helper for indexed naming of the target files.
177   // We need to save into separated files because meshio doesn't
178   // support reading more than one mesh from a MED file.
179   // Look at src/meshio/med/_med.py in meshio git repo for a reference.
180   auto indexedFileName = [](const QString& targetFileName, const int index) -> QString
181   {
182     QString indexedFileName = targetFileName;
183
184     const int lastIndex = indexedFileName.lastIndexOf(".");
185     indexedFileName.insert(lastIndex, "_" + QString::number(index));
186
187     return indexedFileName;
188   };
189
190   // Trim an extension from the filter like in example: 'VTK (.vtk)' => 'VTK'
191   auto getFilterWithoutExt = [](const QString& selectedFilter) -> QString
192   {
193     // Find the start index for an extension in the filter string
194     const int index = selectedFilter.indexOf('(');
195     if (index != -1)
196     {
197       const QString filterWithoutExt = selectedFilter.left(index);
198       return filterWithoutExt.trimmed();
199     }
200
201     return selectedFilter;
202   };
203
204   // Iterate all the meshes from a list
205   auto aMeshIter = aMeshList.begin();
206   for(int aMeshIndex = 0; aMeshIter != aMeshList.end(); aMeshIter++, aMeshIndex++)
207   {
208     SMESH::SMESH_IDSource_var aMeshOrGroup = (*aMeshIter).first;
209     SMESH::SMESH_Mesh_var        aMeshItem = aMeshOrGroup->GetMesh();
210
211     // Exprort this part.
212     aMeshItem->ExportPartToMESHIO(
213       aMeshOrGroup, // mesh part
214       (aMeshIndex ? indexedFileName(targetFileName, aMeshIndex) : targetFileName).toUtf8().data(),
215       getFilterWithoutExt(selectedFilter).toLatin1().data()
216     );
217   }
218 }
219
220 /*!
221   Opens file dialog and returns a choosen target name
222 */
223 QString SMESHGUI_Meshio::GetFileName(QString& selectedFilter, const bool isOpen/* = false*/)
224 {
225   // Get a target directory name
226   QString anInitialPath = SUIT_FileDlg::getLastVisitedPath();
227   if (anInitialPath.isEmpty())
228     anInitialPath = QDir::currentPath();
229
230   // Return a target file name
231   return SUIT_FileDlg::getFileName(
232     SMESHGUI::desktop(),
233     anInitialPath,
234     GetExportFileFilter(),
235     selectedFilter,
236     QObject::tr("SMESH_EXPORT_MESH"),
237     isOpen
238   );
239 }
240
241 /*!
242   Returns true if meshio package is installed
243 */
244 bool SMESHGUI_Meshio::IsMeshioInstalled()
245 {
246   const bool isInstalled = SMESH_Meshio::IsMeshioInstalled();
247   if (!isInstalled)
248   {
249     SUIT_MessageBox::warning(
250       SMESHGUI::desktop(),
251       QObject::tr("SMESH_WARNING"),
252       QObject::tr("SMESH_MESHIO_NOT_INSTALLED")
253     );
254   }
255
256   return isInstalled;
257 }