Salome HOME
0021197: EDF 1772 SMESH: Automatic meshing hypothesis
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
index 2ae3f57dfd77b670db2f3d309714629734801a7d..690f46831b057a3d0622ede0d768ca41f973a2da 100644 (file)
@@ -473,10 +473,12 @@ CORBA::Long SMESH_MeshEditor_i::RemoveOrphanNodes()
   for ( int i = 0; i < seq.size(); i++ )
     IdList.push_back( seq[i] );
 
+  bool ret = anEditor.Remove( IdList, true );
+  myMesh->GetMeshDS()->Modified();
   if ( IdList.size() )
     myMesh->SetIsModified( true );
 
-  return anEditor.Remove( IdList, true );
+  return ret;
 }
 
 //=============================================================================
@@ -1806,16 +1808,30 @@ SMESH_MeshEditor_i::extrusionSweep(const SMESH::long_array & theIDsOfElements,
 #ifdef NO_CAS_CATCH
     OCC_CATCH_SIGNALS;
 #endif
-    TIDSortedElemSet elements;
+    TIDSortedElemSet elements, copyElements;
     arrayToSet(theIDsOfElements, GetMeshDS(), elements, theElementType);
 
     const SMESH::PointStruct * P = &theStepVector.PS;
     gp_Vec stepVec( P->x, P->y, P->z );
 
+    TIDSortedElemSet* workElements = & elements;
+    TPreviewMesh      tmpMesh( SMDSAbs_Face );
+    SMESH_Mesh*       mesh = 0;
+    
+    if ( myPreviewMode ) {
+      SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
+      tmpMesh.Copy( elements, copyElements, select, avoid );
+      mesh = &tmpMesh;
+      workElements = & copyElements;
+    }
+    else {
+       mesh = myMesh;
+    }
+
     TElemOfElemListMap aHystory;
-    ::SMESH_MeshEditor anEditor( myMesh );
+    ::SMESH_MeshEditor anEditor( mesh );
     ::SMESH_MeshEditor::PGroupIDs groupIds =
-        anEditor.ExtrusionSweep (elements, stepVec, theNbOfSteps, aHystory, theMakeGroups);
+        anEditor.ExtrusionSweep (*workElements, stepVec, theNbOfSteps, aHystory, theMakeGroups);
 
     myMesh->GetMeshDS()->Modified();
     storeResult(anEditor);
@@ -2212,10 +2228,26 @@ SMESH_MeshEditor_i::extrusionAlongPathX(const SMESH::long_array &  IDsOfElements
     return EmptyGr;
   }
 
-  TIDSortedElemSet elements;
+  TIDSortedElemSet elements, copyElements;
   arrayToSet(IDsOfElements, GetMeshDS(), elements, ElementType);
 
-  ::SMESH_MeshEditor anEditor( myMesh );
+  TIDSortedElemSet* workElements = &elements;
+  TPreviewMesh      tmpMesh( SMDSAbs_Face );
+  SMESH_Mesh*       mesh = 0;
+
+  if ( myPreviewMode )
+  {
+    SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
+    tmpMesh.Copy( elements, copyElements, select, avoid );
+    mesh = &tmpMesh;
+    workElements = & copyElements;
+  }
+  else
+  {
+    mesh = myMesh;
+  }
+
+  ::SMESH_MeshEditor anEditor( mesh );
   ::SMESH_MeshEditor::Extrusion_Error error;
 
   SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( Path );
@@ -2227,7 +2259,7 @@ SMESH_MeshEditor_i::extrusionAlongPathX(const SMESH::long_array &  IDsOfElements
       Error = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
       return EmptyGr;
     }
-    error = anEditor.ExtrusionAlongTrack( elements, &(aMeshImp->GetImpl()), aNodeStart,
+    error = anEditor.ExtrusionAlongTrack( *workElements, &(aMeshImp->GetImpl()), aNodeStart,
                                           HasAngles, angles, LinearVariation,
                                           HasRefPoint, refPnt, MakeGroups );
     myMesh->GetMeshDS()->Modified();
@@ -2246,7 +2278,7 @@ SMESH_MeshEditor_i::extrusionAlongPathX(const SMESH::long_array &  IDsOfElements
       }
       SMESH_subMesh* aSubMesh =
         aMeshImp->GetImpl().GetSubMeshContaining(aSubMeshImp->GetId());
-      error = anEditor.ExtrusionAlongTrack( elements, aSubMesh, aNodeStart,
+      error = anEditor.ExtrusionAlongTrack( *workElements, aSubMesh, aNodeStart,
                                             HasAngles, angles, LinearVariation,
                                             HasRefPoint, refPnt, MakeGroups );
       myMesh->GetMeshDS()->Modified();
@@ -2879,11 +2911,28 @@ SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
     aTrsf.SetMirror( gp_Ax2( P, V ));
   }
 
-  ::SMESH_MeshEditor anEditor( myMesh );
+  TIDSortedElemSet copyElements;
+  TPreviewMesh      tmpMesh;
+  TIDSortedElemSet* workElements = 0;
+  SMESH_Mesh*       mesh = 0;
+
+  if ( myPreviewMode )
+  {
+    tmpMesh.Copy( theElements, copyElements);
+    mesh = &tmpMesh;
+    workElements = & copyElements;
+  }
+  else
+  {
+    mesh = myMesh;
+    workElements = & theElements;
+  }
+
+  ::SMESH_MeshEditor anEditor( mesh );
   ::SMESH_MeshEditor::PGroupIDs groupIds =
-      anEditor.Transform (theElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
+      anEditor.Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
-  if(theCopy)
+  if(theCopy || myPreviewMode)
     storeResult(anEditor);
   else
     {
@@ -2938,7 +2987,10 @@ void SMESH_MeshEditor_i::MirrorObject(SMESH::SMESH_IDSource_ptr           theObj
                   << theCopy   << " )";
   }
   TIDSortedElemSet elements;
-  if (idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+
+  bool emptyIfIsMesh = myPreviewMode ? false : true;
+
+  if (idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
     mirror(elements, theAxis, theMirrorType, theCopy, false);
 }
 
@@ -3110,11 +3162,28 @@ SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
   const SMESH::PointStruct * P = &theVector.PS;
   aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z ));
 
-  ::SMESH_MeshEditor anEditor( myMesh );
+  TIDSortedElemSet copyElements;
+  TPreviewMesh      tmpMesh;
+  TIDSortedElemSet* workElements = 0;
+  SMESH_Mesh*       mesh = 0;
+
+  if ( myPreviewMode )
+  {
+    tmpMesh.Copy( theElements, copyElements);
+    mesh = &tmpMesh;
+    workElements = & copyElements;
+  }
+  else
+  {
+    mesh = myMesh;
+    workElements = & theElements;
+  }
+
+  ::SMESH_MeshEditor anEditor( mesh );
   ::SMESH_MeshEditor::PGroupIDs groupIds =
-      anEditor.Transform (theElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
+      anEditor.Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
-  if(theCopy)
+  if(theCopy || myPreviewMode)
     storeResult(anEditor);
   else
     {
@@ -3163,7 +3232,10 @@ void SMESH_MeshEditor_i::TranslateObject(SMESH::SMESH_IDSource_ptr theObject,
                   << theCopy << " )";
   }
   TIDSortedElemSet elements;
-  if (idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+
+  bool emptyIfIsMesh = myPreviewMode ? false : true;
+  
+  if (idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
     translate(elements, theVector, theCopy, false);
 }
 
@@ -3328,11 +3400,27 @@ SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
   gp_Trsf aTrsf;
   aTrsf.SetRotation( gp_Ax1( P, V ), theAngle);
 
-  ::SMESH_MeshEditor anEditor( myMesh );
+  TIDSortedElemSet copyElements;
+  TPreviewMesh      tmpMesh;
+  TIDSortedElemSet* workElements = 0;
+  SMESH_Mesh*       mesh = 0;
+
+  if ( myPreviewMode ) {
+    tmpMesh.Copy( theElements, copyElements );
+    mesh = &tmpMesh;
+    workElements = &copyElements;
+  }
+  else
+  {
+    mesh = myMesh;
+    workElements=&theElements;
+  }
+
+  ::SMESH_MeshEditor anEditor( mesh );
   ::SMESH_MeshEditor::PGroupIDs groupIds =
-      anEditor.Transform (theElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
+      anEditor.Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
-  if(theCopy)
+  if(theCopy || myPreviewMode)
     storeResult(anEditor);
   else
     {
@@ -3386,7 +3474,8 @@ void SMESH_MeshEditor_i::RotateObject(SMESH::SMESH_IDSource_ptr theObject,
                   << theCopy << " )";
   }
   TIDSortedElemSet elements;
-  if (idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/1))
+  bool emptyIfIsMesh = myPreviewMode ? false : true;
+  if (idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
     rotate(elements,theAxis,theAngle,theCopy,false);
 }
 
@@ -3561,7 +3650,8 @@ SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
     THROW_SALOME_CORBA_EXCEPTION("Invalid nb of scale factors : 2", SALOME::BAD_PARAM);
 
   TIDSortedElemSet elements;
-  if ( !idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, /*emptyIfIsMesh=*/true))
+  bool emptyIfIsMesh = myPreviewMode ? false : true;
+  if ( !idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
     return 0;
 
   vector<double> S(3);
@@ -3574,11 +3664,28 @@ SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
                    0,    S[1], 0,    thePoint.y * (1-S[1]),
                    0,    0,    S[2], thePoint.z * (1-S[2]),   tol, tol);
 
-  ::SMESH_MeshEditor anEditor( myMesh );
+  TIDSortedElemSet copyElements;
+  TPreviewMesh      tmpMesh;
+  TIDSortedElemSet* workElements = 0;
+  SMESH_Mesh*       mesh = 0;
+  
+  if ( myPreviewMode )
+  {
+    tmpMesh.Copy( elements, copyElements);
+    mesh = &tmpMesh;
+    workElements = & copyElements;
+  }
+  else
+  {
+    mesh = myMesh;
+    workElements = & elements;
+  }
+
+  ::SMESH_MeshEditor anEditor( mesh );
   ::SMESH_MeshEditor::PGroupIDs groupIds =
-      anEditor.Transform (elements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
+      anEditor.Transform (*workElements, aTrsf, theCopy, theMakeGroups, theTargetMesh);
 
-  if(theCopy)
+  if(theCopy || myPreviewMode )
     storeResult(anEditor);
   else
     {
@@ -4538,18 +4645,22 @@ void SMESH_MeshEditor_i::storeResult(::SMESH_MeshEditor& anEditor)
   }
 
   {
-    // add new nodes into myLastCreatedNodes
+    // append new nodes into myLastCreatedNodes
     const SMESH_SequenceOfElemPtr& aSeq = anEditor.GetLastCreatedNodes();
-    myLastCreatedNodes->length(aSeq.Length());
-    for(int i=0; i<aSeq.Length(); i++)
-      myLastCreatedNodes[i] = aSeq.Value(i+1)->GetID();
+    int j = myLastCreatedNodes->length();
+    int newLen = j + aSeq.Length();
+    myLastCreatedNodes->length( newLen );
+    for(int i=0; j<newLen; i++,j++)
+      myLastCreatedNodes[j] = aSeq.Value(i+1)->GetID();
   }
   {
-    // add new elements into myLastCreatedElems
+    // append new elements into myLastCreatedElems
     const SMESH_SequenceOfElemPtr& aSeq = anEditor.GetLastCreatedElems();
-    myLastCreatedElems->length(aSeq.Length());
-    for(int i=0; i<aSeq.Length(); i++)
-      myLastCreatedElems[i] = aSeq.Value(i+1)->GetID();
+    int j = myLastCreatedElems->length();
+    int newLen = j + aSeq.Length();
+    myLastCreatedElems->length( newLen );
+    for(int i=0; j<newLen; i++,j++)
+      myLastCreatedElems[j] = aSeq.Value(i+1)->GetID();
   }
 }
 
@@ -4896,6 +5007,45 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeGroups(const SMESH::ListOfGroups& t
   return aResult;
 }
 
+//================================================================================
+/*!
+ * \brief Creates a hole in a mesh by doubling the nodes of some particular elements.
+ * Works as DoubleNodeGroups(), but returns a new group with newly created nodes.
+ * \param theNodes - group of nodes to be doubled.
+ * \param theModifiedElems - group of elements to be updated.
+ * \return a new group with newly created nodes
+ * \sa DoubleNodeGroups()
+ */
+//================================================================================
+
+SMESH::SMESH_Group_ptr SMESH_MeshEditor_i::DoubleNodeGroupsNew( const SMESH::ListOfGroups& theNodes,
+                                                                const SMESH::ListOfGroups& theModifiedElems )
+{
+  SMESH::SMESH_Group_var aNewGroup;
+
+  TPythonDump pyDump; // suppress dump by the next line
+
+  bool aResult = DoubleNodeGroups( theNodes, theModifiedElems );
+
+  if ( aResult )
+  {
+    // Create group with newly created nodes
+    SMESH::long_array_var anIds = GetLastCreatedNodes();
+    if (anIds->length() > 0) {
+      string anUnindexedName (theNodes[0]->GetName());
+      string aNewName = generateGroupName(anUnindexedName + "_double");
+      aNewGroup = myMesh_i->CreateGroup(SMESH::NODE, aNewName.c_str());
+      aNewGroup->Add(anIds);
+    }
+  }
+
+  pyDump << "createdNodes = " << this << ".DoubleNodeGroupsNew( " << theNodes << ", "
+    << theModifiedElems << " )";
+
+  return aNewGroup._retn();
+}
+
+
 //================================================================================
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
@@ -5132,7 +5282,7 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroupInRegion(SMESH::SMESH_Grou
   \param theAffectedElems - group of elements to which the replicated nodes
   should be associated to.
   \return TRUE if operation has been completed successfully, FALSE otherwise
-  \sa DoubleNodeGroup(), DoubleNodes()
+  \sa DoubleNodeGroup(), DoubleNodes(), DoubleNodeElemGroupsNew()
 */
 //================================================================================
 
@@ -5181,6 +5331,60 @@ CORBA::Boolean SMESH_MeshEditor_i::DoubleNodeElemGroups(const SMESH::ListOfGroup
   return aResult;
 }
 
+//================================================================================
+/*!
+ * \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+ * Works as DoubleNodeElemGroups(), but returns a new group with newly created elements.
+  \param theElems - list of groups of elements (edges or faces) to be replicated
+  \param theNodesNot - list of groups of nodes not to replicated
+  \param theAffectedElems - group of elements to which the replicated nodes
+  should be associated to.
+ * \return a new group with newly created elements
+ * \sa DoubleNodeElemGroups()
+ */
+//================================================================================
+
+SMESH::SMESH_Group_ptr SMESH_MeshEditor_i::DoubleNodeElemGroupsNew(const SMESH::ListOfGroups& theElems,
+                                                                   const SMESH::ListOfGroups& theNodesNot,
+                                                                   const SMESH::ListOfGroups& theAffectedElems)
+{
+  SMESH::SMESH_Group_var aNewGroup;
+  
+  initData();
+
+  ::SMESH_MeshEditor aMeshEditor( myMesh );
+
+  SMESHDS_Mesh* aMeshDS = GetMeshDS();
+  TIDSortedElemSet anElems, aNodes, anAffected;
+  listOfGroupToSet(theElems, aMeshDS, anElems, false );
+  listOfGroupToSet(theNodesNot, aMeshDS, aNodes, true );
+  listOfGroupToSet(theAffectedElems, aMeshDS, anAffected, false );
+
+  bool aResult = aMeshEditor.DoubleNodes( anElems, aNodes, anAffected );
+
+  storeResult( aMeshEditor) ;
+
+  myMesh->GetMeshDS()->Modified();
+  if ( aResult ) {
+    myMesh->SetIsModified( true );
+
+    // Create group with newly created elements
+    SMESH::long_array_var anIds = GetLastCreatedElems();
+    if (anIds->length() > 0) {
+      SMESH::ElementType aGroupType = myMesh_i->GetElementType(anIds[0], true);
+      string anUnindexedName (theElems[0]->GetName());
+      string aNewName = generateGroupName(anUnindexedName + "_double");
+      aNewGroup = myMesh_i->CreateGroup(aGroupType, aNewName.c_str());
+      aNewGroup->Add(anIds);
+    }
+  }
+
+  // Update Python script
+  TPythonDump() << "createdElems = " << this << ".DoubleNodeElemGroupsNew( " << &theElems << ", "
+                << &theNodesNot << ", " << &theAffectedElems << " )";
+  return aNewGroup._retn();
+}
+
 //================================================================================
 /*!
   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
@@ -5324,7 +5528,6 @@ SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
   if ( dim > SMESH::BND_1DFROM2D )
     THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
 
-
   SMESHDS_Mesh* aMeshDS = GetMeshDS();
 
   SMESH::SMESH_Mesh_var mesh_var;
@@ -5361,6 +5564,9 @@ SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
                                   toCopyElements,
                                   toCopyExistingBondary);
     storeResult( aMeshEditor );
+
+    if ( smesh_mesh )
+      smesh_mesh->GetMeshDS()->Modified();
   }
 
   const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
@@ -5385,3 +5591,146 @@ SMESH_MeshEditor_i::MakeBoundaryMesh(SMESH::SMESH_IDSource_ptr idSource,
   group = group_var._retn();
   return mesh_var._retn();
 }
+
+//================================================================================
+/*!
+ * \brief Creates missing boundary elements
+ *  \param dimension - defines type of boundary elements to create
+ *  \param groupName - a name of group to store all boundary elements in,
+ *    "" means not to create the group
+ *  \param meshName - a name of a new mesh, which is a copy of the initial 
+ *    mesh + created boundary elements; "" means not to create the new mesh
+ *  \param toCopyAll - if true, the whole initial mesh will be copied into
+ *    the new mesh else only boundary elements will be copied into the new mesh
+ *  \param groups - optional groups of elements to make boundary around
+ *  \param mesh - returns the mesh where elements were added to
+ *  \param group - returns the created group, if any
+ *  \retval long - number of added boundary elements
+ */
+//================================================================================
+
+CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
+                                                     const char* groupName,
+                                                     const char* meshName,
+                                                     CORBA::Boolean toCopyAll,
+                                                     const SMESH::ListOfIDSources& groups,
+                                                     SMESH::SMESH_Mesh_out mesh,
+                                                     SMESH::SMESH_Group_out group)
+  throw (SALOME::SALOME_Exception)
+{
+  Unexpect aCatch(SALOME_SalomeException);
+
+  initData();
+
+  if ( dim > SMESH::BND_1DFROM2D )
+    THROW_SALOME_CORBA_EXCEPTION("Invalid boundary dimension", SALOME::BAD_PARAM);
+
+  // check that groups belongs to to this mesh and is not this mesh
+  const int nbGroups = groups.length();
+  for ( int i = 0; i < nbGroups; ++i )
+  {
+    SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
+    if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
+      THROW_SALOME_CORBA_EXCEPTION("group does not belong to this mesh", SALOME::BAD_PARAM);
+    if ( SMESH::DownCast<SMESH_Mesh_i*>( groups[i] ))
+      THROW_SALOME_CORBA_EXCEPTION("expect a group but recieve a mesh", SALOME::BAD_PARAM);
+  }
+
+  TPythonDump pyDump;
+
+  int nbAdded = 0;
+  SMESH::SMESH_Mesh_var mesh_var;
+  SMESH::SMESH_Group_var group_var;
+
+  // get mesh to fill
+  mesh_var = SMESH::SMESH_Mesh::_duplicate( myMesh_i->_this() );
+  const bool toCopyMesh = ( strlen( meshName ) > 0 );
+  if ( toCopyMesh )
+  {
+    if ( toCopyAll )
+      mesh_var = SMESH_Gen_i::GetSMESHGen()->CopyMesh(mesh_var,
+                                                      meshName,
+                                                      /*toCopyGroups=*/false,
+                                                      /*toKeepIDs=*/true);
+    else
+      mesh_var = makeMesh(meshName);
+  }
+  SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh_var );
+  SMESH_Mesh*  tgtMesh = &mesh_i->GetImpl();
+
+  // source mesh
+  SMESH_Mesh*     srcMesh = ( toCopyMesh && !toCopyAll ) ? myMesh : tgtMesh;
+  SMESHDS_Mesh* srcMeshDS = srcMesh->GetMeshDS();
+
+  // group of new boundary elements
+  SMESH_Group* smesh_group = 0;
+  SMDSAbs_ElementType elemType = (dim == SMESH::BND_2DFROM3D) ? SMDSAbs_Volume : SMDSAbs_Face;
+  if ( strlen(groupName) )
+  {
+    SMESH::ElementType groupType = SMESH::ElementType( int(elemType)-1 );
+    group_var = mesh_i->CreateGroup( groupType, groupName );
+    if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>( group_var ))
+      smesh_group = group_i->GetSmeshGroup();
+  }
+
+  TIDSortedElemSet elements;
+
+  if ( nbGroups > 0 )
+  {
+    for ( int i = 0; i < nbGroups; ++i )
+    {
+      elements.clear();
+      if ( idSourceToSet( groups[i], srcMeshDS, elements, elemType,/*emptyIfIsMesh=*/false ))
+      {
+        SMESH::Bnd_Dimension bdim = 
+          ( elemType == SMDSAbs_Volume ) ? SMESH::BND_2DFROM3D : SMESH::BND_1DFROM2D;
+        ::SMESH_MeshEditor aMeshEditor( srcMesh );
+        nbAdded += aMeshEditor.MakeBoundaryMesh( elements,
+                                                 ::SMESH_MeshEditor::Bnd_Dimension(bdim),
+                                                 smesh_group,
+                                                 tgtMesh,
+                                                 /*toCopyElements=*/false,
+                                                 /*toCopyExistingBondary=*/srcMesh != tgtMesh,
+                                                 /*toAddExistingBondary=*/true,
+                                                 /*aroundElements=*/true);
+        storeResult( aMeshEditor );
+      }
+    }
+  }
+  else
+  {
+    ::SMESH_MeshEditor aMeshEditor( srcMesh );
+    nbAdded += aMeshEditor.MakeBoundaryMesh( elements,
+                                             ::SMESH_MeshEditor::Bnd_Dimension(dim),
+                                             smesh_group,
+                                             tgtMesh,
+                                             /*toCopyElements=*/false,
+                                             /*toCopyExistingBondary=*/srcMesh != tgtMesh,
+                                             /*toAddExistingBondary=*/true);
+    storeResult( aMeshEditor );
+  }
+  tgtMesh->GetMeshDS()->Modified();
+
+  const char* dimName[] = { "BND_2DFROM3D", "BND_1DFROM3D", "BND_1DFROM2D" };
+
+  // result of MakeBoundaryElements() is a tuple (nb, mesh, group)
+  pyDump << "nbAdded, ";
+  if ( mesh_var->_is_nil() )
+    pyDump << myMesh_i->_this() << ", ";
+  else
+    pyDump << mesh_var << ", ";
+  if ( group_var->_is_nil() )
+    pyDump << "_NoneGroup = "; // assignment to None is forbiden
+  else
+    pyDump << group_var << " = ";
+  pyDump << this << ".MakeBoundaryElements( "
+         << "SMESH." << dimName[int(dim)] << ", "
+         << "'" << groupName << "', "
+         << "'" << meshName<< "', "
+         << toCopyAll << ", "
+         << groups << ")";
+
+  mesh  = mesh_var._retn();
+  group = group_var._retn();
+  return nbAdded;
+}