Salome HOME
bos #16292 [CEA 656] MGCADSurf: option SetEnforced1D mesh
authoreap <eap@opencascade.com>
Wed, 28 Jul 2021 17:36:57 +0000 (20:36 +0300)
committereap <eap@opencascade.com>
Wed, 28 Jul 2021 17:36:57 +0000 (20:36 +0300)
17 files changed:
doc/salome/examples/blsurfdemo.py
doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png [new file with mode: 0644]
doc/salome/gui/BLSURFPLUGIN/input/blsurf_hypo.doc
idl/BLSURFPlugin_Algorithm.idl
src/BLSURFPlugin/BLSURFPluginBuilder.py
src/BLSURFPlugin/BLSURFPlugin_BLSURF.cxx
src/BLSURFPlugin/BLSURFPlugin_BLSURF.hxx
src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx [new file with mode: 0644]
src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx [new file with mode: 0644]
src/BLSURFPlugin/BLSURFPlugin_Hypothesis.cxx
src/BLSURFPlugin/BLSURFPlugin_Hypothesis.hxx
src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.cxx
src/BLSURFPlugin/BLSURFPlugin_Hypothesis_i.hxx
src/BLSURFPlugin/CMakeLists.txt
src/GUI/BLSURFPluginGUI_HypothesisCreator.cxx
src/GUI/BLSURFPluginGUI_HypothesisCreator.h
src/GUI/BLSURFPlugin_msg_en.ts

index 4cb045d365746868d08e007dbaa15ad5a3f35e33..ad4e0d673e3c9170bac1c6cb93230034be758164 100644 (file)
@@ -108,12 +108,33 @@ algo2d.SetAttractorGeom(Face_2, Wire_1, 1, 36.641, 20, 10)
 # the gradation to its maximum
 algo2d.SetGradation( 2.5 )
 
+# -----------------------
+# Adding enforced meshes
+# -----------------------
+
+# create 1D mesh
+OZ       = geompy.MakeVectorDXDYDZ(0, 0, 1)
+circle_1 = geompy.MakeCircle( geompy.MakeVertex( 100, 75,  200 ), OZ, 50 )
+circle_2 = geompy.MakeCircle( geompy.MakeVertex( 100, 150, 200 ), OZ, 70 )
+circles  = geompy.MakeCompound([ circle_1, circle_2 ], theName="circles")
+mesh_1D  = smesh.Mesh( circles, "enforced circles" )
+mesh_1D.Segment().LocalLength( 7 )
+mesh_1D.Compute()
+
+# Add enforced mesh
+algo2d.SetEnforcedMeshes([
+    smeshBuilder.MG_EnforcedMesh1D( mesh_1D, "Enforced edges")])
+
+# -----------------
 # compute the mesh
+# -----------------
+
 cadsurfMesh.Compute()
 
-# ---------------------------------------------------------------
+
+# ================================================================
 # blsurf_construct_mesh_internal_vertices Using internal vertices
-# ---------------------------------------------------------------
+# ================================================================
 
 # Creating a geometry containing internal vertices
 Face_3 = geompy.MakeFaceHW(1, 1, 1)
diff --git a/doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png
new file mode 100644 (file)
index 0000000..cbc928e
Binary files /dev/null and b/doc/salome/gui/BLSURFPLUGIN/images/blsurf_enforced_meshes.png differ
index 1b1c1d546cba441a069f3898f5eb41fc87cb82fe..fefba64eeb41d8dd88c0a72bc8e4206393a1107c 100644 (file)
@@ -392,6 +392,21 @@ A group can optionnaly be defined on those enforced vertices.
 \ref blsurf_top "Back to top"
 
 
+\section blsurf_enforced_meshes Enforced Meshes
+
+\image html blsurf_enforced_meshes.png
+
+MG-CADSurf algorithm can be forced by other 1D meshes, sub-meshes or
+groups. 1D meshes are allowed to pass over face boundaries and to
+intersect other enforced meshes.
+If a group name is given, the enforced 1D elements will be added to the group.
+If the group does not exist, it is created.
+
+\sa Sample TUI Script of the \ref tui_blsurf "creation of a MG-CADSurf hypothesis", including enforced meshes.
+
+\ref blsurf_top "Back to top"
+
+
 \section blsurf_periodicity Periodicity
 
 \subsection periodicity_introduction Introduction
index 7e3bd78cc84f22b80be2cfb0400caeae20c29931..e380f2fcf2c4479eed0ef99f9eace61aedc97c90 100644 (file)
 #ifndef _SMESH_BLSURFALGORITHM_IDL_
 #define _SMESH_BLSURFALGORITHM_IDL_
 
-#include "SMESH_Hypothesis.idl"
 #include "GEOM_Gen.idl"
 #include "SALOME_Exception.idl"
+#include "SMESH_Hypothesis.idl"
+#include "SMESH_Mesh.idl"
 
 /*!
  * BLSURFPlugin: interfaces to BLSURF related hypotheses and algorithms
@@ -37,6 +38,14 @@ module BLSURFPlugin
 {
   typedef sequence<string> string_array;
 
+  // Enforced 1D Mesh
+  struct MG_EnforcedMesh1D
+  {
+    SMESH::SMESH_IDSource mesh;      // mesh, group or sub-mesh
+    string                groupName; // optional name of a group to add mesh edges to
+  };
+  typedef sequence< MG_EnforcedMesh1D > EnforcedMeshesList;
+
   // Enforced vertex name
   typedef string TEnfName;
   // Entry
@@ -44,12 +53,12 @@ module BLSURFPlugin
   typedef sequence<TEntry> TEntryList;
   // Group name
   typedef string TEnfGroupName;
-  
+
   // Coordinates of enforced vertex
   typedef sequence<double,3> TEnfVertexCoords;
   // List of coords
   typedef sequence<TEnfVertexCoords> TEnfVertexCoordsList;
-  
+
   // Enforced vertex
   struct TEnfVertex {
     TEnfName name;
@@ -358,11 +367,17 @@ module BLSURFPlugin
     double GetVolumeProximityRatio();
 
     /*!
-     *Set verbosity level in the range 0 to 100.
+     * Set verbosity level in the range 0 to 100.
      */
     void SetVerbosity(in short theVal) raises (SALOME::SALOME_Exception);
     short GetVerbosity();
 
+    /*!
+     * Set/Get enforced 1D meshes
+     */
+    void SetEnforcedMeshes( in EnforcedMeshesList enforcedMeshes );
+    EnforcedMeshesList GetEnforcedMeshes();
+
     /*!
      * Set enforce_cad_edge_sizes parameter
      *
index ac507f2b8a28738efeea3e18aa9767fee18ad877..8a7e946304973c6129aaf3016b9d1fac77e7db11 100644 (file)
@@ -42,6 +42,8 @@ BLSURF_Custom, BLSURF_GlobalSize, BLSURF_LocalSize = MG_CADSURF_Custom, MG_CADSU
 noBLSURFPlugin = 0
 try:
   import BLSURFPlugin
+  from BLSURFPlugin import MG_EnforcedMesh1D
+
 except ImportError:
   noBLSURFPlugin = 1
   pass
@@ -652,6 +654,21 @@ class BLSURF_Algorithm(Mesh_Algorithm):
   def GetInternalEnforcedVertexAllFacesGroup(self):
     return self.Parameters().GetInternalEnforcedVertexAllFacesGroup()
 
+  #-----------------------------------------
+  #  Enforced mesh
+  #-----------------------------------------
+
+  ## Set enforced 1D meshes
+  #  @param enfMeshes : list of smeshBuilder.MG_EnforcedMesh1D structures
+  #
+  #  Example: cadsurf.SetEnforcedMeshes([ smeshBuilder.MG_EnforcedMesh1D( mesh1D, "Group 1D")]
+  def SetEnforcedMeshes( self, enfMeshes ):
+    from salome.smesh.smeshBuilder import Mesh
+    for em in enfMeshes:
+      if isinstance( em.mesh, Mesh ):
+        em.mesh = em.mesh.GetMesh()
+    return self.Parameters().SetEnforcedMeshes( enfMeshes )
+
   #-----------------------------------------
   #  Attractors
   #-----------------------------------------
index 6bd3f2d3690e2d9b25e79e2add39e80478e73118..14b9f4b0ccf3204a4d3fe1b2b53a61cd63c08c55 100644 (file)
 // ---
 
 #include "BLSURFPlugin_BLSURF.hxx"
-#include "BLSURFPlugin_Hypothesis.hxx"
+
 #include "BLSURFPlugin_Attractor.hxx"
+#include "BLSURFPlugin_EnforcedMesh1D.hxx"
+#include "BLSURFPlugin_Hypothesis.hxx"
 
 extern "C"{
 #include <meshgems/meshgems.h>
 #include <meshgems/cadsurf.h>
 }
 
-#include <structmember.h>
-
-
-#include <Basics_Utils.hxx>
-
 #include <SMDS_EdgePosition.hxx>
 #include <SMESHDS_Group.hxx>
+#include <SMESH_File.hxx>
 #include <SMESH_Gen.hxx>
 #include <SMESH_Group.hxx>
 #include <SMESH_Mesh.hxx>
@@ -47,15 +45,17 @@ extern "C"{
 #include <SMESH_MesherHelper.hxx>
 #include <StdMeshers_FaceSide.hxx>
 #include <StdMeshers_ViscousLayers2D.hxx>
-#include <SMESH_File.hxx>
 
+#include <Basics_Utils.hxx>
 #include <utilities.h>
 
+#include <cstdlib>
 #include <limits>
 #include <list>
-#include <vector>
 #include <set>
-#include <cstdlib>
+#include <vector>
+
+#include <structmember.h> // python
 
 // OPENCASCADE includes
 #include <BRepBndLib.hxx>
@@ -405,14 +405,12 @@ status_t size_on_surface(integer face_id, real *uv, real *size, void *user_data)
 status_t size_on_edge(integer edge_id, real t, real *size, void *user_data);
 status_t size_on_vertex(integer vertex_id, real *size, void *user_data);
 
-typedef struct {
-        gp_XY uv;
-        gp_XYZ xyz;
-} projectionPoint;
-
 /////////////////////////////////////////////////////////
 
-projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint)
+BLSURFPlugin_BLSURF::projectionPoint
+BLSURFPlugin_BLSURF::getProjectionPoint(TopoDS_Face&  theFace,
+                                        const gp_Pnt& thePoint,
+                                        const bool    theAllowStateON)
 {
   projectionPoint myPoint;
 
@@ -444,12 +442,13 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint)
         {
           if ( !foundFace.IsNull() )
             return myPoint; // thePoint seems to be TopAbs_ON
-          foundFace   = face;
-          myPoint.uv  = uv.XY();
-          myPoint.xyz = surface->Value( uv ).XYZ();
+          foundFace     = face;
+          myPoint.uv    = uv.XY();
+          myPoint.xyz   = surface->Value( uv ).XYZ();
+          myPoint.state = FC.State();
           // break;
         }
-        if ( FC.State() == TopAbs_ON )
+        if ( FC.State() == TopAbs_ON && !theAllowStateON )
           return myPoint;
       }
     }
@@ -462,12 +461,15 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint)
         const TopoDS_Face& face = d2f->second.first;
         const gp_Pnt2d &     uv = d2f->second.second;
         BRepClass_FaceClassifier FC( face, uv, Precision::Confusion());
-        if ( FC.State() == TopAbs_IN )
+        if (( FC.State() == TopAbs_IN ) ||
+            ( FC.State() == TopAbs_ON && theAllowStateON ))
         {
-          foundFace   = face;
-          myPoint.uv  = uv.XY();
-          myPoint.xyz = theHelper->GetSurface( face )->Value( uv ).XYZ();
-          break;
+          foundFace     = face;
+          myPoint.uv    = uv.XY();
+          myPoint.xyz   = theHelper->GetSurface( face )->Value( uv ).XYZ();
+          myPoint.state = FC.State();
+          if ( FC.State() == TopAbs_IN )
+            break;
         }
       }
     }
@@ -477,7 +479,7 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint)
     //                            "getProjectionPoint: can't find a face by a vertex");
     theFace = TopoDS::Face( foundFace );
   }
-  else
+  else // !theFace.IsNull()
   {
     Handle(Geom_Surface) surface = BRep_Tool::Surface( theFace );
     GeomAPI_ProjectPointOnSurf projector( thePoint, surface );
@@ -487,12 +489,14 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint)
 
     Standard_Real u,v;
     projector.LowerDistanceParameters(u,v);
-    myPoint.uv = gp_XY(u,v);
-    gp_Pnt aPnt = projector.NearestPoint();
-    myPoint.xyz = gp_XYZ(aPnt.X(),aPnt.Y(),aPnt.Z());
+    myPoint.uv  = gp_XY(u,v);
+    myPoint.xyz = projector.NearestPoint().XYZ();
 
     BRepClass_FaceClassifier FC( theFace, myPoint.uv, Precision::Confusion());
-    if ( FC.State() != TopAbs_IN )
+    myPoint.state = FC.State();
+
+    if (( FC.State() != TopAbs_IN ) &&
+        ( FC.State() != TopAbs_ON || !theAllowStateON ))
       theFace.Nullify();
   }
 
@@ -502,16 +506,8 @@ projectionPoint getProjectionPoint(TopoDS_Face& theFace, const gp_Pnt& thePoint)
 /////////////////////////////////////////////////////////
 TopoDS_Shape BLSURFPlugin_BLSURF::entryToShape(std::string entry)
 {
-  GEOM::GEOM_Object_var aGeomObj;
-  TopoDS_Shape S = TopoDS_Shape();
-  SALOMEDS::SObject_var aSObj = SMESH_Gen_i::GetSMESHGen()->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 = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( aGeomObj.in() );
+  GEOM::GEOM_Object_var aGeomObj = SMESH_Gen_i::GetSMESHGen()->GetGeomObjectByEntry( entry );
+  TopoDS_Shape                 S = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( aGeomObj );
   return S;
 }
 
@@ -520,7 +516,8 @@ void _createEnforcedVertexOnFace(TopoDS_Face faceShape, gp_Pnt aPnt, BLSURFPlugi
   BLSURFPlugin_Hypothesis::TEnfVertexCoords enf_coords, coords, s_coords;
 
   // Find the face and get the (u,v) values of the enforced vertex on the face
-  projectionPoint myPoint = getProjectionPoint(faceShape,aPnt);
+  BLSURFPlugin_BLSURF::projectionPoint myPoint =
+    BLSURFPlugin_BLSURF::getProjectionPoint(faceShape,aPnt);
   if ( faceShape.IsNull() )
     return;
 
@@ -639,30 +636,30 @@ void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction
   // xa
   pos1 = AttractorFunction.find(sep);
   if (pos1!=string::npos)
-  xa = atof(AttractorFunction.substr(10, pos1-10).c_str());
+    xa = atof(AttractorFunction.substr(10, pos1-10).c_str());
   // ya
   pos2 = AttractorFunction.find(sep, pos1+1);
   if (pos2!=string::npos) {
-  ya = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
-  pos1 = pos2;
+    ya = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
+    pos1 = pos2;
   }
   // za
   pos2 = AttractorFunction.find(sep, pos1+1);
   if (pos2!=string::npos) {
-  za = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
-  pos1 = pos2;
+    za = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
+    pos1 = pos2;
   }
   // a
   pos2 = AttractorFunction.find(sep, pos1+1);
   if (pos2!=string::npos) {
-  a = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
-  pos1 = pos2;
+    a = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
+    pos1 = pos2;
   }
   // b
   pos2 = AttractorFunction.find(sep, pos1+1);
   if (pos2!=string::npos) {
-  b = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
-  pos1 = pos2;
+    b = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
+    pos1 = pos2;
   }
   // createNode
   pos2 = AttractorFunction.find(sep, pos1+1);
@@ -674,13 +671,14 @@ void createAttractorOnFace(TopoDS_Shape GeomShape, std::string AttractorFunction
   // d
   pos2 = AttractorFunction.find(")");
   if (pos2!=string::npos) {
-  d = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
+    d = atof(AttractorFunction.substr(pos1+1, pos2-pos1-1).c_str());
   }
 
   // Get the (u,v) values of the attractor on the face
-  projectionPoint myPoint = getProjectionPoint(TopoDS::Face(GeomShape),gp_Pnt(xa,ya,za));
-  gp_XY uvPoint = myPoint.uv;
-  gp_XYZ xyzPoint = myPoint.xyz;
+  BLSURFPlugin_BLSURF::projectionPoint myPoint =
+    BLSURFPlugin_BLSURF::getProjectionPoint(TopoDS::Face(GeomShape),gp_Pnt(xa,ya,za));
+  gp_XY    uvPoint = myPoint.uv;
+  gp_XYZ  xyzPoint = myPoint.xyz;
   Standard_Real u0 = uvPoint.X();
   Standard_Real v0 = uvPoint.Y();
   Standard_Real x0 = xyzPoint.X();
@@ -1931,10 +1929,14 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
 
   SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();
   SMESH_MesherHelper helper( aMesh ), helperWithShape( aMesh );
-  myHelper = theHelper = & helperWithShape;
+  theHelper = & helperWithShape;
   // do not call helper.IsQuadraticSubMesh() because sub-meshes
   // may be cleaned and helper.myTLinkNodeMap gets invalid in such a case
   bool haveQuadraticSubMesh = helperWithShape.IsQuadraticSubMesh( aShape );
+  haveQuadraticSubMesh = haveQuadraticSubMesh || (_hypothesis && _hypothesis->GetQuadraticMesh());
+  helper.SetIsQuadratic( haveQuadraticSubMesh );
+  helperWithShape.SetIsQuadratic( haveQuadraticSubMesh );
+
   bool quadraticSubMeshAndViscousLayer = false;
   bool needMerge = false;
   typedef set< SMESHDS_SubMesh*, ShapeTypeCompare > TSubMeshSet;
@@ -1947,6 +1949,8 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
   TopTools_IndexedDataMapOfShapeListOfShape e2ffmap;
   TopExp::MapShapesAndAncestors( aShape, TopAbs_EDGE, TopAbs_FACE, e2ffmap );
 
+  BLSURFPlugin_EnforcedMesh1D enforcedMesh( helperWithShape, _hypothesis );
+
   // Issue 0019864. On DebianSarge, FE signals do not obey to OSD::SetSignal(false)
 #ifndef WIN32
   feclearexcept( FE_ALL_EXCEPT );
@@ -1988,9 +1992,6 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
 
   SetParameters(_hypothesis, css, aShape);
 
-  haveQuadraticSubMesh = haveQuadraticSubMesh || (_hypothesis != NULL && _hypothesis->GetQuadraticMesh());
-  helper.SetIsQuadratic( haveQuadraticSubMesh );
-
   // To remove as soon as quadratic mesh is allowed - BEGIN
   // GDD: Viscous layer is not allowed with quadratic mesh
   if (_haveViscousLayers && haveQuadraticSubMesh ) {
@@ -2030,8 +2031,8 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
   {
     TopoDS_Face f = TopoDS::Face(face_iter.Current());
 
-    SMESH_subMesh* fSM = aMesh.GetSubMesh( f );
-    if ( !fSM->IsEmpty() ) continue; // skip already meshed FACE with viscous layers
+    //SMESH_subMesh* fSM = aMesh.GetSubMesh( f );
+    //if ( !fSM->IsEmpty() ) continue; // skip already meshed FACE with viscous layers
 
     // make INTERNAL face oriented FORWARD (issue 0020993)
     if (f.Orientation() != TopAbs_FORWARD && f.Orientation() != TopAbs_REVERSED )
@@ -2088,35 +2089,29 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
       }
 
       // Specific size map = Attractor
-      std::map<int,std::vector<double> >::iterator attractor_iter = FaceId2AttractorCoords.begin();
-
-      for (; attractor_iter != FaceId2AttractorCoords.end(); ++attractor_iter) {
-        if (attractor_iter->first == faceKey)
+      std::map<int,std::vector<double> >::iterator attractor_iter =
+        FaceId2AttractorCoords.find( faceKey );
+      if (attractor_iter != FaceId2AttractorCoords.end() )
+      {
+        double * xyzCoords = & attractor_iter->second[2];
+        gp_Pnt P(xyzCoords[0],xyzCoords[1],xyzCoords[2]);
+        BRepClass_FaceClassifier scl(f,P,1e-7);
+        TopAbs_State result = scl.State();
+        if ( result == TopAbs_OUT )
+          MESSAGE("Point is out of face: node is not created");
+        if ( result == TopAbs_UNKNOWN )
+          MESSAGE("Point position on face is unknown: node is not created");
+        if ( result == TopAbs_ON )
+          MESSAGE("Point is on border of face: node is not created");
+        if ( result == TopAbs_IN )
         {
-          double xyzCoords[3]  = {attractor_iter->second[2],
-                                  attractor_iter->second[3],
-                                  attractor_iter->second[4]};
-
-          gp_Pnt P(xyzCoords[0],xyzCoords[1],xyzCoords[2]);
-          BRepClass_FaceClassifier scl(f,P,1e-7);
-          scl.Perform(f, P, 1e-7);
-          TopAbs_State result = scl.State();
-          if ( result == TopAbs_OUT )
-            MESSAGE("Point is out of face: node is not created");
-          if ( result == TopAbs_UNKNOWN )
-            MESSAGE("Point position on face is unknown: node is not created");
-          if ( result == TopAbs_ON )
-            MESSAGE("Point is on border of face: node is not created");
-          if ( result == TopAbs_IN )
-          {
-            // Point is inside face and not on border
-            double uvCoords[2] = {attractor_iter->second[0],attractor_iter->second[1]};
-            ienf++;
-            cad_point_t* point_p = cad_point_new(fce, ienf, uvCoords);
-            cad_point_set_tag(point_p, ienf);
-          }
-          FaceId2AttractorCoords.erase(faceKey);
+          // Point is inside face and not on border
+          double * uvCoords = & attractor_iter->second[0];
+          ienf++;
+          cad_point_t* point_p = cad_point_new(fce, ienf, uvCoords);
+          cad_point_set_tag(point_p, ienf);
         }
+        FaceId2AttractorCoords.erase(faceKey);
       }
 
       // -----------------
@@ -2182,19 +2177,24 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
                                            EDGES
                         now create the edges associated to this face
     *****************************************************************************************/
