Salome HOME
Upgrade to new MG license mechanism and keep compatibility with old ones
[plugins/ghs3dplugin.git] / src / GHS3DPlugin / MG_Tetra_API.cxx
index 1ccd80730eee280102db349d7caa1a03faf77703..7e01ab8d96747850d3b269a1291be1cfcbaa77a4 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2004-2016  CEA/DEN, EDF R&D
+// Copyright (C) 2004-2022  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 
 #include "MG_Tetra_API.hxx"
 
+#ifdef WIN32
+#define NOMINMAX
+#endif
+
 #include <SMESH_Comment.hxx>
 #include <SMESH_File.hxx>
+#include <SMESH_MGLicenseKeyGen.hxx>
 #include <Utils_SALOME_Exception.hxx>
 
-#include <vector>
-#include <iterator>
 #include <cstring>
+#include <iostream>
+#include <iterator>
+#include <vector>
 
 #ifdef USE_MG_LIBS
 
@@ -34,6 +40,9 @@ extern "C"{
 #include <meshgems/tetra.h>
 }
 
+#define MESHGEMS_VERSION_HEX (MESHGEMS_VERSION_MAJOR << 16 | MESHGEMS_VERSION_MINOR << 8 | MESHGEMS_VERSION_PATCH)
+#define MESHGEMS_215 (2 << 16 | 15 << 8 | 0)
+
 struct MG_Tetra_API::LibData
 {
   // MG objects
@@ -50,16 +59,18 @@ struct MG_Tetra_API::LibData
   int                 _nbRequiredEdges;
   std::vector<int>    _triaNodes;
   int                 _nbRequiredTria;
+  std::vector<int>    _tetraNodes;
 
   int                 _count;
   volatile bool&      _cancelled_flag;
   std::string         _errorStr;
   double&             _progress;
+  bool                _progressInCallBack;
 
   LibData( volatile bool & cancelled_flag, double& progress )
     : _context(0), _session(0), _tria_mesh(0), _sizemap(0), _tetra_mesh(0),
       _nbRequiredEdges(0), _nbRequiredTria(0),
-      _cancelled_flag( cancelled_flag ), _progress( progress )
+      _cancelled_flag( cancelled_flag ), _progress( progress ), _progressInCallBack( false )
   {
   }
   // methods setting callbacks implemented after callback definitions
@@ -326,6 +337,11 @@ struct MG_Tetra_API::LibData
     _triaNodes.reserve( nb * 3 );
   }
 
+  void SetNbTetra( int nb )
+  {
+    _tetraNodes.reserve( nb * 4 );
+  }
+
   void SetNbReqVertices( int nb )
   {
     _nodeSize.reserve( nb );
@@ -341,7 +357,7 @@ struct MG_Tetra_API::LibData
     _nbRequiredTria = nb;
   }
 
-  void AddNode( double x, double y, double z, int domain )
+  void AddNode( double x, double y, double z, int /*domain*/ )
   {
     _xyz.push_back( x );
     _xyz.push_back( y );
@@ -353,19 +369,27 @@ struct MG_Tetra_API::LibData
     _nodeSize.push_back( size );
   }
   
-  void AddEdgeNodes( int node1, int node2, int domain )
+  void AddEdgeNodes( int node1, int node2, int /*domain*/ )
   {
     _edgeNodes.push_back( node1 );
     _edgeNodes.push_back( node2 );
   }
   
-  void AddTriaNodes( int node1, int node2, int node3, int domain )
+  void AddTriaNodes( int node1, int node2, int node3, int /*domain*/ )
   {
     _triaNodes.push_back( node1 );
     _triaNodes.push_back( node2 );
     _triaNodes.push_back( node3 );
   }
 
+  void AddTetraNodes( int node1, int node2, int node3, int node4, int /*domain*/ )
+  {
+    _tetraNodes.push_back( node1 );
+    _tetraNodes.push_back( node2 );
+    _tetraNodes.push_back( node3 );
+    _tetraNodes.push_back( node4 );
+  }
+
   int NbNodes()
   {
     return _xyz.size() / 3;
@@ -391,11 +415,21 @@ struct MG_Tetra_API::LibData
     return _triaNodes.size() / 3;
   }
 
+  int NbTetra()
+  {
+    return _tetraNodes.size() / 4;
+  }
+
   int * GetTriaNodes( int iTria )
   {
     return & _triaNodes[ iTria * 3 ];
   }
 
