Salome HOME
75d542a07a656f55e316aabc522f1720890f104f
[plugins/hexoticplugin.git] / src / HexoticPlugin / MG_Hexotic_API.cxx
1 // Copyright (C) 2004-2024  CEA, EDF
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   status_t ret;
676
677   if ( !SMESHUtils_MGLicenseKeyGen::SignMesh( _tria_mesh, "hexa", errorTxt ))
678   {
679     AddError( SMESH_Comment( "Problem with library SalomeMeshGemsKeyGenerator: ") << errorTxt );
680     return false;
681   }
682
683   // Set surface mesh
684   ret = hexa_set_surface_mesh( _session, _tria_mesh );
685   if ( ret != STATUS_OK ) MG_Error( "unable to set surface mesh");
686
687   // Set a sizemap
688   if ( !_nodeSize.empty() )
689   {
690     _sizemap = meshgems_sizemap_new( _tria_mesh, meshgems_sizemap_type_iso_mesh_vertex,
691                                      (void*) &get_vertex_weight, this );
692     if ( !_sizemap ) MG_Error("unable to create a new sizemap");
693
694     ret = hexa_set_sizemap( _session, _sizemap );
695     if ( ret != STATUS_OK ) MG_Error( "unable to set sizemap");
696   }
697
698   //////////////////////////////////////////////////////////////////////////////////////////
699   // const char* file  =  "/tmp/ghs3d_IN.mesh";
700   // mesh_write_mesh( _tria_mesh,file);
701   // std::cout << std::endl << std::endl << "Write " << file << std::endl << std::endl << std::endl;
702
703   ret = hexa_compute_mesh( _session );
704   if ( ret != STATUS_OK ) return false;
705
706   ret = hexa_get_mesh( _session, &_hexa_mesh);
707   if (ret != STATUS_OK) MG_Error( "unable to get resulting mesh");
708
709   //////////////////////////////////////////////////////////////////////////////////////////
710   // file  =  "/tmp/ghs3d_OUT.mesh";
711   // mesh_write_mesh( _hexa_mesh,file);
712   // std::cout << std::endl << std::endl << "Write " << file << std::endl << std::endl << std::endl;
713
714   return true;
715 }
716
717 #else // ifdef USE_MG_LIBS
718
719 struct MG_Hexotic_API::LibData // to avoid compiler warnings
720 {
721   volatile bool& _cancelled_flag;
722   double& _progress;
723   LibData(volatile bool& cancelled_flag, double& progress): _cancelled_flag{cancelled_flag}, _progress{progress} {}
724 };
725
726 #endif // ifdef USE_MG_LIBS
727
728
729 //================================================================================
730 /*!
731  * \brief Constructor
732  */
733 //================================================================================
734
735 MG_Hexotic_API::MG_Hexotic_API(volatile bool& cancelled_flag, double& progress):
736   _isMesh(true), _nbNodes(0), _nbEdges(0), _nbFaces(0), _nbVolumes(0)
737 {
738   _useLib = false;
739   _libData = new LibData( cancelled_flag, progress );
740 #ifdef USE_MG_LIBS
741   _useLib = true;
742   _libData->Init();
743   if ( getenv("MG_HEXA_USE_EXE"))
744     _useLib = false;
745 #endif
746 }
747
748 //================================================================================
749 /*!
750  * \brief Destructor
751  */
752 //================================================================================
753
754 MG_Hexotic_API::~MG_Hexotic_API()
755 {
756 #ifdef USE_MG_LIBS
757   delete _libData;
758   _libData = 0;
759 #endif
760   std::set<int>::iterator id = _openFiles.begin();
761   for ( ; id != _openFiles.end(); ++id )
762     ::GmfCloseMesh( *id );
763   _openFiles.clear();
764 }
765
766 //================================================================================
767 /*!
768  * \brief Return the way of MG usage
769  */
770 //================================================================================
771
772 bool MG_Hexotic_API::IsLibrary()
773 {
774   return _useLib;
775 }
776
777 //================================================================================
778 /*!
779  * \brief Switch to usage of MG-Hexa executable
780  */
781 //================================================================================
782
783 void MG_Hexotic_API::SetUseExecutable()
784 {
785   _useLib = false;
786 }
787
788 //================================================================================
789 /*!
790  * \brief Compute the hexa mesh
791  *  \param [in] cmdLine - a command to run mg_hexa.exe
792  *  \return bool - Ok or not
793  */
794 //================================================================================
795
796 bool MG_Hexotic_API::Compute( const std::string& cmdLine, std::string& errStr )
797 {
798   if ( _useLib ) {
799 #ifdef USE_MG_LIBS
800
801     // split cmdLine
802     std::istringstream strm( cmdLine );
803     std::istream_iterator<std::string> sIt( strm ), sEnd;
804     std::vector< std::string > args( sIt, sEnd );
805
806     // set parameters
807     std::string param, value;
808     for ( size_t i = 1; i < args.size(); ++i )
809     {
810       // look for a param name; it starts from "-"
811       param = args[i];
812       if ( param.size() < 2 || param[0] != '-')
813         continue;
814       while ( param[0] == '-')
815         param = param.substr( 1 );
816
817       value = "";
818       while ( i+1 < args.size() && args[i+1][0] != '-' )
819       {
820         if ( strncmp( "1>", args[i+1].c_str(), 2 ) == 0 )
821           break;
822         if ( !value.empty() ) value += " ";
823         value += args[++i];
824       }
825       if ( !_libData->SetParam( param, value ))
826         std::cout << "Warning: wrong param: '" << param <<"' = '" << value << "'" << std::endl;
827     }
828
829     // compute
830     bool ok = _libData->Compute();
831
832     GetLog(); // write a log file
833     _logFile = ""; // not to write it again
834
835     return ok;
836 #endif
837   }
838   // add MG license key
839   {
840     std::string errorTxt, meshIn;
841     std::string key = SMESHUtils_MGLicenseKeyGen::GetKey( meshIn,
842                                                           _nbNodes, _nbEdges, _nbFaces, _nbVolumes,
843                                                           errorTxt );
844     if ( key.empty() )
845     {
846       errStr = "Problem with library SalomeMeshGemsKeyGenerator: " + errorTxt;
847       return false;
848     }
849     
850     if ( key != "0")
851       const_cast< std::string& >( cmdLine ) += " --key " + key;
852   }
853
854   int err = system( cmdLine.c_str() ); // run
855
856   if ( err )
857     errStr = SMESH_Comment("system(mg-hexa.exe ...) command failed with error: ")
858       << strerror( errno );
859
860   return !err;
861
862 }
863
864 //================================================================================
865 /*!
866  * \brief Prepare for reading a mesh data
867  */
868 //================================================================================
869
870 int  MG_Hexotic_API::GmfOpenMesh(const char* theFile, int rdOrWr, int * ver, int * dim)
871 {
872   if ( _useLib ) {
873 #ifdef USE_MG_LIBS
874     return 1;
875 #endif
876   }
877   int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim );
878   _openFiles.insert( id );
879   return id;
880 }
881
882 //================================================================================
883 /*!
884  * \brief Return nb of entities
885  */
886 //================================================================================
887
888 int MG_Hexotic_API::GmfStatKwd( int iMesh, GmfKwdCod what )
889 {
890   if ( _useLib ) {
891 #ifdef USE_MG_LIBS
892     switch ( what )
893     {
894     case GmfSubDomainFromGeom: return _libData->ReadNbSubDomains();
895     case GmfVertices:          return _libData->ReadNbNodes();
896     case GmfEdges:             return _libData->ReadNbEdges();
897     case GmfTriangles:         return _libData->ReadNbTria();
898     case GmfQuadrilaterals:    return _libData->ReadNbQuads();
899     case GmfTetrahedra:        return _libData->ReadNbTetra();
900     case GmfHexahedra:         return _libData->ReadNbHexa();
901     case GmfCorners:           return _libData->ReadNbCorners();
902     default:                   return 0;
903     }
904     return 0;
905 #endif
906   }
907   return ::GmfStatKwd( iMesh, what );
908 }
909
910 //================================================================================
911 /*!
912  * \brief Prepare for reading some data
913  */
914 //================================================================================
915
916 void MG_Hexotic_API::GmfGotoKwd( int iMesh, GmfKwdCod what )
917 {
918   if ( _useLib ) {
919 #ifdef USE_MG_LIBS
920     _libData->ResetCounter();
921     return;
922 #endif
923   }
924   ::GmfGotoKwd( iMesh, what );
925 }
926
927 //================================================================================
928 /*!
929  * \brief Return index of a domain identified by a triangle normal
930  *  \param [in] iMesh - mesh file index
931  *  \param [in] what - must be GmfSubDomainFromGeom
932  *  \param [out] nbNodes - nb nodes in a face
933  *  \param [out] faceInd - face index
934  *  \param [out] ori - face orientation
935  *  \param [out] domain - domain index
936  *  \param [in] dummy - an artificial param used to discriminate from GmfGetLin() reading
937  *              a triangle
938  */
939 //================================================================================
940
941 void MG_Hexotic_API::GmfGetLin( int iMesh, GmfKwdCod what, int* nbNodes, int* faceInd, int* ori, int* domain, int /*dummy*/ )
942 {
943   if ( _useLib ) {
944 #ifdef USE_MG_LIBS
945     _libData->ReadSubDomain( nbNodes, faceInd, ori, domain );
946     return;
947 #endif
948   }
949   ::GmfGetLin( iMesh, what, nbNodes, faceInd, ori, domain );
950 }
951
952 //================================================================================
953 /*!
954  * \brief Return coordinates of a next node
955  */
956 //================================================================================
957
958 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
959                                double* x, double* y, double *z, int* domain )
960 {
961   if ( _useLib ) {
962 #ifdef USE_MG_LIBS
963     _libData->ReadNodeXYZ( x, y, z, domain );
964     return;
965 #endif
966   }
967   ::GmfGetLin(iMesh, what, x, y, z, domain );
968 }
969
970 //================================================================================
971 /*!
972  * \brief Return coordinates of a next node
973  */
974 //================================================================================
975
976 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
977                                float* x, float* y, float *z, int* domain )
978 {
979   if ( _useLib ) {
980 #ifdef USE_MG_LIBS
981     double X,Y,Z;
982     _libData->ReadNodeXYZ( &X, &Y, &Z, domain );
983     *x = X;
984     *y = Y;
985     *z = Z;
986     return;
987 #endif
988   }
989   ::GmfGetLin(iMesh, what, x, y, z, domain );
990 }
991
992 //================================================================================
993 /*!
994  * \brief Return node index of a next corner
995  */
996 //================================================================================
997
998 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node )
999 {
1000   if ( _useLib ) {
1001 #ifdef USE_MG_LIBS
1002     _libData->ReadCorner( node );
1003     return;
1004 #endif
1005   }
1006   ::GmfGetLin(iMesh, what, node );
1007 }
1008
1009 //================================================================================
1010 /*!
1011  * \brief Return node indices of a next edge
1012  */
1013 //================================================================================
1014
1015 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node1, int* node2, int* domain )
1016 {
1017   if ( _useLib ) {
1018 #ifdef USE_MG_LIBS
1019     _libData->ReadEdgeNodes( node1, node2, domain );
1020     return;
1021 #endif
1022   }
1023   ::GmfGetLin( iMesh, what, node1, node2, domain );
1024 }
1025
1026 //================================================================================
1027 /*!
1028  * \brief Return node indices of a next triangle
1029  */
1030 //================================================================================
1031
1032 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
1033                                int* node1, int* node2, int* node3, int* domain )
1034 {
1035   if ( _useLib ) {
1036 #ifdef USE_MG_LIBS
1037     _libData->ReadTriaNodes( node1, node2, node3, domain );
1038     return;
1039 #endif
1040   }
1041   ::GmfGetLin(iMesh, what, node1, node2, node3, domain );
1042 }
1043
1044 //================================================================================
1045 /*!
1046  * \brief Return node indices of a next tetrahedron or quadrangle
1047  */
1048 //================================================================================
1049
1050 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
1051                                int* node1, int* node2, int* node3, int* node4, int* domain )
1052 {
1053   if ( _useLib ) {
1054 #ifdef USE_MG_LIBS
1055     if ( what == GmfQuadrilaterals )
1056       _libData->ReadQuadNodes( node1, node2, node3, node4, domain );
1057     else
1058       _libData->ReadTetraNodes( node1, node2, node3, node4, domain );
1059     return;
1060 #endif
1061   }
1062   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, domain );
1063 }
1064
1065 //================================================================================
1066 /*!
1067  * \brief Return node indices of a next hexahedron
1068  */
1069 //================================================================================
1070
1071 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
1072                                int* node1, int* node2, int* node3, int* node4,
1073                                int* node5, int* node6, int* node7, int* node8,
1074                                int* domain )
1075 {
1076   if ( _useLib ) {
1077 #ifdef USE_MG_LIBS
1078     _libData->ReadHexaNodes( node1, node2, node3, node4,
1079                              node5, node6, node7, node8, domain );
1080     return;
1081 #endif
1082   }
1083   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, node5, node6, node7, node8, domain );
1084 }
1085
1086 //================================================================================
1087 /*!
1088  * \brief Prepare for passing data to MeshGems
1089  */
1090 //================================================================================
1091
1092 int  MG_Hexotic_API::GmfOpenMesh(const char* theFile, int rdOrWr, int ver, int dim)
1093 {
1094   if ( _useLib ) {
1095 #ifdef USE_MG_LIBS
1096     return 1;
1097 #endif
1098   }
1099   int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim);
1100   _openFiles.insert( id );
1101   return id;
1102 }
1103
1104 //================================================================================
1105 /*!
1106  * \brief Set number of entities
1107  */
1108 //================================================================================
1109
1110 void MG_Hexotic_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nb )
1111 {
1112   if ( iMesh == 1 && _isMesh )
1113   {
1114     switch ( what ) {
1115     case GmfVertices:  _nbNodes += nb; break;
1116     case GmfEdges:     _nbEdges += nb; break;
1117     case GmfTriangles: _nbFaces += nb; break;
1118     default:;
1119     }
1120   }
1121
1122   if ( _useLib ) {
1123 #ifdef USE_MG_LIBS
1124     switch ( what ) {
1125     case GmfVertices:          _libData->SetNbVertices( nb ); break;
1126     case GmfEdges:             _libData->SetNbEdges   ( nb ); break;
1127     case GmfRequiredEdges:     _libData->SetNbReqEdges( nb ); break;
1128     case GmfTriangles:         _libData->SetNbTria    ( nb ); break;
1129     case GmfRequiredTriangles: _libData->SetNbReqTria ( nb ); break;
1130     default:;
1131     }
1132     return;
1133 #endif
1134   }
1135   ::GmfSetKwd(iMesh, what, nb );
1136 }
1137
1138 //================================================================================
1139 /*!
1140  * \brief Set GMF file made by MG-CADSurf to get nb of mesh entities from it
1141  */
1142 //================================================================================
1143
1144 void MG_Hexotic_API::SetInputFile( const std::string mesh2DFile )
1145 {
1146   DriverGMF_Read fileReader;
1147   fileReader.SetFile( mesh2DFile );
1148
1149   smIdType nbVertex, nbEdge, nbFace, nbVol;
1150   if ( fileReader.GetMeshInfo(nbVertex, nbEdge, nbFace, nbVol))
1151   {
1152     _nbNodes += nbVertex;
1153     _nbEdges += nbEdge;
1154     _nbFaces += nbFace;
1155   }
1156 }
1157
1158 //================================================================================
1159 /*!
1160  * \brief Add coordinates of a node
1161  */
1162 //================================================================================
1163
1164 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, double x, double y, double z, int domain)
1165 {
1166   if ( _useLib ) {
1167 #ifdef USE_MG_LIBS
1168     _libData->AddNode( x, y, z, domain );
1169     return;
1170 #endif
1171   }
1172   ::GmfSetLin(iMesh, what, x, y, z, domain);
1173 }
1174
1175 //================================================================================
1176 /*!
1177  * \brief Set number of field entities
1178  *  \param [in] iMesh - solution file index
1179  *  \param [in] what - solution type
1180  *  \param [in] nbNodes - nb of entities
1181  *  \param [in] nbTypes - nb of data entries in each entity
1182  *  \param [in] type - types of the data entries
1183  *
1184  * Used to prepare to storing size at nodes
1185  */
1186 //================================================================================
1187
1188 void MG_Hexotic_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nbNodes, int dummy, int type[] )
1189 {
1190   if ( _useLib ) {
1191 #ifdef USE_MG_LIBS
1192     if ( what == GmfSolAtVertices ) _libData->SetNbReqVertices( nbNodes );
1193     return;
1194 #endif
1195   }
1196   ::GmfSetKwd(iMesh, what, nbNodes, dummy, type );
1197 }
1198
1199 //================================================================================
1200 /*!
1201  * \brief Add solution data
1202  */
1203 //================================================================================
1204
1205 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, double vals[])
1206 {
1207   if ( _useLib ) {
1208 #ifdef USE_MG_LIBS
1209     _libData->AddSizeAtNode( vals[0] );
1210     return;
1211 #endif
1212   }
1213   ::GmfSetLin(iMesh, what, vals);
1214 }
1215
1216 //================================================================================
1217 /*!
1218  * \brief Add edge nodes
1219  */
1220 //================================================================================
1221
1222 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int domain )
1223 {
1224   if ( _useLib ) {
1225 #ifdef USE_MG_LIBS
1226     _libData->AddEdgeNodes( node1, node2, domain );
1227     return;
1228 #endif
1229   }
1230   ::GmfSetLin(iMesh, what, node1, node2, domain );
1231 }
1232
1233 //================================================================================
1234 /*!
1235  * \brief Add a 'required' flag
1236  */
1237 //================================================================================
1238
1239 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, int id )
1240 {
1241   if ( _useLib ) {
1242 #ifdef USE_MG_LIBS
1243     return;
1244 #endif
1245   }
1246   ::GmfSetLin(iMesh, what, id );
1247 }
1248
1249 //================================================================================
1250 /*!
1251  * \brief Add triangle nodes
1252  */
1253 //================================================================================
1254
1255 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int node3, int domain )
1256 {
1257   if ( _useLib ) {
1258 #ifdef USE_MG_LIBS
1259     _libData->AddTriaNodes( node1, node2, node3, domain );
1260     return;
1261 #endif
1262   }
1263   ::GmfSetLin(iMesh, what, node1, node2, node3, domain );
1264 }
1265
1266 //================================================================================
1267 /*!
1268  * \brief Close a file
1269  */
1270 //================================================================================
1271
1272 void MG_Hexotic_API::GmfCloseMesh( int iMesh )
1273 {
1274   if ( _useLib ) {
1275 #ifdef USE_MG_LIBS
1276     return;
1277 #endif
1278   }
1279   ::GmfCloseMesh( iMesh );
1280   _openFiles.erase( iMesh );
1281 }
1282
1283 //================================================================================
1284 /*!
1285  * \brief Return true if the log is not empty
1286  */
1287 //================================================================================
1288
1289 bool MG_Hexotic_API::HasLog()
1290 {
1291   if ( _useLib ) {
1292 #ifdef USE_MG_LIBS
1293     return !_libData->GetErrors().empty();
1294 #endif
1295   }
1296   SMESH_File file( _logFile );
1297   return file.size() > 0;
1298 }
1299
1300 //================================================================================
1301 /*!
1302  * \brief Return log contents
1303  */
1304 //================================================================================
1305
1306 std::string MG_Hexotic_API::GetLog()
1307 {
1308   if ( _useLib ) {
1309 #ifdef USE_MG_LIBS
1310     const std::string& err = _libData->GetErrors();
1311     if ( !_logFile.empty() && !err.empty() )
1312     {
1313       SMESH_File file( _logFile, /*openForReading=*/false );
1314       file.openForWriting();
1315       file.write( err.c_str(), err.size() );
1316     }
1317     return err;
1318 #endif
1319   }
1320   SMESH_File file( _logFile );
1321   return file.exists() ? file.getPos() : "";
1322 }