-    int edgeKey = -1;
-    for (TopExp_Explorer edge_iter(f,TopAbs_EDGE);edge_iter.More();edge_iter.Next())
+
+    std::vector< TopoDS_Edge > edges;
+    for ( TopExp_Explorer edge_iter( f, TopAbs_EDGE ); edge_iter.More(); edge_iter.Next() )
     {
-      TopoDS_Edge e = TopoDS::Edge(edge_iter.Current());
-      int ic = emap.FindIndex(e);
-      if (ic <= 0)
-        ic = emap.Add(e);
+      const TopoDS_Edge& e = TopoDS::Edge( edge_iter.Current() );
+      if ( !enforcedMesh.GetSplitsOfEdge( e, edges, emap ))
+        edges.push_back( e );
+    }
+    for ( const TopoDS_Edge& e : edges )
+    {
+      int ic = emap.Add(e);
 
       double tmin,tmax;
       curves.push_back(BRep_Tool::CurveOnSurface(e, f, tmin, tmax));
 
-      if (HasSizeMapOnEdge){
-        edgeKey = EdgesWithSizeMap.FindIndex(e);
+      if ( HasSizeMapOnEdge )
+      {
+        int edgeKey = EdgesWithSizeMap.FindIndex(e);
         if (EdgeId2SizeMap.find(edgeKey)!=EdgeId2SizeMap.end())
         {
           theSizeMapStr = EdgeId2SizeMap[edgeKey];
@@ -2256,6 +2256,7 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
          The following call sets it to the same value as the edge_id : */
       // IMP23368. Do not set tag to an EDGE shared by FACEs of a hyper-patch
       bool isInHyperPatch = false;
+      if ( e2ffmap.Contains( e )) // not there for a part of EDGE divided by enforced segments
       {
         std::set< int > faceTags, faceIDs;
         TopTools_ListIteratorOfListOfShape fIt( e2ffmap.FindFromKey( e ));
@@ -2275,7 +2276,7 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
       if ( !isInHyperPatch )
         cad_edge_set_tag(edg, ic);
 
-      /* by default, an edge does not necessalry appear in the resulting mesh,
+      /* by default, an edge does not necessarily appear in the resulting mesh,
          unless the following property is set :
       */
       cad_edge_set_property(edg, EDGE_PROPERTY_SOFT_REQUIRED);
@@ -2299,9 +2300,9 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
         for ( int iN = 0; iN < nbNodes; ++iN )
         {
           const UVPtStruct& nData = nodeDataVec[ iN ];
-          double t                = nData.param;
-          real uv[2]              = { nData.u, nData.v };
-          SMESH_TNodeXYZ nXYZ( nData.node );
+          double                t = nData.param;
+          real              uv[2] = { nData.u, nData.v };
+          SMESH_TNodeXYZ     nXYZ = nData.node;
           // cout << "\tt = " << t
           //      << "\t uv = ( " << uv[0] << ","<< uv[1] << " ) "
           //      << "\t u = " << nData.param
@@ -2324,38 +2325,23 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
       *****************************************************************************************/
 
       int npts = 0;
-      int ip1, ip2, *ip;
-      gp_Pnt2d e0 = curves.back()->Value(tmin);
-      gp_Pnt ee0 = surfaces.back()->Value(e0.X(), e0.Y());
-      Standard_Real d1=0,d2=0;
-
-      int vertexKey = -1;
-      for (TopExp_Explorer ex_edge(e ,TopAbs_VERTEX); ex_edge.More(); ex_edge.Next()) {
-        TopoDS_Vertex v = TopoDS::Vertex(ex_edge.Current());
-        ++npts;
-        if (npts == 1){
-          ip = &ip1;
-          d1 = ee0.SquareDistance(BRep_Tool::Pnt(v));
-        } else {
-          ip = &ip2;
-          d2 = ee0.SquareDistance(BRep_Tool::Pnt(v));
-        }
-        *ip = pmap.FindIndex(v);
-        if(*ip <= 0) {
-          *ip = pmap.Add(v);
-          // SMESH_subMesh* sm = aMesh.GetSubMesh(v);
-          // if ( sm->IsMeshComputed() )
-          //   edgeSubmeshes.insert( sm->GetSubMeshDS() );
-        }
+      int   ip[2];
+      double d[2];
+      gp_Pnt2d uv0 = curves.back()->Value(tmin);
+      gp_Pnt    p0 = surfaces.back()->Value( uv0.X(), uv0.Y() );
 
-//        std::string aFileName = "fmap_vertex_";
-//        aFileName.append(val_to_string(*ip));
-//        aFileName.append(".brep");
-//        BRepTools::Write(v,aFileName.c_str());
+      for (TopExp_Explorer ex_edge(e ,TopAbs_VERTEX); ex_edge.More(); ex_edge.Next())
+      {
+        const TopoDS_Vertex& v = TopoDS::Vertex(ex_edge.Current());
+        ip[ npts ] = pmap.Add(v);
+        d [ npts ] = p0.SquareDistance(BRep_Tool::Pnt(v));
+        ++npts;
 
-        if (HasSizeMapOnVertex){
-          vertexKey = VerticesWithSizeMap.FindIndex(v);
-          if (VertexId2SizeMap.find(vertexKey)!=VertexId2SizeMap.end()){
+        if (HasSizeMapOnVertex)
+        {
+          int vertexKey = VerticesWithSizeMap.FindIndex(v);
+          if (VertexId2SizeMap.find(vertexKey)!=VertexId2SizeMap.end())
+          {
             theSizeMapStr = VertexId2SizeMap[vertexKey];
             if (theSizeMapStr.find(bad_end) == (theSizeMapStr.size()-bad_end.size()-1))
               continue;
@@ -2371,23 +2357,65 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
             PyGILState_Release(gstate);
           }
         }
-      }
-      if (npts != 2) {
-        // should not happen
+      } // loop on vertices
+
+      if (npts != 2) { // should not happen
         MESSAGE("An edge does not have 2 extremities.");
-      } else {
-        if (d1 < d2) {
-          // This defines the curves extremity connectivity
-          cad_edge_set_extremities(edg, ip1, ip2);
-          /* set the tag (color) to the same value as the extremity id : */
-          cad_edge_set_extremities_tag(edg, ip1, ip2);
-        }
-        else {
-          cad_edge_set_extremities(edg, ip2, ip1);
-          cad_edge_set_extremities_tag(edg, ip2, ip1);
-        }
+        continue;
       }
+
+      if ( d[0] > d[1] )
+        std::swap( ip[0], ip[1] );
+
+      // This defines the curves extremity connectivity
+      cad_edge_set_extremities    (edg, ip[0], ip[1]);
+      /* set the tag (color) to the same value as the extremity id : */
+      cad_edge_set_extremities_tag(edg, ip[0], ip[1]);
+
     } // for edge
+
+    // ==============================
+    // Add segments of enforced mesh
+    // ==============================
+
+    if ( enforcedMesh.HasSegmentsOnFace( f ))
+    {
+      BLSURFPlugin_EnforcedMesh1D::Segmemnt seg;
+      while ( enforcedMesh.NextSegment( seg, pmap ))
+      {
+        curves.push_back( seg._pcurve );
+
+        cad_edge_t *edg = cad_edge_new( fce, seg._tag, seg._u[0], seg._u[1],
+                                        curv_fun,seg._pcurve.get());
+        cad_edge_set_tag( edg, seg._tag );
+
+        cad_edge_set_property( edg, EDGE_PROPERTY_SOFT_REQUIRED );
+        cad_edge_set_property( edg, EDGE_PROPERTY_INTERNAL );
+
+        cad_edge_set_extremities    ( edg, seg._vTag[0], seg._vTag[1]);
+        cad_edge_set_extremities_tag( edg, seg._vTag[0], seg._vTag[1]);
+
+        dcad_edge_discretization_t *dedge;
+        dcad_get_edge_discretization( dcad, edg, &dedge );
+        dcad_edge_discretization_set_vertex_count( dedge, 2 );
+
+        dcad_edge_discretization_set_vertex_coordinates( dedge, 1,
+                                                         seg._u  [0],
+                                                         &seg._uv[0].ChangeCoord(1),
+                                                         seg._xyz[0].ChangeData() );
+        dcad_edge_discretization_set_vertex_coordinates( dedge, 2,
+                                                         seg._u  [1],
+                                                         &seg._uv[1].ChangeCoord(1),
+                                                         seg._xyz[1].ChangeData() );
+
+        dcad_edge_discretization_set_vertex_tag( dedge, 1, seg._vTag[0] );
+        dcad_edge_discretization_set_vertex_tag( dedge, 2, seg._vTag[1] );
+
+        dcad_edge_discretization_set_property(dedge, DISTENE_DCAD_PROPERTY_REQUIRED);
+      }
+    }
+
+
   } //for face
 
   ///////////////////////
@@ -2502,10 +2530,6 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
     // set_param(css, "max_size",             val_to_string( minFaceSize * 5 ).c_str());
   }
 
-  // TODO: be able to use a mesh in input.
-  // See imsh usage in Products/templates/mg-cadsurf_template_common.cpp
-  // => cadsurf_set_mesh
-
   // Use the original dcad
   cadsurf_set_dcad(css, dcad);
 
@@ -2591,7 +2615,8 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
   std::string GMFFileName = BLSURFPlugin_Hypothesis::GetDefaultGMFFile();
   if (_hypothesis)
     GMFFileName = _hypothesis->GetGMFFile();
-  if (GMFFileName != "") {
+  if (GMFFileName != "")
+  {
     bool asciiFound  = (GMFFileName.find(".mesh", GMFFileName.length()-5) != std::string::npos);
     bool binaryFound = (GMFFileName.find(".meshb",GMFFileName.length()-6) != std::string::npos);
     if (!asciiFound && !binaryFound)
@@ -2604,9 +2629,9 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
   integer *evedg, *evtri, *evquad, *tags_buff, type;
   real xyz[3];
 
-  mesh_get_vertex_count(msh, &nv);
-  mesh_get_edge_count(msh, &ne);
-  mesh_get_triangle_count(msh, &nt);
+  mesh_get_vertex_count    (msh, &nv);
+  mesh_get_edge_count      (msh, &ne);
+  mesh_get_triangle_count  (msh, &nt);
   mesh_get_quadrangle_count(msh, &nq);
 
   evedg  = (integer *)mesh_calloc_generic_buffer(msh);
@@ -2617,82 +2642,79 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
   std::vector<const SMDS_MeshNode*> nodes(nv+1);
   std::vector<bool>                  tags(nv+1);
 
+  BLSURFPlugin_Hypothesis::TEnfVertexCoords projVertex;
+
   /* enumerated vertices */
-  for(int iv=1;iv<=nv;iv++) {
+  for ( int iv = 1; iv <= nv; iv++ )
+  {
     mesh_get_vertex_coordinates(msh, iv, xyz);
     mesh_get_vertex_tag(msh, iv, &tag);
     // Issue 0020656. Use vertex coordinates
     nodes[iv] = NULL;
-    if ( tag > 0 && tag <= pmap.Extent() ) {
-      TopoDS_Vertex v = TopoDS::Vertex(pmap(tag));
-      double      tol = BRep_Tool::Tolerance( v );
-      gp_Pnt        p = BRep_Tool::Pnt( v );
-      if ( p.IsEqual( gp_Pnt( xyz[0], xyz[1], xyz[2]), 1e3*tol))
-        xyz[0] = p.X(), xyz[1] = p.Y(), xyz[2] = p.Z();
-      else
-        tag = 0; // enforced or attracted vertex
-      nodes[iv] = SMESH_Algo::VertexNode( v, meshDS );
+    if ( tag > 0 )
+    {
+      if ( tag <= pmap.Extent() )
+      {
+        TopoDS_Vertex v = TopoDS::Vertex(pmap(tag));
+        double      tol = BRep_Tool::Tolerance( v );
+        gp_Pnt        p = BRep_Tool::Pnt( v );
+        if ( p.IsEqual( gp_Pnt( xyz[0], xyz[1], xyz[2]), 1e3*tol))
+          xyz[0] = p.X(), xyz[1] = p.Y(), xyz[2] = p.Z();
+        else
+          tag = 0; // enforced or attracted vertex
+        nodes[iv] = SMESH_Algo::VertexNode( v, meshDS );
+      }
+      if ( !nodes[iv] && ( nodes[iv] = enforcedMesh.GetNodeByTag( tag, pmap )))
+      {
+        continue;
+      }
     }
     if ( !nodes[iv] )
       nodes[iv] = meshDS->AddNode(xyz[0], xyz[1], xyz[2]);
 
     // Create group of enforced vertices if requested
-    BLSURFPlugin_Hypothesis::TEnfVertexCoords projVertex;
-    projVertex.clear();
-    projVertex.push_back((double)xyz[0]);
-    projVertex.push_back((double)xyz[1]);
-    projVertex.push_back((double)xyz[2]);
-    std::map< BLSURFPlugin_Hypothesis::TEnfVertexCoords, BLSURFPlugin_Hypothesis::TEnfVertexList >::const_iterator enfCoordsIt = EnfVertexCoords2EnfVertexList.find(projVertex);
+    projVertex.assign( xyz, xyz + 3 );
+    auto enfCoordsIt = EnfVertexCoords2EnfVertexList.find( projVertex );
     if (enfCoordsIt != EnfVertexCoords2EnfVertexList.end())
     {
-      BLSURFPlugin_Hypothesis::TEnfVertexList::const_iterator enfListIt = enfCoordsIt->second.begin();
-      BLSURFPlugin_Hypothesis::TEnfVertex *currentEnfVertex;
-      for (; enfListIt != enfCoordsIt->second.end(); ++enfListIt) {
-        currentEnfVertex = (*enfListIt);
-        if (currentEnfVertex->grpName != "") {
-          bool groupDone = false;
-          SMESH_Mesh::GroupIteratorPtr grIt = aMesh.GetGroups();
-          while (grIt->more()) {
+      for ( BLSURFPlugin_Hypothesis::TEnfVertex *currentEnfVertex : enfCoordsIt->second )
+        if (currentEnfVertex->grpName != "")
+        {
+          SMDS_MeshGroup* groupDS = nullptr;
+          for ( SMESH_Mesh::GroupIteratorPtr grIt = aMesh.GetGroups(); grIt->more() && !groupDS; )
+          {
             SMESH_Group * group = grIt->next();
-            if ( !group ) continue;
-            SMESHDS_GroupBase* groupDS = group->GetGroupDS();
-            if ( !groupDS ) continue;
-            if ( groupDS->GetType()==SMDSAbs_Node && currentEnfVertex->grpName.compare(group->GetName())==0) {
-              SMESHDS_Group* aGroupDS = static_cast<SMESHDS_Group*>( groupDS );
-              aGroupDS->SMDSGroup().Add(nodes[iv]);
-              // How can I inform the hypothesis ?
-              //                 _hypothesis->AddEnfVertexNodeID(currentEnfVertex->grpName,nodes[iv]->GetID());
-              groupDone = true;
-              break;
-            }
+            SMESHDS_Group * grp = dynamic_cast< SMESHDS_Group* >( group->GetGroupDS() );
+            if ( grp &&
+                 grp->GetType() == SMDSAbs_Node &&
+                 currentEnfVertex->grpName == group->GetName() )
+              groupDS = &grp->SMDSGroup();
           }
-          if (!groupDone)
+          if ( !groupDS )
           {
-            SMESH_Group* aGroup = aMesh.AddGroup( SMDSAbs_Node, currentEnfVertex->grpName.c_str() );
-            aGroup->SetName( currentEnfVertex->grpName.c_str() );
-            SMESHDS_Group* aGroupDS = static_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
-            aGroupDS->SMDSGroup().Add(nodes[iv]);
-            groupDone = true;
+            SMESH_Group * group = aMesh.AddGroup( SMDSAbs_Node, currentEnfVertex->grpName.c_str() );
+            SMESHDS_Group * grp = static_cast< SMESHDS_Group* >( group->GetGroupDS() );
+            groupDS = &grp->SMDSGroup();
           }
-          if (!groupDone)
-            throw SALOME_Exception(LOCALIZED("An enforced vertex node was not added to a group"));
+          groupDS->Add( nodes[iv] );
         }
-        else
-          MESSAGE("Group name is empty: '"<<currentEnfVertex->grpName<<"' => group is not created");
-      }
     }
 
     // internal points are tagged to zero
-    if(tag > 0 && tag <= pmap.Extent() ){
+    if ( tag > 0 && tag <= pmap.Extent() )
+    {
       meshDS->SetNodeOnVertex(nodes[iv], TopoDS::Vertex(pmap(tag)));
       tags[iv] = false;
-    } else {
+    }
+    else
+    {
       tags[iv] = true;
     }
   }
 
   /* enumerate edges */
-  for(int it=1;it<=ne;it++) {
+  for ( int it = 1; it <= ne; it++ )
+  {
     SMDS_MeshEdge* edg;
     mesh_get_edge_vertices(msh, it, vtx);
     mesh_get_edge_extra_vertices(msh, it, &type, evedg);
@@ -2703,14 +2725,21 @@ bool BLSURFPlugin_BLSURF::compute(SMESH_Mesh&         aMesh,
     // Get the initial tags corresponding to the output tag and redefine the tag as
     // the last of the two initial tags (else the output tag is out of emap and hasn't any meaning)
     mesh_get_composite_tag_definition(msh, tag, &nb_tag, tags_buff);
-    if(nb_tag > 1)
-      tag=tags_buff[nb_tag-1];
+    if ( nb_tag > 1 )
+      tag = tags_buff[ nb_tag-1 ];
     if ( tag < 1 || tag > emap.Extent() )
     {
-      std::cerr << "MG-CADSurf BUG:::: Edge tag " << tag
-                << " does not point to a CAD edge (nb edges " << emap.Extent() << ")" << std::endl;
+      if ( !enforcedMesh.IsSegmentTag( tag )) // it's a false INTERNAL EDGE of enforced mesh
+      {
+        std::cerr << "MG-CADSurf BUG:::: Edge tag " << tag
+                  << " does not point to a CAD edge (nb edges " << emap.Extent() << ")"
+                  << std::endl;
+      }
       continue;
     }
+    if ( meshDS->ShapeToIndex( emap( tag )) == 0 )
+      tag = enforcedMesh.GetTagOfSplitEdge( tag );
+
     if (tags[vtx[0]]) {
       Set_NodeOnEdge(meshDS, nodes[vtx[0]], emap(tag));
       tags[vtx[0]] = false;
@@ -3207,31 +3236,27 @@ void BLSURFPlugin_BLSURF::Set_NodeOnEdge(SMESHDS_Mesh*        meshDS,
  */
 status_t curv_fun(real t, real *uv, real *dt, real *dtt, void *user_data)
 {
-  /* t is given. It contains the t (time) 1D parametric coordintaes
-     of the point PreCAD/MG-CADSurf is querying on the curve */
+  /* t is given. It contains the 1D parametric coordintaes
+     of the point MG-CADSurf is querying on the curve */
 
-  /* user_data identifies the edge PreCAD/MG-CADSurf is querying
-   * (see cad_edge_new later in this example) */
-  const Geom2d_Curve*pargeo = (const Geom2d_Curve*) user_data;
+  /* user_data identifies the edge MG-CADSurf is querying */
+  const Geom2d_Curve* pargeo = (const Geom2d_Curve*) user_data;
 
-  if (uv){
-   /* MG-CADSurf is querying the function evaluation */
-    gp_Pnt2d P;
-    P=pargeo->Value(t);
+  if (uv) {
+    /* MG-CADSurf is querying the function evaluation */
+    gp_Pnt2d P = pargeo->Value(t);
     uv[0]=P.X(); uv[1]=P.Y();
   }
 
-  if(dt) {
-   /* query for the first order derivatives */
-    gp_Vec2d V1;
-    V1=pargeo->DN(t,1);
+  if (dt) {
+    /* query for the first order derivatives */
+    gp_Vec2d V1 = pargeo->DN(t,1);
     dt[0]=V1.X(); dt[1]=V1.Y();
   }
 
-  if(dtt){
+  if (dtt) {
     /* query for the second order derivatives */
-    gp_Vec2d V2;
-    V2=pargeo->DN(t,2);
+    gp_Vec2d V2 = pargeo->DN(t,2);
     dtt[0]=V2.X(); dtt[1]=V2.Y();
   }
 
index 167b7617f72bc1ddf3a5237a6f8be9b69e1663ea..936bdd3dab7fa1e739fc63abd2ed86a8e802695a 100644 (file)
@@ -132,6 +132,16 @@ public:
   typedef std::vector< TEdgePeriodicityIDs > TEdgesIDsPeriodicityVector;
   typedef std::vector< TVertexPeriodicityIDs > TVerticesIDsPeriodicityVector;
 
+  // Point projection on FACE
+  typedef struct {
+    gp_XY        uv;
+    gp_XYZ       xyz;
+    TopAbs_State state;
+  } projectionPoint;
+
+  static projectionPoint getProjectionPoint(TopoDS_Face&  theFace,
+                                            const gp_Pnt& thePoint,
+                                            const bool    theAllowStateON=false);
 
 
 protected:
@@ -162,7 +172,6 @@ private:
 private:
   PyObject *          main_mod;
   PyObject *          main_dict;
-  SMESH_MesherHelper* myHelper;
 
   volatile bool _compute_canceled;
 };
diff --git a/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.cxx
new file mode 100644 (file)
index 0000000..923bdfa
--- /dev/null
@@ -0,0 +1,1332 @@
+// Copyright (C) 2007-2021  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// File      : BLSURFPlugin_EnforcedMesh1D.cxx
+// Author    : Edward AGAPOV (OCC)
+
+#include "BLSURFPlugin_EnforcedMesh1D.hxx"
+
+#include "BLSURFPlugin_BLSURF.hxx"
+
+#include <SMDS_IteratorOnIterators.hxx>
+#include <SMDS_MeshEdge.hxx>
+#include <SMDS_MeshGroup.hxx>
+#include <SMESHDS_Group.hxx>
+#include <SMESHDS_Mesh.hxx>
+#include <SMESH_Group.hxx>
+#include <SMESH_Mesh.hxx>
+#include <SMESH_MeshAlgos.hxx>
+#include <SMESH_MeshEditor.hxx>
+#include <SMESH_MesherHelper.hxx>
+#include <SMESH_TypeDefs.hxx>
+
+#include <BRepAdaptor_Curve.hxx>
+#include <BRepBuilderAPI_MakeVertex.hxx>
+#include <BRep_Tool.hxx>
+#include <Extrema_ExtCC.hxx>
+#include <Extrema_ExtElC.hxx>
+#include <Geom_Line.hxx>
+#include <ShapeAnalysis_Curve.hxx>
+#include <Geom2d_Line.hxx>
+
+// allow range iteration on NCollection_IndexedMap
+template < class IMAP >
+typename IMAP::const_iterator begin( const IMAP &  m ) { return m.cbegin(); }
+template < class IMAP >
+typename IMAP::const_iterator end( const IMAP &  m ) { return m.cend(); }
+
+
+namespace
+{
+  //================================================================================
+  /*!
+   * \brief Look for a node coincident with a given nodes among end nodes of a segment
+   *        and among its internal nodes
+   *  \param [in] p - the epoint
+   *  \param [in] tol - 3D tolarace
+   *  \param [in] segment - the segment
+   *  \param [in] segInternalNodes - map of segment internal nodes
+   *  \param [out] index - return index of found internal node; -1 if an end node is found
+   *  \return const SMDS_MeshNode* - found node
+   */
+  //================================================================================
+
+  const SMDS_MeshNode* findNode( const gp_Pnt&                              p,
+                                 const double                               tol,
+                                 const SMDS_MeshElement*                    segment,
+                                 BLSURFPlugin_EnforcedMesh1D::TNodesOnSeg & segInternalNodes,
+                                 int &                                      index )
+  {
+
+    SMESH_NodeXYZ node0 = segment->GetNode(0);
+    if ( p.IsEqual( node0, tol ))
+      return index = -1, node0.Node();
+    SMESH_NodeXYZ node1 = segment->GetNode(1);
+    if ( p.IsEqual( node1, tol ))
+      return index = -1, node1.Node();
+
+    auto seg2nodes = segInternalNodes.find( segment );
+    if ( seg2nodes != segInternalNodes.end() )
+    {
+      const std::vector< const SMDS_MeshNode* >& nodes = seg2nodes->second;
+      for ( size_t i = 0; i < nodes.size(); ++i )
+        if ( p.IsEqual( SMESH_NodeXYZ( nodes[i] ), tol ))
+        {
+          index = (int) i;
+          return nodes[i];
+        }
+    }
+    return nullptr;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Orient segments to correspond to order of nodes in a branch
+   *  \param [in] braSegs - segments of the branch
+   *  \param [in] braNodes - nodes of the branch
+   *  \param [in] nodeIndex - index of a node of the branch
+   *  \param [inout] mesh - mesh holding the nodes and segments
+   * 
+   * 
+   */
+  //================================================================================
+
+  void orientSegments( const std::vector< const SMDS_MeshElement* > & braSegs,
+                       const std::vector< const SMDS_MeshNode* > &    braNodes,
+                       const size_t                                   nodeIndex,
+                       SMESH_Mesh*                                    mesh )
+  {
+    const SMDS_MeshElement* toReverse[2] = { nullptr, nullptr };
+
+    if ( nodeIndex > 0 &&
+         braSegs[ nodeIndex - 1 ]->GetNode(1) != braNodes[ nodeIndex ])
+      toReverse[ 0 ] = braSegs[ nodeIndex - 1 ];
+    
+    if ( nodeIndex < braSegs.size() &&
+         braSegs[ nodeIndex ]->GetNode(0) != braNodes[ nodeIndex ])
+      toReverse[ bool( toReverse[0]) ] = braSegs[ nodeIndex ];
+
+    if ( !toReverse[0] )
+      return;
+
+    SMESH_MeshEditor editor( mesh );
+    for ( int i = 0; i < 2; ++i )
+      if ( toReverse[ i ])
+        editor.Reorient( toReverse[ i ]);
+  }
+
+} // namespace
+
+//================================================================================
+/*!
+ * \brief Create enforced mesh segments in a mesh
+ *  \param [in] helper - contains the mesh and the shape to compute
+ *  \param [in] hyp - hypothesis containing data of enforced meshes
+ */
+//================================================================================
+
+BLSURFPlugin_EnforcedMesh1D::BLSURFPlugin_EnforcedMesh1D( SMESH_MesherHelper&            helper,
+                                                          const BLSURFPlugin_Hypothesis* hyp )
+  : _mesh ( helper.GetMesh() ),
+    _shape( helper.GetSubShape() ),
+    _helper( *_mesh ),
+    _isQuadratic( helper.GetIsQuadratic() )
+{
+  if ( !hyp || !_mesh || hyp->GetEnforcedMeshes().empty() )
+    return;
+
+  _tol      = 2 * BRep_Tool::MaxTolerance( _shape, TopAbs_VERTEX );
+  _segTag   = 1000 + helper.Count( _shape, TopAbs_EDGE, /*ignoreSame=*/false );
+  _segTag0  = _segTag;
+  _nodeTag0 = 1000 + helper.Count( _shape, TopAbs_VERTEX, /*ignoreSame=*/false );
+
+  for ( const BLSURFPlugin_Hypothesis::EnforcedMesh& enfMesh : hyp->GetEnforcedMeshes() )
+  {
+    copyEnforcedMesh( enfMesh, hyp, _shape );
+  }
+
+  for ( const SMDS_MeshElement* segment : _segmentsOnSeveralShapes )
+  {
+    splitSegmentOnSeveralShapes( segment );
+  }
+
+  for ( const TopoDS_Shape & face : _faces )
+  {
+    splitSelfIntersectingSegments( face );
+  }
+
+  for ( TEdge2Nodes::Iterator e2nn( _nodesOnEdge ); e2nn.More(); e2nn.Next() )
+  {
+    splitEdgeByNodes( e2nn.Key(), e2nn.Value() );
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Convert enforced segments to quadratic
+ */
+//================================================================================
+
+BLSURFPlugin_EnforcedMesh1D::~BLSURFPlugin_EnforcedMesh1D()
+{
+  if ( !_isQuadratic )
+    return;
+
+  _helper.SetIsQuadratic( true );
+
+  SMESHDS_Mesh* meshDS = _mesh->GetMeshDS();
+  std::vector<const SMDS_MeshNode *>    nodes(2);
+  std::vector<const SMDS_MeshElement *> trias;
+
+  SMDS_MeshGroup* group = nullptr;
+  if ( !_name2Group.empty() )
+    group = _name2Group.begin()->second;
+
+  for ( const TopoDS_Shape& f : _faces )
+    if ( HasSegmentsOnFace( TopoDS::Face( f )))
+      while ( _segIterator->more() )
+      {
+        const SMDS_MeshElement* segment = _segIterator->next();
+        if ( segment->GetType() != SMDSAbs_Edge )
+          break;
+
+        nodes[0] = segment->GetNode(0);
+        nodes[1] = segment->GetNode(1);
+        if ( meshDS->GetElementsByNodes( nodes, trias, SMDSAbs_Face ))
+        {
+          if ( !group || !group->Contains( segment ))
+          {
+            SMDS_MeshGroup* otherGroup = nullptr;
+            if ( _name2Group.size() > bool( group ))
+              for ( auto & n2g : _name2Group )
+                if ( n2g.second != group && n2g.second->Contains( segment ))
+                {
+                  otherGroup = n2g.second;
+                  break;
+                }
+            group = otherGroup;
+          }
+
+          _helper.AddTLinks( static_cast< const SMDS_MeshFace* >( trias[0] ));
+
+          meshDS->RemoveFreeElement( segment, meshDS->MeshElements( f ), /*fromGroup=*/false );
+
+          SMDS_MeshElement* quadSegment = _helper.AddEdge( nodes[0], nodes[1],
+                                                           /*id=*/0, /*force3d=*/false );
+          if ( group && segment != quadSegment )
+          {
+            group->Remove( segment );
+            group->Add( quadSegment );
+          }
+        }
+      }
+  return;
+}
+
+//================================================================================
+/*!
+ * \brief Return EDGEs resulted from division of FACE boundary by enforced segments
+ *  \param [in] edge - possibly divided EDGE
+ *  \param [out] splits - split EDGEs
+ *  \return bool - true if the EDGE is split
+ */
+//================================================================================
+
+bool BLSURFPlugin_EnforcedMesh1D::GetSplitsOfEdge( const TopoDS_Edge&           edge,
+                                                   std::vector< TopoDS_Edge > & splits,
+                                                   TopTools_IndexedMapOfShape & edgeTags )
+{
+  std::vector< TopoDS_Edge > * splitsInMap = _edgeSplitsOfEdge.ChangeSeek( edge );
+  if ( !splitsInMap )
+    return false;
+
+  splits.insert( splits.end(), splitsInMap->begin(), splitsInMap->end() );
+
+  int eTag = edgeTags.Add( edge );
+
+  size_t index = splits.size() - 1;
+  for ( size_t i = 0; i < splitsInMap->size(); ++i, --index )
+  {
+    int splitTag = edgeTags.Add( splits[ index ]);
+    _splitTags2EdgeTag[ splitTag ] = eTag;
+
+    if ( edge.Orientation() == TopAbs_REVERSED )
+      splits[ index ].Reverse();
+  }
+
+  return true;
+}
+
+
+//================================================================================
+/*!
+ * \brief Add 1D elements to the mesh
+ */
+//================================================================================
+
+void BLSURFPlugin_EnforcedMesh1D::
+
+copyEnforcedMesh( const BLSURFPlugin_Hypothesis::EnforcedMesh& theEnfMesh,
+                  const BLSURFPlugin_Hypothesis*               theHyp,
+                  const TopoDS_Shape&                          theShape)
+{
+  SMESH_Mesh* mesh1D;
+  SMDS_ElemIteratorPtr segIt = theHyp->GetEnforcedSegments( theEnfMesh, mesh1D );
+  if ( !segIt->more() )
+    return;
+
+  // setup predicates to detect nodes on FACE boundary
+  setupPredicates( theShape );
+
+  SMDS_MeshGroup* group = getGroup( theEnfMesh._groupName );
+  SMESHDS_Mesh*  meshDS = _helper.GetMeshDS();
+
+  // get ordered nodes and segments of theEnfMesh
+  SMESH_MeshAlgos::TElemGroupVector edgeBranches;
+  SMESH_MeshAlgos::TNodeGroupVector nodeBranches;
+  SMESH_MeshAlgos::Get1DBranches( segIt, edgeBranches, nodeBranches );
+
+
+  // Copy nodes and segments from an enforced mesh to my mesh
+
+  TopoDS_Shape vertex, edge;
+
+  // first treat ends of branches that can be shared by branches
+  for ( size_t iB = 0; iB < nodeBranches.size(); ++iB )
+  {
+    std::vector< const SMDS_MeshNode* > &   braNodes = nodeBranches[ iB ];
+    std::vector< const SMDS_MeshElement* > & braSegs = edgeBranches[ iB ];
+
+    for ( int isLast = 0; isLast < 2; ++isLast )
+    {
+      const SMDS_MeshNode* enfNode = isLast ? braNodes.back() : braNodes[0];
+      if ( meshDS->Contains( enfNode ))
+        continue; // already in my mesh
+
+      const SMDS_MeshNode* newNode = copyEnforcedNode( enfNode );
+      if ( !newNode )
+        orientSegments( braSegs, braNodes, isLast ? 0 : braNodes.size() - 1, mesh1D );
+
+      // replace enfNode at branch ends by newNode
+      SMESH_NodeXYZ enfPnt( newNode ? newNode : enfNode );
+      for ( std::vector< const SMDS_MeshNode* > & braNodes : nodeBranches )
+      {
+        for ( int isLast = 0; isLast < 2; ++isLast )
+        {
+          const SMDS_MeshNode* & endNode = isLast ? braNodes.back() : braNodes[0];
+          if ( endNode == enfNode || enfPnt.SquareDistance( endNode ) < _tol*_tol )
+            endNode = newNode;
+        }
+      }
+      continue;
+    }  // loop on branch ends
+  } // loop on nodeBranches
+
+  // copy nodes and segments
+
+  for ( size_t iB = 0; iB < nodeBranches.size(); ++iB )
+  {
+    std::vector< const SMDS_MeshNode* > &   braNodes = nodeBranches[ iB ];
+    std::vector< const SMDS_MeshElement* > & braSegs = edgeBranches[ iB ];
+
+    // copy nodes of the branch
+    for ( size_t i = 0; i < braNodes.size(); ++i )
+    {
+      const SMDS_MeshNode* & enfNode = braNodes[ i ];
+      const SMDS_MeshNode*   newNode = copyEnforcedNode( enfNode );
+
+      if ( !newNode ) // orient segments to be able to get enforced not projected node
+        orientSegments( braSegs, braNodes, i, mesh1D );
+
+      enfNode = newNode;
+    }
+
+    // copy segments of the branch
+    for ( size_t i = 0; i < braSegs.size(); ++i )
+    {
+      //braSegs[ i ] = nullptr;
+
+      const SMDS_MeshNode* node0 = braNodes[ i     ];
+      const SMDS_MeshNode* node1 = braNodes[ i + 1 ];
+      if ( !node0 && !node1 )
+        continue;
+
+      TopoDS_Shape shape0 = _helper.GetSubShapeByNode( node0, meshDS );
+      TopoDS_Shape shape1 = _helper.GetSubShapeByNode( node1, meshDS );
+      if ( shape0.IsNull() && shape1.IsNull() )
+        continue;
+
+      if ( !node0 && shape1.ShapeType() != TopAbs_FACE )
+        continue;
+      if ( !node1 && shape0.ShapeType() != TopAbs_FACE )
+        continue;
+
+      if ( !node0 || !node1 ) // create missing node at location of enforced node projected nowhere
+      {
+        SMESH_NodeXYZ  pn = braSegs[i]->GetNode( !node1 );
+        ( node0 ? node1 : node0 ) = _helper.AddNode( pn->X(), pn->Y(), pn->Z() );
+      }
+
+      SMDS_MeshEdge* newSeg = _helper.AddEdge( node0, node1 );
+      if ( group )
+        group->Add( newSeg );
+      braSegs[ i ] = newSeg;
+
+      // check if the both nodes are on the same FACE
+      TopoDS_Shape face = shape0;
+      if ( !shape0.IsSame( shape1 ) && !shape0.IsNull() && !shape1.IsNull() )
+      {
+        if ( shape0.ShapeType() == TopAbs_FACE &&
+             _helper.IsSubShape( shape1, shape0 ))
+        {
+          face = shape0;
+        }
+        else if ( shape1.ShapeType() == TopAbs_FACE &&
+                  _helper.IsSubShape( shape0, shape1 ))
+        {
+          face = shape1;
+        }
+        else // try to find a FACE by projecting a segment middle point
+        {
+          face.Nullify();
+          gp_Pnt middlePnt = 0.5 * ( SMESH_NodeXYZ( node0 ) + SMESH_NodeXYZ( node1 ));
+          //BLSURFPlugin_BLSURF::projectionPoint projPnt =
+          BLSURFPlugin_BLSURF::getProjectionPoint( TopoDS::Face( face ), middlePnt );
+
+          if ( !face.IsNull() &&
+               ( !_helper.IsSubShape( shape0, face ) ||
+                 !_helper.IsSubShape( shape1, face ) ))
+            face.Nullify();
+        }
+      }
+      if ( !face.IsNull() && face.ShapeType() == TopAbs_FACE )
+      {
+        meshDS->SetMeshElementOnShape( newSeg, face );
+        _faces.Add( face );
+      }
+
+      if ( face.IsNull() || shape0.IsNull() || shape1.IsNull() )
+      {
+        _segmentsOnSeveralShapes.push_back( newSeg );
+      }
+
+    } // loop on branch segments
+    continue;
+  } // loop on branches
+
+  return;
+}
+
+//================================================================================
+/*!
+ * \brief Create a copy of a node of enforced mesh in my mesh
+ *  \param [in] enfNode - enforced node
+ *  \return const SMDS_MeshNode* - a node in my mesh
+ */
+//================================================================================
+
+const SMDS_MeshNode* BLSURFPlugin_EnforcedMesh1D::copyEnforcedNode( const SMDS_MeshNode* enfNode )
+{
+  SMESHDS_Mesh * meshDS = _helper.GetMeshDS();
+
+  if ( !enfNode || meshDS->Contains( enfNode ))
+    return enfNode; // already in my mesh
+
+  SMESH_NodeXYZ enfPnt = enfNode;
+
+  const SMDS_MeshNode* newNode = nullptr;
+
+  // check if enfNode is on VERTEX
+  TopoDS_Vertex vertex;
+  if ( _onVertexPredicate->IsSatisfy( enfNode, &vertex ))
+  {
+    _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+    newNode = SMESH_Algo::VertexNode( vertex, meshDS );
+  }
+
+  // check if enfNode is on EDGE
+  bool setNodeOnEdge = false;
+  TopoDS_Edge edge;
+  if ( !newNode )
+  {
+    setNodeOnEdge = _onEdgePredicate->IsSatisfy( enfNode, &edge );
+    if ( setNodeOnEdge )
+    {
+      newNode = findNodeOnEdge( enfPnt, edge );
+      setNodeOnEdge = !newNode;
+    }
+  }
+
+  // create a new node and set it on FACE
+  if ( !newNode )
+  {
+    TopoDS_Face face;
+    BLSURFPlugin_BLSURF::projectionPoint projPnt =
+      BLSURFPlugin_BLSURF::getProjectionPoint( face, enfPnt, /*allowStateON=*/true );
+    if ( face.IsNull() ) return newNode;
+
+    if ( projPnt.state == TopAbs_ON )
+    {
+      SMDS_MeshNode* projNode = const_cast< SMDS_MeshNode* >( enfNode );
+      projNode->setXYZ( projPnt.xyz.X(), projPnt.xyz.Y(), projPnt.xyz.Z() );
+      vertex.Nullify();
+      edge.Nullify();
+      if ( _onVertexPredicate->IsSatisfy( projNode, &vertex ))
+      {
+        _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+        newNode = SMESH_Algo::VertexNode( vertex, meshDS );
+      }
+      else if (( setNodeOnEdge = _onEdgePredicate->IsSatisfy( projNode, &edge )))
+      {
+        newNode = findNodeOnEdge( projPnt.xyz, edge );
+        setNodeOnEdge = !newNode;
+      }
+      projNode->setXYZ( enfPnt.X(), enfPnt.Y(), enfPnt.Z() );
+    }
+
+    if ( !newNode )
+      newNode = meshDS->AddNode( projPnt.xyz.X(), projPnt.xyz.Y(), projPnt.xyz.Z() );
+
+    if ( vertex.IsNull() && edge.IsNull() )
+      meshDS->SetNodeOnFace( newNode, face, projPnt.uv.X(), projPnt.uv.Y() );
+  }
+
+  // set the new node on EDGE
+  if ( newNode && setNodeOnEdge )
+  {
+    addNodeOnEdge( newNode, edge );
+  }
+
+  return newNode;
+}
+
+//================================================================================
+/*!
+ * \brief Split a segment whose nodes are on different FACEs into smaller parts
+ *        lying each on one FACE
+ */
+//================================================================================
+
+void BLSURFPlugin_EnforcedMesh1D::splitSegmentOnSeveralShapes( const SMDS_MeshElement* segment )
+{
+  const SMDS_MeshNode* node0 = segment->GetNode(0);
+  const SMDS_MeshNode* node1 = segment->GetNode(1);
+  SMESHDS_Mesh * meshDS = _helper.GetMeshDS();
+
+  TopoDS_Shape shape0 = _helper.GetSubShapeByNode( node0, meshDS );
+  TopoDS_Shape shape1 = _helper.GetSubShapeByNode( node1, meshDS );
+
+  if ( shape0.IsNull() )
+  {
+    std::swap( node0, node1 );
+    shape0 = shape1;
+    shape1.Nullify();
+  }
+
+  gp_XYZ   xyz0 = SMESH_NodeXYZ( node0 );
+  gp_XYZ   xyz1 = SMESH_NodeXYZ( node1 );
+  gp_XYZ segDir = ( xyz1 - xyz0 ).Normalized();
+
+  //std::map< double, const SMDS_MeshNode* > mediumNodes; // nodes splitting the segment
+
+  while ( !shape0.IsSame( shape1 )) // move along the segment till shape1
+  {
+    if ( shape0.ShapeType() == TopAbs_FACE ) // make a node on an EDGE of the FACE
+    {                                        // ----------------------------------
+      TopoDS_Edge edge;
+      double paramOnE;
+      gp_Pnt edgeIntPnt = getEdgeIntersection( shape0, xyz0, xyz1, edge, paramOnE );
+      if ( edge.IsNull() )
+        break;
+
+      // check if edgeIntPnt in on VERTEX
+      TopoDS_Vertex vertex;
+      for ( int iV = 0; iV < 2 &&  vertex.IsNull(); ++iV )
+      {
+        TopoDS_Vertex v = _helper.IthVertex( iV, edge );
+        if ( edgeIntPnt.SquareDistance( BRep_Tool::Pnt( v )) < _tol *_tol )
+          vertex = v;
+      }
+
+      // make a node on the EDGE
+      const SMDS_MeshNode* nodeOnEdge = nullptr;
+      if ( vertex.IsNull() )
+      {
+        nodeOnEdge = findNodeOnEdge( edgeIntPnt, edge );
+        if ( !nodeOnEdge )
+        {
+          if ( shape1.IsNull() && node1 )
+          {
+            nodeOnEdge = node1;
+            node1      = nullptr;
+            meshDS->MoveNode( nodeOnEdge, edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() );
+          }
+          else
+          {
+            nodeOnEdge = _helper.AddNode( edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() );
+          }
+          addNodeOnEdge( nodeOnEdge, edge, paramOnE );
+        }
+      }
+      else
+      {
+        _mesh->GetSubMesh( vertex )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
+        nodeOnEdge = SMESH_Algo::VertexNode( vertex, meshDS );
+      }
+
+      // create a sub-segment
+      SMDS_MeshElement* newSeg = _helper.AddEdge( node0, nodeOnEdge );
+      meshDS->SetMeshElementOnShape( newSeg, shape0 );
+
+      SMESH_MeshEditor::AddToSameGroups( newSeg, segment, meshDS );
+
+      node0 = nodeOnEdge;
+      xyz0  = SMESH_NodeXYZ( node0 );
+      if ( vertex.IsNull() )
+        shape0 = edge;
+      else
+        shape0 = vertex;
+    }
+
+    else // shape0 is EDGE or VERTEX; look for the next FACE
+    {    // ------------------------------------------------
+
+      if ( !shape1.IsNull() &&
+           shape1.ShapeType() == TopAbs_FACE &&
+           _helper.IsSubShape( shape0, shape1 )) // shape0 belongs to FACE shape1
+      {
+        SMDS_MeshElement* newSeg = _helper.AddEdge( node0, node1 );
+        SMESH_MeshEditor::AddToSameGroups( newSeg, segment, meshDS );
+        meshDS->SetMeshElementOnShape( newSeg, shape1 );
+        break;
+      }
+      // FACE search
+      TopoDS_Face face;
+      double shift = 10 * _tol;
+      for ( int nbAttemp = 0; face.IsNull() && nbAttemp < 10; ++nbAttemp )
+      {
+        xyz0  += segDir * shift;
+        shift *= 2;
+        BLSURFPlugin_BLSURF::getProjectionPoint( face, xyz0 );
+      }
+      if ( !face.IsNull() )
+      {
+        if ( _helper.IsSubShape( shape0, face ))
+          _faces.Add( face );
+        else
+          break;
+        shape0 = face;
+      }
+      else
+      {
+        break;
+      }
+    }
+    continue;
+  } //while ( !shape0.IsSame( shape1 ))
+
+  meshDS->RemoveFreeElement( segment, /*submesh=*/nullptr );
+}
+
+//================================================================================
+/*!
+ * \brief Find intersection of FACE EDGEs and a segment
+ *  \param [in] theFace - the FACE
+ *  \param [in] thePnt0 - first end of the segment
+ *  \param [in] thePnt1 - last end of the segment
+ *  \param [out] theFounfEdge - return the intersected EDGE
+ *  \param [out] theParamOnEdge - return parameter of intersection point on EDGE
+ *  \return gp_XYZ - point on an EDGE closest to the segment
+ */
+//================================================================================
+
+gp_Pnt BLSURFPlugin_EnforcedMesh1D::getEdgeIntersection( const TopoDS_Shape& theFaceOrEdge,
+                                                         const gp_XYZ&       thePnt0,
+                                                         const gp_XYZ&       thePnt1,
+                                                         TopoDS_Edge &       theFounfEdge,
+                                                         double &            theParamOnEdge)
+{
+  const double segLen = ( thePnt1 - thePnt0 ).Modulus();
+  const double maxSegDist2 = segLen * segLen * 0.5 * 0.5;
+
+  Handle(Geom_Line) segLine = new Geom_Line( thePnt0, thePnt1 - thePnt0 );
+  GeomAdaptor_Curve segLineAdpt( segLine, 0, segLen );
+  
+  TopTools_MapOfShape edges;
+  double minParamOnSeg = segLen;
+  gp_Pnt foundPnt;
+  for ( TopExp_Explorer edgeExp( theFaceOrEdge, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() )
+  {
+    const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() );
+    if ( !edges.Add( edge ))
+      continue;
+
+    Extrema_ExtCC extrema( segLineAdpt, BRepAdaptor_Curve( edge ), _tol, _tol );
+
+    if ( extrema.IsDone() && !extrema.IsParallel() )
+      for ( int i = 1, nb = extrema.NbExt(); i <= nb; ++i )
+        if ( extrema.SquareDistance( i ) < maxSegDist2 )
+        {
+          Extrema_POnCurv pOnSeg, pOnEdge;
+          extrema.Points( i, pOnSeg, pOnEdge );
+          double paramOnSeg = pOnSeg.Parameter();
+          if ( 0 < paramOnSeg && paramOnSeg < minParamOnSeg )
+          {
+            minParamOnSeg = paramOnSeg;
+            foundPnt = pOnEdge.Value();
+            theFounfEdge = edge;
+            theParamOnEdge = pOnEdge.Parameter();
+          }
+        }
+  }
+  return foundPnt;
+}
+
+//================================================================================
+/*!
+ * \brief Split self-intersecting segments on a given FACE
+ */
+//================================================================================
+
+void BLSURFPlugin_EnforcedMesh1D::splitSelfIntersectingSegments( const TopoDS_Shape & theFace )
+{
+  const TopoDS_Face& face = TopoDS::Face( theFace );
+
+  SMESHDS_Mesh* meshDS = _helper.GetMeshDS();
+  SMESHDS_SubMesh*  sm = meshDS->MeshElements( face );
+  if ( !sm || sm->NbElements() <= 1 )
+    return;
+
+  // get ordered nodes and segments on the face
+  SMESH_MeshAlgos::TElemGroupVector edgeBranches;
+  SMESH_MeshAlgos::TNodeGroupVector nodeBranches;
+  SMESH_MeshAlgos::Get1DBranches( sm->GetElements(), edgeBranches, nodeBranches );
+
+  // create element searcher
+  SMESH_ElementSearcher*                       elemSearcher;
+  SMESHUtils::Deleter< SMESH_ElementSearcher > elSearchdeleter;
+  std::vector< const SMDS_MeshElement* >       foundElems;
+  {
+    std::vector< SMDS_ElemIteratorPtr > elemItVec;
+    for ( std::vector< const SMDS_MeshElement* > & braSegs : edgeBranches )
+    {
+      SMDS_ElemIteratorPtr segIt =
+        boost::make_shared< SMDS_ElementVectorIterator >( braSegs.begin(), braSegs.end() );
+      elemItVec.push_back( segIt );
+    }
+    typedef SMDS_IteratorOnIterators< const SMDS_MeshElement*,
+                                      std::vector< SMDS_ElemIteratorPtr > > TVecIterator;
+    SMDS_ElemIteratorPtr segIt = boost::make_shared< TVecIterator >( elemItVec );
+
+    elemSearcher = SMESH_MeshAlgos::GetElementSearcher( *meshDS, segIt, _tol );
+    elSearchdeleter._obj = elemSearcher;
+
+    // force usage of iterators before they die
+    elemSearcher->FindElementsByPoint( gp_Pnt( 0,0,1e+20), SMDSAbs_Edge, foundElems );
+  }
+
+
+  // Find intersecting segments
+
+  std::map< const SMDS_MeshElement* , std::vector< const SMDS_MeshNode* > > segInternalNodes;
+  SMESH_MeshEditor::TListOfListOfNodes nodeGroupsToMerge;
+
+  for ( std::vector< const SMDS_MeshElement* > & braSegs : edgeBranches )
+  {
+    braSegs.push_back( braSegs.back() );
+    const SMDS_MeshElement* prevSeg = nullptr;
+
+    for ( size_t i = 0, nb = braSegs.size() - 1;  i < nb;  ++i )
+    {
+      const SMDS_MeshElement*     seg = braSegs[ i ];
+      const SMDS_MeshElement* nextSeg = braSegs[ i + 1 ];
+      const SMDS_MeshNode*      node0 = seg->GetNode(0);
+      const SMDS_MeshNode*      node1 = seg->GetNode(1);
+
+      gp_XYZ      xyz0 = SMESH_NodeXYZ( node0 );
+      gp_XYZ      xyz1 = SMESH_NodeXYZ( node1 );
+      gp_XYZ middlePnt = 0.5 * ( SMESH_NodeXYZ( node0 ) + SMESH_NodeXYZ( node1 ));
+      double    segLen = ( xyz0 - xyz1 ).Modulus();
+
+      foundElems.clear();
+      elemSearcher->GetElementsInSphere( middlePnt, 0.5 * segLen + _tol, SMDSAbs_Edge, foundElems );
+
+      for ( const SMDS_MeshElement* closeSeg : foundElems )
+      {
+        if ( closeSeg == prevSeg ||
+             closeSeg >= seg     ||
+             closeSeg == nextSeg )
+          continue;
+
+        gp_Pnt   intPnt;
+        gp_Pnt2d uv;
+        if ( intersectSegments( seg, closeSeg, face, intPnt, uv ))
+        {
+          int i0, i1;
+          const SMDS_MeshNode* intNode0 = findNode( intPnt, _tol, seg,      segInternalNodes, i0 );
+          const SMDS_MeshNode* intNode1 = findNode( intPnt, _tol, closeSeg, segInternalNodes, i1 );
+          if      ( !intNode0 && intNode1 )
+          {
+            segInternalNodes[ seg ].push_back( intNode1 );
+          }
+          else if ( !intNode1 && intNode0 )
+          {
+            segInternalNodes[ closeSeg ].push_back( intNode0 );
+          }
+          else if ( intNode1 && intNode0 )
+          {
+            if ( intNode1 == intNode0 )
+              continue;
+            if ( i0 < 0 && i1 < 0 )
+            {
+              nodeGroupsToMerge.push_back  // merge end nodes
+                ( std::list< const SMDS_MeshNode* >({ intNode0, intNode1 }));
+            }
+            else if ( i0 < 0 )
+            {
+              segInternalNodes[ closeSeg ][ i1 ] = intNode0;
+            }
+            else if ( i1 < 0 )
+            {
+              segInternalNodes[ seg ][ i0 ] = intNode1;
+            }
+            else // two internal nodes coincide
+            {
+              segInternalNodes[ seg ][ i0 ] = intNode1;
+              nodeGroupsToMerge.push_back
+                ( std::list< const SMDS_MeshNode* >({ intNode1, intNode0 }));
+            }
+          }
+          else // ( !intNode1 && !intNode0 )
+          {
+            intNode0 = _helper.AddNode( intPnt.X(), intPnt.Y(), intPnt.Z() );
+            meshDS->SetNodeOnFace( intNode0, face, uv.X(), uv.Y() );
+            segInternalNodes[ seg      ].push_back( intNode0 );
+            segInternalNodes[ closeSeg ].push_back( intNode0 );
+          }
+        }
+      }
+
+      prevSeg = seg;
+
+    } // loop on segments of a branch
+  } // loop on branches
+
+
+  findIntersectionWithSeamEdge( face, segInternalNodes ); // on periodic FACE
+
+
+  // Split segments
+
+  for ( auto& seg2nodes : segInternalNodes )
+  {
+    const SMDS_MeshElement*                 seg = seg2nodes.first;
+    std::vector< const SMDS_MeshNode* > & nodes = seg2nodes.second;
+    if ( nodes.empty() ) continue;
+
+    const SMDS_MeshNode* n0 = seg->GetNode( 0 );
+    const SMDS_MeshNode* n1 = seg->GetNode( 1 );
+    nodes.push_back( n1 );
+
+    // sort nodes on the segment
+    gp_Pnt p0 = SMESH_NodeXYZ( n0 );
+    std::map< double, const SMDS_MeshNode* > sortedNodes;
+    for ( SMESH_NodeXYZ pn : nodes )
+      sortedNodes.insert({ p0.SquareDistance( pn ), pn.Node() });
+
+    // make new segments
+    for ( auto & d2n : sortedNodes )
+    {
+      n1 = d2n.second;
+      SMDS_MeshElement* newSeg = _helper.AddEdge( n0, n1 );
+      n0 = n1;
+      meshDS->SetMeshElementOnShape( newSeg, face );
+      SMESH_MeshEditor::AddToSameGroups( newSeg, seg, meshDS );
+    }
+    meshDS->RemoveFreeElement( seg, /*submesh=*/nullptr );
+  }
+
+
+  // merge equal nodes
+  SMESH_MeshEditor( _mesh ).MergeNodes( nodeGroupsToMerge );
+}
+
+//================================================================================
+/*!
+ * \brief Find intersections of segments with a seam EDGE on a periodic FACE
+ */
+//================================================================================
+
+void BLSURFPlugin_EnforcedMesh1D::findIntersectionWithSeamEdge( const TopoDS_Face & face,
+                                                                TNodesOnSeg & segInternalNodes )
+{
+  _helper.SetSubShape( face );
+  if ( !_helper.HasSeam() )
+    return;
+
+  SMESHDS_Mesh* meshDS = _helper.GetMeshDS();
+  SMESHDS_SubMesh*  sm = meshDS->MeshElements( face );
+  if ( !sm || sm->NbElements() == 0 )
+    return;
+
+  TopTools_MapOfShape treatedEdges;
+  for ( TopExp_Explorer edgeExp( face, TopAbs_EDGE ); edgeExp.More(); edgeExp.Next() )
+  {
+    const TopoDS_Edge& edge = TopoDS::Edge( edgeExp.Current() );
+    if ( !_helper.IsSeamShape( edge ) || !treatedEdges.Add( edge ))
+      continue;
+
+    for ( SMDS_ElemIteratorPtr setIt = sm->GetElements(); setIt->more(); )
+    {
+      const SMDS_MeshElement* segment = setIt->next();
+      const SMESH_NodeXYZ         pn0 = segment->GetNode( 0 );
+      const SMESH_NodeXYZ         pn1 = segment->GetNode( 1 );
+
+      gp_XY uv0 = _helper.GetNodeUV( face, pn0.Node() );
+      gp_XY uv1 = _helper.GetNodeUV( face, pn1.Node() );
+
+      for ( int iCoo = 1; iCoo <= 2; ++iCoo )
+        if ( iCoo & _helper.GetPeriodicIndex() )
+        {
+          double distParam = Abs( uv0.Coord( iCoo ) - uv1.Coord( iCoo ));
+          if ( distParam > 0.5 * _helper.GetPeriod( iCoo ))
+          {
+            double paramOnE; TopoDS_Edge edge2;
+            gp_Pnt edgeIntPnt = getEdgeIntersection( edge, pn0, pn1, edge2, paramOnE );
+            if ( edge2.IsNull() )
+              continue;
+
+            const SMDS_MeshNode* nodeOnSeam = findNodeOnEdge( edgeIntPnt, edge );
+            bool isOnEdge = nodeOnSeam;
+
+            int indexOnSegment = 3;
+            if ( !nodeOnSeam )
+              nodeOnSeam = findNode( edgeIntPnt, _tol, segment, segInternalNodes, indexOnSegment );
+
+            if ( !nodeOnSeam )
+            {
+              nodeOnSeam = _helper.AddNode( edgeIntPnt.X(), edgeIntPnt.Y(), edgeIntPnt.Z() );
+            }
+
+            if ( !isOnEdge )
+            {
+              addNodeOnEdge( nodeOnSeam, edge, paramOnE );
+            }
+            if ( indexOnSegment == 3 )
+              segInternalNodes[ segment ].push_back( nodeOnSeam );
+          }
+        }
+    }
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Intersect two segments
+ *  \param [in] seg1 - segment 1
+ *  \param [in] seg2 - segment 2
+ *  \param [in] face - the FACE on which segments lie
+ *  \param [out] intPnt - intersection point
+ *  \param [out] intUV - UV of intersection point on the FACE
+ *  \return bool - true if intersection found
+ */
+//================================================================================
+
+bool BLSURFPlugin_EnforcedMesh1D::intersectSegments( const SMDS_MeshElement* seg1,
+                                                     const SMDS_MeshElement* seg2,
+                                                     const TopoDS_Face&      face,
+                                                     gp_Pnt &                intPnt,
+                                                     gp_Pnt2d &              intUV ) const
+{
+  SMESH_NodeXYZ n10 = seg1->GetNode(0);
+  SMESH_NodeXYZ n11 = seg1->GetNode(1);
+  SMESH_NodeXYZ n20 = seg2->GetNode(0);
+  SMESH_NodeXYZ n21 = seg2->GetNode(1);
+  if ( n10 == n20 || n10 == n21 || n11 == n20 || n10 == n21 )
+    return false;
+
+  gp_Lin lin1( n10, n11 - n10 );
+  gp_Lin lin2( n20, n21 - n20 );
+
+  Extrema_ExtElC extrema( lin1, lin2, Precision::Angular() );
+
+  if ( !extrema.IsDone() || extrema.IsParallel() )
+    return false;
+
+  Extrema_POnCurv poc1, poc2;
+  extrema.Points( 1, poc1, poc2 );
+
+  double len1 = lin1.Direction().XYZ() * ( n11 - n10 );
+  double len2 = lin2.Direction().XYZ() * ( n21 - n20 );
+  double   u1 = poc1.Parameter();
+  double   u2 = poc2.Parameter();
+
+  if ( u1 < -_tol || u1 > len1 + _tol )
+    return false;
+  if ( u2 < -_tol || u2 > len2 + _tol )
+    return false;
+
+  intPnt = 0.5 * ( poc1.Value().XYZ() + poc2.Value().XYZ() );
+
+  // compute approximate UV
+
+  u1 /= len1;
+  u2 /= len2;
+
+  gp_XY uv10 = _helper.GetNodeUV( face, n10.Node(), n11.Node() );
+  gp_XY uv11 = _helper.GetNodeUV( face, n11.Node(), n10.Node() );
+  gp_XY uv1  = uv10 * ( 1 - u1 ) + uv11 * u1;
+
+  gp_XY uv20 = _helper.GetNodeUV( face, n20.Node(), n21.Node() );
+  gp_XY uv21 = _helper.GetNodeUV( face, n21.Node(), n20.Node() );
+  gp_XY uv2  = uv20 * ( 1 - u2 ) + uv21 * u2;
+
+  intUV = 0.5 * ( uv1 + uv2 );
+
+  // compute precise UV and XYZ by projecting intPnt to the FACE
+
+  Handle(ShapeAnalysis_Surface) surface = _helper.GetSurface( face );
+  intUV = surface->NextValueOfUV( intUV, intPnt, _tol );
+  if ( surface->Gap() > Min( len1, len2 ))
+    intUV = surface->ValueOfUV( intPnt, _tol );
+
+  intPnt = surface->Value( intUV );
+
+  return true;
+}
+
+//================================================================================
+/*!
+ * \brief Setup predicates to detect nodes on FACE boundary
+ *  \param [in] shape - shape containing FACEs to mesh
+ */
+//================================================================================
+
+void BLSURFPlugin_EnforcedMesh1D::setupPredicates( const TopoDS_Shape& theShape )
+{
+  if ( _onVertexPredicate )
+    return;
+
+  _onVertexPredicate.reset( new TPredicate() );
+  _onVertexPredicate->SetTolerance( _tol );
+  _onVertexPredicate->SetMesh( _helper.GetMeshDS() );
+  {
+    TopTools_IndexedMapOfShape vertices;
+    TopExp::MapShapes( theShape, TopAbs_VERTEX, vertices );
+    TopoDS_Compound vCompound;
+    BRep_Builder    builder;
+    builder.MakeCompound( vCompound );
+    for ( const TopoDS_Shape& v : vertices )
+      builder.Add( vCompound, v );
+
+    _onVertexPredicate->SetShape( vCompound, SMDSAbs_Node );
+  }
+
+
+  _onEdgePredicate.reset( new TPredicate() );
+  _onEdgePredicate->SetTolerance( _tol );
+  _onEdgePredicate->SetMesh( _helper.GetMeshDS() );
+  {
+    TopTools_IndexedMapOfShape edges;
+    TopExp::MapShapes( theShape, TopAbs_EDGE, edges );
+    TopoDS_Compound eCompound;
+    BRep_Builder    builder;
+    builder.MakeCompound( eCompound );
+    for ( const TopoDS_Shape& e : edges )
+      builder.Add( eCompound, e );
+
+    _onEdgePredicate->SetShape( eCompound, SMDSAbs_Node );
+  }
+  return;
+}
+
+//================================================================================
+/*!
+ * \brief Find or create a group of edges with given name
+ */
+//================================================================================
+
+SMDS_MeshGroup* BLSURFPlugin_EnforcedMesh1D::getGroup( const std::string& groupName )
+{
+  SMDS_MeshGroup* group = nullptr;
+  if ( !groupName.empty() )
+  {
+    if ( _name2Group.count( groupName ))
+      return _name2Group[ groupName ];
+
+    // find existing group
+    for ( SMESH_Mesh::GroupIteratorPtr grIt = _mesh->GetGroups(); grIt->more(); )
+    {
+      SMESH_Group*     grp = grIt->next();
+      SMESHDS_Group* grpDS = dynamic_cast< SMESHDS_Group* >( grp->GetGroupDS() );
+      if ( grpDS &&
+           grpDS->GetType() == SMDSAbs_Edge &&
+           groupName == grp->GetName() )
+      {
+        _name2Group[ groupName ] = & grpDS->SMDSGroup();
+        return & grpDS->SMDSGroup();
+      }
+    }
+
+    // create a new group
+    SMESH_Group*     grp = _mesh->AddGroup( SMDSAbs_Edge, groupName.c_str() );
+    SMESHDS_Group* grpDS = static_cast< SMESHDS_Group* >( grp->GetGroupDS() );
+
+    group = & grpDS->SMDSGroup();
+    _name2Group[ groupName ] = group;
+  }
+  return group;
+}
+
+//================================================================================
+/*!
+ * \brief Look for a node dividing a given EDGE
+ */
+//================================================================================
+
+const SMDS_MeshNode* BLSURFPlugin_EnforcedMesh1D::findNodeOnEdge( const gp_Pnt&      p,
+                                                                  const TopoDS_Edge& edge )
+{
+  // look for an equal node on the EDGE
+  if ( std::vector< const SMDS_MeshNode* >* nodesOnE = _nodesOnEdge.ChangeSeek( edge ))
+    for ( const SMDS_MeshNode* n : *nodesOnE )
+      if ( p.SquareDistance( SMESH_NodeXYZ( n )) < _tol * _tol )
+      {
+        return n;
+      }
+
+  return nullptr;
+}
+
+//================================================================================
+/*!
+ * \brief Add a node to an EDGE
+ */
+//================================================================================
+
+void BLSURFPlugin_EnforcedMesh1D::addNodeOnEdge( const SMDS_MeshNode* node,
+                                                 const TopoDS_Edge&   edge,
+                                                 const double         u)
+{
+  _mesh->GetMeshDS()->SetNodeOnEdge( node, edge, u );
+
+  std::vector< const SMDS_MeshNode* > * nodesOnE = _nodesOnEdge.ChangeSeek( edge );
+  if ( !nodesOnE )
+    nodesOnE = _nodesOnEdge.Bound( edge, std::vector< const SMDS_MeshNode* >() );
+
+  nodesOnE->push_back( node );
+}
+
+//================================================================================
+/*!
+ * \brief Create EDGEs by dividing a given EDGE by nodes on it
+ *  \param [in] edge - the EDGE to divide
+ *  \param [in] nodes - the nodes to divide by
+ */
+//================================================================================
+
+void BLSURFPlugin_EnforcedMesh1D::
+
+splitEdgeByNodes( TopoDS_Edge edge, const std::vector< const SMDS_MeshNode* >& nodes )
+{
+  if ( nodes.empty() )
+    return;
+
+  edge.Orientation( TopAbs_FORWARD );
+
+  TopoDS_Vertex v0 = _helper.IthVertex( 0, edge );
+  TopoDS_Vertex v1 = _helper.IthVertex( 1, edge );
+
+  // create VERTEXes and sort them along the EDGE
+
+  std::map< double, TopoDS_Vertex > sortedVertices;
+
+  BRepAdaptor_Curve curve( edge );
+  for ( SMESH_NodeXYZ pn : nodes )
+  {
+    gp_Pnt projPnt;
+    double u;
+    ShapeAnalysis_Curve().Project( curve, pn, _tol, projPnt, u, false );
+    projPnt = curve.Value( u );
+
+    TopoDS_Vertex v = BRepBuilderAPI_MakeVertex( projPnt );
+
+    sortedVertices.insert({ u, v });
+
+    _nOnE2Vertex[ pn.Node() ] = v;
+  }
+  sortedVertices.insert({ BRep_Tool::Parameter( v1, edge ), v1 });
+
+
+  // create EDGEs
+
+  BRep_Builder builder;
+  std::vector< TopoDS_Edge >& newEdges = *_edgeSplitsOfEdge.Bound( edge, TEdge2Edges::value_type());
+
+  double u0 = BRep_Tool::Parameter( v0, edge );
+  for ( auto& u2v : sortedVertices )
+  {
+    double u1 = u2v.first;
+    v1        = u2v.second;
+
+    TopoDS_Shape newShape = edge.EmptyCopied();
+    TopoDS_Edge  newEdge  = TopoDS::Edge( newShape );
+    builder.Add( newEdge, v0 );
+    builder.Add( newEdge, v1 );
+    builder.Range( newEdge, u0, u1 );
+    newEdges.push_back( newEdge );
+
+    v0 = v1;
+    u0 = u1;
+  }
+
+  return;
+}
+
+//================================================================================
+/*!
+ * \brief  Return true if there are enforced segments on a FACE. Start iteration on segments
+ */
+//================================================================================
+
+bool BLSURFPlugin_EnforcedMesh1D::HasSegmentsOnFace( const TopoDS_Face& face )
+{
+  _segIterator.reset();
+
+  if ( _faces.Contains( face ))
+  {
+    _currentFace = face;
+    _segIterator = _helper.GetMeshDS()->MeshElements( face )->GetElements();
+
+    _helper.SetSubShape( face );
+
+    return _segIterator->more();
+  }
+  return false;
+}
+
+
+//================================================================================
+/*!
+ * \brief Return next segment on the FACE
+ */
+//================================================================================
+
+bool BLSURFPlugin_EnforcedMesh1D::NextSegment( Segmemnt &                   seg,
+                                               TopTools_IndexedMapOfShape & vertexTags )
+{
+  if ( _segIterator && _segIterator->more() )
+  {
+    const SMDS_MeshElement* segment = _segIterator->next();
+
+    while ( segment->GetType() != SMDSAbs_Edge && _segIterator->more() )
+      segment = _segIterator->next();
+    if ( segment->GetType() != SMDSAbs_Edge )
+      return false;
+
+    const SMDS_MeshNode * node[2] = { segment->GetNode(0),
+                                      segment->GetNode(1) };
+
+    seg._tag = _segTag++;
+
+    seg._xyz[0] = SMESH_NodeXYZ( node[0]);
+    seg._xyz[1] = SMESH_NodeXYZ( node[1]);
+
+    seg._uv[0] = _helper.GetNodeUV( _currentFace, node[0], node[1] );
+    seg._uv[1] = _helper.GetNodeUV( _currentFace, node[1], node[0] );
+
+    seg._pcurve = new Geom2d_Line( seg._uv[0], ( seg._uv[1] - seg._uv[0] ));
+
+    seg._u[0] = 0.0;
+    seg._u[1] = ( seg._uv[1] - seg._uv[0] ).Modulus();
+
+    for ( int i = 0; i < 2; ++i )
+    {
+      auto n2v = _nOnE2Vertex.find( node[i] ); // find VERTEX by node
+
+      if ( n2v != _nOnE2Vertex.end() )
+        seg._vTag[i] = vertexTags.Add( n2v->second );
+      else
+        seg._vTag[i] = _nodeTag0 + _nodeTags.Add( node[i] );
+    }
+
+    if ( !_isQuadratic )
+      _mesh->GetMeshDS()->UnSetMeshElementOnShape( segment, _currentFace );
+
+    return true;
+  }
+  return false;
+}
+
+//================================================================================
+/*!
+ * \brief Return enforced node by the tag that was returned by Segmemnt::_vTag[i]
+ */
+//================================================================================
+
+const SMDS_MeshNode*
+BLSURFPlugin_EnforcedMesh1D::GetNodeByTag( int                                tag,
+                                           const TopTools_IndexedMapOfShape & vertexTags )
+{
+  const SMDS_MeshNode* node = nullptr;
+
+  if ( tag <= vertexTags.Size() && !_nOnE2Vertex.empty() )
+  {
+    const TopoDS_Shape& vertex = vertexTags( tag );
+
+    for ( auto n2v = _nOnE2Vertex.begin(); n2v != _nOnE2Vertex.end(); ++n2v )
+      if ( vertex.IsSame( n2v->second ))
+      {
+        node = n2v->first;
+        _nOnE2Vertex.erase( n2v );
+        return node;
+      }
+  }
+
+  tag -= _nodeTag0;
+
+  bool isValid = ( 0 < tag && tag <= _nodeTags.Size() );
+  if ( isValid )
+    node = _nodeTags( tag );
+
+  return node;
+}
+
+//================================================================================
+/*!
+ * \brief Return true if a tag corresponds to the tag of enforced segment
+ *  that was returned by Segment::_tag
+ */
+//================================================================================
+
+bool BLSURFPlugin_EnforcedMesh1D::IsSegmentTag( int tag ) const
+{
+  return ( _segTag0 <= tag && tag <= _segTag );
+}
+
+//================================================================================
+/*!
+ * \brief Return tag of EDGE by tags of its splits
+ */
+//================================================================================
+
+int BLSURFPlugin_EnforcedMesh1D::GetTagOfSplitEdge( int splitTag ) const
+{
+  auto sTag2eTag = _splitTags2EdgeTag.find( splitTag );
+  return ( sTag2eTag == _splitTags2EdgeTag.end() ) ? splitTag : sTag2eTag->second;
+}
diff --git a/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx b/src/BLSURFPlugin/BLSURFPlugin_EnforcedMesh1D.hxx
new file mode 100644 (file)
index 0000000..aac128d
--- /dev/null
@@ -0,0 +1,172 @@
+// Copyright (C) 2007-2021  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// File      : BLSURFPlugin_EnforcedMesh1D.hxx
+// Author    : Edward AGAPOV (OCC)
+
+#ifndef __BLSURFPlugin_EnforcedMesh1D_HXX__
+#define __BLSURFPlugin_EnforcedMesh1D_HXX__
+
+#include "BLSURFPlugin_Hypothesis.hxx"
+
+#include <SMESH_ControlsDef.hxx>
+#include <SMESH_MesherHelper.hxx>
+
+#include <Geom2d_Curve.hxx>
+#include <NCollection_DataMap.hxx>
+#include <NCollection_IndexedMap.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Pnt2d.hxx>
+
+#include <vector>
+#include <map>
+
+class SMDS_MeshElement;
+class SMDS_MeshGroup;
+class SMDS_MeshNode;
+class SMESH_Mesh;
+
+/*!
+ * \brief Implement 1D mesh into the mesh made by MG-CADSurf
+ */
+class BLSURFPlugin_EnforcedMesh1D
+{
+public:
+
+  BLSURFPlugin_EnforcedMesh1D( SMESH_MesherHelper&            helper,
+                               const BLSURFPlugin_Hypothesis* hyp );
+
+  ~BLSURFPlugin_EnforcedMesh1D();
+
+  // Return EDGEs resulted from division of FACE boundary by enforced segments
+  bool GetSplitsOfEdge( const TopoDS_Edge&           edge,
+                        std::vector< TopoDS_Edge > & splits,
+                        TopTools_IndexedMapOfShape & edgeTags );
+
+  // Return true if there are enforced segments on a FACE. Start iteration on segments
+  bool HasSegmentsOnFace( const TopoDS_Face& face );
+
+  // Data of an enforced segment to provide MG-CADSurf with
+  struct Segmemnt
+  {
+    int                  _tag;
+    Handle(Geom2d_Curve) _pcurve;
+
+    // data of two ends
+    double               _u   [2];
+    gp_XY                _uv  [2];
+    gp_XYZ               _xyz [2];
+    int                  _vTag[2];
+  };
+
+  // Return next segment on the FACE. Iteration starts upon calling HasSegmentsOnFace() 
+  bool NextSegment( Segmemnt & seg, TopTools_IndexedMapOfShape & vertexTags );
+
+  // Return enforced node by tag
+  const SMDS_MeshNode* GetNodeByTag( int tag, const TopTools_IndexedMapOfShape & vertexTags );
+
+  // Return true if a tad corresponds to an enforced segment
+  bool IsSegmentTag( int tag ) const;
+
+  // Return tag of EDGE by tags of its splits
+  int GetTagOfSplitEdge( int splitTag ) const;
+
+  typedef std::map< const SMDS_MeshElement* , std::vector< const SMDS_MeshNode* > > TNodesOnSeg;
+
+private:
+
+  void copyEnforcedMesh( const BLSURFPlugin_Hypothesis::EnforcedMesh& theEnfMesh,
+                         const BLSURFPlugin_Hypothesis*               theHyp,
+                         const TopoDS_Shape&                          theShape);
+
+  const SMDS_MeshNode* copyEnforcedNode( const SMDS_MeshNode* enfNode );
+
+  void setupPredicates( const TopoDS_Shape& shape );
+
+  void splitSegmentOnSeveralShapes( const SMDS_MeshElement* segment );
+
+  void splitSelfIntersectingSegments( const TopoDS_Shape & face );
+
+  void findIntersectionWithSeamEdge( const TopoDS_Face & face, TNodesOnSeg & segInternalNodes );
+
+  bool intersectSegments( const SMDS_MeshElement* seg1, const SMDS_MeshElement* seg2,
+                          const TopoDS_Face& face, gp_Pnt& intPnt, gp_Pnt2d& inUV ) const;
+
+  gp_Pnt getEdgeIntersection( const TopoDS_Shape& faceOrEdge,
+                              const gp_XYZ& xyz0, const gp_XYZ& xyz1,
+                              TopoDS_Edge & edge, double & paramOnEdge );
+
+  void splitEdgeByNodes( TopoDS_Edge edge, const std::vector< const SMDS_MeshNode* >& nodes);
+
+  SMDS_MeshGroup* getGroup( const std::string& groupName );
+
+  const SMDS_MeshNode* findNodeOnEdge( const gp_Pnt& p, const TopoDS_Edge& edge );
+  void addNodeOnEdge( const SMDS_MeshNode*node , const TopoDS_Edge& edge, const double u = 0. );
+
+
+  SMESH_Mesh*                              _mesh;
+  TopoDS_Shape                             _shape;
+  SMESH_MesherHelper                       _helper;
+  bool                                     _isQuadratic;
+  std::map< std::string, SMDS_MeshGroup* > _name2Group;
+  double                                   _tol;
+  TopTools_IndexedMapOfShape               _faces;
+
+  // segments whose nodes are on different FACEs;
+  // such segments will be split into segments lying each on own FACE
+  std::vector< const SMDS_MeshElement* >   _segmentsOnSeveralShapes;
+
+  // nodes projected on EDGEs; EDGEs will be divided by them
+  typedef NCollection_DataMap< TopoDS_Edge,
+                               std::vector< const SMDS_MeshNode* >,
+                               TopTools_ShapeMapHasher>              TEdge2Nodes;
+  typedef NCollection_DataMap< TopoDS_Edge,
+                               std::vector< TopoDS_Edge >,
+                               TopTools_ShapeMapHasher>              TEdge2Edges;
+  TEdge2Nodes                               _nodesOnEdge;
+  TEdge2Edges                               _edgeSplitsOfEdge; // result of EDGE division by nodes
+  std::map< int, int >                      _splitTags2EdgeTag;
+  std::map< const SMDS_MeshNode* , TopoDS_Vertex > _nOnE2Vertex; // VERTEXes on _nodesOnEdge
+
+  typedef SMESH::Controls::ElementsOnShape    TPredicate;
+  typedef SMESH::Controls::ElementsOnShapePtr TPredicatePtr;
+  TPredicatePtr                             _onVertexPredicate;
+  TPredicatePtr                             _onEdgePredicate;
+
+  // for iteration of segments of FACE
+
+  SMDS_ElemIteratorPtr                      _segIterator;
+  TopoDS_Face                               _currentFace;
+  int                                       _segTag0;
+  int                                       _segTag;
+
+  typedef NCollection_IndexedMap< const SMDS_MeshNode* > TNodeIndMap;
+  TNodeIndMap                               _nodeTags;
+  int                                       _nodeTag0;
+
+  // nodes not projected to geometry; they are reused during next projection to geometry
+  std::vector< const SMDS_MeshNode* >       _freeNodes;
+
+};
+
+
+#endif
index 9b85b3b0cf3b4768146fee06e771017b211f5e11..bc094a3d41a2ad0ba6ed38c82571103ff52e120d 100644 (file)
 //
 #include "BLSURFPlugin_Hypothesis.hxx"
 #include "BLSURFPlugin_Attractor.hxx"
-#include "SMESH_Gen_i.hxx"
-#include <utilities.h>
-#include <cstring>
-#include <iostream>
-#include <sstream>
+
+#include <SMESHDS_Group.hxx>
+#include <SMESHDS_Mesh.hxx>
+#include <SMESH_Gen_i.hxx>
+#include <SMESH_Group.hxx>
+#include <SMESH_TryCatch.hxx>
 
 #include <Basics_Utils.hxx>
+#include <utilities.h>
 
 // cascade include
-#include "ShapeAnalysis.hxx"
+#include <ShapeAnalysis.hxx>
 
 // CORBA includes
 #include CORBA_CLIENT_HEADER(SALOMEDS)
@@ -974,6 +976,63 @@ int BLSURFPlugin_Hypothesis::GetHyperPatchTag( const int                      fa
   }
   return faceTag;
 }
+
+//=============================================================================
+void BLSURFPlugin_Hypothesis::SetEnforcedMeshes( std::vector< EnforcedMesh > & enforcedMeshes )
+{
+  if ( _enforcedMeshes != enforcedMeshes )
+  {
+    _enforcedMeshes.swap( enforcedMeshes );
+    NotifySubMeshesHypothesisModification();
+  }
+}
+
+//================================================================================
+/*!
+ * \brief Return elements of 1D enforced mesh. Result can be NULL
+ */
+//================================================================================
+
+SMDS_ElemIteratorPtr
+BLSURFPlugin_Hypothesis::GetEnforcedSegments( const EnforcedMesh& enfMesh,
+                                              SMESH_Mesh* &       mesh ) const
+{
+  SMDS_ElemIteratorPtr it;
+  if (( mesh = SMESH_Hypothesis::GetMeshByPersistentID( enfMesh._meshID )))
+  {
+    mesh->Load();
+
+    switch( enfMesh._type )
+    {
+    case ENFORCED_MESH:
+      it = mesh->GetMeshDS()->elementsIterator( SMDSAbs_Edge );
+      break;
+
+    case ENFORCED_GROUP:
+      if ( SMESH_Group* grp = mesh->GetGroup( enfMesh._subID ))
+      {
+        if ( grp->GetGroupDS()->GetType() == SMDSAbs_Edge )
+          it = grp->GetGroupDS()->GetElements();
+      }
+      break;
+
+    case ENFORCED_SUBMESH:
+      if ( SMESH_subMesh* sm = mesh->GetSubMeshContaining( enfMesh._subID ))
+        if ( SMESHDS_SubMesh * smDS = sm->GetSubMeshDS() )
+        {
+          it = smDS->GetElements();
+          if ( it->more() && it->next()->GetType() != SMDSAbs_Edge )
+            it = SMDS_ElemIteratorPtr();
+          else
+            it = smDS->GetElements();
+        }
+      break;
+    }
+  }
+  return it;
+}
+
+
 //=============================================================================
 void BLSURFPlugin_Hypothesis::SetPreCADMergeEdges(bool theVal)
 {
@@ -2292,8 +2351,13 @@ std::ostream & BLSURFPlugin_Hypothesis::SaveTo(std::ostream & save)
   std::ostringstream hpStream;
   boost::archive::text_oarchive( hpStream ) << _hyperPatchEntriesList;
   std::string hpString = hpStream.str();
-  save << " " << hpString.size() <<  " " << hpString;
+  SMESHDS_Hypothesis::SaveString( save, hpString );
 
+  // Enforced meshes
+  std::ostringstream enfMStream;
+  boost::archive::text_oarchive( enfMStream ) << _enforcedMeshes;
+  std::string enfMString = enfMStream.str();
+  SMESHDS_Hypothesis::SaveString( save, enfMString );
 
   return save;
 }
@@ -3328,23 +3392,52 @@ std::istream & BLSURFPlugin_Hypothesis::LoadFrom(std::istream & load)
   }
 
   // hyper-patches as entries (issue bos #20543)
-  if ( static_cast<bool>( load >> i ) && i > 0 )
+  std::string buffer;
+  if ( SMESHDS_Hypothesis::LoadString( load, buffer ))
   {
-    std::string buffer( i, '\0' );
-    load.get( buffer[0] ); // remove a white-space
-    load.get( & buffer[0], i + 1 );
+    std::istringstream istream( buffer.data() );
+    boost::archive::text_iarchive archive( istream );
+    SMESH_TRY;
+    archive >> _hyperPatchEntriesList;
+    SMESH_CATCH( SMESH::printErrorInDebugMode );
+  }
 
+  // Enforced meshes (issue bos $16292)
+  buffer.clear();
+  if ( SMESHDS_Hypothesis::LoadString( load, buffer ))
+  {
     std::istringstream istream( buffer.data() );
     boost::archive::text_iarchive archive( istream );
-    try {
-      archive >> _hyperPatchEntriesList;
-    }
-    catch (...) {}
+    SMESH_TRY;
+    archive >> _enforcedMeshes;
+    SMESH_CATCH( SMESH::printErrorInDebugMode );
   }
 
   return load;
 }
 
+namespace boost {
+  namespace serialization {
+
+    //=======================================================================
+    //function : serialize
+    //purpose  : serialize EnforcedMesh
+    //=======================================================================
+
+    template<class Archive>
+    void serialize(Archive & ar, BLSURFPlugin_Hypothesis::EnforcedMesh & enfM,
+                   const unsigned int /*version*/)
+    {
+      ar & enfM._meshID;
+      ar & enfM._subID;
+      ar & enfM._type;
+      ar & enfM._groupName;
+    }
+
+  } // namespace serialization
+} // namespace boost
+
+
 void BLSURFPlugin_Hypothesis::LoadFacesPeriodicity(std::istream & load)
 {
   bool isOK = true;
index 134a51db1a2b33cd2bd2402ac0323589b2e0f969..693def64b2be4f74426741f8a1b1abedfe715bc1 100644 (file)
 #ifndef _BLSURFPlugin_Hypothesis_HXX_
 #define _BLSURFPlugin_Hypothesis_HXX_
 
-#include "SMESH_Hypothesis.hxx"
+#include "BLSURFPlugin_Attractor.hxx"
+
+#include <SMDS_ElemIterator.hxx>
+#include <SMESH_Hypothesis.hxx>
+#include <smIdType.hxx>
+
 #include <vector>
 #include <map>
 #include <set>
-#include <stdexcept>
 #include <string>
-#include <cstring>
-#include <sstream>
-#include <utilities.h>
-#include <smIdType.hxx>
-#include "BLSURFPlugin_Attractor.hxx"
+
+class SMESH_Mesh;
 
 //  Parameters for work of MG-CADSurf
 
+enum EnforcedMeshType { ENFORCED_MESH, ENFORCED_GROUP, ENFORCED_SUBMESH };
+
 class BLSURFPlugin_Hypothesis: public SMESH_Hypothesis
 {
 public:
@@ -221,9 +224,9 @@ public:
   std::string GetTags();
 
   // Hyper-patches
-  typedef std::set< int > THyperPatchTags;
-  typedef std::vector< THyperPatchTags > THyperPatchList;
-  typedef std::set< std::string > THyperPatchEntries;
+  typedef std::set< int                   > THyperPatchTags;
+  typedef std::vector< THyperPatchTags    > THyperPatchList;
+  typedef std::set< std::string           > THyperPatchEntries;
   typedef std::vector< THyperPatchEntries > THyperPatchEntriesList;
 
   void SetHyperPatches(const THyperPatchList& hpl, bool notifyMesh=true);
@@ -234,6 +237,29 @@ public:
   const THyperPatchEntriesList& GetHyperPatchEntries() const { return _hyperPatchEntriesList; }
   static int GetHyperPatchTag( int faceTag, const BLSURFPlugin_Hypothesis* hyp, int* iPatch=0 );
 
+  // Enforced mesh
+  struct EnforcedMesh
+  {
+    int              _meshID;    // persistent mesh ID
+    int              _subID;     // either persistent group ID or sub-shape ID for sub-mesh
+    EnforcedMeshType _type;      /* specify what _subID means:
+                                    - nothing      for ENFORCED_MESH
+                                    - group ID     for ENFORCED_GROUP
+                                    - sub-shape ID for ENFORCED_SUBMESH */
+    std::string      _groupName; // name of a group to add mesh edges to
+
+    bool operator==(const EnforcedMesh& em ) const
+    {
+      return ( _meshID == em._meshID && _subID == em._subID &&
+               _type == em._type && _groupName == em._groupName );
+    }
+  };
+
+  void SetEnforcedMeshes( std::vector< EnforcedMesh > & enforcedMeshes );
+  const std::vector< EnforcedMesh > & GetEnforcedMeshes() const { return _enforcedMeshes; }
+  SMDS_ElemIteratorPtr GetEnforcedSegments( const EnforcedMesh& enfMesh,
+                                            SMESH_Mesh* &       mesh ) const;
+  
 
   void SetPreCADMergeEdges(bool theVal);
   bool GetPreCADMergeEdges() const { return _preCADMergeEdges; }
@@ -647,30 +673,32 @@ private:
   TSizeMap        _attractors;
   TAttractorMap   _classAttractors;
 
-  TFaceEntryEnfVertexListMap      _faceEntryEnfVertexListMap;
-  TEnfVertexList                  _enfVertexList;
+  TFaceEntryEnfVertexListMap        _faceEntryEnfVertexListMap;
+  TEnfVertexList                    _enfVertexList;
   // maps to get "manual" enf vertex (through their coordinates)
-  TFaceEntryCoordsListMap         _faceEntryCoordsListMap;
-  TCoordsEnfVertexMap             _coordsEnfVertexMap;
+  TFaceEntryCoordsListMap           _faceEntryCoordsListMap;
+  TCoordsEnfVertexMap               _coordsEnfVertexMap;
   // maps to get "geom" enf vertex (through their geom entries)
-  TFaceEntryEnfVertexEntryListMap _faceEntryEnfVertexEntryListMap;
-  TEnfVertexEntryEnfVertexMap     _enfVertexEntryEnfVertexMap;
-  TGroupNameNodeIDMap             _groupNameNodeIDMap;
+  TFaceEntryEnfVertexEntryListMap   _faceEntryEnfVertexEntryListMap;
+  TEnfVertexEntryEnfVertexMap       _enfVertexEntryEnfVertexMap;
+  TGroupNameNodeIDMap               _groupNameNodeIDMap;
   
 //  Enable internal enforced vertices on specific face if requested by user
 //  TFaceEntryInternalVerticesList  _faceEntryInternalVerticesList;
-  bool            _enforcedInternalVerticesAllFaces;
-  TEnfGroupName   _enforcedInternalVerticesAllFacesGroup;
+  bool                              _enforcedInternalVerticesAllFaces;
+  TEnfGroupName                     _enforcedInternalVerticesAllFacesGroup;
   
-  TPreCadPeriodicityVector _preCadFacesPeriodicityVector;
-  TPreCadPeriodicityVector _preCadEdgesPeriodicityVector;
+  TPreCadPeriodicityVector          _preCadFacesPeriodicityVector;
+  TPreCadPeriodicityVector          _preCadEdgesPeriodicityVector;
+
+  TFacesPeriodicityVector           _facesPeriodicityVector;
+  TEdgesPeriodicityVector           _edgesPeriodicityVector;
+  TVerticesPeriodicityVector        _verticesPeriodicityVector;
 
-  TFacesPeriodicityVector    _facesPeriodicityVector;
-  TEdgesPeriodicityVector    _edgesPeriodicityVector;
-  TVerticesPeriodicityVector _verticesPeriodicityVector;
+  THyperPatchList                   _hyperPatchList;
+  THyperPatchEntriesList            _hyperPatchEntriesList;
 
-  THyperPatchList        _hyperPatchList;
-  THyperPatchEntriesList _hyperPatchEntriesList;
+  std::vector< EnforcedMesh >       _enforcedMeshes; // enforced 1D meshes
 
   // Called by SaveTo to store content of _preCadFacesPeriodicityVector and _preCadEdgesPeriodicityVector
   void SavePreCADPeriodicity(std::ostream & save, const char* shapeType);
index fe72d2ef4e3fc252f611554c30d61170af2390cd..5a90eb090190d2cfee1241f1b3d285835255678c 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <SMESH_Gen.hxx>
 #include <SMESH_Gen_i.hxx>
+#include <SMESH_Group_i.hxx>
 #include <SMESH_PythonDump.hxx>
 
 #include <SALOMEDS_wrap.hxx>
 
 using namespace std;
 
+namespace
+{
+  //================================================================================
+  /*!
+   * \brief Return persistent ID of a mesh
+   *  \param [in] mesh - the mesh
+   *  \return int - -1 in case of failure
+   */
+  //================================================================================
+
+  int GetMeshPersistentId( SMESH::SMESH_Mesh_ptr mesh )
+  {
+    int id = -1;
+    if ( SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh ))
+      id = mesh_i->GetImpl().GetMeshDS()->GetPersistentId();
+    return id;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return persistent ID of a group or sub-mesh
+   *  \param [in] meshPart - the mesh part
+   *  \param [out] isGroup - return true if meshPart is a group
+   *  \return int - -1 in case if meshPart is neither a group nor a sub-mesh
+   */
+  //================================================================================
+
+  int GetMeshPartPersistentId( SMESH::SMESH_IDSource_ptr meshPart, bool & isGroup )
+  {
+    int id = -1;
+    isGroup = false;
+    SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( meshPart );
+    if ( group_i )
+    {
+      id = group_i->GetLocalID();
+      isGroup = true;
+    }
+    else
+    {
+      SMESH::SMESH_subMesh_var subMesh = SMESH::SMESH_subMesh::_narrow( meshPart );
+      if ( !subMesh->_is_nil() )
+        id = subMesh->GetId();
+    }
+    return id;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Find a mesh in the study by mesh persistent ID
+   */
+  //================================================================================
+
+  SMESH::SMESH_Mesh_ptr FindMeshByID( int theMeshID )
+  {
+    SMESH::SMESH_Mesh_var mesh;
+
+    SMESH_Gen_i*                gen = SMESH_Gen_i::GetSMESHGen();
+    CORBA::String_var  compDataType = gen->ComponentDataType();
+    SALOMEDS::Study_var      aStudy = gen->getStudyServant();
+    SALOMEDS::SComponent_wrap genSO = aStudy->FindComponent( compDataType.in() );
+    if ( !genSO->_is_nil() )
+    {
+      SALOMEDS::ChildIterator_wrap anIter = aStudy->NewChildIterator( genSO );
+      for ( ; anIter->More(); anIter->Next() )
+      {
+        SALOMEDS::SObject_wrap so = anIter->Value();
+        CORBA::Object_var      obj = gen->SObjectToObject( so );
+        mesh = SMESH::SMESH_Mesh::_narrow( obj );
+        if ( !mesh->_is_nil() && GetMeshPersistentId( mesh ) == theMeshID )
+          break;
+        mesh = SMESH::SMESH_Mesh::_nil();
+      }
+    }
+    return mesh._retn();
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return a group by its ID
+   */
+  //================================================================================
+
+  SMESH::SMESH_GroupBase_ptr GetGroupByID( SMESH::SMESH_Mesh_ptr mesh, int ID )
+  {
+    SMESH::SMESH_GroupBase_var group;
+    if ( !CORBA::is_nil( mesh ))
+    {
+      SMESH::ListOfGroups_var groups = mesh->GetGroups();
+      for ( CORBA::ULong i = 0; i < groups->length(); ++i )
+        if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( groups[i] ))
+          if ( group_i->GetLocalID() == ID )
+          {
+            group = SMESH::SMESH_GroupBase::_narrow( groups[i] );
+            break;
+          }
+    }
+    return group._retn();
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return a sub-mesh by sub-shape ID
+   */
+  //================================================================================
+
+  SMESH::SMESH_subMesh_ptr GetSubMeshByID( SMESH::SMESH_Mesh_ptr mesh,
+                                           const int             shapeID,
+                                           CORBA::Long           subMeshTag )
+  {
+    SMESH::SMESH_subMesh_var subMesh;
+    if ( !CORBA::is_nil( mesh ))
+    {
+      SMESH_Gen_i*              gen = SMESH_Gen_i::GetSMESHGen();
+      SALOMEDS::SObject_wrap meshSO = gen->ObjectToSObject( mesh );
+      SALOMEDS::Study_var    aStudy = gen->getStudyServant();
+      SALOMEDS::SObject_wrap subMeshRootSO;
+      if ( !meshSO->_is_nil() && meshSO->FindSubObject( subMeshTag, subMeshRootSO.inout() ))
+      {
+        SALOMEDS::ChildIterator_wrap anIter = aStudy->NewChildIterator( subMeshRootSO );
+        for ( ; anIter->More(); anIter->Next() )
+        {
+          SALOMEDS::SObject_wrap so = anIter->Value();
+          CORBA::Object_var      obj = gen->SObjectToObject( so );
+          subMesh = SMESH::SMESH_subMesh::_narrow( obj );
+          if ( !subMesh->_is_nil() && subMesh->GetId() == shapeID )
+            break;
+          subMesh = SMESH::SMESH_subMesh::_nil();
+        }
+      }
+      return subMesh._retn();
+    }
+    return subMesh._retn();
+  }
+
+} // namespace
+
 //=============================================================================
 /*!
  *  BLSURFPlugin_Hypothesis_i::BLSURFPlugin_Hypothesis_i
@@ -921,6 +1058,104 @@ CORBA::Short BLSURFPlugin_Hypothesis_i::GetVerbosity() {
   return (CORBA::Short) this->GetImpl()->GetVerbosity();
 }
 
+
+//=============================================================================
+void BLSURFPlugin_Hypothesis_i::SetEnforcedMeshes(const BLSURFPlugin::EnforcedMeshesList& theMeshes )
+{
+  std::vector< ::BLSURFPlugin_Hypothesis::EnforcedMesh > enforcedMeshes;
+  for ( CORBA::ULong i = 0; i < theMeshes.length(); ++i )
+  {
+    const BLSURFPlugin::MG_EnforcedMesh1D & inEM = theMeshes[ i ];
+    if ( CORBA::is_nil( inEM.mesh ))
+      THROW_SALOME_CORBA_EXCEPTION( "NULL enforced mesh",SALOME::BAD_PARAM );
+
+    SMESH::SMESH_Mesh_var mesh = inEM.mesh->GetMesh();
+    if ( CORBA::is_nil( mesh ))
+      THROW_SALOME_CORBA_EXCEPTION( "BAD enforced mesh",SALOME::BAD_PARAM );
+
+    int meshID = GetMeshPersistentId( mesh );
+    if ( meshID < 0 )
+      THROW_SALOME_CORBA_EXCEPTION( "BAD enforced mesh",SALOME::BAD_PARAM );
+
+    bool isGroup = false;
+    int   partID = GetMeshPartPersistentId( inEM.mesh, isGroup );
+    ::EnforcedMeshType partType = ENFORCED_MESH;
+    if ( partID > -1 )
+      partType = isGroup ? ENFORCED_GROUP : ENFORCED_SUBMESH;
+
+    enforcedMeshes.push_back({ meshID, partID, partType, inEM.groupName.in() });
+  }
+
+  this->GetImpl()->SetEnforcedMeshes( enforcedMeshes );
+
+  // dump
+
+  SMESH::TPythonDump pyDump;
+  pyDump << BLSURFPlugin::BLSURFPlugin_Hypothesis_var( _this() )
+         << ".SetEnforcedMeshes([ ";
+
+  for ( CORBA::ULong i = 0; i < theMeshes.length(); ++i )
+  {
+    const BLSURFPlugin::MG_EnforcedMesh1D & inEM = theMeshes[ i ];
+    pyDump << "BLSURFPlugin.MG_EnforcedMesh1D( " << inEM.mesh.in() << ", ";
+    if ( inEM.groupName.in() && inEM.groupName.in()[0] )
+      pyDump << "'" << inEM.groupName.in() << "'";
+    else
+      pyDump << "''";
+    pyDump << ")" << ( i + 1 < theMeshes.length() ? ", " : "])");
+  }
+}
+
+//=============================================================================
+
+BLSURFPlugin::EnforcedMeshesList* BLSURFPlugin_Hypothesis_i::GetEnforcedMeshes()
+{
+  const std::vector< ::BLSURFPlugin_Hypothesis::EnforcedMesh > & hypEnfMeshes =
+    this->GetImpl()->GetEnforcedMeshes();
+
+  BLSURFPlugin::EnforcedMeshesList_var outEnfMeshes = new BLSURFPlugin::EnforcedMeshesList();
+  outEnfMeshes->length( hypEnfMeshes.size() );
+
+  int nbMeshes = 0;
+  for ( size_t i = 0; i < hypEnfMeshes.size(); ++i )
+  {
+    const ::BLSURFPlugin_Hypothesis::EnforcedMesh& enfMeshData = hypEnfMeshes[ i ];
+    BLSURFPlugin::MG_EnforcedMesh1D &               outEnfMesh = outEnfMeshes[ nbMeshes ];
+
+    SMESH::SMESH_Mesh_var mesh = FindMeshByID( enfMeshData._meshID );
+    switch ( enfMeshData._type ) {
+    case ENFORCED_MESH   :
+    {
+      outEnfMesh.mesh = SMESH::SMESH_IDSource::_narrow( mesh );
+      break;
+    }
+    case ENFORCED_GROUP  :
+    {
+      SMESH::SMESH_GroupBase_var group = GetGroupByID( mesh, enfMeshData._subID );
+      outEnfMesh.mesh = SMESH::SMESH_IDSource::_narrow( group );
+      break;
+    }
+    case ENFORCED_SUBMESH:
+    {
+      SMESH::SMESH_subMesh_var subMesh;
+      subMesh   = GetSubMeshByID( mesh, enfMeshData._subID, SMESH::Tag_SubMeshOnEdge );
+      if ( CORBA::is_nil( subMesh ))
+        subMesh = GetSubMeshByID( mesh, enfMeshData._subID, SMESH::Tag_SubMeshOnCompound );
+
+      outEnfMesh.mesh = SMESH::SMESH_IDSource::_narrow( subMesh );
+      break;
+    }
+    default: continue;
+    }
+    outEnfMesh.groupName = enfMeshData._groupName.c_str();
+
+    nbMeshes += ( !CORBA::is_nil( outEnfMesh.mesh ));
+  }
+  outEnfMeshes->length( nbMeshes );
+
+  return outEnfMeshes._retn();
+}
+
 //=============================================================================
 void BLSURFPlugin_Hypothesis_i::SetEnforceCadEdgesSize( CORBA::Boolean toEnforce )
 {
index 5b6c7496eb803b0c02743ecd33af042a1065af6a..00f3bed56c429e1aee03aed1ea626404c3866f4c 100644 (file)
@@ -173,6 +173,12 @@ public:
   void SetVerbosity(CORBA::Short theVal);
   CORBA::Short GetVerbosity();
 
+  /*!
+   * Set/Get enforced 1D meshes
+   */
+  void SetEnforcedMeshes( const BLSURFPlugin::EnforcedMeshesList& enforcedMeshes );
+  BLSURFPlugin::EnforcedMeshesList* GetEnforcedMeshes();
+
   void SetEnforceCadEdgesSize( CORBA::Boolean toEnforce );
   CORBA::Boolean GetEnforceCadEdgesSize();
 
index 62d0fc4f110b8f61dc50a351cca7e0c4eca2246f..a58e725304516b42c3af5c19b030ed49cad85986 100644 (file)
@@ -73,6 +73,7 @@ SET(BLSURFEngine_HEADERS
   BLSURFPlugin_Hypothesis.hxx
   BLSURFPlugin_Hypothesis_i.hxx
   BLSURFPlugin_Attractor.hxx
+  BLSURFPlugin_EnforcedMesh1D.hxx
 )
 
 # --- sources ---
@@ -85,6 +86,7 @@ SET(BLSURFEngine_SOURCES
   BLSURFPlugin_Hypothesis_i.cxx
   BLSURFPlugin_i.cxx
   BLSURFPlugin_Attractor.cxx
+  BLSURFPlugin_EnforcedMesh1D.cxx
 )
 
 # --- scripts ---
index c21e967796705f85f3224dc62ef2649e9be1f9b1..7e0870a22958ecc3e8ade954522af3ee4de1b4ac 100644 (file)
@@ -83,7 +83,8 @@ enum {
   STD_TAB = 0,
   ADV_TAB,
   SMP_TAB,
-  ENF_TAB,
+  ENF_V_TAB,
+  ENF_M_TAB,
   PERIODICITY_TAB,
   HYPERPATCH_TAB,
   SMP_NAME_COLUMN =0,
@@ -104,7 +105,11 @@ enum {
   ENF_VER_ENTRY_COLUMN,
   ENF_VER_GROUP_COLUMN,
   ENF_VER_NB_COLUMNS,
-// Periodicity
+
+  // Enforced 1D meshes
+  ENF_MESH_NB_COLUMNS = 2,
+
+  // Periodicity
   PERIODICITY_OBJ_SOURCE_COLUMN = 0,
   PERIODICITY_OBJ_TARGET_COLUMN,
   PERIODICITY_P1_SOURCE_COLUMN,
@@ -713,39 +718,39 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame()
   lay->addWidget( myTabWidget );
 
   myName = 0;
-  
+
   // basic parameters
   myStdGroup = new QWidget();
   QGridLayout* aStdLayout = new QGridLayout( myStdGroup );
   aStdLayout->setSpacing( 6 );
   aStdLayout->setMargin( 11 );
-  
+
   if( isCreation() )
     myName = new QLineEdit( myStdGroup );
   myStdWidget = new BLSURFPluginGUI_StdWidget(myStdGroup);
   if ( !hasGeom() ) {
     myStdWidget->myPhysicalMesh->removeItem( PhysicalLocalSize );
   }
-  
+
   int row = 0;
   if( isCreation() ) {
     aStdLayout->addWidget( new QLabel( tr( "SMESH_NAME" ), myStdGroup ),    0, 0, 1, 1 );
     aStdLayout->addWidget( myName,                                      row++, 1, 1, 3 );
   }
   aStdLayout->addWidget( myStdWidget,                                   row++, 0, 1, 4 );
-  
+
   row = 0;
   if( isCreation() )
     row = 1;
   aStdLayout->setRowStretch(row,1);
   aStdLayout->setColumnStretch(1,1);
 
-  
+
   // advanced parameters
   myAdvGroup = new QWidget();
   QGridLayout* anAdvLayout = new QGridLayout( myAdvGroup );
   anAdvLayout->setSpacing( 6 );
-  anAdvLayout->setMargin( 11 );  
+  anAdvLayout->setMargin( 11 );
   myAdvWidget = new BLSURFPluginGUI_AdvWidget(myAdvGroup);
   anAdvLayout->addWidget( myAdvWidget );
 
@@ -756,7 +761,7 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame()
 
   //Layout
   QGridLayout* anSmpLayout = new QGridLayout(mySmpGroup);
-  
+
   // Table
   mySizeMapTable = new QTreeWidget( mySmpGroup );
   mySizeMapTable ->setMinimumWidth(200);
@@ -951,7 +956,7 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame()
 
   anEnfLayout->addWidget(myEnforcedTreeWidget,     0, 0, ENF_VER_NB_LINES, 1);
   QGridLayout* anEnfLayout2 = new QGridLayout(myEnfGroup);
-//  FACE AND VERTEX SELECTION
+  //  FACE AND VERTEX SELECTION
   //anEnfLayout2->addWidget(myEnfFaceWdg,             ENF_VER_FACE, 0, 1, 2);
   anEnfLayout2->addWidget(myEnfVertexWdg,           ENF_VER_VERTEX, 0, 1, 2);
   anEnfLayout2->addWidget(myXCoordLabel,            ENF_VER_X_COORD, 0, 1, 1);
@@ -970,6 +975,56 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame()
   anEnfLayout2->setRowStretch(ENF_VER_NB_LINES+1, 1);
   anEnfLayout->addLayout(anEnfLayout2, 0,1,ENF_VER_NB_LINES+1,2);
 
+  // ---------------------------
+  // Enforced meshes parameters
+  // ---------------------------
+
+  myEnfMeshGroup = new QWidget();
+  QGridLayout* anEnfMeshLayout = new QGridLayout(myEnfMeshGroup);
+
+  myEnfMeshTableWdg = new QTableWidget(myEnfGroup);
+  //myEnfMeshTableWdg->setRowCount( 0 );
+  myEnfMeshTableWdg->setColumnCount( ENF_MESH_NB_COLUMNS );
+  myEnfMeshTableWdg->setSortingEnabled(true);
+  myEnfMeshTableWdg->verticalHeader()->hide();
+  myEnfMeshTableWdg->setHorizontalHeaderLabels( QStringList()
+                                                << tr( "ENF_NAME_COLUMN" )
+                                                << tr( "ENF_GROUP_COLUMN" ));
+  myEnfMeshTableWdg->horizontalHeader()->setStretchLastSection(true);
+  myEnfMeshTableWdg->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
+  myEnfMeshTableWdg->setAlternatingRowColors(true);
+  myEnfMeshTableWdg->setSelectionMode(QAbstractItemView::ExtendedSelection);
+  myEnfMeshTableWdg->setSelectionBehavior(QAbstractItemView::SelectItems);
+  myEnfMeshTableWdg->resizeColumnsToContents();
+  //myEnfMeshTableWdg->setItemDelegate(new EnforcedMeshTableWidgetDelegate());
+
+  myEnfMeshWdg = new StdMeshersGUI_ObjectReferenceParamWdg( SMESH::IDSOURCE_EDGE, myEnfMeshGroup, /*multiSel=*/false);
+  myEnfMeshWdg->SetDefaultText(tr("ENF_SELECT_MESH"), "QLineEdit { color: grey }");
+
+  myEnfMeshWdg->AvoidSimultaneousSelection(myEnfVertexWdg);
+  myEnfMeshWdg->AvoidSimultaneousSelection(myGeomSelWdg1);
+  myEnfMeshWdg->AvoidSimultaneousSelection(myGeomSelWdg2);
+  myEnfMeshWdg->AvoidSimultaneousSelection(myAttSelWdg);
+
+  QLabel* enforcedGroupNameLabel = new QLabel( tr( "ENF_GROUP_LABEL" ), myEnfMeshGroup );
+  myEnforcedGroupName = new QLineEdit(myEnfMeshGroup);
+
+  myAddEnfMeshButton    = new QPushButton(tr("ENF_ADD"),myEnfMeshGroup);
+  myRemoveEnfMeshButton = new QPushButton(tr("ENF_REMOVE"),myEnfMeshGroup);
+
+  QGridLayout* anEnfMeshLayout2 = new QGridLayout(myEnfMeshGroup);
+  anEnfMeshLayout2->addWidget(myEnfMeshWdg,             0, 0, 1, 2);
+  anEnfMeshLayout2->addWidget(enforcedGroupNameLabel,   1, 0, 1, 1);
+  anEnfMeshLayout2->addWidget(myEnforcedGroupName,      1, 1, 1, 1);
+  anEnfMeshLayout2->addWidget(myAddEnfMeshButton,       2, 0, 1, 2);
+  anEnfMeshLayout2->addWidget(myRemoveEnfMeshButton,    3, 0, 1, 2);
+  anEnfMeshLayout2->setRowStretch( 4, 1 );
+
+  anEnfMeshLayout->addWidget(myEnfMeshTableWdg, 0, 0, 5, 1);
+  anEnfMeshLayout->addLayout(anEnfMeshLayout2,  0, 1, 1, 1);
+  anEnfMeshLayout->setRowStretch( 2, 1 );
+
+
   // ---
   // Periodicity parameters
   myPeriodicityGroup = new QWidget( dlg() );
@@ -1200,7 +1255,8 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame()
   myTabWidget->insertTab( ADV_TAB, myAdvGroup, tr( "BLSURF_ADV_ARGS" ) );
   if ( hasGeom() ) {
     myTabWidget->insertTab( SMP_TAB, mySmpGroup, tr( "LOCAL_SIZE" ) );
-    myTabWidget->insertTab( ENF_TAB, myEnfGroup, tr( "BLSURF_ENF_VER" ) );
+    myTabWidget->insertTab( ENF_V_TAB, myEnfGroup, tr( "BLSURF_ENF_VER" ) );
+    myTabWidget->insertTab( ENF_M_TAB, myEnfMeshGroup, tr( "ENF_MESH" ) );
     myTabWidget->insertTab( PERIODICITY_TAB, myPeriodicityGroup, tr( "BLSURF_PERIODICITY" ) );
     myTabWidget->insertTab( HYPERPATCH_TAB, hpGroup, tr( "BLSURF_HYPERPATCH_TAB" ));
   }
@@ -1208,47 +1264,55 @@ QFrame* BLSURFPluginGUI_HypothesisCreator::buildFrame()
   {
     mySmpGroup->hide();
     myEnfGroup->hide();
+    myEnfMeshGroup->hide();
     myPeriodicityGroup->hide();
     hpGroup->hide();
   }
   myTabWidget->setCurrentIndex( STD_TAB );
 
-  connect( myAdvWidget->addBtn, SIGNAL( clicked() ),           this, SLOT( onAddOption() ) );
+  connect( myAdvWidget->addBtn, SIGNAL( clicked() ),                           SLOT( onAddOption() ) );
 
   // Size Maps
-  connect( addMapButton,        SIGNAL( clicked()),                    this,         SLOT( onAddMap() ) );
-  connect( removeMapButton,     SIGNAL( clicked()),                    this,         SLOT( onRemoveMap() ) );
-  connect( modifyMapButton,     SIGNAL( clicked()),                    this,         SLOT( onModifyMap() ) );
-  connect( mySizeMapTable,      SIGNAL( itemClicked (QTreeWidgetItem *, int)),this,  SLOT( onSmpItemClicked(QTreeWidgetItem *, int) ) );
-  connect( myGeomSelWdg2,       SIGNAL( contentModified() ),           this,         SLOT( onMapGeomContentModified() ) );
-  connect( myGeomSelWdg1,       SIGNAL( contentModified() ),           this,         SLOT( onMapGeomContentModified() ) );
-  connect( myAttSelWdg,         SIGNAL( contentModified() ),           this,         SLOT( onMapGeomContentModified() ) );
-  connect( mySizeMapTable,      SIGNAL( itemChanged (QTreeWidgetItem *, int)),this,  SLOT( onSetSizeMap(QTreeWidgetItem *, int) ) );
-  connect( myAttractorCheck,    SIGNAL( stateChanged ( int )),         this,         SLOT( onAttractorClicked( int ) ) );
-  connect( myConstSizeCheck,    SIGNAL( stateChanged ( int )),         this,         SLOT( onConstSizeClicked( int ) ) );
-  connect( smpTab,              SIGNAL( currentChanged ( int )),       this,         SLOT( onTabChanged( int ) ) );
-  connect( myTabWidget,         SIGNAL( currentChanged ( int )),       this,         SLOT( onTabChanged( int ) ) );
+  connect( addMapButton,        SIGNAL( clicked()),                            SLOT( onAddMap() ) );
+  connect( removeMapButton,     SIGNAL( clicked()),                            SLOT( onRemoveMap() ) );
+  connect( modifyMapButton,     SIGNAL( clicked()),                            SLOT( onModifyMap() ) );
+  connect( mySizeMapTable,      SIGNAL( itemClicked (QTreeWidgetItem *, int)), SLOT( onSmpItemClicked(QTreeWidgetItem *, int) ) );
+  connect( myGeomSelWdg2,       SIGNAL( contentModified() ),                   SLOT( onMapGeomContentModified() ) );
+  connect( myGeomSelWdg1,       SIGNAL( contentModified() ),                   SLOT( onMapGeomContentModified() ) );
+  connect( myAttSelWdg,         SIGNAL( contentModified() ),                   SLOT( onMapGeomContentModified() ) );
+  connect( mySizeMapTable,      SIGNAL( itemChanged (QTreeWidgetItem *, int)), SLOT( onSetSizeMap(QTreeWidgetItem *, int) ) );
+  connect( myAttractorCheck,    SIGNAL( stateChanged ( int )),                 SLOT( onAttractorClicked( int ) ) );
+  connect( myConstSizeCheck,    SIGNAL( stateChanged ( int )),                 SLOT( onConstSizeClicked( int ) ) );
+  connect( smpTab,              SIGNAL( currentChanged ( int )),               SLOT( onTabChanged( int ) ) );
+  connect( myTabWidget,         SIGNAL( currentChanged ( int )),               SLOT( onTabChanged( int ) ) );
 
   // Enforced vertices
-  connect( myEnforcedTreeWidget,SIGNAL( itemClicked(QTreeWidgetItem *, int)), this,  SLOT( synchronizeCoords() ) );
-  connect( myEnforcedTreeWidget,SIGNAL( itemChanged(QTreeWidgetItem *, int)), this,  SLOT( updateEnforcedVertexValues(QTreeWidgetItem *, int) ) );
-  connect( myEnforcedTreeWidget,SIGNAL( itemSelectionChanged() ),      this,         SLOT( synchronizeCoords() ) );
-  connect( addVertexButton,     SIGNAL( clicked()),                    this,         SLOT( onAddEnforcedVertices() ) );
-  connect( removeVertexButton,  SIGNAL( clicked()),                    this,         SLOT( onRemoveEnforcedVertex() ) );
-  connect( myEnfVertexWdg,      SIGNAL( contentModified()),            this,         SLOT( onSelectEnforcedVertex() ) );
-  connect( myInternalEnforcedVerticesAllFaces, SIGNAL( stateChanged ( int )), this,  SLOT( onInternalVerticesClicked( int ) ) );
+  connect( myEnforcedTreeWidget,SIGNAL( itemClicked(QTreeWidgetItem *, int)),  SLOT( synchronizeCoords() ) );
+  connect( myEnforcedTreeWidget,SIGNAL( itemChanged(QTreeWidgetItem *, int)),  SLOT( updateEnforcedVertexValues(QTreeWidgetItem *, int) ) );
+  connect( myEnforcedTreeWidget,SIGNAL( itemSelectionChanged() ),              SLOT( synchronizeCoords() ) );
+  connect( addVertexButton,     SIGNAL( clicked()),                            SLOT( onAddEnforcedVertices() ) );
+  connect( removeVertexButton,  SIGNAL( clicked()),                            SLOT( onRemoveEnforcedVertex() ) );
+  connect( myEnfVertexWdg,      SIGNAL( contentModified()),                    SLOT( onSelectEnforcedVertex() ) );
+  connect( myInternalEnforcedVerticesAllFaces, SIGNAL( stateChanged ( int )),  SLOT( onInternalVerticesClicked( int ) ) );
+
+  // Enforced mesh
+  connect( myAddEnfMeshButton,    SIGNAL( clicked()),              SLOT( onAddEnforcedMesh()));
+  connect( myRemoveEnfMeshButton, SIGNAL( clicked()),              SLOT( onRemoveEnforcedMesh()));
+  connect( myEnfMeshWdg,          SIGNAL( contentModified()),      SLOT( onEnforcedMeshSelected()));
+  connect( myEnfMeshTableWdg,     SIGNAL( itemSelectionChanged()), SLOT( onEnfMeshTableSelected()));
+
 
   // Periodicity
-  connect( myPeriodicityAddButton,     SIGNAL( clicked()),                    this,   SLOT( onAddPeriodicity() ) );
-  connect( myPeriodicityRemoveButton,  SIGNAL( clicked()),                    this,   SLOT( onRemovePeriodicity() ) );
-  connect( myPeriodicityTreeWidget,    SIGNAL( itemClicked(QTreeWidgetItem*, int)), this, SLOT( onPeriodicityTreeClicked(QTreeWidgetItem *, int) ) );
-  connect( myPeriodicityGroupBox2,     SIGNAL(toggled(bool)),                 this,   SLOT(onPeriodicityByVerticesChecked(bool)));
+  connect( myPeriodicityAddButton,     SIGNAL( clicked()),                     SLOT( onAddPeriodicity() ) );
+  connect( myPeriodicityRemoveButton,  SIGNAL( clicked()),                     SLOT( onRemovePeriodicity() ) );
+  connect( myPeriodicityTreeWidget,    SIGNAL( itemClicked(QTreeWidgetItem*, int)), SLOT( onPeriodicityTreeClicked(QTreeWidgetItem *, int) ) );
+  connect( myPeriodicityGroupBox2,     SIGNAL(toggled(bool)),                  SLOT(onPeriodicityByVerticesChecked(bool)));
 
   ListOfWidgets::const_iterator anIt = myPeriodicitySelectionWidgets.begin();
   for (; anIt != myPeriodicitySelectionWidgets.end(); anIt++)
   {
     StdMeshersGUI_ObjectReferenceParamWdg * w1 = ( StdMeshersGUI_ObjectReferenceParamWdg* ) ( *anIt );
-    connect( w1,     SIGNAL(contentModified ()),                 this,   SLOT(onPeriodicityContentModified()));
+    connect( w1, SIGNAL( contentModified ()), SLOT( onPeriodicityContentModified() ));
 
   }
 
@@ -2025,6 +2089,7 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const
   }
 
   // Hyper patches
+
   QString patchEntries;
   for ( int i = 0; i < data.hyperpatches.size(); ++i )
   {
@@ -2036,6 +2101,18 @@ void BLSURFPluginGUI_HypothesisCreator::retrieveParams() const
   that->myStdWidget->onPhysicalMeshChanged();
   that->myStdWidget->onGeometricMeshChanged();
   that->onStateChange();
+
+  // Enforced mesh
+
+  BLSURFPlugin::BLSURFPlugin_Hypothesis_var h =
+    BLSURFPlugin::BLSURFPlugin_Hypothesis::_narrow( initParamsHypothesis() );
+
+  BLSURFPlugin::EnforcedMeshesList_var enfMeshes = h->GetEnforcedMeshes();
+  for ( CORBA::ULong i = 0; i < enfMeshes->length(); ++i )
+  {
+    BLSURFPlugin::MG_EnforcedMesh1D & enfMesh = enfMeshes[i];
+    that->addEnforcedMesh( enfMesh.mesh.in(), enfMesh.groupName.in() );
+  }
 }
 
 /** BLSURFPluginGUI_HypothesisCreator::storeParams()
@@ -2589,6 +2666,31 @@ bool BLSURFPluginGUI_HypothesisCreator::storeParamsToHypo( const BlsurfHypothesi
       h->SetHyperPatches( hpl );
 
 
+    // Enforced meshes
+    BLSURFPlugin::EnforcedMeshesList_var enfMeshesList = new BLSURFPlugin::EnforcedMeshesList();
+    enfMeshesList->length( myEnfMeshTableWdg->rowCount() );
+
+    int nbMeshes = 0;
+    for ( int row = 0, nbRow = myEnfMeshTableWdg->rowCount(); row < nbRow; ++row )
+    {
+      QTableWidgetItem *  meshCell = myEnfMeshTableWdg->item( row, 0 );
+      QString                entry = meshCell->data( Qt::UserRole ).toString();
+      QTableWidgetItem * groupCell = myEnfMeshTableWdg->item( row, 1 );
+      QString            groupName = groupCell->text();
+
+      SMESH::SMESH_IDSource_var mesh = SMESH::EntryToInterface< SMESH::SMESH_IDSource >( entry );
+      if ( !mesh->_is_nil() )
+      {
+        enfMeshesList[ nbMeshes ].mesh = SMESH::SMESH_IDSource::_duplicate( mesh );
+        enfMeshesList[ nbMeshes ].groupName = CORBA::string_dup( groupName.toStdString().c_str() );
+        ++nbMeshes;
+      }
+    }
+    enfMeshesList->length( nbMeshes );
+
+    h->SetEnforcedMeshes( enfMeshesList );
+
+
   } // try
   catch(...) {
     ok = false;
@@ -2898,6 +3000,7 @@ void BLSURFPluginGUI_HypothesisCreator::onTabChanged(int tab)
     myPeriodicityP1TargetWdg  ->deactivateSelection();
     myPeriodicityP2TargetWdg  ->deactivateSelection();
     myPeriodicityP3TargetWdg  ->deactivateSelection();
+    myEnfMeshWdg              ->deactivateSelection();
     if ( myHyPatchFaceSelBtn->isChecked() )
       myHyPatchFaceSelBtn->toggle();
     if ( myHyPatchGroupSelBtn->isChecked() )
@@ -2934,6 +3037,15 @@ void BLSURFPluginGUI_HypothesisCreator::onTabChanged(int tab)
     mySmpSizeSpin->RangeStepAndValidator(minSize, maxSize, 1.0, "length_precision");
     myAttSizeSpin->RangeStepAndValidator(minSize, maxSize, 1.0, "length_precision");
   }
+
+  if ( tab == ENF_M_TAB )
+  {
+    myEnfMeshWdg->activateSelection();
+    onEnforcedMeshSelected(); // update buttons
+    onEnfMeshTableSelected();
+    if ( myEnforcedGroupName->text().isEmpty() )
+      myEnforcedGroupName->setText("Group 1D");
+  }
 }
 
 void BLSURFPluginGUI_HypothesisCreator::onAttractorClicked(int state)
@@ -3573,6 +3685,153 @@ void BLSURFPluginGUI_HypothesisCreator::onHyPatchRemove()
   }
 }
 
+//================================================================================
+/*!
+ * \brief Add a new row in Enforced mesh table
+ */
+//================================================================================
+
+void BLSURFPluginGUI_HypothesisCreator::addEnforcedMesh( SMESH::SMESH_IDSource_ptr mesh,
+                                                         const QString&            groupName  )
+{
+  _PTR(SObject) sobj = SMESH::FindSObject( mesh );
+  if ( !sobj )
+    return;
+
+  QString meshEntry = sobj->GetID().c_str();
+  QString meshName  = sobj->GetName().c_str();
+
+  QTableWidgetItem* meshCell = new QTableWidgetItem( meshName );
+  meshCell->setData( Qt::UserRole, meshEntry );
+  meshCell->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
+
+  QTableWidgetItem* groupCell = new QTableWidgetItem( groupName );
+  groupCell->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable );
+
+  int row = myEnfMeshTableWdg->rowCount();
+  myEnfMeshTableWdg->insertRow( row );
+  myEnfMeshTableWdg->setItem( row, 0, meshCell );
+  myEnfMeshTableWdg->setItem( row, 1, groupCell );
+
+  myEnfMeshTableWdg->resizeColumnToContents( 0 );
+  myEnfMeshTableWdg->resizeColumnToContents( 1 );
+}
+
+//================================================================================
+/*!
+ * \brief SLOT called when [Add] is clicked in Enforced mesh tab.
+ *        Add an item to the enforced meshes table
+ */
+//================================================================================
+
+void BLSURFPluginGUI_HypothesisCreator::onAddEnforcedMesh()
+{
+  if ( myEnfMeshWdg->NbObjects() != 1 )
+    return;
+
+  SMESH::SMESH_IDSource_var mesh = myEnfMeshWdg->GetObject< SMESH::SMESH_IDSource >();
+  QString              groupName = myEnforcedGroupName->text().simplified();
+
+  addEnforcedMesh( mesh, groupName );
+
+  selectionMgr()->clearSelected();
+  myEnfMeshWdg->SetObject( SMESH::SMESH_IDSource::_nil() );
+}
+
+//================================================================================
+/*!
+ * \brief SLOT called when [Remove] is clicked in Enforced mesh tab.
+ *        Remove a selected mesh from the enforced meshes table
+ */
+//================================================================================
+
+void BLSURFPluginGUI_HypothesisCreator::onRemoveEnforcedMesh()
+{
+  QList<int> selectedRows;
+  QList<QTableWidgetItem *> selectedItems = myEnfMeshTableWdg->selectedItems();
+  QTableWidgetItem* item;
+  int row;
+  foreach( item, selectedItems )
+  {
+    row = item->row();
+    if (!selectedRows.contains( row ) )
+      selectedRows.append(row);
+  }
+
+  qSort( selectedRows );
+  QListIterator<int> it( selectedRows );
+  it.toBack();
+  while ( it.hasPrevious() ) {
+    row = it.previous();
+    myEnfMeshTableWdg->removeRow(row );
+  }
+
+  myEnfMeshTableWdg->selectionModel()->clearSelection();
+
+  onEnforcedMeshSelected(); // to activate [Add] if possible
+}
+
+//================================================================================
+/*!
+ * \brief SLOT called when mesh selection changes. Enable/disable [Add] button
+ */
+//================================================================================
+
+void BLSURFPluginGUI_HypothesisCreator::onEnforcedMeshSelected()
+{
+  bool enable = ( myEnfMeshWdg->NbObjects() == 1 );
+  if ( enable )
+  {
+    // check if a selected mesh contains segments
+    SMESH::SMESH_IDSource_var mesh = myEnfMeshWdg->GetObject< SMESH::SMESH_IDSource >();
+    if (( enable = !mesh->_is_nil() ))
+    {
+      SMESH::array_of_ElementType_var types = mesh->GetTypes();
+      if (( enable = ( types->length() > 0 )))
+      {
+        enable = false;
+        for ( CORBA::ULong i = 0; i < types->length() &&  !enable; ++i )
+          enable = ( types[ i ] = SMESH::EDGE );
+      }
+    }
+
+    // check if this mesh is already in the table
+    if ( enable )
+    {
+      _PTR(SObject) sobj = SMESH::FindSObject( mesh );
+      if (( enable = bool( sobj )))
+      {
+        QString meshEntry = sobj->GetID().c_str();
+        for ( int row = 0, nbRow = myEnfMeshTableWdg->rowCount(); row < nbRow &&  enable; ++row )
+        {
+          QTableWidgetItem * cell = myEnfMeshTableWdg->item( row, 0 );
+          enable = ( meshEntry != cell->data( Qt::UserRole ).toString() );
+        }
+      }
+    }
+  }
+  myAddEnfMeshButton->setEnabled( enable );
+}
+
+//================================================================================
+/*!
+ * \brief SLOT called when selection changes in the table. Enable/disable [Remove] button
+ */
+//================================================================================
+
+void BLSURFPluginGUI_HypothesisCreator::onEnfMeshTableSelected()
+{
+  bool enable = !myEnfMeshTableWdg->selectedItems().empty();
+
+  myRemoveEnfMeshButton->setEnabled( enable );
+}
+
+//================================================================================
+/*!
+ * \brief Return false if algorithm is a re-mesher
+ */
+//================================================================================
+
 bool BLSURFPluginGUI_HypothesisCreator::hasGeom() const
 {
   return hypType() == BLSURFPlugin_Hypothesis::GetHypType(true);
index 0f5788e5c44f48b1d480f5a75bae968af500d0fb..1ae9ef408b5424246a7871b4543fc4e375108b10 100644 (file)
@@ -242,6 +242,11 @@ protected slots:
   void                onSelectEnforcedVertex();
   void                clearEnforcedVertexWidgets();
   void                onInternalVerticesClicked(int);
+  // Enforced mesh tab
+  void                onAddEnforcedMesh();
+  void                onRemoveEnforcedMesh();
+  void                onEnforcedMeshSelected();
+  void                onEnfMeshTableSelected();
   // Periodicity tab
   void                onPeriodicityByVerticesChecked(bool);
   void                onAddPeriodicity();
@@ -274,6 +279,8 @@ private:
   void                addHyPatchToTable(const QString& tags, const QString& entries);
   bool                hasGeom() const;
 
+  void                addEnforcedMesh( SMESH::SMESH_IDSource_ptr mesh, const QString& groupName );
+
 private:
   
   QTabWidget*             myTabWidget;
@@ -336,6 +343,17 @@ private:
   QCheckBox           *myInternalEnforcedVerticesAllFaces;
   QLineEdit           *myInternalEnforcedVerticesAllFacesGroup;
 
+
+  // Enforced meshes
+  QWidget*             myEnfMeshGroup;
+  StdMeshersGUI_ObjectReferenceParamWdg *myEnfMeshWdg;
+  QTableWidget*        myEnfMeshTableWdg;
+  QLineEdit*           myEnforcedGroupName;
+  QPushButton*         myAddEnfMeshButton;
+  QPushButton*         myRemoveEnfMeshButton;
+
+
+
   // map =  entry , size map
   QMap<QString, QString>          mySMPMap;           // Map <face entry, size>
   QMap<QString, TAttractorVec >   myATTMap;           // Map <face entry, att. entry, etc>
@@ -396,7 +414,7 @@ private:
 
 class EnforcedTreeWidgetDelegate : public QItemDelegate
 {
-    Q_OBJECT
+  Q_OBJECT
 
 public:
   EnforcedTreeWidgetDelegate(QObject *parent = 0);
@@ -409,7 +427,7 @@ public:
                     const QModelIndex &index) const;
 
   void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
-                    const QModelIndex &index) const;
+                            const QModelIndex &index) const;
 
   bool vertexExists(QAbstractItemModel *model, const QModelIndex &index, QString value) const;
 };
index 9016435f197c45583ec62c7ef0b265680e1df1d5..537e927db588695bb65fbaf55e2c578755f9025c 100644 (file)
@@ -695,6 +695,37 @@ The smaller this distance is, the closer the mesh is to the exact surface (only
         <translation>Hyper-patch</translation>
     </message>
 </context>
+<context>
+    <name>BLSURFPluginGUI_HypothesisCreator</name>
+    <message>
+        <source>ENF_NAME_COLUMN</source>
+        <translation>1D object</translation>
+    </message>
+    <message>
+        <source>ENF_GROUP_COLUMN</source>
+        <translation>Group name</translation>
+    </message>
+    <message>
+        <source>ENF_SELECT_MESH</source>
+        <translation>Select 1D object</translation>
+    </message>
+    <message>
+        <source>ENF_GROUP_LABEL</source>
+        <translation>Group name</translation>
+    </message>
+    <message>
+        <source>ENF_ADD</source>
+        <translation>Add</translation>
+    </message>
+    <message>
+        <source>ENF_REMOVE</source>
+        <translation>Remove</translation>
+    </message>
+    <message>
+        <source>ENF_MESH</source>
+        <translation>Enforced mesh</translation>
+    </message>
+</context>
 <context>
     <name>BLSURFPluginGUI_AdvWidget</name>
     <message>