Salome HOME
155f9dba3c5eb20bed06a85d4ac5f8d36802f53d
[plugins/hexoticplugin.git] / src / HexoticPlugin / MG_Hexotic_API.cxx
1 // Copyright (C) 2004-2021  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "MG_Hexotic_API.hxx"
21
22 #ifdef WIN32
23 #define NOMINMAX
24 #endif
25
26 #include <DriverGMF_Read.hxx>
27 #include <SMESH_Comment.hxx>
28 #include <SMESH_File.hxx>
29 #include <SMESH_MGLicenseKeyGen.hxx>
30 #include <Utils_SALOME_Exception.hxx>
31
32 #include <cstring>
33 #include <iostream>
34 #include <iterator>
35 #include <vector>
36
37 #ifdef USE_MG_LIBS
38
39 extern "C"{
40 #include <meshgems/meshgems.h>
41 #include <meshgems/hexa.h>
42 }
43
44 struct MG_Hexotic_API::LibData
45 {
46   // MG objects
47   context_t *       _context;
48   hexa_session_t * _session;
49   mesh_t *          _tria_mesh;
50   sizemap_t *       _sizemap;
51   mesh_t *          _hexa_mesh;
52
53   // data to pass to MG
54   std::vector<double> _xyz;
55   std::vector<double> _nodeSize; // required nodes
56   std::vector<int>    _edgeNodesTags;
57   int                 _nbRequiredEdges;
58   std::vector<int>    _triaNodesTags;
59   int                 _nbRequiredTria;
60
61   std::vector<int>    _corners;
62
63   int                 _count;
64   volatile bool&      _cancelled_flag;
65   std::string         _errorStr;
66   double&             _progress;
67   double              _msgCost;
68
69   LibData( volatile bool & cancelled_flag, double& progress )
70     : _context(0), _session(0), _tria_mesh(0), _sizemap(0), _hexa_mesh(0),
71       _nbRequiredEdges(0), _nbRequiredTria(0),
72       _cancelled_flag( cancelled_flag ), _progress( progress ), _msgCost( 0.00015 )
73   {
74   }
75   // methods setting callbacks implemented after callback definitions
76   void Init();
77   bool Compute();
78
79   ~LibData()
80   {
81     if ( _hexa_mesh )
82       hexa_regain_mesh( _session, _hexa_mesh );
83     if ( _tria_mesh )
84       mesh_delete( _tria_mesh );
85     if ( _sizemap )
86       sizemap_delete( _sizemap );
87     if ( _session )
88       hexa_session_delete( _session );
89     if ( _context )
90       context_delete( _context );
91
92     _hexa_mesh = 0;
93     _session = 0;
94     _tria_mesh = 0;
95     _sizemap = 0;
96     _context = 0;
97   }
98
99   void AddError( const char *txt )
100   {
101     if ( txt )
102     {
103       _errorStr += txt;
104     }
105   }
106
107   const std::string& GetErrors()
108   {
109     return _errorStr;
110   }
111
112   void MG_Error(const char* txt="")
113   {
114     SMESH_Comment msg("\nMeshGems error. ");
115     msg << txt << "\n";
116     AddError( msg.c_str() );
117   }
118
119   bool SetParam( const std::string& param, const std::string& value )
120   {
121     status_t ret = hexa_set_param( _session, param.c_str(), value.c_str() );
122 #ifdef _DEBUG_
123     //std::cout << param << " = " << value << std::endl;
124 #endif
125     return ( ret == STATUS_OK );
126   }
127
128   bool Cancelled()
129   {
130     return _cancelled_flag;
131   }
132
133   int ReadNbSubDomains()
134   {
135     integer nb = 0;
136     status_t ret = mesh_get_subdomain_count( _hexa_mesh, & nb );
137
138     if ( ret != STATUS_OK ) MG_Error("mesh_get_subdomain_count problem");
139     return nb;
140   }
141
142   int ReadNbNodes()
143   {
144     _corners.clear();
145
146     integer nb = 0;
147     status_t ret = mesh_get_vertex_count( _hexa_mesh, & nb );
148
149     if ( ret != STATUS_OK ) MG_Error("mesh_get_vertex_count problem");
150     return nb;
151   }
152
153   int ReadNbEdges()
154   {
155     integer nb = 0;
156     status_t ret = mesh_get_edge_count( _hexa_mesh, & nb );
157
158     if ( ret != STATUS_OK ) MG_Error("mesh_get_edge_count problem");
159     return nb;
160   }
161
162   int ReadNbTria()
163   {
164     integer nb = 0;
165     status_t ret = mesh_get_triangle_count( _hexa_mesh, & nb );
166
167     if ( ret != STATUS_OK ) MG_Error("mesh_get_triangle_count problem");
168     return nb;
169   }
170
171   int ReadNbQuads()
172   {
173     integer nb = 0;
174     status_t ret = mesh_get_quadrangle_count( _hexa_mesh, & nb );
175
176     if ( ret != STATUS_OK ) MG_Error("mesh_get_quadrangle_count problem");
177     return nb;
178   }
179
180   int ReadNbTetra()
181   {
182     integer nb = 0;
183     status_t ret = mesh_get_tetrahedron_count( _hexa_mesh, & nb );
184
185     if ( ret != STATUS_OK ) MG_Error("mesh_get_tetrahedron_count problem");
186     return nb;
187   }
188
189   int ReadNbHexa()
190   {
191     integer nb = 0;
192     status_t ret = mesh_get_hexahedron_count( _hexa_mesh, & nb );
193
194     if ( ret != STATUS_OK ) MG_Error("mesh_get_hexahedron_count problem");
195     return nb;
196   }
197
198   int ReadNbCorners()
199   {
200     return _corners.size();
201   }
202
203   void ResetCounter()
204   {
205     _count = 1;
206   }
207
208   void ReadSubDomain( int* nbNodes, int* faceInd, int* ori, int* domain )
209   {
210     integer tag, seed_type, seed_idx, seed_orientation;
211     status_t ret = mesh_get_subdomain_description( _hexa_mesh, _count,
212                                                    &tag, &seed_type, &seed_idx, &seed_orientation);
213
214     if ( ret != STATUS_OK ) MG_Error( "unable to get a sub-domain description");
215
216     *nbNodes = 3;
217     *faceInd = seed_idx;
218     *domain  = tag;
219     *ori     = seed_orientation;
220
221     ++_count;
222   }
223   void ReadNodeXYZ( double* x, double* y, double *z, int* /*domain*/  )
224   {
225     real coo[3];
226     status_t ret = mesh_get_vertex_coordinates( _hexa_mesh, _count, coo );
227     if ( ret != STATUS_OK ) MG_Error( "unable to get resulting vertices" );
228
229     *x = coo[0];
230     *y = coo[1];
231     *z = coo[2];
232
233     integer isCorner = 0;
234     ret = mesh_get_vertex_corner_property( _hexa_mesh, _count, &isCorner);
235     if (ret != STATUS_OK) MG_Error( "unable to get resulting vertex property" );
236     if ( isCorner )
237       _corners.push_back( _count );
238
239     ++_count;
240   }
241
242   void ReadEdgeNodes( int* node1, int* node2, int* domain )
243   {
244     integer vtx[2], tag;
245     status_t ret = mesh_get_edge_vertices( _hexa_mesh, _count, vtx);
246     if (ret != STATUS_OK) MG_Error( "unable to get resulting edge" );
247
248     *node1 = vtx[0];
249     *node2 = vtx[1];
250
251     ret = mesh_get_edge_tag( _hexa_mesh, _count, &tag );
252     if (ret != STATUS_OK) MG_Error( "unable to get resulting edge tag" );
253
254     *domain = tag;
255
256     ++_count;
257   }
258
259   void ReadTriaNodes( int* node1, int* node2, int* node3, int* domain )
260   {
261     integer vtx[3], tag;
262     status_t ret = mesh_get_triangle_vertices( _hexa_mesh, _count, vtx);
263     if (ret != STATUS_OK) MG_Error( "unable to get resulting triangle" );
264
265     *node1 = vtx[0];
266     *node2 = vtx[1];
267     *node3 = vtx[2];
268
269     ret = mesh_get_triangle_tag( _hexa_mesh, _count, &tag );
270     if (ret != STATUS_OK) MG_Error( "unable to get resulting triangle tag" );
271
272     *domain = tag;
273
274     ++_count;
275   }
276
277   void ReadQuadNodes( int* node1, int* node2, int* node3, int* node4, int* domain )
278   {
279     integer vtx[4], tag;
280     status_t ret = mesh_get_quadrangle_vertices( _hexa_mesh, _count, vtx);
281     if (ret != STATUS_OK) MG_Error( "unable to get resulting quadrangle" );
282
283     *node1 = vtx[0];
284     *node2 = vtx[1];
285     *node3 = vtx[2];
286     *node4 = vtx[3];
287
288     ret = mesh_get_quadrangle_tag( _hexa_mesh, _count, &tag );
289     if (ret != STATUS_OK) MG_Error( "unable to get resulting quadrangle tag" );
290
291     *domain = tag;
292
293     ++_count;
294   }
295
296   void ReadTetraNodes( int* node1, int* node2, int* node3, int* node4, int* domain )
297   {
298     integer vtx[4], tag;
299     status_t ret = mesh_get_tetrahedron_vertices( _hexa_mesh, _count, vtx);
300     if (ret != STATUS_OK) MG_Error( "unable to get resulting tetrahedron" );
301
302     *node1 = vtx[0];
303     *node2 = vtx[1];
304     *node3 = vtx[2];
305     *node4 = vtx[3];
306
307     ret = mesh_get_tetrahedron_tag( _hexa_mesh, _count, &tag );
308     if (ret != STATUS_OK) MG_Error( "unable to get resulting tetrahedron tag" );
309
310     *domain = tag;
311
312     ++_count;
313   }
314
315   void ReadHexaNodes( int* node1, int* node2, int* node3, int* node4,
316                       int* node5, int* node6, int* node7, int* node8, int* domain )
317   {
318     integer vtx[8], tag;
319     status_t ret = mesh_get_hexahedron_vertices( _hexa_mesh, _count, vtx);
320     if (ret != STATUS_OK) MG_Error( "unable to get resulting hexahedron" );
321
322     *node1 = vtx[0];
323     *node2 = vtx[1];
324     *node3 = vtx[2];
325     *node4 = vtx[3];
326     *node5 = vtx[4];
327     *node6 = vtx[5];
328     *node7 = vtx[6];
329     *node8 = vtx[7];
330
331     ret = mesh_get_hexahedron_tag( _hexa_mesh, _count, &tag );
332     if (ret != STATUS_OK) MG_Error( "unable to get resulting hexahedron tag" );
333
334     *domain = tag;
335
336     ++_count;
337   }
338
339   void ReadCorner( int* node )
340   {
341     if ( _count <= ReadNbCorners() )
342       *node = _corners[ _count - 1 ];
343     else
344       *node = 0;
345
346     ++_count;
347   }
348
349   void SetNbVertices( int nb )
350   {
351     _xyz.reserve( _xyz.capacity() + nb );
352   }
353
354   void SetNbEdges( int nb )
355   {
356     _edgeNodesTags.reserve( nb * 3 );
357   }
358
359   void SetNbTria( int nb )
360   {
361     _triaNodesTags.reserve( nb * 4 );
362   }
363
364   void SetNbReqVertices( int nb )
365   {
366     _nodeSize.reserve( nb );
367   }
368
369   void SetNbReqEdges( int nb )
370   {
371     _nbRequiredEdges = nb;
372   }
373
374   void SetNbReqTria( int nb )
375   {
376     _nbRequiredTria = nb;
377   }
378
379   void AddNode( double x, double y, double z, int /*domain*/ )
380   {
381     _xyz.push_back( x );
382     _xyz.push_back( y );
383     _xyz.push_back( z );
384   }
385
386   void AddSizeAtNode( double size )
387   {
388     _nodeSize.push_back( size );
389   }
390   
391   void AddEdgeNodes( int node1, int node2, int domain )
392   {
393     _edgeNodesTags.push_back( node1 );
394     _edgeNodesTags.push_back( node2 );
395     _edgeNodesTags.push_back( domain );
396   }
397   
398   void AddTriaNodes( int node1, int node2, int node3, int domain )
399   {
400     _triaNodesTags.push_back( node1 );
401     _triaNodesTags.push_back( node2 );
402     _triaNodesTags.push_back( node3 );
403     _triaNodesTags.push_back( domain );
404   }
405
406   int NbNodes()
407   {
408     return _xyz.size() / 3;
409   }
410
411   double* NodeCoord( int iNode )
412   {
413     return & _xyz[ iNode * 3 ];
414   }
415
416   int NbEdges()
417   {
418     return _edgeNodesTags.size() / 3;
419   }
420
421   int* GetEdgeNodes( int iEdge )
422   {
423     return & _edgeNodesTags[ iEdge * 3 ];
424   }
425
426   int GetEdgeTag( int iEdge )
427   {
428     return _edgeNodesTags[ iEdge * 3 + 2 ];
429   }
430
431   int NbTriangles()
432   {
433     return _triaNodesTags.size() / 4;
434   }
435
436   int * GetTriaNodes( int iTria )
437   {
438     return & _triaNodesTags[ iTria * 4 ];
439   }
440
441   int GetTriaTag( int iTria )
442   {
443     return _triaNodesTags[ iTria * 4 + 3 ];
444   }
445
446   int IsVertexRequired( int iNode )
447   {
448     return ! ( iNode < int( NbNodes() - _nodeSize.size() ));
449   }
450
451   double GetSizeAtVertex( int iNode )
452   {
453     return IsVertexRequired( iNode ) ? _nodeSize[ iNode - NbNodes() + _nodeSize.size() ] : 0.;
454   }
455 };
456
457 namespace // functions called by MG library to exchange with the application
458 {
459   status_t get_vertex_count(integer * nbvtx, void *user_data)
460   {
461     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
462     *nbvtx = data->NbNodes();
463
464     return STATUS_OK;
465   }
466
467   status_t get_vertex_coordinates(integer ivtx, real * xyz, void *user_data)
468   {
469     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
470     double* coord = data->NodeCoord( ivtx-1 );
471     for (int j = 0; j < 3; j++)
472       xyz[j] = coord[j];
473
474     return STATUS_OK;
475   }
476   status_t get_edge_count(integer * nbedge, void *user_data)
477   {
478     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
479     *nbedge = data->NbEdges();
480
481     return STATUS_OK;
482   }
483
484   status_t get_edge_vertices(integer iedge, integer * vedge, void *user_data)
485   {
486     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
487     int* nodes = data->GetEdgeNodes( iedge-1 );
488     vedge[0] = nodes[0];
489     vedge[1] = nodes[1];
490
491     return STATUS_OK;
492   }
493
494   status_t get_edge_tag(integer iedge, integer * tag, void *user_data)
495   {
496     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
497     * tag = data->GetEdgeTag( iedge-1 );
498
499     return STATUS_OK;
500   }
501
502   status_t get_triangle_count(integer * nbtri, void *user_data)
503   {
504     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
505     *nbtri = data->NbTriangles();
506
507     return STATUS_OK;
508   }
509
510   status_t get_triangle_vertices(integer itri, integer * vtri, void *user_data)
511   {
512     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
513     int* nodes = data->GetTriaNodes( itri-1 );
514     vtri[0] = nodes[0];
515     vtri[1] = nodes[1];
516     vtri[2] = nodes[2];
517
518     return STATUS_OK;
519   }
520
521   status_t get_triangle_tag(integer itri, integer * tag, void *user_data)
522   {
523     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
524     * tag = data->GetTriaTag( itri-1 );
525
526     return STATUS_OK;
527   }
528
529   // status_t get_triangle_extra_vertices(integer itri, integer * typetri,
530   //                                      integer * evtri, void *user_data)
531   // {
532   //   int j;
533   //   MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
534
535   //   if (1) {
536   //     /* We want to describe a linear "3 nodes" triangle */
537   //     *typetri = MESHGEMS_MESH_ELEMENT_TYPE_TRIA3;
538   //   } else {
539   //     /* We want to describe a quadratic "6 nodes" triangle */
540   //     *typetri = MESHGEMS_MESH_ELEMENT_TYPE_TRIA6;
541   //     for (j = 0; j < 3; j++)
542   //       evtri[j] = 0;             /* the j'th quadratic vertex index of the itri'th triangle */
543   //   }
544
545   //   return STATUS_OK;
546   // }
547
548   // status_t get_tetrahedron_count(integer * nbtetra, void *user_data)
549   // {
550   //   MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
551
552   //   *nbtetra = 0;                 /* the number of tetra in your input mesh (0 if you describe a surface mesh) */
553
554   //   return STATUS_OK;
555   // }
556
557   // status_t get_tetrahedron_vertices(integer itetra, integer * vtetra,
558   //                                   void *user_data)
559   // {
560   //   int j;
561   //   MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
562
563   //   for (j = 0; j < 4; j++)
564   //     vtetra[j] = 0;              /* the j'th vertex index of the itetra'th tetrahedron */
565
566   //   return STATUS_OK;
567   // }
568
569   status_t get_vertex_required_property(integer ivtx, integer * rvtx, void *user_data)
570   {
571     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
572     *rvtx = data->IsVertexRequired( ivtx - 1 );
573
574     return STATUS_OK;
575   }
576
577   status_t get_vertex_weight(integer ivtx, real * wvtx, void *user_data)
578   {
579     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
580     *wvtx = data->GetSizeAtVertex( ivtx - 1 );
581
582     return STATUS_OK;
583   }
584
585   status_t my_message_cb(message_t * msg, void *user_data)
586   {
587     char *desc;
588     message_get_description(msg, &desc);
589
590     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
591     data->AddError( desc );
592
593 #ifdef _DEBUG_
594     //std::cout << desc << std::endl;
595 #endif
596
597     // Compute progress
598     // corresponding messages are:
599     // " | Analyzing the surface mesh |"         => 1 %
600     // " | Building and conforming the octree |" => 8 %
601     // " | Subdomains and boundary recovery |"   => 15%
602     // " | Mesh bending and smoothing |"         => 45%
603     // " | Final mesh statistics |"              => 99%
604
605     double newProgress = std::min( 0.99, data->_progress + data->_msgCost );
606     if ( strlen( desc ) > 25 )
607     {
608       if      ( strncmp( desc+3, "Analyzing the surface mesh", 26 ) == 0 )
609         newProgress = 0.01, data->_msgCost = ( 0.08 - 0.01 ) / 10;
610       else if ( strncmp( desc+3, "Building and conforming the octree", 34 ) == 0 )
611         newProgress = 0.08, data->_msgCost = ( 0.15 - 0.08 ) / 100;
612       else if ( strncmp( desc+3, "Subdomains and boundary recovery", 32 ) == 0 )
613         newProgress = 0.15, data->_msgCost = ( 0.45 - 0.15 ) / 20;
614       else if ( strncmp( desc+3, "Mesh bending and smoothing", 26 ) == 0 )
615         newProgress = 0.45, data->_msgCost = ( 0.99 - 0.45 ) / 65;
616       else if ( strncmp( desc+3, "Final mesh statistics", 21 ) == 0 )
617         newProgress = 0.99;
618     }
619     data->_progress = std::max( data->_progress, newProgress );
620
621     return STATUS_OK;
622   }
623
624   status_t my_interrupt_callback(integer *interrupt_status, void *user_data)
625   {
626     MG_Hexotic_API::LibData* data = (MG_Hexotic_API::LibData *) user_data;
627     *interrupt_status = ( data->Cancelled() ? INTERRUPT_STOP : INTERRUPT_CONTINUE );
628
629     return STATUS_OK;
630   }
631
632 } // end namespace
633
634
635 void MG_Hexotic_API::LibData::Init()
636 {
637   status_t ret;
638
639   // Create the meshgems working context
640   _context = context_new();
641   if ( !_context ) MG_Error( "unable to create a new context" );
642
643   // Set the message callback for the _context.
644   ret = context_set_message_callback( _context, my_message_cb, this );
645   if ( ret != STATUS_OK ) MG_Error("in context_set_message_callback");
646
647   // Create the structure holding the callbacks giving access to triangle mesh
648   _tria_mesh = mesh_new( _context );
649   if ( !_tria_mesh ) MG_Error("unable to create a new mesh");
650
651   // Set callbacks to provide triangle mesh data
652   mesh_set_get_vertex_count( _tria_mesh, get_vertex_count, this );
653   mesh_set_get_vertex_coordinates( _tria_mesh, get_vertex_coordinates, this );
654   mesh_set_get_vertex_required_property( _tria_mesh, get_vertex_required_property, this );
655   mesh_set_get_edge_count( _tria_mesh, get_edge_count, this);
656   mesh_set_get_edge_vertices( _tria_mesh, get_edge_vertices, this );
657   mesh_set_get_edge_tag( _tria_mesh, get_edge_tag, this );
658   mesh_set_get_triangle_count( _tria_mesh, get_triangle_count, this );
659   mesh_set_get_triangle_vertices( _tria_mesh, get_triangle_vertices, this );
660   mesh_set_get_triangle_tag( _tria_mesh, get_triangle_tag, this );
661
662   // Create a hexa session
663   _session = hexa_session_new( _context );
664   if ( !_session ) MG_Error( "unable to create a new hexa session");
665
666   ret = hexa_set_interrupt_callback( _session, my_interrupt_callback, this );
667   if ( ret != STATUS_OK ) MG_Error("in hexa_set_interrupt_callback");
668
669 }
670
671 bool MG_Hexotic_API::LibData::Compute()
672 {
673   // MG license
674   std::string errorTxt;
675   if ( !SMESHUtils_MGLicenseKeyGen::SignMesh( _tria_mesh, errorTxt ))
676   {
677     AddError( SMESH_Comment( "Problem with library SalomeMeshGemsKeyGenerator: ") << errorTxt );
678     return false;
679   }
680
681   // Set surface mesh
682   status_t ret = hexa_set_surface_mesh( _session, _tria_mesh );
683   if ( ret != STATUS_OK ) MG_Error( "unable to set surface mesh");
684
685   // Set a sizemap
686   if ( !_nodeSize.empty() )
687   {
688     _sizemap = meshgems_sizemap_new( _tria_mesh, meshgems_sizemap_type_iso_mesh_vertex,
689                                      (void*) &get_vertex_weight, this );
690     if ( !_sizemap ) MG_Error("unable to create a new sizemap");
691
692     ret = hexa_set_sizemap( _session, _sizemap );
693     if ( ret != STATUS_OK ) MG_Error( "unable to set sizemap");
694   }
695
696   //////////////////////////////////////////////////////////////////////////////////////////
697   // const char* file  =  "/tmp/ghs3d_IN.mesh";
698   // mesh_write_mesh( _tria_mesh,file);
699   // std::cout << std::endl << std::endl << "Write " << file << std::endl << std::endl << std::endl;
700
701   ret = hexa_compute_mesh( _session );
702   if ( ret != STATUS_OK ) return false;
703
704   ret = hexa_get_mesh( _session, &_hexa_mesh);
705   if (ret != STATUS_OK) MG_Error( "unable to get resulting mesh");
706
707   //////////////////////////////////////////////////////////////////////////////////////////
708   // file  =  "/tmp/ghs3d_OUT.mesh";
709   // mesh_write_mesh( _hexa_mesh,file);
710   // std::cout << std::endl << std::endl << "Write " << file << std::endl << std::endl << std::endl;
711
712   return true;
713 }
714
715 #else // ifdef USE_MG_LIBS
716
717 struct MG_Hexotic_API::LibData // to avoid compiler warnings
718 {
719   volatile bool& _cancelled_flag;
720   double& _progress;
721   LibData(volatile bool& cancelled_flag, double& progress): _cancelled_flag{cancelled_flag}, _progress{progress} {}
722 };
723
724 #endif // ifdef USE_MG_LIBS
725
726
727 //================================================================================
728 /*!
729  * \brief Constructor
730  */
731 //================================================================================
732
733 MG_Hexotic_API::MG_Hexotic_API(volatile bool& cancelled_flag, double& progress):
734   _isMesh(true), _nbNodes(0), _nbEdges(0), _nbFaces(0), _nbVolumes(0)
735 {
736   _useLib = false;
737   _libData = new LibData( cancelled_flag, progress );
738 #ifdef USE_MG_LIBS
739   _useLib = true;
740   _libData->Init();
741   if ( getenv("MG_HEXA_USE_EXE"))
742     _useLib = false;
743 #endif
744 }
745
746 //================================================================================
747 /*!
748  * \brief Destructor
749  */
750 //================================================================================
751
752 MG_Hexotic_API::~MG_Hexotic_API()
753 {
754 #ifdef USE_MG_LIBS
755   delete _libData;
756   _libData = 0;
757 #endif
758   std::set<int>::iterator id = _openFiles.begin();
759   for ( ; id != _openFiles.end(); ++id )
760     ::GmfCloseMesh( *id );
761   _openFiles.clear();
762 }
763
764 //================================================================================
765 /*!
766  * \brief Return the way of MG usage
767  */
768 //================================================================================
769
770 bool MG_Hexotic_API::IsLibrary()
771 {
772   return _useLib;
773 }
774
775 //================================================================================
776 /*!
777  * \brief Switch to usage of MG-Hexa executable
778  */
779 //================================================================================
780
781 void MG_Hexotic_API::SetUseExecutable()
782 {
783   _useLib = false;
784 }
785
786 //================================================================================
787 /*!
788  * \brief Compute the hexa mesh
789  *  \param [in] cmdLine - a command to run mg_hexa.exe
790  *  \return bool - Ok or not
791  */
792 //================================================================================
793
794 bool MG_Hexotic_API::Compute( const std::string& cmdLine, std::string& errStr )
795 {
796   if ( _useLib ) {
797 #ifdef USE_MG_LIBS
798
799     // split cmdLine
800     std::istringstream strm( cmdLine );
801     std::istream_iterator<std::string> sIt( strm ), sEnd;
802     std::vector< std::string > args( sIt, sEnd );
803
804     // set parameters
805     std::string param, value;
806     for ( size_t i = 1; i < args.size(); ++i )
807     {
808       // look for a param name; it starts from "-"
809       param = args[i];
810       if ( param.size() < 2 || param[0] != '-')
811         continue;
812       while ( param[0] == '-')
813         param = param.substr( 1 );
814
815       value = "";
816       while ( i+1 < args.size() && args[i+1][0] != '-' )
817       {
818         if ( strncmp( "1>", args[i+1].c_str(), 2 ) == 0 )
819           break;
820         if ( !value.empty() ) value += " ";
821         value += args[++i];
822       }
823       if ( !_libData->SetParam( param, value ))
824         std::cout << "Warning: wrong param: '" << param <<"' = '" << value << "'" << std::endl;
825     }
826
827     // compute
828     bool ok = _libData->Compute();
829
830     GetLog(); // write a log file
831     _logFile = ""; // not to write it again
832
833     return ok;
834 #endif
835   }
836   // add MG license key
837   {
838     std::string errorTxt, meshIn;
839     std::string key = SMESHUtils_MGLicenseKeyGen::GetKey( meshIn,
840                                                           _nbNodes, _nbEdges, _nbFaces, _nbVolumes,
841                                                           errorTxt );
842     if ( key.empty() )
843     {
844       errStr = "Problem with library SalomeMeshGemsKeyGenerator: " + errorTxt;
845       return false;
846     }
847
848     const_cast< std::string& >( cmdLine ) += " --key " + key;
849   }
850
851   int err = system( cmdLine.c_str() ); // run
852
853   if ( err )
854     errStr = SMESH_Comment("system(mg-hexa.exe ...) command failed with error: ")
855       << strerror( errno );
856
857   return !err;
858
859 }
860
861 //================================================================================
862 /*!
863  * \brief Prepare for reading a mesh data
864  */
865 //================================================================================
866
867 int  MG_Hexotic_API::GmfOpenMesh(const char* theFile, int rdOrWr, int * ver, int * dim)
868 {
869   if ( _useLib ) {
870 #ifdef USE_MG_LIBS
871     return 1;
872 #endif
873   }
874   int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim );
875   _openFiles.insert( id );
876   return id;
877 }
878
879 //================================================================================
880 /*!
881  * \brief Return nb of entities
882  */
883 //================================================================================
884
885 int MG_Hexotic_API::GmfStatKwd( int iMesh, GmfKwdCod what )
886 {
887   if ( _useLib ) {
888 #ifdef USE_MG_LIBS
889     switch ( what )
890     {
891     case GmfSubDomainFromGeom: return _libData->ReadNbSubDomains();
892     case GmfVertices:          return _libData->ReadNbNodes();
893     case GmfEdges:             return _libData->ReadNbEdges();
894     case GmfTriangles:         return _libData->ReadNbTria();
895     case GmfQuadrilaterals:    return _libData->ReadNbQuads();
896     case GmfTetrahedra:        return _libData->ReadNbTetra();
897     case GmfHexahedra:         return _libData->ReadNbHexa();
898     case GmfCorners:           return _libData->ReadNbCorners();
899     default:                   return 0;
900     }
901     return 0;
902 #endif
903   }
904   return ::GmfStatKwd( iMesh, what );
905 }
906
907 //================================================================================
908 /*!
909  * \brief Prepare for reading some data
910  */
911 //================================================================================
912
913 void MG_Hexotic_API::GmfGotoKwd( int iMesh, GmfKwdCod what )
914 {
915   if ( _useLib ) {
916 #ifdef USE_MG_LIBS
917     _libData->ResetCounter();
918     return;
919 #endif
920   }
921   ::GmfGotoKwd( iMesh, what );
922 }
923
924 //================================================================================
925 /*!
926  * \brief Return index of a domain identified by a triangle normal
927  *  \param [in] iMesh - mesh file index
928  *  \param [in] what - must be GmfSubDomainFromGeom
929  *  \param [out] nbNodes - nb nodes in a face
930  *  \param [out] faceInd - face index
931  *  \param [out] ori - face orientation
932  *  \param [out] domain - domain index
933  *  \param [in] dummy - an artificial param used to discriminate from GmfGetLin() reading
934  *              a triangle
935  */
936 //================================================================================
937
938 void MG_Hexotic_API::GmfGetLin( int iMesh, GmfKwdCod what, int* nbNodes, int* faceInd, int* ori, int* domain, int /*dummy*/ )
939 {
940   if ( _useLib ) {
941 #ifdef USE_MG_LIBS
942     _libData->ReadSubDomain( nbNodes, faceInd, ori, domain );
943     return;
944 #endif
945   }
946   ::GmfGetLin( iMesh, what, nbNodes, faceInd, ori, domain );
947 }
948
949 //================================================================================
950 /*!
951  * \brief Return coordinates of a next node
952  */
953 //================================================================================
954
955 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
956                                double* x, double* y, double *z, int* domain )
957 {
958   if ( _useLib ) {
959 #ifdef USE_MG_LIBS
960     _libData->ReadNodeXYZ( x, y, z, domain );
961     return;
962 #endif
963   }
964   ::GmfGetLin(iMesh, what, x, y, z, domain );
965 }
966
967 //================================================================================
968 /*!
969  * \brief Return coordinates of a next node
970  */
971 //================================================================================
972
973 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
974                                float* x, float* y, float *z, int* domain )
975 {
976   if ( _useLib ) {
977 #ifdef USE_MG_LIBS
978     double X,Y,Z;
979     _libData->ReadNodeXYZ( &X, &Y, &Z, domain );
980     *x = X;
981     *y = Y;
982     *z = Z;
983     return;
984 #endif
985   }
986   ::GmfGetLin(iMesh, what, x, y, z, domain );
987 }
988
989 //================================================================================
990 /*!
991  * \brief Return node index of a next corner
992  */
993 //================================================================================
994
995 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node )
996 {
997   if ( _useLib ) {
998 #ifdef USE_MG_LIBS
999     _libData->ReadCorner( node );
1000     return;
1001 #endif
1002   }
1003   ::GmfGetLin(iMesh, what, node );
1004 }
1005
1006 //================================================================================
1007 /*!
1008  * \brief Return node indices of a next edge
1009  */
1010 //================================================================================
1011
1012 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node1, int* node2, int* domain )
1013 {
1014   if ( _useLib ) {
1015 #ifdef USE_MG_LIBS
1016     _libData->ReadEdgeNodes( node1, node2, domain );
1017     return;
1018 #endif
1019   }
1020   ::GmfGetLin( iMesh, what, node1, node2, domain );
1021 }
1022
1023 //================================================================================
1024 /*!
1025  * \brief Return node indices of a next triangle
1026  */
1027 //================================================================================
1028
1029 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
1030                                int* node1, int* node2, int* node3, int* domain )
1031 {
1032   if ( _useLib ) {
1033 #ifdef USE_MG_LIBS
1034     _libData->ReadTriaNodes( node1, node2, node3, domain );
1035     return;
1036 #endif
1037   }
1038   ::GmfGetLin(iMesh, what, node1, node2, node3, domain );
1039 }
1040
1041 //================================================================================
1042 /*!
1043  * \brief Return node indices of a next tetrahedron or quadrangle
1044  */
1045 //================================================================================
1046
1047 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
1048                                int* node1, int* node2, int* node3, int* node4, int* domain )
1049 {
1050   if ( _useLib ) {
1051 #ifdef USE_MG_LIBS
1052     if ( what == GmfQuadrilaterals )
1053       _libData->ReadQuadNodes( node1, node2, node3, node4, domain );
1054     else
1055       _libData->ReadTetraNodes( node1, node2, node3, node4, domain );
1056     return;
1057 #endif
1058   }
1059   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, domain );
1060 }
1061
1062 //================================================================================
1063 /*!
1064  * \brief Return node indices of a next hexahedron
1065  */
1066 //================================================================================
1067
1068 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
1069                                int* node1, int* node2, int* node3, int* node4,
1070                                int* node5, int* node6, int* node7, int* node8,
1071                                int* domain )
1072 {
1073   if ( _useLib ) {
1074 #ifdef USE_MG_LIBS
1075     _libData->ReadHexaNodes( node1, node2, node3, node4,
1076                              node5, node6, node7, node8, domain );
1077     return;
1078 #endif
1079   }
1080   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, node5, node6, node7, node8, domain );
1081 }
1082
1083 //================================================================================
1084 /*!
1085  * \brief Prepare for passing data to MeshGems
1086  */
1087 //================================================================================
1088
1089 int  MG_Hexotic_API::GmfOpenMesh(const char* theFile, int rdOrWr, int ver, int dim)
1090 {
1091   if ( _useLib ) {
1092 #ifdef USE_MG_LIBS
1093     return 1;
1094 #endif
1095   }
1096   int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim);
1097   _openFiles.insert( id );
1098   return id;
1099 }
1100
1101 //================================================================================
1102 /*!
1103  * \brief Set number of entities
1104  */
1105 //================================================================================
1106
1107 void MG_Hexotic_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nb )
1108 {
1109   if ( iMesh == 1 && _isMesh )
1110   {
1111     switch ( what ) {
1112     case GmfVertices:  _nbNodes += nb; break;
1113     case GmfEdges:     _nbEdges += nb; break;
1114     case GmfTriangles: _nbFaces += nb; break;
1115     default:;
1116     }
1117   }
1118
1119   if ( _useLib ) {
1120 #ifdef USE_MG_LIBS
1121     switch ( what ) {
1122     case GmfVertices:          _libData->SetNbVertices( nb ); break;
1123     case GmfEdges:             _libData->SetNbEdges   ( nb ); break;
1124     case GmfRequiredEdges:     _libData->SetNbReqEdges( nb ); break;
1125     case GmfTriangles:         _libData->SetNbTria    ( nb ); break;
1126     case GmfRequiredTriangles: _libData->SetNbReqTria ( nb ); break;
1127     default:;
1128     }
1129     return;
1130 #endif
1131   }
1132   ::GmfSetKwd(iMesh, what, nb );
1133 }
1134
1135 //================================================================================
1136 /*!
1137  * \brief Set GMF file made by MG-CADSurf to get nb of mesh entities from it
1138  */
1139 //================================================================================
1140
1141 void MG_Hexotic_API::SetInputFile( const std::string mesh2DFile )
1142 {
1143   DriverGMF_Read fileReader;
1144   fileReader.SetFile( mesh2DFile );
1145
1146   smIdType nbVertex, nbEdge, nbFace, nbVol;
1147   if ( fileReader.GetMeshInfo(nbVertex, nbEdge, nbFace, nbVol))
1148   {
1149     _nbNodes += nbVertex;
1150     _nbEdges += nbEdge;
1151     _nbFaces += nbFace;
1152   }
1153 }
1154
1155 //================================================================================
1156 /*!
1157  * \brief Add coordinates of a node
1158  */
1159 //================================================================================
1160
1161 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, double x, double y, double z, int domain)
1162 {
1163   if ( _useLib ) {
1164 #ifdef USE_MG_LIBS
1165     _libData->AddNode( x, y, z, domain );
1166     return;
1167 #endif
1168   }
1169   ::GmfSetLin(iMesh, what, x, y, z, domain);
1170 }
1171
1172 //================================================================================
1173 /*!
1174  * \brief Set number of field entities
1175  *  \param [in] iMesh - solution file index
1176  *  \param [in] what - solution type
1177  *  \param [in] nbNodes - nb of entities
1178  *  \param [in] nbTypes - nb of data entries in each entity
1179  *  \param [in] type - types of the data entries
1180  *
1181  * Used to prepare to storing size at nodes
1182  */
1183 //================================================================================
1184
1185 void MG_Hexotic_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nbNodes, int dummy, int type[] )
1186 {
1187   if ( _useLib ) {
1188 #ifdef USE_MG_LIBS
1189     if ( what == GmfSolAtVertices ) _libData->SetNbReqVertices( nbNodes );
1190     return;
1191 #endif
1192   }
1193   ::GmfSetKwd(iMesh, what, nbNodes, dummy, type );
1194 }
1195
1196 //================================================================================
1197 /*!
1198  * \brief Add solution data
1199  */
1200 //================================================================================
1201
1202 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, double vals[])
1203 {
1204   if ( _useLib ) {
1205 #ifdef USE_MG_LIBS
1206     _libData->AddSizeAtNode( vals[0] );
1207     return;
1208 #endif
1209   }
1210   ::GmfSetLin(iMesh, what, vals);
1211 }
1212
1213 //================================================================================
1214 /*!
1215  * \brief Add edge nodes
1216  */
1217 //================================================================================
1218
1219 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int domain )
1220 {
1221   if ( _useLib ) {
1222 #ifdef USE_MG_LIBS
1223     _libData->AddEdgeNodes( node1, node2, domain );
1224     return;
1225 #endif
1226   }
1227   ::GmfSetLin(iMesh, what, node1, node2, domain );
1228 }
1229
1230 //================================================================================
1231 /*!
1232  * \brief Add a 'required' flag
1233  */
1234 //================================================================================
1235
1236 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, int id )
1237 {
1238   if ( _useLib ) {
1239 #ifdef USE_MG_LIBS
1240     return;
1241 #endif
1242   }
1243   ::GmfSetLin(iMesh, what, id );
1244 }
1245
1246 //================================================================================
1247 /*!
1248  * \brief Add triangle nodes
1249  */
1250 //================================================================================
1251
1252 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int node3, int domain )
1253 {
1254   if ( _useLib ) {
1255 #ifdef USE_MG_LIBS
1256     _libData->AddTriaNodes( node1, node2, node3, domain );
1257     return;
1258 #endif
1259   }
1260   ::GmfSetLin(iMesh, what, node1, node2, node3, domain );
1261 }
1262
1263 //================================================================================
1264 /*!
1265  * \brief Close a file
1266  */
1267 //================================================================================
1268
1269 void MG_Hexotic_API::GmfCloseMesh( int iMesh )
1270 {
1271   if ( _useLib ) {
1272 #ifdef USE_MG_LIBS
1273     return;
1274 #endif
1275   }
1276   ::GmfCloseMesh( iMesh );
1277   _openFiles.erase( iMesh );
1278 }
1279
1280 //================================================================================
1281 /*!
1282  * \brief Return true if the log is not empty
1283  */
1284 //================================================================================
1285
1286 bool MG_Hexotic_API::HasLog()
1287 {
1288   if ( _useLib ) {
1289 #ifdef USE_MG_LIBS
1290     return !_libData->GetErrors().empty();
1291 #endif
1292   }
1293   SMESH_File file( _logFile );
1294   return file.size() > 0;
1295 }
1296
1297 //================================================================================
1298 /*!
1299  * \brief Return log contents
1300  */
1301 //================================================================================
1302
1303 std::string MG_Hexotic_API::GetLog()
1304 {
1305   if ( _useLib ) {
1306 #ifdef USE_MG_LIBS
1307     const std::string& err = _libData->GetErrors();
1308     if ( !_logFile.empty() && !err.empty() )
1309     {
1310       SMESH_File file( _logFile, /*openForReading=*/false );
1311       file.openForWriting();
1312       file.write( err.c_str(), err.size() );
1313     }
1314     return err;
1315 #endif
1316   }
1317   SMESH_File file( _logFile );
1318   return file.exists() ? file.getPos() : "";
1319 }