Salome HOME
23617: EDF 14133 - Complete Merge Nodes / Merge Elements operations
authoreap <eap@opencascade.com>
Fri, 18 Jan 2019 18:31:22 +0000 (21:31 +0300)
committereap <eap@opencascade.com>
Fri, 18 Jan 2019 18:31:22 +0000 (21:31 +0300)
+
1) fix bug that SMESH_MeshEditor::DoubleElements() can't duplicate all
   elements if they are of different dimension
2) Add QString GetName( Handle(SALOME_InteractiveObject)& ) that gets
   missing name from SObject.

18 files changed:
doc/salome/examples/transforming_meshes_ex05.py
doc/salome/examples/transforming_meshes_ex06.py
doc/salome/gui/SMESH/images/mergeelems.png
doc/salome/gui/SMESH/images/mergeelems_auto.png
doc/salome/gui/SMESH/images/mergenodes.png
doc/salome/gui/SMESH/images/mergenodes_auto.png
doc/salome/gui/SMESH/input/merging_elements.rst
doc/salome/gui/SMESH/input/merging_nodes.rst
idl/SMESH_MeshEditor.idl
src/SMESH/SMESH_MeshEditor.cxx
src/SMESHGUI/SMESHGUI_MergeDlg.cxx
src/SMESHGUI/SMESHGUI_MergeDlg.h
src/SMESHGUI/SMESHGUI_Utils.cxx
src/SMESHGUI/SMESHGUI_Utils.h
src/SMESHGUI/SMESH_msg_en.ts
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_I/SMESH_MeshEditor_i.hxx
src/SMESH_SWIG/smeshBuilder.py

index deba1c4..0adf024 100644 (file)
@@ -1,14 +1,24 @@
 # Merging Nodes
 
 import SMESH_mechanic, SMESH
-mesh = SMESH_mechanic.mesh
+mesh  = SMESH_mechanic.mesh
+smesh = SMESH_mechanic.smesh
 
-# merge nodes
+# criterion of coincidence
 Tolerance = 4.0
 
+# find close nodes of triangle elements only
+triangleFilter = smesh.GetFilter( SMESH.FACE, SMESH.FT_ElemGeomType,'=', SMESH.Geom_TRIANGLE )
+GroupsOfNodesOfTriangles = mesh.FindCoincidentNodesOnPart([triangleFilter],Tolerance)
+
 # prevent nodes located on geom edges from removal during merge:
 # create a group including all nodes on edges
 allSegs = mesh.MakeGroup( "all segments", SMESH.EDGE, SMESH.FT_ElemGeomType,'=', SMESH.Geom_EDGE )
 
-GroupsOfNodes =  mesh.FindCoincidentNodes(Tolerance)
+mesh.MergeNodes(GroupsOfNodesOfTriangles, NodesToKeep=allSegs)
+
+
+# find close nodes in the whole mesh
+GroupsOfNodes = mesh.FindCoincidentNodes(Tolerance)
+
 mesh.MergeNodes(GroupsOfNodes, NodesToKeep=allSegs)
index 1d973da..433ae19 100644 (file)
@@ -3,11 +3,10 @@
 
 import salome
 salome.salome_init()
-import GEOM
 from salome.geom import geomBuilder
 geompy = geomBuilder.New()
 
-import SMESH, SALOMEDS
+import SMESH
 from salome.smesh import smeshBuilder
 smesh =  smeshBuilder.New()
 
@@ -43,6 +42,9 @@ algo2D.LengthFromEdges()
 
 trias.Compute()
 
+# create a group of all triangles currently present in the mesh
+faceTriGroup = trias.Group( face1, "face triangles" )
+
 # create a path mesh
 circlemesh = smesh.Mesh(circle, "Path mesh")
 algo = circlemesh.Segment()
@@ -50,14 +52,19 @@ algo.NumberOfSegments(10)
 circlemesh.Compute()
 
 # extrusion of the mesh
-trias.ExtrusionAlongPath([], circlemesh, circle,
-                         1, 0, [], 0, SMESH.PointStruct(0, 0, 0))
+trias.ExtrusionAlongPath([], circlemesh, circle, 1, MakeGroups=True )
+
+# get a group "opposite" to faceTriGroup within the generated prismatic mesh
+oppositeGroup = trias.GetGroupByName( faceTriGroup.GetName() + "_top" )[0]
+
+# get edges of the groups
+edgeGroup = trias.CreateDimGroup([ faceTriGroup, oppositeGroup ], SMESH.EDGE, "face edges")
 
-# merge nodes
+# merge nodes of the groups only
 print("Number of nodes before MergeNodes:", end=' ') 
 trias.NbNodes()
 tolerance = 0.001
-array_of_nodes_groups = trias.FindCoincidentNodes(tolerance)
+array_of_nodes_groups = trias.FindCoincidentNodesOnPart([faceTriGroup, oppositeGroup], tolerance)
 
 trias.MergeNodes(array_of_nodes_groups)
 
@@ -65,16 +72,15 @@ print("Number of nodes after MergeNodes:", trias.NbNodes())
 print("")
 print("Number of elements before MergeEqualElements:")
 print("Edges      : ", trias.NbEdges())
-print("Triangles  : ", trias.NbTriangles())
-print("Quadrangles: ", trias.NbQuadrangles())
+print("Faces      : ", trias.NbFaces())
 print("Volumes    : ", trias.NbVolumes())
 
-# merge elements
-trias.MergeEqualElements()
+# merge elements of the groups
+equalFaces = trias.FindEqualElements( [faceTriGroup, oppositeGroup, edgeGroup] )
+trias.MergeElements( equalFaces )
 print("Number of elements after MergeEqualElements:")
 print("Edges      : ", trias.NbEdges())
-print("Triangles  : ", trias.NbTriangles())
-print("Quadrangles: ", trias.NbQuadrangles())
+print("Faces      : ", trias.NbFaces())
 print("Volumes    : ", trias.NbVolumes())
 
 salome.sg.updateObjBrowser()
index 40d614f..f35955a 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/mergeelems.png and b/doc/salome/gui/SMESH/images/mergeelems.png differ
index 6e2b306..ffbb092 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/mergeelems_auto.png and b/doc/salome/gui/SMESH/images/mergeelems_auto.png differ
index fc75f70..2676025 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/mergenodes.png and b/doc/salome/gui/SMESH/images/mergenodes.png differ
index e270469..e01aacc 100644 (file)
Binary files a/doc/salome/gui/SMESH/images/mergenodes_auto.png and b/doc/salome/gui/SMESH/images/mergenodes_auto.png differ
index 43a2709..628e364 100644 (file)
@@ -17,10 +17,23 @@ To merge elements choose in the main menu **Modification** -> **Transformation**
 .. image:: ../images/mergeelems_auto.png
        :align: center
 
+.. |ad| image:: ../images/add.png
+.. |rm| image:: ../images/remove.png
+.. |mv| image:: ../images/sort.png
+
 In this dialog:
 
-       * **Name** is the name of the mesh object whose elements will be merged. 
+       * **Names** contains names of the selected mesh objects whose elements will be merged.
        * **Automatic** or **Manual** Mode allows choosing how the elements are processed. In the **Automatic** Mode all elements created on the same nodes will be merged. In **Manual** mode you can adjust groups of coincident elements detected by the program.
+       * **Exclude groups from detection** group allows to ignore the elements which belong to the specified mesh groups. This control is active provided that the mesh includes groups.
+       * **Elements to keep during the merge** group allows to specify elements to keep in the mesh. (By default an element being the first in a group of coincident elements is kept.) It is possible to either select elements in the Viewer or select groups whose elements will be kept.
+  
+               * *Selection* button activates selection of elements to keep.
+               * **Elements** button activates selection of elements in the Viewer.
+               * **Groups and sub-meshes** button activates selection of groups and sub-meshes.
+               * **Add** button adds selected elements or groups to the list.
+               * Elements or groups selected in the list can be removed using **Remove** button.
+
 
          If the **Manual** Mode is selected, additional controls are available:
 
@@ -36,20 +49,9 @@ In this dialog:
                * **Show double elements IDs** check-box shows/hides identifiers of elements of the selected groups in the 3D viewer.
                * **Edit selected group of coincident elements** list allows editing the selected group:
     
-                        .. image:: ../images/add.png
-                           :align: center
-
-                       * adds to the group the elements selected in the viewer.
-    
-                       .. image:: ../images/remove.png
-                           :align: center
-
-                       * removes the selected elements from the group.
-    
-                        .. image:: ../images/sort.png
-                           :align: center
-
-                       * moves the selected element to the first position in the group in order to keep it in the mesh.
+                       * |ad| adds to the group the elements selected in the viewer.
+                       * |rm| removes the selected elements from the group.
+                       * |mv| moves the selected element to the first position in the group in order to keep it in the mesh.
     
   
 
index e7bba52..18096ba 100644 (file)
@@ -12,14 +12,18 @@ This functionality allows user to detect groups of coincident nodes with specifi
 .. centered::
        *"Merge nodes"* menu button
 
+.. |ad| image:: ../images/add.png
+.. |rm| image:: ../images/remove.png
+.. |mv| image:: ../images/sort.png
+
 *To merge nodes of your mesh:*
 
 #. Choose **Modification** -> **Transformation** -> **Merge nodes** menu item. The following dialog box shall appear:
 
        .. image:: ../images/mergenodes_auto.png
                :align: center
