Salome HOME
Fix compilation error
[plugins/blsurfplugin.git] / src / BLSURFPlugin / BLSURFPlugin_Hypothesis.cxx
index 7d2be5b279286d74d0ee9d34537c56925ad8e0fa..cec87cac89653578dcc362c52cf1ca3461422ce3 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D
+// Copyright (C) 2007-2019  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
@@ -49,8 +49,8 @@ namespace
 }
 
 //=============================================================================
-BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_Gen * gen) :
-  SMESH_Hypothesis(hypId, studyId, gen), 
+BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, SMESH_Gen * gen, bool hasgeom) :
+  SMESH_Hypothesis(hypId, gen),
   _physicalMesh(GetDefaultPhysicalMesh()),
   _geometricMesh(GetDefaultGeometricMesh()),
   _phySize(GetDefaultPhySize()),
@@ -63,9 +63,9 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
   _gradation(GetDefaultGradation()),
   _useVolumeGradation(GetDefaultUseVolumeGradation()),
   _volumeGradation(GetDefaultVolumeGradation()),
-  _quadAllowed(GetDefaultQuadAllowed()),
+  _elementType(GetDefaultElementType()),
   _angleMesh(GetDefaultAngleMesh()),
-  _chordalError(GetDefaultChordalError()), 
+  _chordalError(GetDefaultChordalError()),
   _anisotropic(GetDefaultAnisotropic()),
   _anisotropicRatio(GetDefaultAnisotropicRatio()),
   _removeTinyEdges(GetDefaultRemoveTinyEdges()),
@@ -80,8 +80,13 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
   _quadraticMesh(GetDefaultQuadraticMesh()),
   _verb(GetDefaultVerbosity()),
   _topology(GetDefaultTopology()),
+  _useSurfaceProximity(GetDefaultUseSurfaceProximity()),
+  _nbSurfaceProximityLayers(GetDefaultNbSurfaceProximityLayers()),
+  _surfaceProximityRatio(GetDefaultSurfaceProximityRatio()),
+  _useVolumeProximity(GetDefaultUseVolumeProximity()),
+  _nbVolumeProximityLayers(GetDefaultNbVolumeProximityLayers()),
+  _volumeProximityRatio(GetDefaultVolumeProximityRatio()),
   _preCADMergeEdges(GetDefaultPreCADMergeEdges()),
-  _preCADRemoveTinyUVEdges(GetDefaultPreCADRemoveTinyUVEdges()),
   _preCADRemoveDuplicateCADFaces(GetDefaultPreCADRemoveDuplicateCADFaces()),
   _preCADProcess3DTopology(GetDefaultPreCADProcess3DTopology()),
   _preCADDiscardInput(GetDefaultPreCADDiscardInput()),
@@ -100,39 +105,35 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
   _preCadEdgesPeriodicityVector(GetDefaultPreCadEdgesPeriodicityVector()),
   _GMFFileName(GetDefaultGMFFile())
 {
-  _name = GetHypType();
+  _name = GetHypType(hasgeom);
   _param_algo_dim = 2;
-  
-//   _GMFFileMode = false; // GMF ascii mode
 
   // Advanced options with their defaults according to MG User Manual
 
-  const char* boolOptionNames[] = {         "enforce_cad_edge_sizes",                   // default = 0
-                                            // "correct_surface_intersections",            // default = 1
-                                            // "create_tag_on_collision",                  // default = 1
-                                            "jacobian_rectification_respect_geometry",  // default = 1
-                                            "rectify_jacobian",                         // default = 1
-                                            "respect_geometry",                         // default = 1
-                                            // "optimise_tiny_edges",                      // default = 0
-                                            // "remove_duplicate_cad_faces",               // default = 1
-                                            "tiny_edge_avoid_surface_intersections",    // default = 1
-                                            // "tiny_edge_respect_geometry",               // default = 0
-                                            "" // mark of end
-      };
+  const char* boolOptionNames[] = { "enforce_cad_edge_sizes",                   // default = 0
+                                    "jacobian_rectification_respect_geometry",  // default = 1
+                                    "rectify_jacobian",                         // default = 1
+                                    "respect_geometry",                         // default = 1
+                                    "tiny_edge_avoid_surface_intersections",    // default = 1
+                                    "debug",                                    // default = 0
+                                    "allow_patch_independent",                   // false
+                                    "" // mark of end
+  };
 
   const char* intOptionNames[] = {          "max_number_of_points_per_patch",           // default = 100000
+                                            "max_number_of_threads",                    // default = 4
                                             "" // mark of end
-      };
+  };
   const char* doubleOptionNames[] = {       // "surface_intersections_processing_max_cost",// default = 15
                                             // "periodic_tolerance",                       // default = diag/100
                                             // "volume_gradation",
                                             // "tiny_edge_optimisation_length",            // default = diag * 1e-6
-                                            "" // mark of end
-      };
+    "" // mark of end
+  };
   const char* charOptionNames[] = {         // "required_entities",                        // default = "respect"
                                             // "tags",                                     // default = "respect"
-                                            "" // mark of end
-      };
+    "" // mark of end
+  };
 
   // PreCAD advanced options
   const char* preCADboolOptionNames[] = {   "closed_geometry",                          // default = 0
@@ -140,9 +141,12 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
                                             "merge_edges",                              // default =  = 1
                                             "remove_duplicate_cad_faces",               // default = 1
                                             // "create_tag_on_collision",                  // default = 1
-                                            "debug",                                    // default = 0 
                                             "process_3d_topology",                      // default = 1
                                             // "remove_tiny_edges",                        // default = 0
+                                            // remove_tiny_uv_edges option is not documented
+                                            // but it is useful that the user can change it to disable all preprocessing options
+                                            "remove_tiny_uv_edges",                        // default = 1
+                                            "compute_ridges",                             // true
                                             "" // mark of end
       };
   const char* preCADintOptionNames[] = {    // "manifold_geometry",                        // default = 0
@@ -165,7 +169,7 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
     _option2value[boolOptionNames[i++]].clear();
   }
   i = 0;
