Salome HOME
d3fda9b0af069c1a14d438ba6f3f759c197a4da2
[plugins/hexoticplugin.git] / src / HexoticPlugin / MG_Hexotic_API.cxx
1 // Copyright (C) 2004-2022  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     if ( key != "0")
849       const_cast< std::string& >( cmdLine ) += " --key " + key;
850   }
851
852   int err = system( cmdLine.c_str() ); // run
853
854   if ( err )
855     errStr = SMESH_Comment("system(mg-hexa.exe ...) command failed with error: ")
856       << strerror( errno );
857
858   return !err;
859
860 }
861
862 //================================================================================
863 /*!
864  * \brief Prepare for reading a mesh data
865  */
866 //================================================================================
867
868 int  MG_Hexotic_API::GmfOpenMesh(const char* theFile, int rdOrWr, int * ver, int * dim)
869 {
870   if ( _useLib ) {
871 #ifdef USE_MG_LIBS
872     return 1;
873 #endif
874   }
875   int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim );
876   _openFiles.insert( id );
877   return id;
878 }
879
880 //================================================================================
881 /*!
882  * \brief Return nb of entities
883  */
884 //================================================================================
885
886 int MG_Hexotic_API::GmfStatKwd( int iMesh, GmfKwdCod what )
887 {
888   if ( _useLib ) {
889 #ifdef USE_MG_LIBS
890     switch ( what )
891     {
892     case GmfSubDomainFromGeom: return _libData->ReadNbSubDomains();
893     case GmfVertices:          return _libData->ReadNbNodes();
894     case GmfEdges:             return _libData->ReadNbEdges();
895     case GmfTriangles:         return _libData->ReadNbTria();
896     case GmfQuadrilaterals:    return _libData->ReadNbQuads();
897     case GmfTetrahedra:        return _libData->ReadNbTetra();
898     case GmfHexahedra:         return _libData->ReadNbHexa();
899     case GmfCorners:           return _libData->ReadNbCorners();
900     default:                   return 0;
901     }
902     return 0;
903 #endif
904   }
905   return ::GmfStatKwd( iMesh, what );
906 }
907
908 //================================================================================
909 /*!
910  * \brief Prepare for reading some data
911  */
912 //================================================================================
913
914 void MG_Hexotic_API::GmfGotoKwd( int iMesh, GmfKwdCod what )
915 {
916   if ( _useLib ) {
917 #ifdef USE_MG_LIBS
918     _libData->ResetCounter();
919     return;
920 #endif
921   }
922   ::GmfGotoKwd( iMesh, what );
923 }
924
925 //================================================================================
926 /*!
927  * \brief Return index of a domain identified by a triangle normal
928  *  \param [in] iMesh - mesh file index
929  *  \param [in] what - must be GmfSubDomainFromGeom
930  *  \param [out] nbNodes - nb nodes in a face
931  *  \param [out] faceInd - face index
932  *  \param [out] ori - face orientation
933  *  \param [out] domain - domain index
934  *  \param [in] dummy - an artificial param used to discriminate from GmfGetLin() reading
935  *              a triangle
936  */
937 //================================================================================
938
939 void MG_Hexotic_API::GmfGetLin( int iMesh, GmfKwdCod what, int* nbNodes, int* faceInd, int* ori, int* domain, int /*dummy*/ )
940 {
941   if ( _useLib ) {
942 #ifdef USE_MG_LIBS
943     _libData->ReadSubDomain( nbNodes, faceInd, ori, domain );
944     return;
945 #endif
946   }
947   ::GmfGetLin( iMesh, what, nbNodes, faceInd, ori, domain );
948 }
949
950 //================================================================================
951 /*!
952  * \brief Return coordinates of a next node
953  */
954 //================================================================================
955
956 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
957                                double* x, double* y, double *z, int* domain )
958 {
959   if ( _useLib ) {
960 #ifdef USE_MG_LIBS
961     _libData->ReadNodeXYZ( x, y, z, domain );
962     return;
963 #endif
964   }
965   ::GmfGetLin(iMesh, what, x, y, z, domain );
966 }
967
968 //================================================================================
969 /*!
970  * \brief Return coordinates of a next node
971  */
972 //================================================================================
973
974 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
975                                float* x, float* y, float *z, int* domain )
976 {
977   if ( _useLib ) {
978 #ifdef USE_MG_LIBS
979     double X,Y,Z;
980     _libData->ReadNodeXYZ( &X, &Y, &Z, domain );
981     *x = X;
982     *y = Y;
983     *z = Z;
984     return;
985 #endif
986   }
987   ::GmfGetLin(iMesh, what, x, y, z, domain );
988 }
989
990 //================================================================================
991 /*!
992  * \brief Return node index of a next corner
993  */
994 //================================================================================
995
996 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node )
997 {
998   if ( _useLib ) {
999 #ifdef USE_MG_LIBS
1000     _libData->ReadCorner( node );
1001     return;
1002 #endif
1003   }
1004   ::GmfGetLin(iMesh, what, node );
1005 }
1006
1007 //================================================================================
1008 /*!
1009  * \brief Return node indices of a next edge
1010  */
1011 //================================================================================
1012
1013 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what, int* node1, int* node2, int* domain )
1014 {
1015   if ( _useLib ) {
1016 #ifdef USE_MG_LIBS
1017     _libData->ReadEdgeNodes( node1, node2, domain );
1018     return;
1019 #endif
1020   }
1021   ::GmfGetLin( iMesh, what, node1, node2, domain );
1022 }
1023
1024 //================================================================================
1025 /*!
1026  * \brief Return node indices of a next triangle
1027  */
1028 //================================================================================
1029
1030 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
1031                                int* node1, int* node2, int* node3, int* domain )
1032 {
1033   if ( _useLib ) {
1034 #ifdef USE_MG_LIBS
1035     _libData->ReadTriaNodes( node1, node2, node3, domain );
1036     return;
1037 #endif
1038   }
1039   ::GmfGetLin(iMesh, what, node1, node2, node3, domain );
1040 }
1041
1042 //================================================================================
1043 /*!
1044  * \brief Return node indices of a next tetrahedron or quadrangle
1045  */
1046 //================================================================================
1047
1048 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
1049                                int* node1, int* node2, int* node3, int* node4, int* domain )
1050 {
1051   if ( _useLib ) {
1052 #ifdef USE_MG_LIBS
1053     if ( what == GmfQuadrilaterals )
1054       _libData->ReadQuadNodes( node1, node2, node3, node4, domain );
1055     else
1056       _libData->ReadTetraNodes( node1, node2, node3, node4, domain );
1057     return;
1058 #endif
1059   }
1060   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, domain );
1061 }
1062
1063 //================================================================================
1064 /*!
1065  * \brief Return node indices of a next hexahedron
1066  */
1067 //================================================================================
1068
1069 void MG_Hexotic_API::GmfGetLin(int iMesh, GmfKwdCod what,
1070                                int* node1, int* node2, int* node3, int* node4,
1071                                int* node5, int* node6, int* node7, int* node8,
1072                                int* domain )
1073 {
1074   if ( _useLib ) {
1075 #ifdef USE_MG_LIBS
1076     _libData->ReadHexaNodes( node1, node2, node3, node4,
1077                              node5, node6, node7, node8, domain );
1078     return;
1079 #endif
1080   }
1081   ::GmfGetLin(iMesh, what, node1, node2, node3, node4, node5, node6, node7, node8, domain );
1082 }
1083
1084 //================================================================================
1085 /*!
1086  * \brief Prepare for passing data to MeshGems
1087  */
1088 //================================================================================
1089
1090 int  MG_Hexotic_API::GmfOpenMesh(const char* theFile, int rdOrWr, int ver, int dim)
1091 {
1092   if ( _useLib ) {
1093 #ifdef USE_MG_LIBS
1094     return 1;
1095 #endif
1096   }
1097   int id = ::GmfOpenMesh(theFile, rdOrWr, ver, dim);
1098   _openFiles.insert( id );
1099   return id;
1100 }
1101
1102 //================================================================================
1103 /*!
1104  * \brief Set number of entities
1105  */
1106 //================================================================================
1107
1108 void MG_Hexotic_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nb )
1109 {
1110   if ( iMesh == 1 && _isMesh )
1111   {
1112     switch ( what ) {
1113     case GmfVertices:  _nbNodes += nb; break;
1114     case GmfEdges:     _nbEdges += nb; break;
1115     case GmfTriangles: _nbFaces += nb; break;
1116     default:;
1117     }
1118   }
1119
1120   if ( _useLib ) {
1121 #ifdef USE_MG_LIBS
1122     switch ( what ) {
1123     case GmfVertices:          _libData->SetNbVertices( nb ); break;
1124     case GmfEdges:             _libData->SetNbEdges   ( nb ); break;
1125     case GmfRequiredEdges:     _libData->SetNbReqEdges( nb ); break;
1126     case GmfTriangles:         _libData->SetNbTria    ( nb ); break;
1127     case GmfRequiredTriangles: _libData->SetNbReqTria ( nb ); break;
1128     default:;
1129     }
1130     return;
1131 #endif
1132   }
1133   ::GmfSetKwd(iMesh, what, nb );
1134 }
1135
1136 //================================================================================
1137 /*!
1138  * \brief Set GMF file made by MG-CADSurf to get nb of mesh entities from it
1139  */
1140 //================================================================================
1141
1142 void MG_Hexotic_API::SetInputFile( const std::string mesh2DFile )
1143 {
1144   DriverGMF_Read fileReader;
1145   fileReader.SetFile( mesh2DFile );
1146
1147   smIdType nbVertex, nbEdge, nbFace, nbVol;
1148   if ( fileReader.GetMeshInfo(nbVertex, nbEdge, nbFace, nbVol))
1149   {
1150     _nbNodes += nbVertex;
1151     _nbEdges += nbEdge;
1152     _nbFaces += nbFace;
1153   }
1154 }
1155
1156 //================================================================================
1157 /*!
1158  * \brief Add coordinates of a node
1159  */
1160 //================================================================================
1161
1162 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, double x, double y, double z, int domain)
1163 {
1164   if ( _useLib ) {
1165 #ifdef USE_MG_LIBS
1166     _libData->AddNode( x, y, z, domain );
1167     return;
1168 #endif
1169   }
1170   ::GmfSetLin(iMesh, what, x, y, z, domain);
1171 }
1172
1173 //================================================================================
1174 /*!
1175  * \brief Set number of field entities
1176  *  \param [in] iMesh - solution file index
1177  *  \param [in] what - solution type
1178  *  \param [in] nbNodes - nb of entities
1179  *  \param [in] nbTypes - nb of data entries in each entity
1180  *  \param [in] type - types of the data entries
1181  *
1182  * Used to prepare to storing size at nodes
1183  */
1184 //================================================================================
1185
1186 void MG_Hexotic_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nbNodes, int dummy, int type[] )
1187 {
1188   if ( _useLib ) {
1189 #ifdef USE_MG_LIBS
1190     if ( what == GmfSolAtVertices ) _libData->SetNbReqVertices( nbNodes );
1191     return;
1192 #endif
1193   }
1194   ::GmfSetKwd(iMesh, what, nbNodes, dummy, type );
1195 }
1196
1197 //================================================================================
1198 /*!
1199  * \brief Add solution data
1200  */
1201 //================================================================================
1202
1203 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, double vals[])
1204 {
1205   if ( _useLib ) {
1206 #ifdef USE_MG_LIBS
1207     _libData->AddSizeAtNode( vals[0] );
1208     return;
1209 #endif
1210   }
1211   ::GmfSetLin(iMesh, what, vals);
1212 }
1213
1214 //================================================================================
1215 /*!
1216  * \brief Add edge nodes
1217  */
1218 //================================================================================
1219
1220 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int domain )
1221 {
1222   if ( _useLib ) {
1223 #ifdef USE_MG_LIBS
1224     _libData->AddEdgeNodes( node1, node2, domain );
1225     return;
1226 #endif
1227   }
1228   ::GmfSetLin(iMesh, what, node1, node2, domain );
1229 }
1230
1231 //================================================================================
1232 /*!
1233  * \brief Add a 'required' flag
1234  */
1235 //================================================================================
1236
1237 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, int id )
1238 {
1239   if ( _useLib ) {
1240 #ifdef USE_MG_LIBS
1241     return;
1242 #endif
1243   }
1244   ::GmfSetLin(iMesh, what, id );
1245 }
1246
1247 //================================================================================
1248 /*!
1249  * \brief Add triangle nodes
1250  */
1251 //================================================================================
1252
1253 void MG_Hexotic_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, int node3, int domain )
1254 {
1255   if ( _useLib ) {
1256 #ifdef USE_MG_LIBS
1257     _libData->AddTriaNodes( node1, node2, node3, domain );
1258     return;
1259 #endif
1260   }
1261   ::GmfSetLin(iMesh, what, node1, node2, node3, domain );
1262 }
1263
1264 //================================================================================
1265 /*!
1266  * \brief Close a file
1267  */
1268 //================================================================================
1269
1270 void MG_Hexotic_API::GmfCloseMesh( int iMesh )
1271 {
1272   if ( _useLib ) {
1273 #ifdef USE_MG_LIBS
1274     return;
1275 #endif
1276   }
1277   ::GmfCloseMesh( iMesh );
1278   _openFiles.erase( iMesh );
1279 }
1280
1281 //================================================================================
1282 /*!
1283  * \brief Return true if the log is not empty
1284  */
1285 //================================================================================
1286
1287 bool MG_Hexotic_API::HasLog()
1288 {
1289   if ( _useLib ) {
1290 #ifdef USE_MG_LIBS
1291     return !_libData->GetErrors().empty();
1292 #endif
1293   }
1294   SMESH_File file( _logFile );
1295   return file.size() > 0;
1296 }
1297
1298 //================================================================================
1299 /*!
1300  * \brief Return log contents
1301  */
1302 //================================================================================
1303
1304 std::string MG_Hexotic_API::GetLog()
1305 {
1306   if ( _useLib ) {
1307 #ifdef USE_MG_LIBS
1308     const std::string& err = _libData->GetErrors();
1309     if ( !_logFile.empty() && !err.empty() )
1310     {
1311       SMESH_File file( _logFile, /*openForReading=*/false );
1312       file.openForWriting();
1313       file.write( err.c_str(), err.size() );
1314     }
1315     return err;
1316 #endif
1317   }
1318   SMESH_File file( _logFile );
1319   return file.exists() ? file.getPos() : "";
1320 }