+  int * GetTetraNodes( int iTet )
+  {
+    return & _tetraNodes[ iTet * 4 ];
+  }
+
   int IsVertexRequired( int iNode )
   {
     return ! ( iNode < int( NbNodes() - _nodeSize.size() ));
@@ -482,26 +516,25 @@ namespace // functions called by MG library to exchange with the application
   //   return STATUS_OK;
   // }
 
-  // status_t get_tetrahedron_count(integer * nbtetra, void *user_data)
-  // {
-  //   MG_Tetra_API::LibData* data = (MG_Tetra_API::LibData *) user_data;
-
-  //   *nbtetra = 0;                 /* the number of tetra in your input mesh (0 if you describe a surface mesh) */
-
-  //   return STATUS_OK;
-  // }
+  status_t get_tetrahedron_count(integer * nbtetra, void *user_data)
+  {
+    MG_Tetra_API::LibData* data = (MG_Tetra_API::LibData *) user_data;
+    *nbtetra = data->NbTetra();
 
-  // status_t get_tetrahedron_vertices(integer itetra, integer * vtetra,
-  //                                   void *user_data)
-  // {
-  //   int j;
-  //   MG_Tetra_API::LibData* data = (MG_Tetra_API::LibData *) user_data;
+    return STATUS_OK;
+  }
 
-  //   for (j = 0; j < 4; j++)
-  //     vtetra[j] = 0;              /* the j'th vertex index of the itetra'th tetrahedron */
+  status_t get_tetrahedron_vertices(integer itetra, integer * vtetra,
+                                    void *user_data)
+  {
+    int j;
+    MG_Tetra_API::LibData* data = (MG_Tetra_API::LibData *) user_data;
+    int* nodes = data->GetTetraNodes( itetra-1 );
+    for (j = 0; j < 4; j++)
+      vtetra[j] = nodes[j];
 
-  //   return STATUS_OK;
-  // }
+    return STATUS_OK;
+  }
 
   status_t get_vertex_required_property(integer ivtx, integer * rvtx, void *user_data)
   {
@@ -531,26 +564,37 @@ namespace // functions called by MG library to exchange with the application
     //std::cout << desc << std::endl;
 #endif
 
-    // Compute progress
-    // corresponding messages are:
-    // "  -- PHASE 1 COMPLETED"               => 10 %
-    // "  -- PHASE 2 COMPLETED"               => 25 %
-    // "     ** ITERATION   1"                => 25.* %
-    // "     ** ITERATION   2"                => 25.* %
-    // "  -- PHASE 3 COMPLETED"               => 70 %
-    // "  -- PHASE 4 COMPLETED"               => 98 %
-
-    if ( strncmp( "-- PHASE ", desc + 2, 9 ) == 0 && desc[ 13 ] == 'C' )
+    if ( strncmp( "MGMESSAGE  1009001 ", desc, 19 ) == 0 )
     {
-      const double progress[] = { 10., 25., 70., 98., 100., 100., 100. };
-      int       phase = atoi( desc + 11 );
-      data->_progress = std::max( data->_progress, progress[ phase - 1 ] / 100. );
+      // progress message (10%): "MGMESSAGE  1009001  0 1 1.000000e+01"
+      data->_progress = atof( desc + 24 );
+
+      data->_progressInCallBack = true;
     }
-    else if ( strncmp( "** ITERATION ", desc + 5, 13 ) == 0 )
+
+    if ( !data->_progressInCallBack )
     {
-      int         iter = atoi( desc + 20 );
-      double   percent = 25. + iter * ( 70 - 25 ) / 20.;
-      data->_progress = std::max( data->_progress, ( percent / 100. ));
+      // Compute progress
+      // corresponding messages are:
+      // "  -- PHASE 1 COMPLETED"               => 10 %
+      // "  -- PHASE 2 COMPLETED"               => 25 %
+      // "     ** ITERATION   1"                => 25.* %
+      // "     ** ITERATION   2"                => 25.* %
+      // "  -- PHASE 3 COMPLETED"               => 70 %
+      // "  -- PHASE 4 COMPLETED"               => 98 %
+
+      if ( strncmp( "-- PHASE ", desc + 2, 9 ) == 0 && desc[ 13 ] == 'C' )
+      {
+        const double progress[] = { 10., 25., 70., 98., 100., 100., 100. };
+        int       phase = atoi( desc + 11 );
+        data->_progress = std::max( data->_progress, progress[ phase - 1 ] / 100. );
+      }
+      else if ( strncmp( "** ITERATION ", desc + 5, 13 ) == 0 )
+      {
+        int         iter = atoi( desc + 20 );
+        double   percent = 25. + iter * ( 70 - 25 ) / 20.;
+        data->_progress = std::max( data->_progress, ( percent / 100. ));
+      }
     }
 
     return STATUS_OK;
@@ -592,6 +636,8 @@ void MG_Tetra_API::LibData::Init()
   mesh_set_get_edge_vertices( _tria_mesh, get_edge_vertices, this );
   mesh_set_get_triangle_count( _tria_mesh, get_triangle_count, this );
   mesh_set_get_triangle_vertices( _tria_mesh, get_triangle_vertices, this );
+  mesh_set_get_tetrahedron_count( _tria_mesh, get_tetrahedron_count, this );
+  mesh_set_get_tetrahedron_vertices( _tria_mesh, get_tetrahedron_vertices, this );
 
   // Create a tetra session
   _session = tetra_session_new( _context );
@@ -604,9 +650,51 @@ void MG_Tetra_API::LibData::Init()
 
 bool MG_Tetra_API::LibData::Compute()
 {
-  // Set surface mesh
-  status_t ret = tetra_set_surface_mesh( _session, _tria_mesh );
-  if ( ret != STATUS_OK ) MG_Error( "unable to set surface mesh");
+  status_t ret;
+  std::string errorTxt;
+
+#if MESHGEMS_VERSION_HEX > MESHGEMS_215
+  // need to unlock Tetra license only once
+  std::string SPATIAL_LICENSE = SMESHUtils_MGLicenseKeyGen::GetKey(errorTxt);
+  ret = meshgems_tetra_unlock_product(SPATIAL_LICENSE.c_str());
+  if STATUS_IS_ERROR( ret )
+    {
+    AddError( SMESH_Comment( "Problem with SPATIAL_LICENSE to unlock Tetra: ") << errorTxt );
+    return false;
+    }
+  else
+    MESSAGE("SPATIAL_LICENSE unlock Tetra: " << ret);
+#endif
+
+  if ( _tetraNodes.empty() )
+  {
+#if MESHGEMS_VERSION_HEX < MESHGEMS_215
+    // Sign the surface mesh
+    if ( !SMESHUtils_MGLicenseKeyGen::SignMesh( _tria_mesh, errorTxt ))
+    {
+      AddError( SMESH_Comment( "Problem with library SalomeMeshGemsKeyGenerator: ") << errorTxt );
+      return false;
+    }
+#endif
+    // Set surface mesh
+    ret = tetra_set_surface_mesh( _session, _tria_mesh );
+    if ( ret != STATUS_OK ) MG_Error( "unable to set surface mesh");
+  }
+  else
+  {
+#if MESHGEMS_VERSION_HEX < MESHGEMS_215
+    // Sign the volume mesh
+    // TOOD: check if there is a typo here. Should be _tetra_mesh ?
+    if ( !SMESHUtils_MGLicenseKeyGen::SignMesh( _tria_mesh, errorTxt ))
+    {
+      AddError( SMESH_Comment( "Problem with library SalomeMeshGemsKeyGenerator: ") << errorTxt );
+      return false;
+    }
+#endif
+    // TOOD: check if there is a typo here. Should be _tetra_mesh ?
+    ret = tetra_set_volume_mesh( _session, _tria_mesh );
+    if ( ret != STATUS_OK ) MG_Error( "unable to set volume mesh");
+  }
 
   // Set a sizemap
   if ( !_nodeSize.empty() )
@@ -631,13 +719,24 @@ bool MG_Tetra_API::LibData::Compute()
   if (ret != STATUS_OK) MG_Error( "unable to get resulting mesh");
 
   //////////////////////////////////////////////////////////////////////////////////////////
-  // file  =  "/tmp/ghs3d_OUT.mesh";
-  // mesh_write_mesh( _tetra_mesh,file);
-  // std::cout << std::endl << std::endl << "Write " << file << std::endl << std::endl << std::endl;
-
+  // {
+  //   const char* file  =  "/tmp/ghs3d_OUT.mesh";
+  //   mesh_write_mesh( _tetra_mesh,file);
+  //   std::cout << std::endl << std::endl << "Write " << file << std::endl << std::endl << std::endl;
+  // }
   return true;
 }
 
+#else // ifdef USE_MG_LIBS
+
+struct MG_Tetra_API::LibData // to avoid compiler warnings
+{
+  volatile bool& _cancelled_flag;
+  double& _progress;
+  LibData(volatile bool& cancelled_flag, double& progress):
+    _cancelled_flag{cancelled_flag}, _progress{progress}
+  {}
+};
 
 #endif // ifdef USE_MG_LIBS
 
@@ -648,15 +747,17 @@ bool MG_Tetra_API::LibData::Compute()
  */
 //================================================================================
 
-MG_Tetra_API::MG_Tetra_API(volatile bool& cancelled_flag, double& progress)
+MG_Tetra_API::MG_Tetra_API(volatile bool& cancelled_flag, double& progress):
+  _nbNodes(0), _nbEdges(0), _nbFaces(0), _nbVolumes(0)
 {
+  _useLib = false;
+  _libData = new LibData( cancelled_flag, progress );
 #ifdef USE_MG_LIBS
   _useLib = true;
-  _libData = new LibData( cancelled_flag, progress );
   _libData->Init();
-#endif
   if ( getenv("MG_TETRA_USE_EXE"))
     _useLib = false;
+#endif
 }
 
 //================================================================================
@@ -731,6 +832,8 @@ bool MG_Tetra_API::Compute( const std::string& cmdLine, std::string& errStr )
       value = "";
       while ( i+1 < args.size() && args[i+1][0] != '-' )
       {
+        if ( strncmp( "1>", args[i+1].c_str(), 2 ) == 0 )
+          break;
         if ( !value.empty() ) value += " ";
         value += args[++i];
       }
@@ -739,7 +842,7 @@ bool MG_Tetra_API::Compute( const std::string& cmdLine, std::string& errStr )
     }
 
     // compute
-    bool ok =  _libData->Compute();
+    bool ok = _libData->Compute();
 
     GetLog(); // write a log file
     _logFile = ""; // not to write it again
@@ -748,6 +851,22 @@ bool MG_Tetra_API::Compute( const std::string& cmdLine, std::string& errStr )
 #endif
   }
 