-
-       * **Name** is the name of the mesh whose nodes will be merged.
+        
+       * **Names** contains names of the selected mesh objects whose nodes will be merged.
        * **Automatic** or **Manual** mode allows choosing how the nodes are processed. In **Manual** mode you can adjust groups of coincident nodes detected by the program and/or select any nodes to be merged.
        * **Tolerance** is a maximum distance between nodes sufficient for merging.
        * Activation of **No merge of corner and medium nodes of quadratic cells** check-box prevents merging medium nodes of quadratic elements with corner nodes. This check-box is enabled provided that the selected mesh includes quadratic elements.
@@ -53,20 +57,9 @@ This functionality allows user to detect groups of coincident nodes with specifi
 
        * **Edit selected group of coincident nodes** list allows editing the selected group:
     
-          .. image:: ../images/add.png
-             :align: center
-
-         * adds to the group the nodes selected in the viewer.
-    
-          .. image:: ../images/remove.png
-             :align: center
-
-         * removes from the group the selected nodes.
-    
-          .. image:: ../images/sort.png
-             :align: center
-
-         * moves the selected node to the first position in the group in order to keep it in the mesh.
+         * |ad| adds to the group the nodes selected in the viewer.
+         * |rm| removes from the group the selected nodes.
+         * |mv| moves the selected node to the first position in the group in order to keep it in the mesh.
 
 #. To confirm your choice click **Apply** or **Apply and Close** button.
 
index 9491b92..482f8e9 100644 (file)
@@ -723,7 +723,7 @@ module SMESH
                                     in  boolean             SeparateCornersAndMedium)
       raises (SALOME::SALOME_Exception);
 
-    void FindCoincidentNodesOnPartBut (in  SMESH_IDSource      SubMeshOrGroup,
+    void FindCoincidentNodesOnPartBut (in  ListOfIDSources     SubMeshOrGroup,
                                        in  double              Tolerance,
                                        out array_of_long_array GroupsOfNodes,
                                        in  ListOfIDSources     ExceptSubMeshOrGroups,
@@ -740,7 +740,8 @@ module SMESH
      * \param MeshOrSubMeshOrGroup Mesh or SubMesh, or Group of elements for searching.
      * \return List of groups of equal elements.
      */
-    void FindEqualElements (in  SMESH_IDSource      MeshOrSubMeshOrGroup,
+    void FindEqualElements (in  ListOfIDSources     MeshOrSubMeshOrGroup,
+                            in  ListOfIDSources     ExceptSubMeshOrGroups,
                             out array_of_long_array GroupsOfElementsID) 
       raises (SALOME::SALOME_Exception);
 
@@ -748,7 +749,8 @@ module SMESH
      * \brief Merge elements in each given group.
      * \param GroupsOfElementsID Groups of elements for merging.
      */
-    void MergeElements(in array_of_long_array GroupsOfElementsID) 
+    void MergeElements(in array_of_long_array    GroupsOfElementsID,
+                       in SMESH::ListOfIDSources ElementsToKeep) 
       raises (SALOME::SALOME_Exception);
 
     /*!
index 6ec5305..81db6b6 100644 (file)
@@ -10941,7 +10941,7 @@ void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
   }
   else
   {
-    type = (*theElements.begin())->GetType();
+    //type = (*theElements.begin())->GetType();
     elemIt = SMESHUtils::elemSetIterator( theElements );
   }
 
@@ -10956,7 +10956,8 @@ void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
   while ( elemIt->more() )
   {
     const SMDS_MeshElement* elem = elemIt->next();
-    if ( elem->GetType() != type || elem->isMarked() )
+    if (( type != SMDSAbs_All && elem->GetType() != type ) ||
+        ( elem->isMarked() ))
       continue;
 
     elemType.Init( elem, /*basicOnly=*/false );
index 6bba063..f76bab4 100644 (file)
@@ -114,9 +114,10 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
     mySelectionMgr(SMESH::GetSelectionMgr(theModule)),
     myAction(theAction)
 {
+  const bool isElems = ( myAction == MERGE_ELEMENTS );
   setModal(false);
   setAttribute(Qt::WA_DeleteOnClose, true);
-  setWindowTitle(myAction == MERGE_ELEMENTS ? tr("SMESH_MERGE_ELEMENTS") : tr("SMESH_MERGE_NODES"));
+  setWindowTitle( isElems ? tr("SMESH_MERGE_ELEMENTS") : tr("SMESH_MERGE_NODES"));
 
   myIdPreview = new SMESHGUI_IdPreview(SMESH::GetViewWindow( mySMESHGUI ));
 
@@ -155,7 +156,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   GroupMeshLayout->setSpacing(SPACING);
   GroupMeshLayout->setMargin(MARGIN);
 
-  TextLabelName = new QLabel(tr("SMESH_NAME"), GroupMesh);
+  TextLabelName = new QLabel(tr("SMESH_NAMES"), GroupMesh);
   SelectMeshButton = new QPushButton(GroupMesh);
   SelectMeshButton->setIcon(IconSelect);
   LineEditMesh = new QLineEdit(GroupMesh);
@@ -168,10 +169,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   /***************************************************************/
   // Controls for coincident elements detecting
 
-  GroupCoincident = new QGroupBox(myAction == MERGE_ELEMENTS ?
-                                  tr("COINCIDENT_ELEMENTS") :
-                                  tr("COINCIDENT_NODES"),
-                                  this);
+  GroupCoincident = new QGroupBox(tr(isElems ? "COINCIDENT_ELEMENTS" : "COINCIDENT_NODES"), this);
 
   QGridLayout* aCoincidentLayout = new QGridLayout(GroupCoincident);
   aCoincidentLayout->setSpacing(SPACING);
@@ -202,55 +200,6 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
     NodeSpecLayout->addWidget(SpinBoxTolerance,         0, 1 );
     NodeSpecLayout->addWidget(SeparateCornersAndMedium, 1, 0, 1, 2 );
     NodeSpecLayout->addWidget(AvoidMakingHoles,         2, 0, 1, 2 );
-
-    /***************************************************************/
-    // Exclude groups
-
-    GroupExclude = new QGroupBox(tr("EXCLUDE_GROUPS"), this );
-    GroupExclude->setCheckable( true );
-    GroupExclude->setChecked( false );
-    ListExclude = new QListWidget( GroupExclude );
-    QVBoxLayout* GroupExcludeLayout = new QVBoxLayout(GroupExclude);
-    GroupExcludeLayout->setSpacing(SPACING);
-    GroupExcludeLayout->setMargin(MARGIN);
-    GroupExcludeLayout->addWidget(ListExclude);
-
-    /***************************************************************/
-    // Nodes to keep
-
-    GroupKeep = new QGroupBox(tr("KEEP_NODES"), this);
-    SelectKeepNodesButton = new QPushButton( GroupKeep );
-    SelectKeepNodesButton->setIcon( IconSelect );
-    QLabel*       selectLabel = new QLabel(tr("SELECT"));
-    QRadioButton*   idsButton = new QRadioButton(tr("SMESH_NODES"), GroupKeep);
-    QRadioButton* groupButton = new QRadioButton(tr("GROUP_SUBMESH"), GroupKeep);
-    KeepFromButGroup = new QButtonGroup( this );
-    KeepFromButGroup->addButton( idsButton,   0 );
-    KeepFromButGroup->addButton( groupButton, 1 );
-    groupButton->setChecked( true );
-    KeepList = new QListWidget( GroupKeep );
-    KeepList->setSelectionMode(QAbstractItemView::ExtendedSelection);
-    KeepList->setFlow(QListView::TopToBottom);
-    AddKeepNodesButton    = new QPushButton(tr("SMESH_BUT_ADD"), GroupKeep );
-    RemoveKeepNodesButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupKeep );
-    QGridLayout* GroupKeepLayout = new QGridLayout(GroupKeep);
-    GroupKeepLayout->setSpacing( SPACING );
-    GroupKeepLayout->setMargin ( MARGIN );
-    GroupKeepLayout->addWidget( SelectKeepNodesButton, 0, 0 );
-    GroupKeepLayout->addWidget( selectLabel,           0, 1 );
-    GroupKeepLayout->addWidget( idsButton,             0, 2 );
-    GroupKeepLayout->addWidget( groupButton,           0, 3, 1, 2 );
-    GroupKeepLayout->addWidget( KeepList,              1, 0, 3, 4 );
-    GroupKeepLayout->addWidget( AddKeepNodesButton,    1, 4, 1, 1 );
-    GroupKeepLayout->addWidget( RemoveKeepNodesButton, 2, 4, 1, 1 );
-    GroupKeepLayout->setRowStretch(3, 5);
-
-    // Costruction of the logical filter
-    QList<SUIT_SelectionFilter*> aListOfFilters;
-    aListOfFilters << new SMESH_TypeFilter (SMESH::SUBMESH)
-                   << new SMESH_TypeFilter (SMESH::GROUP);
-    mySubMeshOrGroupFilter =
-      new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true);
   }
   else {
     NodeSpecWidget         = 0;
@@ -258,13 +207,63 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
     GroupExclude           = 0;
     ListExclude            = 0;
     KeepFromButGroup       = 0;
-    SelectKeepNodesButton  = 0;
-    AddKeepNodesButton     = 0;
-    RemoveKeepNodesButton  = 0;
+    SelectKeepButton  = 0;
+    AddKeepButton     = 0;
+    RemoveKeepButton  = 0;
     KeepList               = 0;
     mySubMeshOrGroupFilter = 0;
   }
 