-  while (preCADboolOptionNames[i][0])
+  while (preCADboolOptionNames[i][0] && hasgeom)
   {
     _boolOptions.insert( preCADboolOptionNames[i] );
     _preCADoption2value[preCADboolOptionNames[i++]].clear();
@@ -175,7 +179,7 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
     _option2value[intOptionNames[i++]].clear();
   
   i = 0;
-  while (preCADintOptionNames[i][0])
+  while (preCADintOptionNames[i][0] && hasgeom)
     _preCADoption2value[preCADintOptionNames[i++]].clear();
 
   i = 0;
@@ -184,7 +188,7 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
     _option2value[doubleOptionNames[i++]].clear();
   }
   i = 0;
-  while (preCADdoubleOptionNames[i][0]) {
+  while (preCADdoubleOptionNames[i][0] && hasgeom) {
     _preCADdoubleOptions.insert(preCADdoubleOptionNames[i]);
     _preCADoption2value[preCADdoubleOptionNames[i++]].clear();
   }
@@ -194,7 +198,7 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
     _option2value[charOptionNames[i++]].clear();
   }
   i = 0;
-  while (preCADcharOptionNames[i][0]) {
+  while (preCADcharOptionNames[i][0] && hasgeom) {
     _preCADcharOptions.insert(preCADcharOptionNames[i]);
     _preCADoption2value[preCADcharOptionNames[i++]].clear();
   }
@@ -204,19 +208,27 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
   _defaultOptionValues["enforce_cad_edge_sizes"                 ] = "no";
   _defaultOptionValues["jacobian_rectification_respect_geometry"] = "yes";
   _defaultOptionValues["max_number_of_points_per_patch"         ] = "0";
+  _defaultOptionValues["max_number_of_threads"                  ] = "4";
   _defaultOptionValues["rectify_jacobian"                       ] = "yes";
   _defaultOptionValues["respect_geometry"                       ] = "yes";
   _defaultOptionValues["tiny_edge_avoid_surface_intersections"  ] = "yes";
-  _defaultOptionValues["process_3d_topology"                    ] = "no";
-  _defaultOptionValues["closed_geometry"                        ] = "no";
+  //_defaultOptionValues["use_deprecated_patch_mesher"          ] = "no";
   _defaultOptionValues["debug"                                  ] = "no";
-  _defaultOptionValues["discard_input_topology"                 ] = "no";
-  _defaultOptionValues["merge_edges"                            ] = "no";
-  _defaultOptionValues["periodic_tolerance"                     ] = "1e-5*D";
-  _defaultOptionValues["remove_duplicate_cad_faces"             ] = "no";
-  _defaultOptionValues["required_entities"                      ] = "respect";
-  _defaultOptionValues["sewing_tolerance"                       ] = "5e-4*D";
-  _defaultOptionValues["tags"                                   ] = "respect";
+  _defaultOptionValues["allow_patch_independent"                ] = "no";
+  if ( hasgeom )
+  {
+    _defaultOptionValues["closed_geometry"                        ] = "no";
+    _defaultOptionValues["discard_input_topology"                 ] = "no";
+    _defaultOptionValues["merge_edges"                            ] = "no";
+    _defaultOptionValues["periodic_tolerance"                     ] = "1e-5*D";
+    _defaultOptionValues["process_3d_topology"                    ] = "no";
+    _defaultOptionValues["remove_duplicate_cad_faces"             ] = "no";
+    _defaultOptionValues["remove_tiny_uv_edges"                   ] = "no";
+    _defaultOptionValues["required_entities"                      ] = "respect";
+    _defaultOptionValues["sewing_tolerance"                       ] = "5e-4*D";
+    _defaultOptionValues["tags"                                   ] = "respect";
+    _defaultOptionValues["compute_ridges"                         ] = "yes";
+  }
 
 #ifdef _DEBUG_
   // check validity of option names of _defaultOptionValues
@@ -225,38 +237,22 @@ BLSURFPlugin_Hypothesis::BLSURFPlugin_Hypothesis(int hypId, int studyId, SMESH_G
     ASSERT( _option2value.count( n2v->first ) || _preCADoption2value.count( n2v->first ));
   ASSERT( _option2value.size() + _preCADoption2value.size() == _defaultOptionValues.size() );
 #endif
-      
-  _sizeMap.clear();
-  _attractors.clear();
-  _faceEntryEnfVertexListMap.clear();
-  _enfVertexList.clear();
-  _faceEntryCoordsListMap.clear();
-  _coordsEnfVertexMap.clear();
-  _faceEntryEnfVertexEntryListMap.clear();
-  _enfVertexEntryEnfVertexMap.clear();
-  _groupNameNodeIDMap.clear();
 
-  /* TODO GROUPS
-   _groupNameEnfVertexListMap.clear();
-   _enfVertexGroupNameMap.clear();
-   */
 }
 
 TopoDS_Shape BLSURFPlugin_Hypothesis::entryToShape(std::string entry)
 {
   GEOM::GEOM_Object_var aGeomObj;
-  SMESH_Gen_i* smeshGen_i = SMESH_Gen_i::GetSMESHGen();
-  SALOMEDS::Study_ptr myStudy = smeshGen_i->GetCurrentStudy();
   
   TopoDS_Shape S = TopoDS_Shape();
-  SALOMEDS::SObject_var aSObj = myStudy->FindObjectID( entry.c_str() );
+  SALOMEDS::SObject_var aSObj = SMESH_Gen_i::getStudyServant()->FindObjectID( entry.c_str() );
   if (!aSObj->_is_nil() ) {
     CORBA::Object_var obj = aSObj->GetObject();
     aGeomObj = GEOM::GEOM_Object::_narrow(obj);
     aSObj->UnRegister();
   }
   if ( !aGeomObj->_is_nil() )
-    S = smeshGen_i->GeomObjectToShape( aGeomObj.in() );
+    S = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( aGeomObj.in() );
   return S;
 }
 
@@ -349,9 +345,9 @@ void BLSURFPlugin_Hypothesis::SetVolumeGradation(double theVal) {
 }
 
 //=============================================================================
-void BLSURFPlugin_Hypothesis::SetQuadAllowed(bool theVal) {
-  if (theVal != _quadAllowed) {
-    _quadAllowed = theVal;
+void BLSURFPlugin_Hypothesis::SetElementType(ElementType theElementType) {
+  if (theElementType != _elementType) {
+    _elementType = theElementType;
     NotifySubMeshesHypothesisModification();
   }
 }
@@ -476,6 +472,66 @@ void BLSURFPlugin_Hypothesis::SetTopology(Topology theTopology) {
   }
 }
 
+//=============================================================================
+void BLSURFPlugin_Hypothesis::SetUseSurfaceProximity( bool toUse )
+{
+  if ( _useSurfaceProximity != toUse )
+  {
+    _useSurfaceProximity = toUse;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=============================================================================
+void BLSURFPlugin_Hypothesis::SetNbSurfaceProximityLayers( int nbLayers )
+{
+  if ( _nbSurfaceProximityLayers != nbLayers )
+  {
+    _nbSurfaceProximityLayers = nbLayers;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=============================================================================
+void BLSURFPlugin_Hypothesis::SetSurfaceProximityRatio( double ratio )
+{
+  if ( _surfaceProximityRatio != ratio )
+  {
+    _surfaceProximityRatio = ratio;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=============================================================================
+void BLSURFPlugin_Hypothesis::SetUseVolumeProximity( bool toUse )
+{
+  if ( _useVolumeProximity != toUse )
+  {
+    _useVolumeProximity = toUse;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=============================================================================
+void BLSURFPlugin_Hypothesis::SetNbVolumeProximityLayers( int nbLayers )
+{
+  if ( _nbVolumeProximityLayers != nbLayers )
+  {
+    _nbVolumeProximityLayers = nbLayers;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//=============================================================================
+void BLSURFPlugin_Hypothesis::SetVolumeProximityRatio( double ratio )
+{
+  if ( _volumeProximityRatio != ratio )
+  {
+    _volumeProximityRatio = ratio;
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
 //=============================================================================
 void BLSURFPlugin_Hypothesis::SetVerbosity(int theVal) {
   if (theVal != _verb) {
@@ -530,6 +586,21 @@ bool BLSURFPlugin_Hypothesis::GetJacobianRectification()
 }
 //=============================================================================
 
+void BLSURFPlugin_Hypothesis::SetUseDeprecatedPatchMesher( bool useDeprecatedPatchMesher )
+{
+  // if ( GetUseDeprecatedPatchMesher() != useDeprecatedPatchMesher )
+  // {
+  //   SetOptionValue( "use_deprecated_patch_mesher", useDeprecatedPatchMesher ? "yes" : "no" );
+  //   NotifySubMeshesHypothesisModification();
+  // }
+}
+//=============================================================================
+bool BLSURFPlugin_Hypothesis::GetUseDeprecatedPatchMesher()
+{
+  return false;//ToBool( GetOptionValue("use_deprecated_patch_mesher", GET_DEFAULT()));
+}
+//=============================================================================
+
 void BLSURFPlugin_Hypothesis::SetMaxNumberOfPointsPerPatch( int nb )
   throw (std::invalid_argument)
 {
@@ -549,6 +620,25 @@ int BLSURFPlugin_Hypothesis::GetMaxNumberOfPointsPerPatch()
 }
 //=============================================================================
 
+void BLSURFPlugin_Hypothesis::SetMaxNumberOfThreads( int nb )
+  throw (std::invalid_argument)
+{
+  if ( nb < 0 )
+    throw std::invalid_argument( SMESH_Comment("Invalid number of threads: ") << nb );
+
+  if ( GetMaxNumberOfThreads() != nb )
+  {
+    SetOptionValue("max_number_of_threads", SMESH_Comment( nb ));
+    NotifySubMeshesHypothesisModification();
+  }
+}
+//=============================================================================
+int BLSURFPlugin_Hypothesis::GetMaxNumberOfThreads()
+{
+  return ToInt( GetOptionValue("max_number_of_threads", GET_DEFAULT()));
+}
+//=============================================================================
+
 void BLSURFPlugin_Hypothesis::SetRespectGeometry( bool toRespect )
 {
   if ( GetRespectGeometry() != toRespect )
@@ -684,20 +774,83 @@ std::string BLSURFPlugin_Hypothesis::GetTags()
   return GetPreCADOptionValue("tags", GET_DEFAULT());
 }
 //=============================================================================
-void BLSURFPlugin_Hypothesis::SetPreCADMergeEdges(bool theVal)
+void BLSURFPlugin_Hypothesis::SetHyperPatches(const THyperPatchList& hpl)
 {
-  if (theVal != ToBool( GetPreCADOptionValue("merge_edges", GET_DEFAULT()))) {
-    _preCADMergeEdges = theVal;
-    SetPreCADOptionValue("merge_edges", theVal ? "yes" : "no" );
+  if ( hpl != _hyperPatchList )
+  {
+    // join patches sharing tags
+    _hyperPatchList.clear();
+    for ( size_t i = 0; i < hpl.size(); ++i )
+    {
+      const THyperPatchTags& tags = hpl[i];
+      if ( tags.size() < 2 ) continue;
+
+      std::set<int> iPatches;
+      if ( !_hyperPatchList.empty() )
+      {
+        THyperPatchTags::iterator t = tags.begin();
+        for ( ; t != tags.end(); ++t )
+        {
+          int iPatch = -1;
+          GetHyperPatchTag( *t, this, &iPatch );
+          if ( iPatch >= 0 )
+            iPatches.insert( iPatch );
+        }
+      }
+
+      if ( iPatches.empty() )
+      {
+        _hyperPatchList.push_back( tags );
+      }
+      else
+      {
+        std::set<int>::iterator iPatch = iPatches.begin();
+        THyperPatchTags&     mainPatch = _hyperPatchList[ *iPatch ];
+        mainPatch.insert( tags.begin(), tags.end() );
+
+        for ( ++iPatch; iPatch != iPatches.end(); ++iPatch )
+        {
+          mainPatch.insert( _hyperPatchList[ *iPatch ].begin(), _hyperPatchList[ *iPatch ].end() );
+          _hyperPatchList[ *iPatch ].clear();
+        }
+        if ( iPatches.size() > 1 )
+          for ( int j = _hyperPatchList.size()-1; j > 0; --j )
+            if ( _hyperPatchList[j].empty() )
+              _hyperPatchList.erase( _hyperPatchList.begin() + j );
+      }
+    }
     NotifySubMeshesHypothesisModification();
   }
 }
+//=============================================================================
+/*!
+ * \brief Return a tag of a face taking into account the hyper-patches. Optionally
+ *        return an index of a patch including the face
+ */
+//================================================================================
 
+int BLSURFPlugin_Hypothesis::GetHyperPatchTag( const int                      faceTag,
+                                               const BLSURFPlugin_Hypothesis* hyp,
+                                               int*                           iPatch)
+{
+  if ( hyp )
+  {
+    const THyperPatchList& hpl = hyp->_hyperPatchList;
+    for ( size_t i = 0; i < hpl.size(); ++i )
+      if ( hpl[i].count( faceTag ))
+      {
+        if ( iPatch ) *iPatch = i;
+        return *( hpl[i].begin() );
+      }
+  }
+  return faceTag;
+}
 //=============================================================================
-void BLSURFPlugin_Hypothesis::SetPreCADRemoveTinyUVEdges(bool theVal)
+void BLSURFPlugin_Hypothesis::SetPreCADMergeEdges(bool theVal)
 {
-  if (theVal != _preCADRemoveTinyUVEdges) {
-    _preCADRemoveTinyUVEdges = theVal;
+  if (theVal != ToBool( GetPreCADOptionValue("merge_edges", GET_DEFAULT()))) {
+    _preCADMergeEdges = theVal;
+    SetPreCADOptionValue("merge_edges", theVal ? "yes" : "no" );
     NotifySubMeshesHypothesisModification();
   }
 }
@@ -736,7 +889,7 @@ void BLSURFPlugin_Hypothesis::SetPreCADDiscardInput(bool theVal)
 // Return true if any PreCAD option is activated
 bool BLSURFPlugin_Hypothesis::HasPreCADOptions(const BLSURFPlugin_Hypothesis* hyp)
 {
-  if ( !hyp )
+  if ( !hyp || hyp->_name == GetHypType(/*hasgeom=*/false))
   {
     return false;
   }
@@ -753,6 +906,7 @@ bool BLSURFPlugin_Hypothesis::HasPreCADOptions(const BLSURFPlugin_Hypothesis* hy
            !hyp->_facesPeriodicityVector.empty()                                         ||
            !hyp->_edgesPeriodicityVector.empty()                                         ||
            !hyp->_verticesPeriodicityVector.empty()                                      ||
+           !hyp->GetHyperPatches().empty()                                               ||
            hyp->GetTopology() != FromCAD );
 }
 
@@ -1337,16 +1491,10 @@ bool BLSURFPlugin_Hypothesis::SetEnforcedVertex(TEntry        theFaceEntry,
 //   //////// CREATE ////////////
   if (toCreate) {
     toNotify = true;
-    _faceEntryEnfVertexListMap[theFaceEntry].insert(newEnfVertex);
-    _enfVertexList.insert(newEnfVertex);
-    if (theVertexEntry == "") {
-      _faceEntryCoordsListMap[theFaceEntry].insert(newEnfVertex->coords);
-      _coordsEnfVertexMap[newEnfVertex->coords] = newEnfVertex;
-    }
-    else {
-      _faceEntryEnfVertexEntryListMap[theFaceEntry].insert(newEnfVertex->geomEntry);
-      _enfVertexEntryEnfVertexMap[newEnfVertex->geomEntry] = newEnfVertex;
-    }
+    AddEnforcedVertex( theFaceEntry, newEnfVertex );
+  }
+  else {
+    delete newEnfVertex;
   }
 
   if (toNotify)
@@ -1355,6 +1503,27 @@ bool BLSURFPlugin_Hypothesis::SetEnforcedVertex(TEntry        theFaceEntry,
   return toNotify;
 }
 
+//=======================================================================
+//function : AddEnforcedVertex
+//=======================================================================
+
+void BLSURFPlugin_Hypothesis::AddEnforcedVertex( const TEntry& faceEntry,
+                                                 TEnfVertex *  newEnfVertex )
+{
+  if ( newEnfVertex )
+  {
+    _faceEntryEnfVertexListMap[faceEntry].insert(newEnfVertex);
+    _enfVertexList.insert(newEnfVertex);
+    if ( newEnfVertex->geomEntry.empty() ) {
+      _faceEntryCoordsListMap[faceEntry].insert(newEnfVertex->coords);
+      _coordsEnfVertexMap[newEnfVertex->coords] = newEnfVertex;
+    }
+    else {
+      _faceEntryEnfVertexEntryListMap[faceEntry].insert(newEnfVertex->geomEntry);
+      _enfVertexEntryEnfVertexMap[newEnfVertex->geomEntry] = newEnfVertex;
+    }
+  }
+}
 
 //=======================================================================
 //function : GetEnforcedVertices
@@ -1599,18 +1768,25 @@ bool BLSURFPlugin_Hypothesis::ClearEnforcedVertices(const TEntry& theFaceEntry)
 //=======================================================================
 //function : ClearAllEnforcedVertices
 //=======================================================================
-void BLSURFPlugin_Hypothesis::ClearAllEnforcedVertices() {
+void BLSURFPlugin_Hypothesis::ClearAllEnforcedVertices()
+{
   _faceEntryEnfVertexListMap.clear();
-  _enfVertexList.clear();
   _faceEntryCoordsListMap.clear();
   _coordsEnfVertexMap.clear();
   _faceEntryEnfVertexEntryListMap.clear();
   _enfVertexEntryEnfVertexMap.clear();
+  
+  TEnfVertexList::iterator it_enfVertex = _enfVertexList.begin();
+  for ( ; it_enfVertex != _enfVertexList.end(); ++it_enfVertex )
+    delete *it_enfVertex;
+  _enfVertexList.clear();
+
 //  Enable internal enforced vertices on specific face if requested by user
 //  _faceEntryInternalVerticesList.clear();
   NotifySubMeshesHypothesisModification();
 }
 
+
 //================================================================================
 /*!
  * \brief Return the enforced vertices
@@ -1759,7 +1935,7 @@ void BLSURFPlugin_Hypothesis::ClearPreCadPeriodicityVectors() {
 //function : AddPreCadFacesPeriodicity
 //=======================================================================
 void BLSURFPlugin_Hypothesis::AddPreCadFacesPeriodicity(TEntry theFace1Entry, TEntry theFace2Entry,
-    std::vector<std::string> &theSourceVerticesEntries, std::vector<std::string> &theTargetVerticesEntries) {
+                                                        std::vector<std::string> &theSourceVerticesEntries, std::vector<std::string> &theTargetVerticesEntries) {
 
   TPreCadPeriodicity preCadFacesPeriodicity;
   preCadFacesPeriodicity.shape1Entry = theFace1Entry;
@@ -1790,44 +1966,45 @@ void BLSURFPlugin_Hypothesis::AddPreCadEdgesPeriodicity(TEntry theEdge1Entry, TE
 }
 
 //=============================================================================
-std::ostream & BLSURFPlugin_Hypothesis::SaveTo(std::ostream & save) {
-   // We must keep at least the same number of arguments when increasing the SALOME version
-   // When MG-CADSurf becomes CADMESH, some parameters were fused into a single one. Thus the same
-   // parameter can be written several times to keep the old global number of parameters.
+std::ostream & BLSURFPlugin_Hypothesis::SaveTo(std::ostream & save)
+{
+  // We must keep at least the same number of arguments when increasing the SALOME version
+  // When MG-CADSurf becomes CADMESH, some parameters were fused into a single one. Thus the same
+  // parameter can be written several times to keep the old global number of parameters.
+
+  // Treat old options which are now in the advanced options
+  TOptionValues::iterator op_val;
+  int _decimesh = -1;
+  int _preCADRemoveNanoEdges = -1;
+  double _preCADEpsNano = -1.0;
+  op_val = _option2value.find("respect_geometry");
+  if (op_val != _option2value.end()) {
+    std::string value = op_val->second;
+    if (!value.empty())
+      _decimesh = value.compare("1") == 0 ? 1 : 0;
+  }
+  op_val = _preCADoption2value.find("remove_tiny_edges");
+  if (op_val != _preCADoption2value.end()) {
+    std::string value = op_val->second;
+    if (!value.empty())
+      _preCADRemoveNanoEdges = value.compare("1") == 0 ? 1 : 0;
+  }
+  op_val = _preCADoption2value.find("tiny_edge_length");
+  if (op_val != _preCADoption2value.end()) {
+    std::string value = op_val->second;
+    if (!value.empty())
+      _preCADEpsNano = strtod(value.c_str(), NULL);
+  }
 
-   // Treat old options which are now in the advanced options
-   TOptionValues::iterator op_val;
-   int _decimesh = -1;
-   int _preCADRemoveNanoEdges = -1;
-   double _preCADEpsNano = -1.0;
-   op_val = _option2value.find("respect_geometry");
-   if (op_val != _option2value.end()) {
-     std::string value = op_val->second;
-     if (!value.empty())
-       _decimesh = value.compare("1") == 0 ? 1 : 0;
-   }
-   op_val = _preCADoption2value.find("remove_tiny_edges");
-   if (op_val != _preCADoption2value.end()) {
-     std::string value = op_val->second;
-     if (!value.empty())
-       _preCADRemoveNanoEdges = value.compare("1") == 0 ? 1 : 0;
-   }
-   op_val = _preCADoption2value.find("tiny_edge_length");
-   if (op_val != _preCADoption2value.end()) {
-     std::string value = op_val->second;
-     if (!value.empty())
-       _preCADEpsNano = strtod(value.c_str(), NULL);
-   }
-   
   save << " " << (int) _topology << " " << (int) _physicalMesh << " " << (int) _geometricMesh << " " << _phySize << " "
-      << _angleMesh << " " << _gradation << " " << (int) _quadAllowed << " " << _decimesh;
+       << _angleMesh << " " << _gradation << " " << (int) _elementType << " " << _decimesh;
   save << " " << _minSize << " " << _maxSize << " " << _angleMesh << " " << _minSize << " " << _maxSize << " " << _verb;
   save << " " << (int) _preCADMergeEdges << " " << _preCADRemoveNanoEdges << " " << (int) _preCADDiscardInput << " " << _preCADEpsNano ;
   save << " " << (int) _enforcedInternalVerticesAllFaces;
   save << " " << (int) _phySizeRel << " " << (int) _minSizeRel << " " << (int) _maxSizeRel << " " << _chordalError ;
   save << " " << (int) _anisotropic << " " << _anisotropicRatio << " " << (int) _removeTinyEdges << " " << _tinyEdgeLength ;
   save << " " << (int) _badElementRemoval << " " << _badElementAspectRatio << " " << (int) _optimizeMesh << " " << (int) _quadraticMesh ;
-  save << " " << (int) _preCADProcess3DTopology << " " << (int) _preCADRemoveDuplicateCADFaces << " " << (int) _preCADRemoveTinyUVEdges;
+  save << " " << (int) _preCADProcess3DTopology << " " << (int) _preCADRemoveDuplicateCADFaces;
   save << " " << (int)_optimiseTinyEdges << " " << _tinyEdgeOptimisationLength;
   save << " " << (int)_correctSurfaceIntersec << " " << _corrSurfaceIntersCost;
   save << " " << (int)_useGradation << " " << (int)_useVolumeGradation << " " << _volumeGradation;
@@ -1956,6 +2133,25 @@ std::ostream & BLSURFPlugin_Hypothesis::SaveTo(std::ostream & save) {
   SaveEdgesPeriodicity(save);
   SaveVerticesPeriodicity(save);
 
+  // HYPER-PATCHES
+  save << " " << _hyperPatchList.size() << " ";
+  for ( size_t i = 0; i < _hyperPatchList.size(); ++i )
+  {
+    THyperPatchTags& patch = _hyperPatchList[i];
+    save << patch.size() << " ";
+    THyperPatchTags::iterator tag = patch.begin();
+    for ( ; tag != patch.end(); ++tag )
+      save << *tag << " ";
+  }
+
+  // New options in 2.9.6 (issue #17784)
+  save << " " << _useSurfaceProximity;
+  save << " " << _nbSurfaceProximityLayers;
+  save << " " << _surfaceProximityRatio;
+  save << " " << _useVolumeProximity;
+  save << " " << _nbVolumeProximityLayers;
+  save << " " << _volumeProximityRatio;
+
   return save;
 }
 
@@ -2091,7 +2287,8 @@ void BLSURFPlugin_Hypothesis::SavePreCADPeriodicity(std::ostream & save, const c
 }
 
 //=============================================================================
-std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
+std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load)
+{
   bool isOK = true;
   int i;
   double val;
@@ -2135,7 +2332,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
 
   isOK = static_cast<bool>(load >> i);
   if (isOK)
-    _quadAllowed = (bool) i;
+    _elementType = (ElementType) i;
   else
     load.clear(std::ios::badbit | load.rdstate());
 
@@ -2359,12 +2556,6 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
       else
         load.clear(std::ios::badbit | load.rdstate());
 
-      isOK = static_cast<bool>(load >> i);
-      if (isOK)
-        _preCADRemoveTinyUVEdges = (bool) i;
-      else
-        load.clear(std::ios::badbit | load.rdstate());
-
       isOK = static_cast<bool>(load >> i);
       if (isOK)
         _optimiseTinyEdges = (bool) i;
@@ -2707,7 +2898,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
         break;
       isOK = static_cast<bool>(load >> newAtShapeEntry);
       if (!isOK)
-    break;
+        break;
       isOK = static_cast<bool>(load >> attParams[0]>>attParams[1]>>attParams[2]>>attParams[3]); //>>step);
     }
     if (isOK) {
@@ -2745,17 +2936,17 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
 // __ENFORCED_VERTICES_BEGIN__ 
 // __BEGIN_VERTEX__  => no name, no entry
 // __BEGIN_GROUP__ mon groupe __END_GROUP__
-// __BEGIN_COORDS__ 10 10 10 __END_COORDS__ 
-// __BEGIN_FACELIST__ 0:1:1:1:1 __END_FACELIST__ 
-// __END_VERTEX__ 
+// __BEGIN_COORDS__ 10 10 10 __END_COORDS__
+// __BEGIN_FACELIST__ 0:1:1:1:1 __END_FACELIST__
+// __END_VERTEX__
 // __BEGIN_VERTEX__ => no coords
-// __BEGIN_NAME__ mes points __END_NAME__ 
+// __BEGIN_NAME__ mes points __END_NAME__
 // __BEGIN_ENTRY__ 0:1:1:4 __END_ENTRY__
 // __BEGIN_GROUP__ mon groupe __END_GROUP__
 // __BEGIN_FACELIST__ 0:1:1:1:3 __END_FACELIST__
-// __END_VERTEX__ 
+// __END_VERTEX__
 // __ENFORCED_VERTICES_END__
-// 
+//
 
   std::string enfSeparator;
   std::string enfName;
@@ -2764,27 +2955,28 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
   TEntryList enfFaceEntryList;
   double enfCoords[3];
   bool hasCoords = false;
-  
+
   _faceEntryEnfVertexListMap.clear();
   _enfVertexList.clear();
   _faceEntryCoordsListMap.clear();
   _coordsEnfVertexMap.clear();
   _faceEntryEnfVertexEntryListMap.clear();
   _enfVertexEntryEnfVertexMap.clear();
-  
-  
-  while (isOK && hasEnforcedVertex) {
+
+
+  while (isOK && hasEnforcedVertex)
+  {
     isOK = static_cast<bool>(load >> enfSeparator); // __BEGIN_VERTEX__
     TEnfVertex *enfVertex = new TEnfVertex();
     if (enfSeparator == "__ENFORCED_VERTICES_END__")
       break; // __ENFORCED_VERTICES_END__
     if (enfSeparator != "__BEGIN_VERTEX__")
       throw std::exception();
-    
+
     while (isOK) {
       isOK = static_cast<bool>(load >> enfSeparator);
       if (enfSeparator == "__END_VERTEX__") {
-        
+
         enfVertex->name = enfName;
         enfVertex->geomEntry = enfGeomEntry;
         enfVertex->grpName = enfGroup;
@@ -2792,9 +2984,9 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
         if (hasCoords)
           enfVertex->coords.assign(enfCoords,enfCoords+3);
         enfVertex->faceEntries = enfFaceEntryList;
-        
+
         _enfVertexList.insert(enfVertex);
-        
+
         if (enfVertex->coords.size()) {
           _coordsEnfVertexMap[enfVertex->coords] = enfVertex;
           for (TEntryList::const_iterator it = enfVertex->faceEntries.begin() ; it != enfVertex->faceEntries.end(); ++it) {
@@ -2809,7 +3001,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
             _faceEntryEnfVertexListMap[(*it)].insert(enfVertex);
           }
         }
-        
+
         enfName.clear();
         enfGeomEntry.clear();
         enfGroup.clear();
@@ -2817,7 +3009,7 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
         hasCoords = false;
         break; // __END_VERTEX__
       }
-        
+
       if (enfSeparator == "__BEGIN_NAME__") {  // __BEGIN_NAME__
         while (isOK && (enfSeparator != "__END_NAME__")) {
           isOK = static_cast<bool>(load >> enfSeparator);
@@ -2828,14 +3020,14 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
           }
         }
       }
-        
+
       if (enfSeparator == "__BEGIN_ENTRY__") {  // __BEGIN_ENTRY__
         isOK = static_cast<bool>(load >> enfGeomEntry);
         isOK = static_cast<bool>(load >> enfSeparator); // __END_ENTRY__
         if (enfSeparator != "__END_ENTRY__")
           throw std::exception();
       }
-        
+
       if (enfSeparator == "__BEGIN_GROUP__") {  // __BEGIN_GROUP__
         while (isOK && (enfSeparator != "__END_GROUP__")) {
           isOK = static_cast<bool>(load >> enfSeparator);
@@ -2846,15 +3038,15 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
           }
         }
       }
-        
+
       if (enfSeparator == "__BEGIN_COORDS__") {  // __BEGIN_COORDS__
         hasCoords = true;
         isOK = static_cast<bool>(load >> enfCoords[0] >> enfCoords[1] >> enfCoords[2]);
         isOK = static_cast<bool>(load >> enfSeparator); // __END_COORDS__
         if (enfSeparator != "__END_COORDS__")
           throw std::exception();
-      } 
-        
+      }
+
       if (enfSeparator == "__BEGIN_FACELIST__") {  // __BEGIN_FACELIST__
         while (isOK && (enfSeparator != "__END_FACELIST__")) {
           isOK = static_cast<bool>(load >> enfSeparator);
@@ -2862,13 +3054,30 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
             enfFaceEntryList.insert(enfSeparator);
           }
         }
-      } 
+      }
+    }
+  }
+
+  if ( hasEnforcedVertex ) {
+    isOK = static_cast<bool>(load >> option_or_sm);
+    if (isOK) {
+      if (option_or_sm == "__PRECAD_FACES_PERIODICITY_BEGIN__")
+        hasPreCADFacesPeriodicity = true;
+      else if (option_or_sm == "__PRECAD_EDGES_PERIODICITY_BEGIN__")
+        hasPreCADEdgesPeriodicity = true;
+      else if (option_or_sm == "__FACES_PERIODICITY_BEGIN__")
+        hasFacesPeriodicity = true;
+      else if (option_or_sm == "__EDGES_PERIODICITY_BEGIN__")
+        hasEdgesPeriodicity = true;
+      else if (option_or_sm == "__VERTICES_PERIODICITY_BEGIN__")
+        hasVerticesPeriodicity = true;
     }
   }
 
   // PERIODICITY
 
-  if (hasPreCADFacesPeriodicity){
+  if (hasPreCADFacesPeriodicity)
+  {
     LoadPreCADPeriodicity(load, "FACES");
 
     isOK = static_cast<bool>(load >> option_or_sm);
@@ -2884,7 +3093,8 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
     }
   }
 
-  if (hasPreCADEdgesPeriodicity){
+  if (hasPreCADEdgesPeriodicity)
+  {
     LoadPreCADPeriodicity(load, "EDGES");
 
     isOK = static_cast<bool>(load >> option_or_sm);
@@ -2898,8 +3108,9 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
     }
   }
 
-  if (hasFacesPeriodicity){
-      LoadFacesPeriodicity(load);
+  if (hasFacesPeriodicity)
+  {
+    LoadFacesPeriodicity(load);
 
     isOK = static_cast<bool>(load >> option_or_sm);
     if (isOK) {
@@ -2910,8 +3121,9 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
     }
   }
 
-  if (hasEdgesPeriodicity){
-      LoadEdgesPeriodicity(load);
+  if (hasEdgesPeriodicity)
+  {
+    LoadEdgesPeriodicity(load);
 
     isOK = static_cast<bool>(load >> option_or_sm);
     if (isOK)
@@ -2920,7 +3132,48 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load) {
   }
 
   if (hasVerticesPeriodicity)
-      LoadVerticesPeriodicity(load);
+    LoadVerticesPeriodicity(load);
+
+  // HYPER-PATCHES
+  if ( !option_or_sm.empty() && option_or_sm[0] == '_' )
+    isOK = static_cast<bool>(load >> option_or_sm);
+  if ( isOK && !option_or_sm.empty() )
+  {
+    int nbPatches = atoi( option_or_sm.c_str() );
+    if ( nbPatches >= 0 )
+    {
+      _hyperPatchList.resize( nbPatches );
+      for ( int iP = 0; iP < nbPatches && isOK; ++iP )
+      {
+        isOK = static_cast<bool>(load >> i) && i >= 2;
+        if ( !isOK ) break;
+        int nbTags = i;
+        for ( int iT = 0; iT < nbTags; ++iT )
+        {
+          if (( isOK = static_cast<bool>(load >> i)))
+            _hyperPatchList[ iP ].insert( i );
+          else
+            break;
+        }
+      }
+      if ( !isOK ) // remove invalid patches
+      {
+        for ( i = nbPatches - 1; i >= 0; i-- )
+          if ( _hyperPatchList[i].size() < 2 )
+            _hyperPatchList.resize( i );
+      }
+    }
+  }
+
+  // New options in 2.9.6 (issue #17784)
+  if ( static_cast<bool>( load >> _useSurfaceProximity ));
+  {
+    load >> _nbSurfaceProximityLayers;
+    load >> _surfaceProximityRatio;
+    load >> _useVolumeProximity;
+    load >> _nbVolumeProximityLayers;
+    isOK = static_cast<bool>( load >> _volumeProximityRatio );
+  }
 
   return load;
 }
@@ -3050,8 +3303,8 @@ void BLSURFPlugin_Hypothesis::LoadEdgesPeriodicity(std::istream & load){
   }
 }
 
-void BLSURFPlugin_Hypothesis::LoadVerticesPeriodicity(std::istream & load){
-
+void BLSURFPlugin_Hypothesis::LoadVerticesPeriodicity(std::istream & load)
+{
   bool isOK = true;
 
   std::string periodicitySeparator;
@@ -3157,7 +3410,7 @@ void BLSURFPlugin_Hypothesis::LoadPreCADPeriodicity(std::istream & load, const c
         if (hasTargetVertices)
           periodicity_i->theTargetVerticesEntries = theTargetVerticesEntries;
 
-        if ( shapeType  &&  strcmp( shapeType, "FACES" ))
+        if ( shapeType  &&  strcmp( shapeType, "FACES" ) == 0 )
           _preCadFacesPeriodicityVector.push_back(*periodicity_i);
         else
           _preCadEdgesPeriodicityVector.push_back(*periodicity_i);