+  // add MG license key
+  {
+    std::string errorTxt, meshIn;
+    std::string key = SMESHUtils_MGLicenseKeyGen::GetKey( meshIn,
+                                                          _nbNodes, _nbEdges, _nbFaces, _nbVolumes,
+                                                          errorTxt );
+    if ( key.empty() )
+    {
+      errStr = "Problem with library SalomeMeshGemsKeyGenerator: " + errorTxt;
+      return false;
+    }
+
+    if ( key != "0")
+      const_cast< std::string& >( cmdLine ) += " --key " + key;
+  }
+
   int err = system( cmdLine.c_str() ); // run
 
   if ( err )
@@ -834,7 +953,7 @@ void MG_Tetra_API::GmfGotoKwd( int iMesh, GmfKwdCod what )
  */
 //================================================================================
 
-void MG_Tetra_API::GmfGetLin( int iMesh, GmfKwdCod what, int* nbNodes, int* faceInd, int* ori, int* domain, int dummy )
+void MG_Tetra_API::GmfGetLin( int iMesh, GmfKwdCod what, int* nbNodes, int* faceInd, int* ori, int* domain, int /*dummy*/ )
 {
   if ( _useLib ) {
 #ifdef USE_MG_LIBS
@@ -1005,6 +1124,17 @@ int  MG_Tetra_API::GmfOpenMesh(const char* theFile, int rdOrWr, int ver, int dim
 
 void MG_Tetra_API::GmfSetKwd(int iMesh, GmfKwdCod what, int nb )
 {
+  //if ( iMesh == 1 )
+  {
+    switch ( what ) {
+    case GmfVertices:   _nbNodes   += nb; break;
+    case GmfEdges:      _nbEdges   += nb; break;
+    case GmfTriangles:  _nbFaces   += nb; break;
+    case GmfTetrahedra: _nbVolumes += nb; break;
+    default:;
+    }
+  }
+
   if ( _useLib ) {
 #ifdef USE_MG_LIBS
     switch ( what ) {
@@ -1129,6 +1259,24 @@ void MG_Tetra_API::GmfSetLin(int iMesh, GmfKwdCod what, int node1, int node2, in
   ::GmfSetLin(iMesh, what, node1, node2, node3, domain );
 }
 
+//================================================================================
+/*!
+ * \brief Add tetra nodes
+ */
+//================================================================================
+
+void MG_Tetra_API::GmfSetLin(int iMesh, GmfKwdCod what,
+                             int node1, int node2, int node3, int node4, int domain )
+{
+  if ( _useLib ) {
+#ifdef USE_MG_LIBS
+    _libData->AddTetraNodes( node1, node2, node3, node4, domain );
+    return;
+#endif
+  }
+  ::GmfSetLin(iMesh, what, node1, node2, node3, node4, domain );
+}
+
 //================================================================================
 /*!
  * \brief Close a file