+  /***************************************************************/
+  // Exclude groups
+
+  GroupExclude = new QGroupBox(tr("EXCLUDE_GROUPS"), this );
+  GroupExclude->setCheckable( true );
+  GroupExclude->setChecked( false );
+  ListExclude = new QListWidget( GroupExclude );
+  QVBoxLayout* GroupExcludeLayout = new QVBoxLayout(GroupExclude);
+  GroupExcludeLayout->setSpacing(SPACING);
+  GroupExcludeLayout->setMargin(MARGIN);
+  GroupExcludeLayout->addWidget(ListExclude);
+
+  /***************************************************************/
+  // Nodes/elements to keep
+
+  GroupKeep = new QGroupBox(tr( isElems ? "KEEP_ELEMENTS" : "KEEP_NODES"), this);
+  SelectKeepButton = new QPushButton( GroupKeep );
+  SelectKeepButton->setIcon( IconSelect );
+  QLabel*       selectLabel = new QLabel(tr("SELECT"));
+  QRadioButton*   idsButton = new QRadioButton(tr(isElems ? "SMESH_ELEMENTS" : "SMESH_NODES"),
+                                               GroupKeep);
+  QRadioButton* groupButton = new QRadioButton(tr("GROUP_SUBMESH"), GroupKeep);
+  KeepFromButGroup = new QButtonGroup( this );
+  KeepFromButGroup->addButton( idsButton,   0 );
+  KeepFromButGroup->addButton( groupButton, 1 );
+  groupButton->setChecked( true );
+  KeepList = new QListWidget( GroupKeep );
+  KeepList->setSelectionMode(QAbstractItemView::ExtendedSelection);
+  KeepList->setFlow(QListView::TopToBottom);
+  AddKeepButton    = new QPushButton(tr("SMESH_BUT_ADD"), GroupKeep );
+  RemoveKeepButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupKeep );
+  QGridLayout* GroupKeepLayout = new QGridLayout(GroupKeep);
+  GroupKeepLayout->setSpacing( SPACING );
+  GroupKeepLayout->setMargin ( MARGIN );
+  GroupKeepLayout->addWidget( SelectKeepButton, 0, 0 );
+  GroupKeepLayout->addWidget( selectLabel,           0, 1 );
+  GroupKeepLayout->addWidget( idsButton,             0, 2 );
+  GroupKeepLayout->addWidget( groupButton,           0, 3, 1, 2 );
+  GroupKeepLayout->addWidget( KeepList,              1, 0, 3, 4 );
+  GroupKeepLayout->addWidget( AddKeepButton,    1, 4, 1, 1 );
+  GroupKeepLayout->addWidget( RemoveKeepButton, 2, 4, 1, 1 );
+  GroupKeepLayout->setRowStretch(3, 5);
+
+  // Costruction of the logical filter
+  QList<SUIT_SelectionFilter*> aListOfFilters;
+  aListOfFilters << new SMESH_TypeFilter (SMESH::SUBMESH)
+                 << new SMESH_TypeFilter (SMESH::GROUP);
+  mySubMeshOrGroupFilter =
+    new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, /*takeOwnership=*/true);
+
   ListCoincident = new QListWidget(GroupCoincident);
   ListCoincident->setSelectionMode(QListWidget::ExtendedSelection);
 
@@ -273,7 +272,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   RemoveGroupButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupCoincident);
 
   SelectAllCB = new QCheckBox(tr("SELECT_ALL"), GroupCoincident);
-  ShowIDs = new QCheckBox(myAction == MERGE_ELEMENTS ? tr("SHOW_ELEMS_IDS") : tr("SHOW_NODES_IDS"), GroupCoincident);
+  ShowIDs = new QCheckBox( isElems ? tr("SHOW_ELEMS_IDS") : tr("SHOW_NODES_IDS"), GroupCoincident);
 
   aCoincidentLayout->addWidget(ListCoincident,    0, 0, 4, 2);
   aCoincidentLayout->addWidget(DetectButton,      0, 2);
@@ -287,9 +286,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   /***************************************************************/
   // Controls for editing the selected group
 
-  GroupEdit = new QGroupBox(myAction == MERGE_NODES ?
-                            tr("EDIT_SELECTED_NODE_GROUP") :
-                            tr("EDIT_SELECTED_ELEM_GROUP"), this);
+  GroupEdit = new QGroupBox( tr(isElems ? "EDIT_SELECTED_ELEM_GROUP" : "EDIT_SELECTED_NODE_GROUP"), this);
   QGridLayout* GroupEditLayout = new QGridLayout(GroupEdit);
   GroupEditLayout->setSpacing(SPACING);
   GroupEditLayout->setMargin(MARGIN);
@@ -338,7 +335,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   GroupButtonsLayout->addWidget(buttonHelp);
 
   /***************************************************************/
-  if (myAction == MERGE_NODES)
+  //if (myAction == MERGE_NODES)
   {
     QWidget* LeftWdg = new QWidget( this );
     QVBoxLayout* LeftLayout = new QVBoxLayout(LeftWdg);
@@ -346,7 +343,8 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
     LeftLayout->setMargin(0);
     LeftLayout->addWidget(TypeBox);
     LeftLayout->addWidget(GroupMesh);
-    LeftLayout->addWidget(NodeSpecWidget);
+    if ( !isElems )
+      LeftLayout->addWidget(NodeSpecWidget);
     LeftLayout->addWidget(GroupCoincident);
     LeftLayout->addStretch();
     LeftLayout->addWidget(GroupButtons);
@@ -368,17 +366,17 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
     DlgLayout->addWidget( LeftWdg );
     DlgLayout->addWidget( RightWdg );
   }
-  else
-  {
-    QVBoxLayout* DlgLayout = new QVBoxLayout(this);
-    DlgLayout->setSpacing(SPACING);
-    DlgLayout->setMargin(MARGIN);
-    DlgLayout->addWidget(TypeBox);
-    DlgLayout->addWidget(GroupMesh);
-    DlgLayout->addWidget(GroupCoincident);
-    DlgLayout->addWidget(GroupEdit);
-    DlgLayout->addWidget(GroupButtons);
-  }
+  // else
+  // {
+  //   QVBoxLayout* DlgLayout = new QVBoxLayout(this);
+  //   DlgLayout->setSpacing(SPACING);
+  //   DlgLayout->setMargin(MARGIN);
+  //   DlgLayout->addWidget(TypeBox);
+  //   DlgLayout->addWidget(GroupMesh);
+  //   DlgLayout->addWidget(GroupCoincident);
+  //   DlgLayout->addWidget(GroupEdit);
+  //   DlgLayout->addWidget(GroupButtons);
+  // }
 
   GroupCoincident->hide();
   GroupEdit->hide();
@@ -415,7 +413,7 @@ void SMESHGUI_MergeDlg::Init()
   myEditCurrentArgument = (QWidget*)LineEditMesh;
 
   myActor = 0;
-  mySubMeshOrGroup = SMESH::SMESH_subMesh::_nil();
+  mySubMeshOrGroups = new SMESH::ListOfIDSources;
 
   mySelector = (SMESH::GetViewWindow( mySMESHGUI ))->GetSelector();
 
@@ -430,11 +428,11 @@ void SMESHGUI_MergeDlg::Init()
 
   if ( KeepList )
   {
-    connect(SelectKeepNodesButton, SIGNAL (clicked()), this, SLOT(SetEditCurrentArgument()));
-    connect(KeepFromButGroup, SIGNAL (buttonClicked(int)), SLOT(onKeepNodeSourceChanged(int)));
-    connect(AddKeepNodesButton, SIGNAL (clicked()), this, SLOT(onAddKeepNode()));
-    connect(RemoveKeepNodesButton, SIGNAL (clicked()), this, SLOT(onRemoveKeepNode()));
-    connect(KeepList, SIGNAL (itemSelectionChanged()), this, SLOT(onSelectKeepNode()));
+    connect(SelectKeepButton, SIGNAL (clicked()), this, SLOT(SetEditCurrentArgument()));
+    connect(KeepFromButGroup, SIGNAL (buttonClicked(int)), SLOT(onKeepSourceChanged(int)));
+    connect(AddKeepButton, SIGNAL (clicked()), this, SLOT(onAddKeep()));
+    connect(RemoveKeepButton, SIGNAL (clicked()), this, SLOT(onRemoveKeep()));
+    connect(KeepList, SIGNAL (itemSelectionChanged()), this, SLOT(onSelectKeep()));
   }
   connect(SelectMeshButton, SIGNAL (clicked()), this, SLOT(SetEditCurrentArgument()));
   connect(DetectButton, SIGNAL (clicked()), this, SLOT(onDetect()));
@@ -539,7 +537,8 @@ bool SMESHGUI_MergeDlg::ClickOnApply()
     aGroupsOfElements->length(ListCoincident->count());
 
     int anArrayNum = 0;
