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