Salome HOME
0021177: EDF 1563 SMESH: Preview of mesh during a modification
[modules/smesh.git] / src / SMESH_I / SMESH_MeshEditor_i.cxx
index 4ce4b901e6f9b165c43980d96be18fc4b2d5f4f1..bb155c7bcb0394e09f9fee7ad4afd298e5a5f39a 100644 (file)
@@ -234,7 +234,7 @@ namespace {
   }
   //================================================================================
   /*!
-   * \brief function for conversion long_array to TIDSortedElemSet
+   * \brief function for conversion of long_array to TIDSortedElemSet
    * \param IDs - array of IDs
    * \param aMesh - mesh
    * \param aMap - collection to fill
@@ -317,6 +317,50 @@ namespace {
           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
     }
   }
+
+  //================================================================================
+  /*!
+   * \brief Returns elements connected to the given elements
+   */
+  //================================================================================
+
+  void getElementsAround(const TIDSortedElemSet& theElements,
+                         const SMESHDS_Mesh*     theMeshDS,
+                         TIDSortedElemSet&       theElementsAround)
+  {
+    if ( theElements.empty() ) return;
+
+    SMDSAbs_ElementType elemType    = (*theElements.begin())->GetType();
+    bool sameElemType = ( elemType == (*theElements.rbegin())->GetType() );
+    if ( sameElemType &&
+         theMeshDS->GetMeshInfo().NbElements( elemType ) == theElements.size() )
+      return; // all the elements are in theElements
+
+    if ( !sameElemType )
+      elemType = SMDSAbs_All;
+
+    TIDSortedElemSet visitedNodes;
+    TIDSortedElemSet::const_iterator elemIt = theElements.begin();
+    for ( ; elemIt != theElements.end(); ++elemIt )
+    {
+      const SMDS_MeshElement* e = *elemIt;
+      int i = e->NbCornerNodes();
+      while ( --i != -1 )
+      {
+        const SMDS_MeshNode* n = e->GetNode( i );
+        if ( visitedNodes.insert( n ).second )
+        {
+          SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator(elemType);
+          while ( invIt->more() )
+          {
+            const SMDS_MeshElement* elemAround = invIt->next();
+            if ( !theElements.count( elemAround ))
+              theElementsAround.insert( elemAround );
+          }
+        }
+      }
+    }
+  }
 }
 
 //=============================================================================