-    for (int i = 0; i < ListCoincident->count(); i++) {
+    for (int i = 0; i < ListCoincident->count(); i++)
+    {
       QStringList aListIds = ListCoincident->item(i)->text().split(" ", QString::SkipEmptyParts);
 
       anIds->length(aListIds.count());
@@ -549,13 +548,13 @@ bool SMESHGUI_MergeDlg::ClickOnApply()
       aGroupsOfElements[anArrayNum++] = anIds.inout();
     }
 
-    SMESH::ListOfIDSources_var nodesToKeep;
+    SMESH::ListOfIDSources_var toKeep;
     SMESH::IDSource_wrap tmpIdSource;
-    if ( myAction == MERGE_NODES )
+    //if ( myAction == MERGE_NODES )
     {
-      nodesToKeep = new SMESH::ListOfIDSources();
+      toKeep = new SMESH::ListOfIDSources();
       int i, nb = KeepList->count();
-      if ( isKeepNodesIDsSelection() )
+      if ( isKeepIDsSelection() )
       {
         SMESH::long_array_var anIdList = new SMESH::long_array();
         anIdList->length(nb);
@@ -565,13 +564,13 @@ bool SMESHGUI_MergeDlg::ClickOnApply()
         if ( nb > 0 )
         {
           tmpIdSource = aMeshEditor->MakeIDSource( anIdList, SMESH::NODE );
-          nodesToKeep->length( 1 );
-          nodesToKeep[0] = SMESH::SMESH_IDSource::_duplicate( tmpIdSource.in() );
+          toKeep->length( 1 );
+          toKeep[0] = SMESH::SMESH_IDSource::_duplicate( tmpIdSource.in() );
         }
       }
       else
       {
-        nodesToKeep->length( nb );
+        toKeep->length( nb );
         int nbObj = 0;
         for (i = 0; i < nb; i++)
         {
@@ -581,17 +580,17 @@ bool SMESHGUI_MergeDlg::ClickOnApply()
           SMESH::SMESH_IDSource_var idSrc =
             SMESH::IObjectToInterface<SMESH::SMESH_IDSource>( anIO );
           if ( !idSrc->_is_nil() )
-            nodesToKeep[ nbObj++ ] = SMESH::SMESH_IDSource::_duplicate( idSrc );
+            toKeep[ nbObj++ ] = SMESH::SMESH_IDSource::_duplicate( idSrc );
         }
-        nodesToKeep->length( nbObj );
+        toKeep->length( nbObj );
       }
       KeepList->clear();
     }
 
     if( myAction == MERGE_NODES )
-      aMeshEditor->MergeNodes( aGroupsOfElements.inout(), nodesToKeep, AvoidMakingHoles->isChecked() );
+      aMeshEditor->MergeNodes( aGroupsOfElements.inout(), toKeep, AvoidMakingHoles->isChecked() );
     else
-      aMeshEditor->MergeElements( aGroupsOfElements.inout() );
+      aMeshEditor->MergeElements( aGroupsOfElements.inout(), toKeep );
 
     if ( myTypeId == TYPE_AUTO ) {
       if ( myAction == MERGE_NODES )
@@ -601,8 +600,8 @@ bool SMESHGUI_MergeDlg::ClickOnApply()
         SUIT_MessageBox::information(SMESHGUI::desktop(), tr("SMESH_INFORMATION"),
                                      tr("SMESH_MERGED_ELEMENTS").arg(QString::number(ListCoincident->count()).toLatin1().data()));
     }
-    if ( & nodesToKeep.in() )
-      nodesToKeep->length(0); // release before tmpIdSource calls UnRegister()
+    if ( & toKeep.in() )
+      toKeep->length(0); // release before tmpIdSource calls UnRegister()
 
   }
   catch(...) {
@@ -747,11 +746,12 @@ void SMESHGUI_MergeDlg::updateControls()
                           myMesh->NbVolumesOfOrder( SMESH::ORDER_QUADRATIC ) > 0 ));
 
     SeparateCornersAndMedium->setEnabled( has2ndOrder );
-
+  }
+  {
     if ( myEditCurrentArgument != KeepList )
     {
-      AddKeepNodesButton->setEnabled( false );
-      RemoveKeepNodesButton->setEnabled( false );
+      AddKeepButton->setEnabled( false );
+      RemoveKeepButton->setEnabled( false );
       KeepList->clearSelection();
     }
   }
@@ -776,38 +776,38 @@ void SMESHGUI_MergeDlg::onDetect()
     SMESH::array_of_long_array_var aGroupsArray;
     SMESH::ListOfIDSources_var aExcludeGroups = new SMESH::ListOfIDSources;
 
-    SMESH::SMESH_IDSource_var src;
-    if ( mySubMeshOrGroup->_is_nil() ) src = SMESH::SMESH_IDSource::_duplicate( myMesh );
-    else                               src = SMESH::SMESH_IDSource::_duplicate( mySubMeshOrGroup );
+    for ( int i = 0; GroupExclude->isChecked() && i < ListExclude->count(); i++ ) {
+      if ( ListExclude->item( i )->checkState() == Qt::Checked ) {
+        aExcludeGroups->length( aExcludeGroups->length()+1 );
+        aExcludeGroups[ aExcludeGroups->length()-1 ] = SMESH::SMESH_IDSource::_narrow( myGroups[i] );
+      }
+    }
 
     switch (myAction) {
     case MERGE_NODES :
-      for ( int i = 0; GroupExclude->isChecked() && i < ListExclude->count(); i++ ) {
-        if ( ListExclude->item( i )->checkState() == Qt::Checked ) {
-          aExcludeGroups->length( aExcludeGroups->length()+1 );
-          aExcludeGroups[ aExcludeGroups->length()-1 ] = SMESH::SMESH_IDSource::_duplicate( myGroups[i] );
-        }
-      }
-      aMeshEditor->FindCoincidentNodesOnPartBut(src.in(),
-                                                SpinBoxTolerance->GetValue(), 
+      aMeshEditor->FindCoincidentNodesOnPartBut(mySubMeshOrGroups.in(),
+                                                SpinBoxTolerance->GetValue(),
                                                 aGroupsArray.out(),
                                                 aExcludeGroups.in(),
                                                 SeparateCornersAndMedium->isEnabled() &&
                                                 SeparateCornersAndMedium->isChecked());
       break;
     case MERGE_ELEMENTS :
-      aMeshEditor->FindEqualElements(src.in(), aGroupsArray.out());
+      aMeshEditor->FindEqualElements(mySubMeshOrGroups.in(),
+                                     aExcludeGroups.in(),
+                                     aGroupsArray.out());
       break;
     }
-    
-    for (int i = 0; i < (int)aGroupsArray->length(); i++) {
+
+    for ( CORBA::ULong i = 0; i < aGroupsArray->length(); i++)
+    {
       SMESH::long_array& aGroup = aGroupsArray[i];
 
       QStringList anIDs;
-      for (int j = 0; j < (int)aGroup.length(); j++)
-        anIDs.append(QString::number(aGroup[j]));
+      for ( CORBA::ULong j = 0; j < aGroup.length(); j++ )
+        anIDs.append( QString::number( aGroup[j] ));
 
-      ListCoincident->addItem(anIDs.join(" "));
+      ListCoincident->addItem( anIDs.join(" "));
     }
   } catch(...) {
   }
@@ -830,7 +830,7 @@ void SMESHGUI_MergeDlg::onSelectGroup()
     SelectAllCB->setChecked( false );
 
   if ( myEditCurrentArgument == (QWidget*)KeepList && KeepList &&
-       !isKeepNodesIDsSelection() )
+       !isKeepIDsSelection() )
   {
     // restore selection of nodes after selection of sub-meshes
     mySelectionMgr->clearFilters();
@@ -938,7 +938,7 @@ void SMESHGUI_MergeDlg::onSelectElementFromGroup()
     myIdPreview->SetPointsLabeled(false);
 
   if ( myEditCurrentArgument == (QWidget*)KeepList && KeepList &&
-       !isKeepNodesIDsSelection() )
+       !isKeepIDsSelection() )
   {
     // restore selection of nodes after selection of sub-meshes
     mySelectionMgr->clearFilters();
@@ -1113,15 +1113,16 @@ void SMESHGUI_MergeDlg::SetEditCurrentArgument()
     if (myTypeId == TYPE_MANUAL)
       mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter);
   }
-  else if ( send == SelectKeepNodesButton && send )
+  else if ( send == SelectKeepButton && send )
   {
     myEditCurrentArgument = (QWidget*)KeepList;
-    KeepList->setWrapping( isKeepNodesIDsSelection() );
-    if ( isKeepNodesIDsSelection() )
+    KeepList->setWrapping( isKeepIDsSelection() );
+    if ( isKeepIDsSelection() )
     {
-      SMESH::SetPointRepresentation( true );
+      bool isElems = ( myAction == MERGE_ELEMENTS );
+      SMESH::SetPointRepresentation( !isElems );
       if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
-        aViewWindow->SetSelectionMode( NodeSelection );
+        aViewWindow->SetSelectionMode( isElems ? CellSelection : NodeSelection );
     }
     else
     {
@@ -1150,12 +1151,13 @@ void SMESHGUI_MergeDlg::SelectionIntoArgument()
 
     ListCoincident->clear();
     ListEdit->clear();
+    ListExclude->clear();
     myActor = 0;
     myMesh = SMESH::SMESH_Mesh::_nil();
     QString aCurrentEntry = myEntry;
 
     int nbSel = SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString);
-    if (nbSel != 1) {
+    if (nbSel == 0) {
       myIdPreview->SetPointsLabeled(false);
       SMESH::SetPointRepresentation(false);
       mySelectionMgr->clearFilters();
@@ -1177,43 +1179,72 @@ void SMESHGUI_MergeDlg::SelectionIntoArgument()
     if (myMesh->_is_nil())
       return;
 
-    LineEditMesh->setText(aString);
-
     myActor = SMESH::FindActorByEntry(IO->getEntry());
     if (!myActor)
       myActor = SMESH::FindActorByObject(myMesh);
 
-    if ( myActor && myTypeId == TYPE_MANUAL && mySelector->IsSelectionEnabled() ) {
-      mySubMeshOrGroup = SMESH::SMESH_IDSource::_nil();
-      mySelectionMgr->installFilter(myMeshOrSubMeshOrGroupFilter);
+    mySubMeshOrGroups->length( nbSel );
+    nbSel = 0;
+    bool isMeshSelected = false;
+    while ( !aList.IsEmpty() )
+    {
+      IO = aList.First();
+      aList.RemoveFirst();
+      SMESH::SMESH_IDSource_var idSrc = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO);
+      if ( !idSrc->_is_nil() )
+      {
+        SMESH::SMESH_Mesh_var mesh = idSrc->GetMesh();
+        if ( !mesh->_is_equivalent( myMesh ))
+        {
+          nbSel = 0;
+          break;
+        }
+        mySubMeshOrGroups[ nbSel++ ] = idSrc;
+        if ( idSrc->_is_equivalent( myMesh ))
+        {
+          isMeshSelected = true;
+          mySubMeshOrGroups[ 0 ] = idSrc;
+          aString = SMESH::GetName( IO );
+          // break; -- to check if other selected belongs to myMesh
+        }
+      }
+    }
 
-      if ((!SMESH::IObjectToInterface<SMESH::SMESH_subMesh>(IO)->_is_nil() || //SUBMESH OR GROUP
-           !SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>(IO)->_is_nil()) &&
-          !SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO)->_is_nil())
-        mySubMeshOrGroup = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO);
+    if ( isMeshSelected && nbSel > 1 )
+      nbSel = 1;
+    mySubMeshOrGroups->length( nbSel );
 
-      if (myAction == MERGE_NODES) {
-        SMESH::SetPointRepresentation(true);
-        if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
-          aViewWindow->SetSelectionMode(NodeSelection);
-      }
-      else
-        if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
-          aViewWindow->SetSelectionMode(CellSelection);
+    if ( nbSel == 0 )
+    {
+      LineEditMesh->setText("");
+      return;
+    }
+
+    LineEditMesh->setText( aString );
+
+    if (myAction == MERGE_NODES) {
+      SMESH::SetPointRepresentation(true);
+      if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+        aViewWindow->SetSelectionMode(NodeSelection);
     }
+    else
+      if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+        aViewWindow->SetSelectionMode(CellSelection);
 
     // process groups
-    if ( myAction == MERGE_NODES && !myMesh->_is_nil() && myEntry != aCurrentEntry ) {
-      myGroups.clear();
-      ListExclude->clear();
+    myGroups.clear();
+    if ( isMeshSelected )
+    {
       SMESH::ListOfGroups_var aListOfGroups = myMesh->GetGroups();
       GroupExclude->setEnabled( aListOfGroups->length() > 0 );
-      for( int i = 0, n = aListOfGroups->length(); i < n; i++ ) {
+      for ( int i = 0, n = aListOfGroups->length(); i < n; i++ ) {
         SMESH::SMESH_GroupBase_var aGroup = aListOfGroups[i];
-        if ( !aGroup->_is_nil() ) { // && aGroup->GetType() == SMESH::NODE
+        if ( !aGroup->_is_nil() ) {
+          if ( myAction == MERGE_ELEMENTS && aGroup->GetType() == SMESH::NODE )
+            continue;
           QString aGroupName( aGroup->GetName() );
           if ( !aGroupName.isEmpty() ) {
-            myGroups.append(SMESH::SMESH_GroupBase::_duplicate(aGroup));
+            myGroups.append( aGroup );
             QListWidgetItem* item = new QListWidgetItem( aGroupName );
             item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable );
             item->setCheckState( Qt::Unchecked );
@@ -1228,9 +1259,9 @@ void SMESHGUI_MergeDlg::SelectionIntoArgument()
 
   else if (myEditCurrentArgument == (QWidget*)KeepList && KeepList)
   {
-    AddKeepNodesButton->setEnabled( false );
-    RemoveKeepNodesButton->setEnabled( false );
-    if ( isKeepNodesIDsSelection() )
+    AddKeepButton->setEnabled( false );
+    RemoveKeepButton->setEnabled( false );
+    if ( isKeepIDsSelection() )
     {
       if (!myMesh->_is_nil() && !myActor)
         myActor = SMESH::FindActorByObject(myMesh);
@@ -1258,9 +1289,9 @@ void SMESHGUI_MergeDlg::SelectionIntoArgument()
           KeepList->blockSignals(true);
           foreach(anItem, listItemsToSel) anItem->setSelected(true);
           KeepList->blockSignals(blocked);
-          //onSelectKeepNode();
-          AddKeepNodesButton->setEnabled( nbFound < aNbNodes );
-          RemoveKeepNodesButton->setEnabled( nbFound > 0 );
+          //onSelectKeep();
+          AddKeepButton->setEnabled( nbFound < aNbNodes );
+          RemoveKeepButton->setEnabled( nbFound > 0 );
         }
       }
     }
@@ -1272,10 +1303,10 @@ void SMESHGUI_MergeDlg::SelectionIntoArgument()
       SALOME_ListIteratorOfListIO anIt (aList);
       for ( ; anIt.More() && !hasNewSelected; anIt.Next())
         if ( anIt.Value()->hasEntry() )
-          hasNewSelected = isNewKeepNodesGroup( anIt.Value()->getEntry() );
+          hasNewSelected = isNewKeepGroup( anIt.Value()->getEntry() );
 
-      AddKeepNodesButton->setEnabled( hasNewSelected );
-      //RemoveKeepNodesButton->setEnabled( KeepList->selectedItems().count() );
+      AddKeepButton->setEnabled( hasNewSelected );
+      //RemoveKeepButton->setEnabled( KeepList->selectedItems().count() );
     }
   }
 }
@@ -1292,7 +1323,7 @@ void SMESHGUI_MergeDlg::DeactivateActiveDialog()
     GroupCoincident->setEnabled(false);
     GroupEdit->setEnabled(false);
     GroupButtons->setEnabled(false);
-    if (myAction == MERGE_NODES)
+    //if (myAction == MERGE_NODES)
     {
       GroupExclude->setEnabled(false);
       GroupKeep->setEnabled(false);
@@ -1318,7 +1349,7 @@ void SMESHGUI_MergeDlg::ActivateThisDialog()
   GroupCoincident->setEnabled(true);
   GroupEdit->setEnabled(true);
   GroupButtons->setEnabled(true);
-  if (myAction == MERGE_NODES)
+  //if (myAction == MERGE_NODES)
   {
     GroupExclude->setEnabled(false);
     GroupKeep->setEnabled(false);
@@ -1390,16 +1421,7 @@ void SMESHGUI_MergeDlg::onTypeChanged (int id)
 
     SMESH::UpdateView();
 
-    // Costruction of the logical filter
-    SMESH_TypeFilter* aMeshOrSubMeshFilter = new SMESH_TypeFilter (SMESH::MESHorSUBMESH);
-    SMESH_TypeFilter* aSmeshGroupFilter    = new SMESH_TypeFilter (SMESH::GROUP);
-    
-    QList<SUIT_SelectionFilter*> aListOfFilters;
-    if (aMeshOrSubMeshFilter) aListOfFilters.append(aMeshOrSubMeshFilter);
-    if (aSmeshGroupFilter)    aListOfFilters.append(aSmeshGroupFilter);
-    
-    myMeshOrSubMeshOrGroupFilter =
-      new SMESH_LogicalFilter (aListOfFilters, SMESH_LogicalFilter::LO_OR, true);
+    myMeshOrSubMeshOrGroupFilter = new SMESH_TypeFilter (SMESH::IDSOURCE);
 
     if (myAction == MERGE_NODES) {
       SMESH::SetPointRepresentation(true);
@@ -1426,23 +1448,23 @@ void SMESHGUI_MergeDlg::onTypeChanged (int id)
 }
 
 //=======================================================================
-//function : isKeepNodesIDsSelection
+//function : isKeepIDsSelection
 //purpose  : Return true of Nodes to keep are selected by IDs
 //=======================================================================
 
-bool SMESHGUI_MergeDlg::isKeepNodesIDsSelection()
+bool SMESHGUI_MergeDlg::isKeepIDsSelection()
 {
   return KeepFromButGroup && KeepFromButGroup->checkedId() == 0;
 }
 
 //=======================================================================
-//function : isNewKeepNodesGroup
+//function : isNewKeepGroup
 //purpose  : Return true if an object with given entry is NOT present in KeepList
 //=======================================================================
 
-bool SMESHGUI_MergeDlg::isNewKeepNodesGroup( const char* entry )
+bool SMESHGUI_MergeDlg::isNewKeepGroup( const char* entry )
 {
-  if ( !entry || isKeepNodesIDsSelection() )
+  if ( !entry || isKeepIDsSelection() )
     return false;
 
   for ( int i = 0; i < KeepList->count(); i++ )
@@ -1453,17 +1475,17 @@ bool SMESHGUI_MergeDlg::isNewKeepNodesGroup( const char* entry )
 }
 
 //=======================================================================
-//function : onAddKeepNode
+//function : onAddKeep
 //purpose  : SLOT called when [Add] of Nodes To Keep group is pressed
 //=======================================================================
 
-void SMESHGUI_MergeDlg::onAddKeepNode()
+void SMESHGUI_MergeDlg::onAddKeep()
 {
   if ( myIsBusy )
     return;
   myIsBusy = true;
 
-  if ( isKeepNodesIDsSelection() )
+  if ( isKeepIDsSelection() )
   {
     //KeepList->clearSelection();
     QString anIDs = "";
@@ -1494,9 +1516,9 @@ void SMESHGUI_MergeDlg::onAddKeepNode()
       KeepList->blockSignals(true);
       foreach(anItem, listItemsToSel) anItem->setSelected(true);
       KeepList->blockSignals(blocked);
-      //onSelectKeepNode();
+      //onSelectKeep();
     }
-    RemoveKeepNodesButton->setEnabled( aNbNodes > 0 );
+    RemoveKeepButton->setEnabled( aNbNodes > 0 );
   }
   else
   {
@@ -1505,29 +1527,29 @@ void SMESHGUI_MergeDlg::onAddKeepNode()
     SALOME_ListIteratorOfListIO anIt (aList);
     for ( ; anIt.More(); anIt.Next()) {
       Handle(SALOME_InteractiveObject) anIO = anIt.Value();
-      if ( isNewKeepNodesGroup( anIO->getEntry() ))
+      if ( isNewKeepGroup( anIO->getEntry() ))
       {
         QListWidgetItem* anItem = new QListWidgetItem( anIO->getName() );
         anItem->setData( Qt::UserRole, QString( anIO->getEntry() ));
         KeepList->addItem(anItem);
       }
     }
-    //RemoveKeepNodesButton->setEnabled( KeepList->selectedItems().count() );
+    //RemoveKeepButton->setEnabled( KeepList->selectedItems().count() );
   }
 
-  AddKeepNodesButton->setEnabled( false );
+  AddKeepButton->setEnabled( false );
 
   myIsBusy = false;
 }
 
 //=======================================================================
-//function : onRemoveKeepNode
+//function : onRemoveKeep
 //purpose  : SLOT called when [Remove] of Nodes To Keep group is pressed
 //=======================================================================
 
-void SMESHGUI_MergeDlg::onRemoveKeepNode()
+void SMESHGUI_MergeDlg::onRemoveKeep()
 {
-  // if ( isKeepNodesIDsSelection() )
+  // if ( isKeepIDsSelection() )
   // {
   // }
   // else
@@ -1536,24 +1558,24 @@ void SMESHGUI_MergeDlg::onRemoveKeepNode()
     QListWidgetItem* item;
     foreach(item, selItems) delete item;
   }
-  if ( isKeepNodesIDsSelection() )
+  if ( isKeepIDsSelection() )
   {
-    AddKeepNodesButton->setEnabled( false );
+    AddKeepButton->setEnabled( false );
   }
-  RemoveKeepNodesButton->setEnabled( false );
+  RemoveKeepButton->setEnabled( false );
 }
 
 //=======================================================================
-//function : onSelectKeepNode
+//function : onSelectKeep
 //purpose  : SLOT called when selection in KeepList changes
 //=======================================================================
 
-void SMESHGUI_MergeDlg::onSelectKeepNode()
+void SMESHGUI_MergeDlg::onSelectKeep()
 {
   if ( myIsBusy || !isEnabled() ) return;
   myIsBusy = true;
 
-  if ( isKeepNodesIDsSelection() )
+  if ( isKeepIDsSelection() )
   {
     if ( myActor )
     {
@@ -1567,25 +1589,25 @@ void SMESHGUI_MergeDlg::onSelectKeepNode()
       aList.Append(myActor->getIO());
       mySelectionMgr->setSelectedObjects(aList,false);
 
-      AddKeepNodesButton->setEnabled( false );
-      RemoveKeepNodesButton->setEnabled( aIndexes.Extent() > 0 );
+      AddKeepButton->setEnabled( false );
+      RemoveKeepButton->setEnabled( aIndexes.Extent() > 0 );
     }
   }
   else
   {
-    RemoveKeepNodesButton->setEnabled( KeepList->selectedItems().count() );
+    RemoveKeepButton->setEnabled( KeepList->selectedItems().count() );
   }
   myIsBusy = false;
 }
 
 //=======================================================================
-//function : onKeepNodeSourceChanged
+//function : onKeepSourceChanged
 //purpose  : SLOT called when type of source of Nodes To Keep change from
 //           IDs to groups or vice versa
 //=======================================================================
 
-void SMESHGUI_MergeDlg::onKeepNodeSourceChanged(int isGroup)
+void SMESHGUI_MergeDlg::onKeepSourceChanged(int isGroup)
 {
   KeepList->clear();
-  SelectKeepNodesButton->click();
+  SelectKeepButton->click();
 }
index 6b087b6..f9af9af 100644 (file)
@@ -85,8 +85,8 @@ private:
   void                      enterEvent( QEvent* );              /* mouse enter the QWidget */
   void                      keyPressEvent( QKeyEvent* );
   void                      onEditGroup();
-  bool                      isKeepNodesIDsSelection();
-  bool                      isNewKeepNodesGroup( const char* entry );
+  bool                      isKeepIDsSelection();
+  bool                      isNewKeepGroup( const char* entry );
 
   void                      FindGravityCenter( TColStd_MapOfInteger&,
                                                std::vector<int>& , 
@@ -96,23 +96,29 @@ private:
 private:
   typedef QList<SMESH::SMESH_GroupBase_var> GrpList;
 
-  SMESHGUI*                 mySMESHGUI;     /* Current SMESHGUI object */
-  LightApp_SelectionMgr*    mySelectionMgr; /* User shape selection */
-  SVTK_Selector*            mySelector;
+  SMESHGUI*                  mySMESHGUI;     /* Current SMESHGUI object */
+  LightApp_SelectionMgr*     mySelectionMgr; /* User shape selection */
+  SVTK_Selector*             mySelector;
   
-  QWidget*                  myEditCurrentArgument;
+  QWidget*                   myEditCurrentArgument;
 
-  SMESH::SMESH_Mesh_var     myMesh;
-  SMESH::SMESH_IDSource_var mySubMeshOrGroup;
-  SMESH_Actor*              myActor;
-  SUIT_SelectionFilter*     myMeshOrSubMeshOrGroupFilter;
-  SUIT_SelectionFilter*     mySubMeshOrGroupFilter;
+  SMESH::SMESH_Mesh_var      myMesh;
+  SMESH::ListOfIDSources_var mySubMeshOrGroups;
+  GrpList                    myGroups;
+  QString                    myEntry;
 
-  SMESHGUI_IdPreview*       myIdPreview;
+  SMESH_Actor*               myActor;
+  SUIT_SelectionFilter*      myMeshOrSubMeshOrGroupFilter;
+  SUIT_SelectionFilter*      mySubMeshOrGroupFilter;
+
+  SMESHGUI_IdPreview*        myIdPreview;
+  QString                    myHelpFileName;
+
+  int                        myAction;
+  bool                       myIsBusy;
+  int                        myTypeId; // manual(1) or automatic(0)
+    
 
-  int                       myAction;
-  bool                      myIsBusy;
-  int                       myTypeId; // manual(1) or automatic(0)
 
   // Widgets
 
@@ -152,18 +158,13 @@ private:
 
   QGroupBox*                GroupKeep;
   QButtonGroup*             KeepFromButGroup;
-  QPushButton*              SelectKeepNodesButton;
-  QPushButton*              AddKeepNodesButton;
-  QPushButton*              RemoveKeepNodesButton;
+  QPushButton*              SelectKeepButton;
+  QPushButton*              AddKeepButton;
+  QPushButton*              RemoveKeepButton;
   QListWidget*              KeepList;
 
   QGroupBox*                TypeBox;
   QButtonGroup*             GroupType;
-    
-  QString                   myHelpFileName;
-
-  QString                   myEntry;
-  GrpList                   myGroups;
 
 protected slots:
   virtual void              reject();
@@ -174,10 +175,10 @@ protected slots:
   void                      ClickOnHelp();
   void                      updateControls();
   void                      onDetect();
-  void                      onAddKeepNode();
-  void                      onRemoveKeepNode();
-  void                      onSelectKeepNode();
-  void                      onKeepNodeSourceChanged(int);
+  void                      onAddKeep();
+  void                      onRemoveKeep();
+  void                      onSelectKeep();
+  void                      onKeepSourceChanged(int);
   void                      onAddGroup();
   void                      onRemoveGroup();
   void                      onSelectGroup();
index 5721e53..11d10cb 100644 (file)
@@ -242,13 +242,30 @@ namespace SMESH
     int aNbSel = selected.Extent();
     if (aNbSel == 1) {
       Handle(SALOME_InteractiveObject) anIObject = selected.First();
-      theName = QString( anIObject->getName() ).trimmed();
+      theName = GetName( anIObject );
     } else {
       theName = QObject::tr("SMESH_OBJECTS_SELECTED").arg(aNbSel);
     }
     return aNbSel;
   }
 
+  QString GetName( const Handle(SALOME_InteractiveObject)& theIO )
+  {
+    QString name;
+    if ( !theIO.IsNull() )
+    {
+      name = QString( theIO->getName() ).trimmed();
+
+      if ( name.isEmpty() && theIO->hasEntry() )
+      {
+        _PTR(SObject) sObj = getStudy()->FindObjectID( theIO->getEntry() );
+        if ( sObj )
+          name = sObj->GetName().c_str();
+      }
+    }
+    return name.trimmed();
+  }
+
   _PTR(SObject) GetMeshOrSubmesh (_PTR(SObject) theSObject)
   {
     GEOM::GEOM_Object_var aShape = SObjectToInterface<GEOM::GEOM_Object>(theSObject);
index 41d2e67..a403da8 100644 (file)
@@ -168,6 +168,9 @@ SMESHGUI_EXPORT
   int GetNameOfSelectedIObjects( LightApp_SelectionMgr*, QString& );
 
 SMESHGUI_EXPORT
+  QString GetName( const Handle(SALOME_InteractiveObject)& theIO );
+
+SMESHGUI_EXPORT
   _PTR(SObject) GetMeshOrSubmesh( _PTR(SObject) );
 
 SMESHGUI_EXPORT
index c4ffdde..222fa1e 100644 (file)
@@ -2293,6 +2293,10 @@ Check algorithm documentation for supported geometry</translation>
         <translation>Name</translation>
     </message>
     <message>
+        <source>SMESH_NAMES</source>
+        <translation>Names</translation>
+    </message>
+    <message>
         <source>SMESH_NODES</source>
         <translation>Nodes</translation>
     </message>
@@ -5491,6 +5495,10 @@ Please select a group and try again</translation>
         <translation>Nodes to keep during the merge</translation>
     </message>
     <message>
+        <source>KEEP_ELEMENTS</source>
+        <translation>Elements to keep during the merge</translation>
+    </message>
+    <message>
         <source>GROUP_SUBMESH</source>
         <translation>Groups and sub-meshes</translation>
     </message>
index f1e40ec..b03eca3 100644 (file)
@@ -298,33 +298,35 @@ namespace MeshEditor_I {
    */
   //================================================================================
 
-  void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr  theObject,
-                         const SMESHDS_Mesh*        theMeshDS,
-                         TIDSortedNodeSet&          theNodeSet)
+  void idSourceToNodeSet(SMESH::SMESH_IDSource_ptr theObject,
+                         const SMESHDS_Mesh*       theMeshDS,
+                         TIDSortedNodeSet&         theNodeSet)
 
   {
     if ( CORBA::is_nil( theObject ) )
       return;
-    SMESH::array_of_ElementType_var types = theObject->GetTypes();
-    SMESH::long_array_var     aElementsId = theObject->GetIDs();
-    if ( types->length() == 1 && types[0] == SMESH::NODE)
+    if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
     {
-      for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
-        if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] ))
-          theNodeSet.insert( theNodeSet.end(), n);
-    }
-    else if ( SMESH::DownCast<SMESH_Mesh_i*>( theObject ))
-    {
-      SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator();
-      while ( nIt->more( ))
+      for ( SMDS_NodeIteratorPtr nIt = theMeshDS->nodesIterator(); nIt->more(); )
         if ( const SMDS_MeshElement * elem = nIt->next() )
           theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
     }
     else
     {
-      for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
-        if ( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] ))
-          theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
+      SMESH::array_of_ElementType_var types = theObject->GetTypes();
+      SMESH::long_array_var     aElementsId = theObject->GetIDs();
+      if ( types->length() == 1 && types[0] == SMESH::NODE)
+      {
+        for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
+          if ( const SMDS_MeshNode * n = theMeshDS->FindNode( aElementsId[i] ))
+            theNodeSet.insert( theNodeSet.end(), n);
+      }
+      else
+      {
+        for ( CORBA::ULong i = 0; i < aElementsId->length(); i++ )
+          if ( const SMDS_MeshElement * elem = theMeshDS->FindElement( aElementsId[i] ))
+            theNodeSet.insert( elem->begin_nodes(), elem->end_nodes());
+      }
     }
   }
 