@@ -1799,7 +1843,7 @@ SMESH::ListOfGroups*
 SMESH_MeshEditor_i::extrusionSweep(const SMESH::long_array & theIDsOfElements,
                                    const SMESH::DirStruct &  theStepVector,
                                    CORBA::Long               theNbOfSteps,
-                                   const bool                theMakeGroups,
+                                   bool                      theMakeGroups,
                                    const SMDSAbs_ElementType theElementType)
 {
   initData();
@@ -1816,16 +1860,14 @@ SMESH_MeshEditor_i::extrusionSweep(const SMESH::long_array & theIDsOfElements,
 
     TIDSortedElemSet* workElements = & elements;
     TPreviewMesh      tmpMesh( SMDSAbs_Face );
-    SMESH_Mesh*       mesh = 0;
+    SMESH_Mesh*       mesh = myMesh;
     
     if ( myPreviewMode ) {
       SMDSAbs_ElementType select = SMDSAbs_All, avoid = SMDSAbs_Volume;
       tmpMesh.Copy( elements, copyElements, select, avoid );
       mesh = &tmpMesh;
       workElements = & copyElements;
-    }
-    else {
-       mesh = myMesh;
+      theMakeGroups = false;
     }
 
     TElemOfElemListMap aHystory;
@@ -2208,7 +2250,7 @@ SMESH_MeshEditor_i::extrusionAlongPathX(const SMESH::long_array &  IDsOfElements
                                         CORBA::Boolean             LinearVariation,
                                         CORBA::Boolean             HasRefPoint,
                                         const SMESH::PointStruct&  RefPoint,
-                                        const bool                 MakeGroups,
+                                        bool                       MakeGroups,
                                         const SMDSAbs_ElementType  ElementType,
                                         SMESH::SMESH_MeshEditor::Extrusion_Error & Error)
 {
@@ -2233,7 +2275,7 @@ SMESH_MeshEditor_i::extrusionAlongPathX(const SMESH::long_array &  IDsOfElements
 
   TIDSortedElemSet* workElements = &elements;
   TPreviewMesh      tmpMesh( SMDSAbs_Face );
-  SMESH_Mesh*       mesh = 0;
+  SMESH_Mesh*       mesh = myMesh;
 
   if ( myPreviewMode )
   {
@@ -2241,17 +2283,14 @@ SMESH_MeshEditor_i::extrusionAlongPathX(const SMESH::long_array &  IDsOfElements
     tmpMesh.Copy( elements, copyElements, select, avoid );
     mesh = &tmpMesh;
     workElements = & copyElements;
-  }
-  else
-  {
-    mesh = myMesh;
+    MakeGroups = false;
   }
 
   ::SMESH_MeshEditor anEditor( mesh );
   ::SMESH_MeshEditor::Extrusion_Error error;
 
-  SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( Path );
-  if(aMeshImp) {
+  if ( SMESH_Mesh_i* aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( Path ))
+  {
     // path as mesh
     SMDS_MeshNode* aNodeStart =
       (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(NodeStart);
@@ -2264,36 +2303,34 @@ SMESH_MeshEditor_i::extrusionAlongPathX(const SMESH::long_array &  IDsOfElements
                                           HasRefPoint, refPnt, MakeGroups );
     myMesh->GetMeshDS()->Modified();
   }
-  else {
-    SMESH_subMesh_i* aSubMeshImp = SMESH::DownCast<SMESH_subMesh_i*>( Path );
-    if(aSubMeshImp) {
-      // path as submesh
-      SMESH::SMESH_Mesh_ptr aPathMesh = aSubMeshImp->GetFather();
-      aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( aPathMesh );
-      SMDS_MeshNode* aNodeStart =
-        (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(NodeStart);
-      if ( !aNodeStart ) {
-        Error = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
-        return EmptyGr;
-      }
-      SMESH_subMesh* aSubMesh =
-        aMeshImp->GetImpl().GetSubMeshContaining(aSubMeshImp->GetId());
-      error = anEditor.ExtrusionAlongTrack( *workElements, aSubMesh, aNodeStart,
-                                            HasAngles, angles, LinearVariation,
-                                            HasRefPoint, refPnt, MakeGroups );
-      myMesh->GetMeshDS()->Modified();
-    }
-    else {
-      SMESH_Group_i* aGroupImp = SMESH::DownCast<SMESH_Group_i*>( Path );
-      if(aGroupImp) {
-        // path as group of 1D elements
-      }
-      else {
-        // invalid path
-        Error = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
-        return EmptyGr;
-      }
+  else if ( SMESH_subMesh_i* aSubMeshImp = SMESH::DownCast<SMESH_subMesh_i*>( Path ))
+  {
+    // path as submesh
+    SMESH::SMESH_Mesh_ptr aPathMesh = aSubMeshImp->GetFather();
+    aMeshImp = SMESH::DownCast<SMESH_Mesh_i*>( aPathMesh );
+    SMDS_MeshNode* aNodeStart =
+      (SMDS_MeshNode*)aMeshImp->GetImpl().GetMeshDS()->FindNode(NodeStart);
+    if ( !aNodeStart ) {
+      Error = SMESH::SMESH_MeshEditor::EXTR_BAD_STARTING_NODE;
+      return EmptyGr;
     }
+    SMESH_subMesh* aSubMesh =
+      aMeshImp->GetImpl().GetSubMeshContaining(aSubMeshImp->GetId());
+    error = anEditor.ExtrusionAlongTrack( *workElements, aSubMesh, aNodeStart,
+                                          HasAngles, angles, LinearVariation,
+                                          HasRefPoint, refPnt, MakeGroups );
+    myMesh->GetMeshDS()->Modified();
+  }
+  else if ( SMESH::DownCast<SMESH_Group_i*>( Path ))
+  {
+    // path as group of 1D elements
+    // ????????
+  }
+  else
+  {
+    // invalid path
+    Error = SMESH::SMESH_MeshEditor::EXTR_BAD_PATH_SHAPE;
+    return EmptyGr;
   }
 
   storeResult(anEditor);
@@ -2891,7 +2928,7 @@ SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
                            const SMESH::AxisStruct &           theAxis,
                            SMESH::SMESH_MeshEditor::MirrorType theMirrorType,
                            CORBA::Boolean                      theCopy,
-                           const bool                          theMakeGroups,
+                           bool                                theMakeGroups,
                            ::SMESH_Mesh*                       theTargetMesh)
 {
   initData();
@@ -2911,21 +2948,23 @@ SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
     aTrsf.SetMirror( gp_Ax2( P, V ));
   }
 
-  TIDSortedElemSet copyElements;
+  TIDSortedElemSet  copyElements;
   TPreviewMesh      tmpMesh;
-  TIDSortedElemSet* workElements = 0;
-  SMESH_Mesh*       mesh = 0;
+  TIDSortedElemSet* workElements = & theElements;
+  SMESH_Mesh*       mesh = myMesh;
 
   if ( myPreviewMode )
   {
     tmpMesh.Copy( theElements, copyElements);
+    if ( !theCopy )
+    {
+      TIDSortedElemSet elemsAround, elemsAroundCopy;
+      getElementsAround( theElements, GetMeshDS(), elemsAround );
+      tmpMesh.Copy( elemsAround, elemsAroundCopy);
+    }
     mesh = &tmpMesh;
     workElements = & copyElements;
-  }
-  else
-  {
-    mesh = myMesh;
-    workElements = & theElements;
+    theMakeGroups = false;
   }
 
   ::SMESH_MeshEditor anEditor( mesh );
@@ -2935,11 +2974,10 @@ SMESH_MeshEditor_i::mirror(TIDSortedElemSet &                  theElements,
   if(theCopy || myPreviewMode)
     storeResult(anEditor);
   else
-    {
-      myMesh->GetMeshDS()->Modified();
-      myMesh->SetIsModified( true );
-    }
-
+  {
+    myMesh->SetIsModified( true );
+    myMesh->GetMeshDS()->Modified();
+  }
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
 }
 
@@ -3153,7 +3191,7 @@ SMESH::ListOfGroups*
 SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
                               const SMESH::DirStruct &  theVector,
                               CORBA::Boolean            theCopy,
-                              const bool                theMakeGroups,
+                              bool                      theMakeGroups,
                               ::SMESH_Mesh*             theTargetMesh)
 {
   initData();
@@ -3162,21 +3200,23 @@ SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
   const SMESH::PointStruct * P = &theVector.PS;
   aTrsf.SetTranslation( gp_Vec( P->x, P->y, P->z ));
 
-  TIDSortedElemSet copyElements;
+  TIDSortedElemSet  copyElements;
+  TIDSortedElemSet* workElements = &theElements;
   TPreviewMesh      tmpMesh;
-  TIDSortedElemSet* workElements = 0;
-  SMESH_Mesh*       mesh = 0;
+  SMESH_Mesh*       mesh = myMesh;
 
   if ( myPreviewMode )
   {
     tmpMesh.Copy( theElements, copyElements);
+    if ( !theCopy )
+    {
+      TIDSortedElemSet elemsAround, elemsAroundCopy;
+      getElementsAround( theElements, GetMeshDS(), elemsAround );
+      tmpMesh.Copy( elemsAround, elemsAroundCopy);
+    }
     mesh = &tmpMesh;
     workElements = & copyElements;
-  }
-  else
-  {
-    mesh = myMesh;
-    workElements = & theElements;
+    theMakeGroups = false;
   }
 
   ::SMESH_MeshEditor anEditor( mesh );
@@ -3186,10 +3226,10 @@ SMESH_MeshEditor_i::translate(TIDSortedElemSet        & theElements,
   if(theCopy || myPreviewMode)
     storeResult(anEditor);
   else
-    {
-      myMesh->GetMeshDS()->Modified();
-      myMesh->SetIsModified( true );
-    }
+  {
+    myMesh->GetMeshDS()->Modified();
+    myMesh->SetIsModified( true );
+  }
 
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
 }
@@ -3389,7 +3429,7 @@ SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
                            const SMESH::AxisStruct & theAxis,
                            CORBA::Double             theAngle,
                            CORBA::Boolean            theCopy,
-                           const bool                theMakeGroups,
+                           bool                      theMakeGroups,
                            ::SMESH_Mesh*             theTargetMesh)
 {
   initData();
@@ -3400,20 +3440,22 @@ SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
   gp_Trsf aTrsf;
   aTrsf.SetRotation( gp_Ax1( P, V ), theAngle);
 
-  TIDSortedElemSet copyElements;
+  TIDSortedElemSet  copyElements;
+  TIDSortedElemSet* workElements = &theElements;
   TPreviewMesh      tmpMesh;
-  TIDSortedElemSet* workElements = 0;
-  SMESH_Mesh*       mesh = 0;
+  SMESH_Mesh*       mesh = myMesh;
 
   if ( myPreviewMode ) {
     tmpMesh.Copy( theElements, copyElements );
+    if ( !theCopy )
+    {
+      TIDSortedElemSet elemsAround, elemsAroundCopy;
+      getElementsAround( theElements, GetMeshDS(), elemsAround );
+      tmpMesh.Copy( elemsAround, elemsAroundCopy);
+    }
     mesh = &tmpMesh;
     workElements = &copyElements;
-  }
-  else
-  {
-    mesh = myMesh;
-    workElements=&theElements;
+    theMakeGroups = false;
   }
 
   ::SMESH_MeshEditor anEditor( mesh );
@@ -3423,10 +3465,10 @@ SMESH_MeshEditor_i::rotate(TIDSortedElemSet &        theElements,
   if(theCopy || myPreviewMode)
     storeResult(anEditor);
   else
-    {
-      myMesh->GetMeshDS()->Modified();
-      myMesh->SetIsModified( true );
-    }
+  {
+    myMesh->GetMeshDS()->Modified();
+    myMesh->SetIsModified( true );
+  }
 
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
 }
@@ -3640,7 +3682,7 @@ SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
                           const SMESH::PointStruct&  thePoint,
                           const SMESH::double_array& theScaleFact,
                           CORBA::Boolean             theCopy,
-                          const bool                 theMakeGroups,
+                          bool                       theMakeGroups,
                           ::SMESH_Mesh*              theTargetMesh)
 {
   initData();
@@ -3654,31 +3696,34 @@ SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
   if ( !idSourceToSet(theObject, GetMeshDS(), elements, SMDSAbs_All, emptyIfIsMesh))
     return 0;
 
-  vector<double> S(3);
-  S[0] = theScaleFact[0];
-  S[1] = (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1];
-  S[2] = (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2];
+  double S[3] = {
+    theScaleFact[0],
+    (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[1],
+    (theScaleFact.length() == 1) ? theScaleFact[0] : theScaleFact[2],
+  };
   double tol = std::numeric_limits<double>::max();
   gp_Trsf aTrsf;
   aTrsf.SetValues( S[0], 0,    0,    thePoint.x * (1-S[0]),
                    0,    S[1], 0,    thePoint.y * (1-S[1]),
                    0,    0,    S[2], thePoint.z * (1-S[2]),   tol, tol);
 
-  TIDSortedElemSet copyElements;
+  TIDSortedElemSet  copyElements;
   TPreviewMesh      tmpMesh;
-  TIDSortedElemSet* workElements = 0;
-  SMESH_Mesh*       mesh = 0;
+  TIDSortedElemSet* workElements = &elements;
+  SMESH_Mesh*       mesh = myMesh;
   
   if ( myPreviewMode )
   {
     tmpMesh.Copy( elements, copyElements);
+    if ( !theCopy )
+    {
+      TIDSortedElemSet elemsAround, elemsAroundCopy;
+      getElementsAround( elements, GetMeshDS(), elemsAround );
+      tmpMesh.Copy( elemsAround, elemsAroundCopy);
+    }
     mesh = &tmpMesh;
     workElements = & copyElements;
-  }
-  else
-  {
-    mesh = myMesh;
-    workElements = & elements;
+    theMakeGroups = false;
   }
 
   ::SMESH_MeshEditor anEditor( mesh );
@@ -3688,10 +3733,10 @@ SMESH_MeshEditor_i::scale(SMESH::SMESH_IDSource_ptr  theObject,
   if(theCopy || myPreviewMode )
     storeResult(anEditor);
   else
-    {
-      myMesh->GetMeshDS()->Modified();
-      myMesh->SetIsModified( true );
-    }
+  {
+    myMesh->GetMeshDS()->Modified();
+    myMesh->SetIsModified( true );
+  }
   return theMakeGroups ? getGroups(groupIds.get()) : 0;
 }
 
@@ -4645,18 +4690,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();
   }
 }
 
@@ -5524,7 +5573,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;
@@ -5561,6 +5609,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" };
@@ -5585,3 +5636,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 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;
+}