@@ -4199,13 +4201,13 @@ FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr      theObject,
 
 //================================================================================
 /*!
- * \brief Finds nodes coincident with Tolerance within Object excluding nodes within
+ * \brief Finds nodes coincident with Tolerance within Objects excluding nodes within
  *        ExceptSubMeshOrGroups
  */
 //================================================================================
 
 void SMESH_MeshEditor_i::
-FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
+FindCoincidentNodesOnPartBut(const SMESH::ListOfIDSources&  theObjects,
                              CORBA::Double                  theTolerance,
                              SMESH::array_of_long_array_out theGroupsOfNodes,
                              const SMESH::ListOfIDSources&  theExceptSubMeshOrGroups,
@@ -4216,9 +4218,11 @@ FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
   initData();
 
   TIDSortedNodeSet nodes;
-  prepareIdSource( theObject );
-  idSourceToNodeSet( theObject, getMeshDS(), nodes );
-
+  for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
+  {
+    prepareIdSource( theObjects[i] );
+    idSourceToNodeSet( theObjects[i], getMeshDS(), nodes );
+  }
   for ( CORBA::ULong i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
   {
     if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
@@ -4229,7 +4233,7 @@ FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      theObject,
   findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
 
   TPythonDump() << "coincident_nodes_on_part = " << this << ".FindCoincidentNodesOnPartBut( "
-                << theObject<<", "
+                << theObject<<", "
                 << theTolerance << ", "
                 << theExceptSubMeshOrGroups << ", "
                 << theSeparateCornersAndMedium << " )";
@@ -4302,30 +4306,47 @@ void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfN
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObject,
-                                           SMESH::array_of_long_array_out GroupsOfElementsID)
+void SMESH_MeshEditor_i::FindEqualElements(const SMESH::ListOfIDSources&  theObjects,
+                                           const SMESH::ListOfIDSources&  theExceptObjects,
+                                           SMESH::array_of_long_array_out theGroupsOfElementsID)
   throw (SALOME::SALOME_Exception)
 {
   SMESH_TRY;
   initData();
 
-  SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
-  if ( !( !group->_is_nil() && group->GetType() == SMESH::NODE ))
+  theGroupsOfElementsID = new SMESH::array_of_long_array;
+
+  TIDSortedElemSet elems;
+  bool hasOkObject = false;
+  bool emptyIfIsMesh= ( theObjects.length() == 1 && theExceptObjects.length() == 0 );
+
+  for ( CORBA::ULong i = 0; i < theObjects.length(); ++i )
   {
-    TIDSortedElemSet elems;
-    idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true);
+    SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow( theObjects[i] );
+    if ( !( !group->_is_nil() && group->GetType() == SMESH::NODE ))
+      if ( idSourceToSet( theObjects[i], getMeshDS(), elems, SMDSAbs_All, emptyIfIsMesh ))
+        hasOkObject = true;
+  }
+
+  if ( hasOkObject )
+  {
+    for ( CORBA::ULong i = 0; i < theExceptObjects.length(); ++i )
+    {
+      if ( SMDS_ElemIteratorPtr elemIt = myMesh_i->GetElements( theExceptObjects[i], SMESH::ALL ))
+        while ( elemIt->more() )
+          elems.erase( elemIt->next() );
+    }
 
     ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
     getEditor().FindEqualElements( elems, aListOfListOfElementsID );
 
-    GroupsOfElementsID = new SMESH::array_of_long_array;
-    GroupsOfElementsID->length( aListOfListOfElementsID.size() );
+    theGroupsOfElementsID->length( aListOfListOfElementsID.size() );
 
     ::SMESH_MeshEditor::TListOfListOfElementsID::iterator arraysIt =
         aListOfListOfElementsID.begin();
     for (CORBA::Long j = 0; arraysIt != aListOfListOfElementsID.end(); ++arraysIt, ++j)
     {
-      SMESH::long_array& aGroup = (*GroupsOfElementsID)[ j ];
+      SMESH::long_array& aGroup = (*theGroupsOfElementsID)[ j ];
       list<int>&      listOfIDs = *arraysIt;
       aGroup.length( listOfIDs.size() );
       list<int>::iterator idIt = listOfIDs.begin();
@@ -4334,7 +4355,8 @@ void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObj
     }
 
     TPythonDump() << "equal_elements = " << this << ".FindEqualElements( "
-                  <<theObject<<" )";
+                  << theObjects << ", "
+                  << theExceptObjects << " )";
   }
 
   SMESH_CATCH( SMESH::throwCorbaException );
@@ -4345,7 +4367,8 @@ void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr      theObj
 //purpose  :
 //=======================================================================
 
-void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsOfElementsID)
+void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& theGroupsOfElementsID,
+                                       const SMESH::ListOfIDSources&     theElementsToKeep)
   throw (SALOME::SALOME_Exception)
 {
   SMESH_TRY;
@@ -4354,15 +4377,31 @@ void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsO
   TPythonDump aTPythonDump;
   aTPythonDump << this << ".MergeElements( [";
 
+  NCollection_Map< int > idsToKeep;
+  for ( CORBA::ULong i = 0; i < theElementsToKeep.length(); i++ )
+  {
+    if ( CORBA::is_nil( theElementsToKeep[i] ))
+      continue;
+    SMESH::array_of_ElementType_var elemTypes = theElementsToKeep[i]->GetTypes();
+    if ( elemTypes->length() == 1 && elemTypes[0] == SMESH::NODE )
+      continue;
+    SMESH::long_array_var elementsId = theElementsToKeep[i]->GetIDs();
+    for ( CORBA::ULong j = 0; j < elementsId->length(); ++j )
+      idsToKeep.Add( elementsId[ j ]);
+  }
+
   ::SMESH_MeshEditor::TListOfListOfElementsID aListOfListOfElementsID;
 
-  for ( CORBA::ULong i = 0; i < GroupsOfElementsID.length(); i++ ) {
-    const SMESH::long_array& anElemsIDGroup = GroupsOfElementsID[ i ];
+  for ( CORBA::ULong i = 0; i < theGroupsOfElementsID.length(); i++ )
+  {
+    const SMESH::long_array& anElemsIDGroup = theGroupsOfElementsID[ i ];
     aListOfListOfElementsID.push_back( list< int >() );
     list< int >& aListOfElemsID = aListOfListOfElementsID.back();
-    for ( CORBA::ULong j = 0; j < anElemsIDGroup.length(); j++ ) {
+    for ( CORBA::ULong j = 0; j < anElemsIDGroup.length(); j++ )
+    {
       CORBA::Long id = anElemsIDGroup[ j ];
-      aListOfElemsID.push_back( id );
+      if ( idsToKeep.Contains( id )) aListOfElemsID.push_front( id );
+      else                           aListOfElemsID.push_back( id );
     }
     if ( aListOfElemsID.size() < 2 )
       aListOfListOfElementsID.pop_back();
@@ -4374,7 +4413,7 @@ void SMESH_MeshEditor_i::MergeElements(const SMESH::array_of_long_array& GroupsO
 
   declareMeshModified( /*isReComputeSafe=*/true );
 
-  aTPythonDump << "] )";
+  aTPythonDump << "], " << theElementsToKeep << " )";
 
   SMESH_CATCH( SMESH::throwCorbaException );
 }
@@ -5809,10 +5848,21 @@ bool SMESH_MeshEditor_i::idSourceToSet(SMESH::SMESH_IDSource_ptr  theIDSource,
   }
   if ( emptyIfIsMesh && SMESH::DownCast<SMESH_Mesh_i*>( theIDSource ))
   {
-    if ( error && getMeshDS()->GetMeshInfo().NbElements( theType ) == 0 )
+    if ( error && theMeshDS->GetMeshInfo().NbElements( theType ) == 0 )
       *error = IDSource_EMPTY;
     return true;
   }
+  if ( getMeshDS() == theMeshDS ) // check if theIDSource belongs to myMesh
+  {
+    SMESH::SMESH_Mesh_var mesh = theIDSource->GetMesh();
+    SMESH_Mesh_i*       mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+    if ( mesh_i && mesh_i != myMesh_i )
+    {
+      if ( error )
+        *error = IDSource_INVALID;
+      return false;
+    }
+  }
   prepareIdSource( theIDSource );
   SMESH::long_array_var anIDs = theIDSource->GetIDs();
   if ( anIDs->length() == 0 )
index 462d42d..d8c46a6 100644 (file)
@@ -501,7 +501,7 @@ public:
                                  SMESH::array_of_long_array_out GroupsOfNodes,
                                  CORBA::Boolean                 SeparateCornersAndMedium)
     throw (SALOME::SALOME_Exception);
-  void FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr      Object,
+  void FindCoincidentNodesOnPartBut(const SMESH::ListOfIDSources&  Objects,
                                     CORBA::Double                  Tolerance,
                                     SMESH::array_of_long_array_out GroupsOfNodes,
                                     const SMESH::ListOfIDSources&  ExceptSubMeshOrGroups,
@@ -511,10 +511,12 @@ public:
                    const SMESH::ListOfIDSources&     NodesToKeep,
                    CORBA::Boolean                    AvoidMakingHoles )
     throw (SALOME::SALOME_Exception);
-  void FindEqualElements(SMESH::SMESH_IDSource_ptr      Object,
+  void FindEqualElements(const SMESH::ListOfIDSources&  Objects,
+                         const SMESH::ListOfIDSources&  ExceptSubMeshOrGroups,
                          SMESH::array_of_long_array_out GroupsOfElementsID)
     throw (SALOME::SALOME_Exception);
-  void MergeElements(const SMESH::array_of_long_array& GroupsOfElementsID)
+  void MergeElements(const SMESH::array_of_long_array& GroupsOfElementsID,
+                     const SMESH::ListOfIDSources&     ElementsToKeep)
     throw (SALOME::SALOME_Exception);
   void MergeEqualElements()
     throw (SALOME::SALOME_Exception);
index 0268587..20b7bc0 100755 (executable)
@@ -5680,6 +5680,8 @@ class Mesh(metaclass = MeshMeta):
         Example: :ref:`tui_extrusion_along_path`
         """
 
+        if not IDsOfElements:
+            IDsOfElements = [ self.GetMesh() ]
         n,e,f = [],IDsOfElements,IDsOfElements
         gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape,
                                                NodeStart, HasAngles, Angles,
@@ -6239,7 +6241,7 @@ class Mesh(metaclass = MeshMeta):
 
         Parameters:
             Tolerance: the value of tolerance
-            SubMeshOrGroup: :class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>` or node IDs
+            SubMeshOrGroup: list of :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>` or of node IDs
             exceptNodes: list of either SubMeshes, Groups or node IDs to exclude from search
             SeparateCornerAndMediumNodes: if *True*, in quadratic mesh puts
                 corner and medium nodes in separate groups thus preventing
@@ -6250,11 +6252,16 @@ class Mesh(metaclass = MeshMeta):
         """
 
         unRegister = genObjUnRegister()
-        if (isinstance( SubMeshOrGroup, Mesh )):
-            SubMeshOrGroup = SubMeshOrGroup.GetMesh()
-        if isinstance( SubMeshOrGroup, list ):
-            SubMeshOrGroup = self.GetIDSource( SubMeshOrGroup, SMESH.NODE )
-            unRegister.set( SubMeshOrGroup )
+        if not isinstance( SubMeshOrGroup, list ):
+            SubMeshOrGroup = [ SubMeshOrGroup ]
+        for i,obj in enumerate( SubMeshOrGroup ):
+            if isinstance( obj, Mesh ):
+                SubMeshOrGroup = [ obj.GetMesh() ]
+                break
+            if isinstance( obj, int ):
+                SubMeshOrGroup = self.GetIDSource( SubMeshOrGroup, SMESH.NODE )
+                unRegister.set( SubMeshOrGroup )
+                break
 
         if not isinstance( exceptNodes, list ):
             exceptNodes = [ exceptNodes ]
@@ -6272,44 +6279,72 @@ class Mesh(metaclass = MeshMeta):
         Parameters:
             GroupsOfNodes: a list of groups of nodes IDs for merging.
                 E.g. [[1,12,13],[25,4]] means that nodes 12, 13 and 4 will be removed and replaced
-                in all elements and groups by nodes 1 and 25 correspondingly
+                in all elements and mesh groups by nodes 1 and 25 correspondingly
             NodesToKeep: nodes to keep in the mesh: a list of groups, sub-meshes or node IDs.
                 If *NodesToKeep* does not include a node to keep for some group to merge,
                 then the first node in the group is kept.
             AvoidMakingHoles: prevent merging nodes which cause removal of elements becoming
                 invalid
         """
-        # NodesToKeep are converted to SMESH.SMESH_IDSource in meshEditor.MergeNodes()
         self.editor.MergeNodes( GroupsOfNodes, NodesToKeep, AvoidMakingHoles )
 
-    def FindEqualElements (self, MeshOrSubMeshOrGroup=None):
+    def FindEqualElements (self, MeshOrSubMeshOrGroup=None, exceptElements=[]):
         """
         Find the elements built on the same nodes.
 
         Parameters:
-            MeshOrSubMeshOrGroup: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
+            MeshOrSubMeshOrGroup: :class:`mesh, sub-meshes, groups or filters <SMESH.SMESH_IDSource>` or element IDs to check for equal elements
+            exceptElements: list of either SubMeshes, Groups or elements IDs to exclude from search
+
 
         Returns:
             the list of groups of equal elements IDs (e.g. [[1,12,13],[4,25]])
         """
 
-        if not MeshOrSubMeshOrGroup:
-            MeshOrSubMeshOrGroup=self.mesh
+        unRegister = genObjUnRegister()
+        if MeshOrSubMeshOrGroup is None:
+            MeshOrSubMeshOrGroup = [ self.mesh ]
         elif isinstance( MeshOrSubMeshOrGroup, Mesh ):
-            MeshOrSubMeshOrGroup = MeshOrSubMeshOrGroup.GetMesh()
-        return self.editor.FindEqualElements( MeshOrSubMeshOrGroup )
-
-    def MergeElements(self, GroupsOfElementsID):
+            MeshOrSubMeshOrGroup = [ MeshOrSubMeshOrGroup.GetMesh() ]
+        elif not isinstance( MeshOrSubMeshOrGroup, list ):
+            MeshOrSubMeshOrGroup = [ MeshOrSubMeshOrGroup ]
+        if isinstance( MeshOrSubMeshOrGroup[0], int ):
+            MeshOrSubMeshOrGroup = [ self.GetIDSource( MeshOrSubMeshOrGroup, SMESH.ALL )]
+            unRegister.set( MeshOrSubMeshOrGroup )
+        for item in MeshOrSubMeshOrGroup:
+            if isinstance( item, Mesh ):
+                MeshOrSubMeshOrGroup = [ item.GetMesh() ]
+
+        if not isinstance( exceptElements, list ):
+            exceptElements = [ exceptElements ]
+        if exceptElements and isinstance( exceptElements[0], int ):
+            exceptElements = [ self.GetIDSource( exceptElements, SMESH.ALL )]
+            unRegister.set( exceptElements )
+
+        return self.editor.FindEqualElements( MeshOrSubMeshOrGroup, exceptElements )
+
+    def MergeElements(self, GroupsOfElementsID, ElementsToKeep=[]):
         """
         Merge elements in each given group.
 
         Parameters:
             GroupsOfElementsID: a list of groups (lists) of elements IDs for merging
                 (e.g. [[1,12,13],[25,4]] means that elements 12, 13 and 4 will be removed and
-                replaced in all groups by elements 1 and 25)
+                replaced in all mesh groups by elements 1 and 25)
+            ElementsToKeep: elements to keep in the mesh: a list of groups, sub-meshes or node IDs.
+                If *ElementsToKeep* does not include an element to keep for some group to merge,
+                then the first element in the group is kept.
         """
 
-        self.editor.MergeElements(GroupsOfElementsID)
+        unRegister = genObjUnRegister()
+        if ElementsToKeep:
+            if not isinstance( ElementsToKeep, list ):
+                ElementsToKeep = [ ElementsToKeep ]
+            if isinstance( ElementsToKeep[0], int ):
+                ElementsToKeep = [ self.GetIDSource( ElementsToKeep, SMESH.ALL )]
+                unRegister.set( ElementsToKeep )
+
+        self.editor.MergeElements( GroupsOfElementsID, ElementsToKeep )
 
     def MergeEqualElements(self):
         """