Salome HOME
IMP 23078: [CEA 1498] Sewing of meshes without having to set the nodes ids V7_7_0b1
authoreap <eap@opencascade.com>
Fri, 18 Sep 2015 14:10:34 +0000 (17:10 +0300)
committereap <eap@opencascade.com>
Fri, 18 Sep 2015 14:10:34 +0000 (17:10 +0300)
32 files changed:
doc/salome/gui/SMESH/input/2d_meshing_hypo.doc
doc/salome/gui/SMESH/input/creating_groups.doc
doc/salome/gui/SMESH/input/index.doc
doc/salome/gui/SMESH/input/merging_nodes.doc
doc/salome/gui/SMESH/input/mesh_infos.doc
doc/salome/gui/SMESH/input/sewing_meshes.doc
doc/salome/gui/SMESH/input/viewing_meshes_overview.doc
idl/SMESH_MeshEditor.idl
src/OBJECT/SMESH_Object.cxx
src/SMDS/SMDS_MeshNode.cxx
src/SMESH/SMESH_MeshEditor.cxx
src/SMESH/SMESH_Pattern.cxx
src/SMESHGUI/CMakeLists.txt
src/SMESHGUI/SMESHGUI_IdPreview.cxx [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_IdPreview.h [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_MergeDlg.cxx
src/SMESHGUI/SMESHGUI_MergeDlg.h
src/SMESHGUI/SMESHGUI_PreVisualObj.cxx [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_PreVisualObj.h [new file with mode: 0644]
src/SMESHGUI/SMESHGUI_SewingDlg.cxx
src/SMESHGUI/SMESHGUI_SewingDlg.h
src/SMESHGUI/SMESH_msg_en.ts
src/SMESHUtils/CMakeLists.txt
src/SMESHUtils/SMESH_FreeBorders.cxx [new file with mode: 0644]
src/SMESHUtils/SMESH_MeshAlgos.cxx
src/SMESHUtils/SMESH_MeshAlgos.hxx
src/SMESH_I/SMESH_2smeshpy.cxx
src/SMESH_I/SMESH_DumpPython.cxx
src/SMESH_I/SMESH_MeshEditor_i.cxx
src/SMESH_I/SMESH_MeshEditor_i.hxx
src/SMESH_I/SMESH_PythonDump.hxx
src/SMESH_SWIG/smeshBuilder.py

index c014ee6..308a689 100644 (file)
@@ -38,7 +38,7 @@ the meshed face boundary.
 
 \image html hypo_quad_params_dialog.png "Quadrangle parameters: Transition"
 
-<b>Quadrangle parameters</b> is a hypothesis for Quadrangle (Mapping) algorithm.
+<b>Quadrangle parameters</b> is a hypothesis for \ref quad_ijk_algo_page.
 
 <b>Transition</b> tab is used to define the algorithm of transition
 between opposite sides of the face with a different number of
index 61077e0..da12c83 100644 (file)
@@ -23,7 +23,9 @@ elements which will form your group:</li>
 </ul>
 <li><b>Name</b> field allows to enter the name of your new group.</li>
 <li><b>Color</b> - allows to assign to the group a certain color. The
-  chosen color is used to display the elements of the group.</li>
+  chosen color is used to display the elements of the group.<br>
+  Activation of <em>Auto Color</em> item in mesh context menu
+  switches on a random choice of a color for a new group.</li>
 </ul>
 Mesh module distinguishes between the three Group types:
 <b>Standalone Group</b>, <b>Group on Geometry</b> and <b>Group on Filter</b>.
index f81ce43..9ecb7c5 100644 (file)
   either \ref importing_exporting_meshes_page "imported" or manually
   created); 
  </li>
-<li>\ref importing_exporting_meshes_page "importing and exporting meshes in various formats";</li> 
+<li>\ref importing_exporting_meshes_page "importing and exporting meshes" 
+  in various formats;</li>
 <li>\subpage modifying_meshes_page "modifying meshes" with a vast
   array of dedicated operations;</li> 
-<li>\subpage grouping_elements_page "creating groups of mesh
-  elements";</li>
+<li>\subpage grouping_elements_page "creating groups" of mesh
+  elements;</li>
 <li>filtering mesh entities (nodes or elements) using
   \subpage filters_page "Filters" functionality for \ref
   grouping_elements_page "creating groups" and applying \ref
   modifying_meshes_page "mesh modifications";</li>
 <li>\subpage viewing_meshes_overview_page "viewing meshes" in
-  the VTK viewer;</li>
+  the VTK viewer and \ref mesh_infos_page "getting info" on mesh
+  and its sub-objects;</li>
 <li>applying to meshes \subpage quality_page "Quality Controls", 
   allowing to highlight important elements;</li>
 <li>taking various \subpage measurements_page "measurements" of the
index 439e1fe..31c93f7 100644 (file)
@@ -21,10 +21,10 @@ then converted to the single node.
 processed.
 <li>\b Tolerance is a maximum distance between nodes sufficient for
 merging.</li>
-<li>Activation of <b>No merge of corner and medium nodes</b> 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.</li>
+<li>Activation of <b>No merge of corner and medium nodes of quadratic
+    cells</b> 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.</li>
 <li><b>Exclude Groups</b> group box allows to ignore the nodes which
 belong to the specified mesh groups.</li>
 <li><b>Nodes to keep</b> group box allows to specify nodes to keep in
index cd9860a..2013cd4 100644 (file)
@@ -14,14 +14,16 @@ in the toolbar.
 <em>"Mesh Information" button</em></center>
 
 The <b>Mesh Information</b> dialog box provides three tab pages:
-- <b>\ref advanced_mesh_infos_anchor "Base Info"</b> - to show base
-information about the selected mesh object.
+- <b>\ref advanced_mesh_infos_anchor "Base Info"</b> - to show
+  base and quantitative information about the selected mesh object.
 - <b>\ref mesh_element_info_anchor "Element Info"</b> - to show
-detailed information about the selected mesh node or element.
-- <b>\ref mesh_addition_info_anchor "Additional Info"</b> - to show additional information available
-for the selected mesh, sub-mesh or group object.
+  detailed information about the selected mesh nodes or elements.
+- <b>\ref mesh_addition_info_anchor "Additional Info"</b> - to show
+  additional information available for the selected mesh, sub-mesh or
+  group object. 
 - <b>\ref mesh_quality_info_anchor "Quality Info"</b> - to show
-overall quality information about the selected mesh, sub-mesh or group object.
+  overall quality information about the selected mesh, sub-mesh or group
+  object. 
 
 \anchor advanced_mesh_infos_anchor
 <h2>Base Information</h2>
index b7640f3..8b7bb76 100644 (file)
@@ -27,7 +27,13 @@ the type of sewing operation you would like to perform.</li>
 \anchor free_borders_anchor
 <h2>Sew free borders</h2>
 
-This functionality allows you to unite two free borders of a 2D mesh.
+This functionality allows you to unite free borders of a 2D mesh.
+
+There are two working modes: \a Automatic and \a Manual. In the \b
+Automatic mode, the program finds free borders coincident within a
+certain tolerance and sew them. Optionally it is possible to adjust
+the found free borders before sewing. In the \b Manual mode you are to
+define borders to sew by picking three nodes of each border.
 
 \image html sewing1.png
 
index 2486855..2472c24 100644 (file)
@@ -26,8 +26,11 @@ information about the mesh.</li>
 <li>\subpage find_element_by_point_page "Find Element by Point" -
 allows to find all mesh elements, to which belongs a point with the
 given coordinates.</li>
-<li><b>Auto Color</b> - switch on / off auto-assigning colors for the groups.</li>
-<li>\subpage numbering_page "Numbering"  - allows to display the ID
+<li><b>Auto Color</b> - switch on / off auto-assigning colors for the
+  groups. If switched on, a default color of a new group in 
+  \ref creating_groups_page "Create Group" dialog is chosen
+  randomly. </li>
+<li>\subpage numbering_page "Numbering" - allows to display the ID
 numbers of all meshing elements or nodes composing your mesh in the
 viewer.</li>
 <li>\subpage display_mode_page "Display Mode" - allows to select between
index 57f50fb..8c63fdb 100644 (file)
 
 module SMESH
 {
+  interface NumericalFunctor;
+
   enum Bnd_Dimension { BND_2DFROM3D, BND_1DFROM3D, BND_1DFROM2D };
 
+
+  struct FreeBorder
+  {
+    SMESH::long_array nodeIDs; // all nodes defining a free border
+    // 1st and last node is same in a closed border
+  };
+  struct FreeBorderPart
+  {
+    short border; // border index within a sequence<FreeBorder>
+    long  node1;  // node index within the border-th FreeBorder
+    long  node2;
+    long  nodeLast;
+  };
+  typedef sequence<FreeBorder>       ListOfFreeBorders;
+  typedef sequence<FreeBorderPart>   FreeBordersGroup;
+  typedef sequence<FreeBordersGroup> ListOfFreeBorderGroups;
+
+  struct CoincidentFreeBorders
+  {
+    ListOfFreeBorders      borders;          // nodes of all free borders
+    ListOfFreeBorderGroups coincidentGroups; // groups of coincident parts of borders
+  };
+
+
   /*!
    * This interface makes modifications on the Mesh - removing elements and nodes etc.
    */
-  interface NumericalFunctor;
-
   interface SMESH_MeshEditor
   {
    /*!
@@ -723,6 +747,21 @@ module SMESH
     short GetPointState(in double x, in double y, in double z) 
       raises (SALOME::SALOME_Exception);
 
+    /*!
+     * Returns groups of FreeBorder's coincident within the given tolerance.
+     * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
+     * to free borders being compared is used.
+     */
+    CoincidentFreeBorders FindCoincidentFreeBorders(in double tolerance);
+
+    /*!
+     * Sew FreeBorder's of each group
+     */
+    short SewCoincidentFreeBorders (in CoincidentFreeBorders freeBorders,
+                                    in boolean               createPolygons,
+                                    in boolean               createPolyedrs)
+      raises (SALOME::SALOME_Exception);
+
     enum Sew_Error {
       SEW_OK,
       SEW_BORDER1_NOT_FOUND,
index bcb5899..1767ddf 100644 (file)
@@ -559,22 +559,8 @@ bool SMESH_VisualObjDef::GetEdgeNodes( const int theElemId,
   if ( theEdgeNum < 0 || theEdgeNum > 3 || (nbNodes != 3 && nbNodes != 4) || theEdgeNum > nbNodes )
     return false;
 
-  vector<int> anIds( nbNodes );
-  SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
-  int i = 0;
-  while( anIter->more() && i < nbNodes )
-    anIds[ i++ ] = anIter->next()->GetID();
-
-  if ( theEdgeNum < nbNodes - 1 )
-  {
-    theNodeId1 = anIds[ theEdgeNum ];
-    theNodeId2 = anIds[ theEdgeNum + 1 ];
-  }
-  else
-  {
-    theNodeId1 = anIds[ nbNodes - 1 ];
-    theNodeId2 = anIds[ 0 ];
-  }
+  theNodeId1 = anElem->GetNode( theEdgeNum - 1       )->GetID();
+  theNodeId2 = anElem->GetNode( theEdgeNum % nbNodes )->GetID();
 
   return true;
 }
index 3bd528b..3524480 100644 (file)
@@ -42,7 +42,7 @@ int SMDS_MeshNode::nbNodes =0;
 
 //=======================================================================
 //function : SMDS_MeshNode
-//purpose  : 
+//purpose  :
 //=======================================================================
 SMDS_MeshNode::SMDS_MeshNode() :
   SMDS_MeshElement(-1, -1, 0),
@@ -83,31 +83,31 @@ SMDS_MeshNode::~SMDS_MeshNode()
 
 //=======================================================================
 //function : RemoveInverseElement
-//purpose  : 
+//purpose  :
 //=======================================================================
 
 void SMDS_MeshNode::RemoveInverseElement(const SMDS_MeshElement * parent)
 {
-    //MESSAGE("RemoveInverseElement " << myID << " " << parent->GetID());
-    const SMDS_MeshCell* cell = dynamic_cast<const SMDS_MeshCell*>(parent);
-    MYASSERT(cell);
-    SMDS_Mesh::_meshList[myMeshId]->getGrid()->RemoveReferenceToCell(myVtkID, cell->getVtkId());
+  //MESSAGE("RemoveInverseElement " << myID << " " << parent->GetID());
+  const SMDS_MeshCell* cell = dynamic_cast<const SMDS_MeshCell*>(parent);
+  MYASSERT(cell);
+  SMDS_Mesh::_meshList[myMeshId]->getGrid()->RemoveReferenceToCell(myVtkID, cell->getVtkId());
 }
 
 //=======================================================================
 //function : Print
-//purpose  : 
+//purpose  :
 //=======================================================================
 
 void SMDS_MeshNode::Print(ostream & OS) const
 {
-        OS << "Node <" << myID << "> : X = " << X() << " Y = "
-                << Y() << " Z = " << Z() << endl;
+  OS << "Node <" << myID << "> : X = " << X() << " Y = "
+     << Y() << " Z = " << Z() << endl;
 }
 
 //=======================================================================
 //function : SetPosition
-//purpose  : 
+//purpose  :
 //=======================================================================
 
 void SMDS_MeshNode::SetPosition(const SMDS_PositionPtr& aPos)
@@ -121,7 +121,7 @@ void SMDS_MeshNode::SetPosition(const SMDS_PositionPtr& aPos)
 
 //=======================================================================
 //function : GetPosition
-//purpose  : 
+//purpose  :
 //=======================================================================
 
 const SMDS_PositionPtr& SMDS_MeshNode::GetPosition() const
@@ -178,10 +178,10 @@ public:
     int smdsId = myMesh->fromVtkToSmds(vtkId);
     const SMDS_MeshElement* elem = myMesh->FindElement(smdsId);
     if (!elem)
-      {
-        MESSAGE("SMDS_MeshNode_MyInvIterator problem Null element");
-        throw SALOME_Exception("SMDS_MeshNode_MyInvIterator problem Null element");
-      }
+    {
+      MESSAGE("SMDS_MeshNode_MyInvIterator problem Null element");
+      throw SALOME_Exception("SMDS_MeshNode_MyInvIterator problem Null element");
+    }
     //MESSAGE("vtkId " << vtkId << " smdsId " << smdsId << " " << elem->GetType());
     iter++;
     return elem;
@@ -189,11 +189,11 @@ public:
 };
 
 SMDS_ElemIteratorPtr SMDS_MeshNode::
-        GetInverseElementIterator(SMDSAbs_ElementType type) const
+GetInverseElementIterator(SMDSAbs_ElementType type) const
 {
-    vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID);
-    //MESSAGE("myID " << myID << " ncells " << l.ncells);
-    return SMDS_ElemIteratorPtr(new SMDS_MeshNode_MyInvIterator(SMDS_Mesh::_meshList[myMeshId], l.cells, l.ncells, type));
+  vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID);
+  //MESSAGE("myID " << myID << " ncells " << l.ncells);
+  return SMDS_ElemIteratorPtr(new SMDS_MeshNode_MyInvIterator(SMDS_Mesh::_meshList[myMeshId], l.cells, l.ncells, type));
 }
 
 // Same as GetInverseElementIterator but the create iterator only return
@@ -208,47 +208,47 @@ private:
   int  iter;
   vector<SMDS_MeshElement*> myFiltCells;
 
- public:
+public:
   SMDS_MeshNode_MyIterator(SMDS_Mesh *mesh,
                            vtkIdType* cells,
                            int ncells,
                            SMDSAbs_ElementType type):
     myMesh(mesh), myCells(cells), myNcells(ncells), myType(type), iter(0)
   {
-        //MESSAGE("myNcells " << myNcells);
-       for (; iter<ncells; iter++)
-        {
-           int vtkId = myCells[iter];
-           int smdsId = myMesh->fromVtkToSmds(vtkId);
-           //MESSAGE("vtkId " << vtkId << " smdsId " << smdsId);
-           const SMDS_MeshElement* elem = myMesh->FindElement(smdsId);
-           if (elem->GetType() == type)
-               myFiltCells.push_back((SMDS_MeshElement*)elem);
-        }
-        myNcells = myFiltCells.size();
-        //MESSAGE("myNcells " << myNcells);
-       iter = 0;
-        //MESSAGE("SMDS_MeshNode_MyIterator (filter) " << ncells << " " << myNcells);
+    //MESSAGE("myNcells " << myNcells);
+    for (; iter<ncells; iter++)
+    {
+      int vtkId = myCells[iter];
+      int smdsId = myMesh->fromVtkToSmds(vtkId);
+      //MESSAGE("vtkId " << vtkId << " smdsId " << smdsId);
+      const SMDS_MeshElement* elem = myMesh->FindElement(smdsId);
+      if (elem->GetType() == type)
+        myFiltCells.push_back((SMDS_MeshElement*)elem);
+    }
+    myNcells = myFiltCells.size();
+    //MESSAGE("myNcells " << myNcells);
+    iter = 0;
+    //MESSAGE("SMDS_MeshNode_MyIterator (filter) " << ncells << " " << myNcells);
   }
 
   bool more()
   {
-      return (iter< myNcells);
+    return (iter< myNcells);
   }
 
   const SMDS_MeshElement* next()
   {
-      const SMDS_MeshElement* elem = myFiltCells[iter];
-      iter++;
-      return elem;
+    const SMDS_MeshElement* elem = myFiltCells[iter];
+    iter++;
+    return elem;
   }
 };
 
 SMDS_ElemIteratorPtr SMDS_MeshNode::
-        elementsIterator(SMDSAbs_ElementType type) const
+elementsIterator(SMDSAbs_ElementType type) const
 {
   if(type==SMDSAbs_Node)
-    return SMDS_MeshElement::elementsIterator(SMDSAbs_Node); 
+    return SMDS_MeshElement::elementsIterator(SMDSAbs_Node);
   else
   {
     vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID);
@@ -258,7 +258,7 @@ SMDS_ElemIteratorPtr SMDS_MeshNode::
 
 int SMDS_MeshNode::NbNodes() const
 {
-        return 1;
+  return 1;
 }
 
 double* SMDS_MeshNode::getCoord() const
@@ -305,7 +305,7 @@ void SMDS_MeshNode::setXYZ(double x, double y, double z)
 
 SMDSAbs_ElementType SMDS_MeshNode::GetType() const
 {
-        return SMDSAbs_Node;
+  return SMDSAbs_Node;
 }
 
 vtkIdType SMDS_MeshNode::GetVtkType() const
@@ -358,11 +358,11 @@ int SMDS_MeshNode::NbInverseElements(SMDSAbs_ElementType type) const
   int nb = 0;
   SMDS_Mesh *mesh = SMDS_Mesh::_meshList[myMeshId];
   for (int i=0; i<l.ncells; i++)
-        {
-           const SMDS_MeshElement* elem = mesh->FindElement(mesh->fromVtkToSmds(l.cells[i]));
-           if (elem->GetType() == type)
-                nb++;
-        }
+  {
+    const SMDS_MeshElement* elem = mesh->FindElement(mesh->fromVtkToSmds(l.cells[i]));
+    if (elem->GetType() == type)
+      nb++;
+  }
   return nb;
 }
 
@@ -371,14 +371,14 @@ int SMDS_MeshNode::NbInverseElements(SMDSAbs_ElementType type) const
 ///////////////////////////////////////////////////////////////////////////////
 bool operator<(const SMDS_MeshNode& e1, const SMDS_MeshNode& e2)
 {
-        return e1.getVtkId()<e2.getVtkId();
-        /*if(e1.myX<e2.myX) return true;
-        else if(e1.myX==e2.myX)
-        {
-                if(e1.myY<e2.myY) return true;
-                else if(e1.myY==e2.myY) return (e1.myZ<e2.myZ);
-                else return false;
-        }
-        else return false;*/
+  return e1.getVtkId()<e2.getVtkId();
+  /*if(e1.myX<e2.myX) return true;
+    else if(e1.myX==e2.myX)
+    {
+    if(e1.myY<e2.myY) return true;
+    else if(e1.myY==e2.myY) return (e1.myZ<e2.myZ);
+    else return false;
+    }
+    else return false;*/
 }
 
index 44bd3e2..c3a62bf 100644 (file)
@@ -8269,6 +8269,8 @@ bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
 //=======================================================================
 //function : SewFreeBorder
 //purpose  :
+//warning  : for border-to-side sewing theSideSecondNode is considered as
+//           the last side node and theSideThirdNode is not used
 //=======================================================================
 
 SMESH_MeshEditor::Sew_Error
index f92b56b..eae5aee 100644 (file)
@@ -620,39 +620,26 @@ bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
     // ---------------------------------------------------------------
 
     // get all faces
-    list< const SMDS_MeshElement* > faces;
-    if ( nbElems > 0 ) {
-      SMDS_ElemIteratorPtr fIt = fSubMesh->GetElements();
-      while ( fIt->more() ) {
-        const SMDS_MeshElement* f = fIt->next();
-        if ( f && f->GetType() == SMDSAbs_Face )
-          faces.push_back( f );
-      }
-    }
-    else {
-      SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
-      while ( fIt->more() )
-        faces.push_back( fIt->next() );
-    }
+    SMDS_ElemIteratorPtr fIt;
+    if ( nbElems > 0 )
+      fIt = fSubMesh->GetElements();
+    else
+      fIt = aMeshDS->elementsIterator( SMDSAbs_Face );
 
     // put nodes of all faces into the nodePointIDMap and fill myElemPointIDs
-    list< const SMDS_MeshElement* >::iterator fIt = faces.begin();
-    for ( ; fIt != faces.end(); ++fIt )
+    while ( fIt->more() )
     {
+      const SMDS_MeshElement* face = fIt->next();
       myElemPointIDs.push_back( TElemDef() );
       TElemDef& elemPoints = myElemPointIDs.back();
-      int nbNodes = (*fIt)->NbCornerNodes();
+      int nbNodes = face->NbCornerNodes();
       for ( int i = 0;i < nbNodes; ++i )
       {
-        const SMDS_MeshElement* node = (*fIt)->GetNode( i );
+        const SMDS_MeshElement* node = face->GetNode( i );
         TNodePointIDMap::iterator nIdIt = nodePointIDMap.insert( make_pair( node, -1 )).first;
         if ( nIdIt->second == -1 )
-        {
-          elemPoints.push_back( iPoint );
           nIdIt->second = iPoint++;
-        }
-        else
-          elemPoints.push_back( (*nIdIt).second );
+        elemPoints.push_back( (*nIdIt).second );
       }
     }
     myPoints.resize( iPoint );
index b334baa..c62f185 100644 (file)
@@ -142,6 +142,8 @@ SET(_moc_HEADERS
   SMESHGUI_FieldSelectorWdg.h
   SMESHGUI_DisplayEntitiesDlg.h
   SMESHGUI_SplitBiQuad.h
+  SMESHGUI_PreVisualObj.h
+  SMESHGUI_IdPreview.h
 )
 
 # header files / no moc processing
@@ -251,6 +253,8 @@ SET(_other_SOURCES
   SMESHGUI_FieldSelectorWdg.cxx
   SMESHGUI_DisplayEntitiesDlg.cxx
   SMESHGUI_SplitBiQuad.cxx
+  SMESHGUI_PreVisualObj.cxx
+  SMESHGUI_IdPreview.cxx
 )
 
 # sources / to compile
diff --git a/src/SMESHGUI/SMESHGUI_IdPreview.cxx b/src/SMESHGUI/SMESHGUI_IdPreview.cxx
new file mode 100644 (file)
index 0000000..7999bee
--- /dev/null
@@ -0,0 +1,202 @@
+// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SMESHGUI_IdPreview.h"
+
+#include <SALOME_Actor.h>
+#include <SMDS_Mesh.hxx>
+#include <SVTK_ViewWindow.h>
+
+#include <TColStd_MapOfInteger.hxx>
+#include <TColStd_MapIteratorOfMapOfInteger.hxx>
+
+#include <vtkActor2D.h>
+#include <vtkDataSetMapper.h>
+#include <vtkLabeledDataMapper.h>
+#include <vtkMaskPoints.h>
+#include <vtkPointData.h>
+#include <vtkProperty2D.h>
+#include <vtkRenderer.h>
+#include <vtkSelectVisiblePoints.h>
+#include <vtkTextProperty.h>
+#include <vtkUnstructuredGrid.h>
+
+// Extracted from SMESHGUI_MergeDlg.cxx
+
+SMESHGUI_IdPreview::SMESHGUI_IdPreview(SVTK_ViewWindow* theViewWindow):
+  myViewWindow(theViewWindow)
+{
+  myIdGrid = vtkUnstructuredGrid::New();
+
+  // Create and display actor
+  vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
+  aMapper->SetInputData( myIdGrid );
+
+  myIdActor = SALOME_Actor::New();
+  myIdActor->SetInfinitive(true);
+  myIdActor->VisibilityOff();
+  myIdActor->PickableOff();
+
+  myIdActor->SetMapper( aMapper );
+  aMapper->Delete();
+
+  myViewWindow->AddActor(myIdActor);
+
+  //Definition of points numbering pipeline
+  myPointsNumDataSet = vtkUnstructuredGrid::New();
+
+  myPtsMaskPoints = vtkMaskPoints::New();
+  myPtsMaskPoints->SetInputData(myPointsNumDataSet);
+  myPtsMaskPoints->SetOnRatio(1);
+
+  myPtsSelectVisiblePoints = vtkSelectVisiblePoints::New();
+  myPtsSelectVisiblePoints->SetInputConnection(myPtsMaskPoints->GetOutputPort());
+  myPtsSelectVisiblePoints->SelectInvisibleOff();
+  myPtsSelectVisiblePoints->SetTolerance(0.1);
+    
+  myPtsLabeledDataMapper = vtkLabeledDataMapper::New();
+  myPtsLabeledDataMapper->SetInputConnection(myPtsSelectVisiblePoints->GetOutputPort());
+  myPtsLabeledDataMapper->SetLabelModeToLabelScalars();
+    
+  vtkTextProperty* aPtsTextProp = vtkTextProperty::New();
+  aPtsTextProp->SetFontFamilyToTimes();
+  static int aPointsFontSize = 12;
+  aPtsTextProp->SetFontSize(aPointsFontSize);
+  aPtsTextProp->SetBold(1);
+  aPtsTextProp->SetItalic(0);
+  aPtsTextProp->SetShadow(0);
+  myPtsLabeledDataMapper->SetLabelTextProperty(aPtsTextProp);
+  aPtsTextProp->Delete();
+  
+  myIsPointsLabeled = false;
+
+  myPointLabels = vtkActor2D::New();
+  myPointLabels->SetMapper(myPtsLabeledDataMapper);
+  myPointLabels->GetProperty()->SetColor(1,1,1);
+  myPointLabels->SetVisibility(myIsPointsLabeled);
+
+  AddToRender(myViewWindow->getRenderer());
+}
+
+void SMESHGUI_IdPreview::SetPointsData ( SMDS_Mesh*                   theMesh,
+                                         const TColStd_MapOfInteger & theNodesIdMap )
+{
+  vtkPoints* aPoints = vtkPoints::New();
+  aPoints->SetNumberOfPoints(theNodesIdMap.Extent());
+  myIDs.clear();
+
+  TColStd_MapIteratorOfMapOfInteger idIter( theNodesIdMap );
+  for( int i = 0; idIter.More(); idIter.Next(), i++ )
+  {
+    const SMDS_MeshNode* aNode = theMesh->FindNode(idIter.Key());
+    aPoints->SetPoint( i, aNode->X(), aNode->Y(), aNode->Z() );
+    myIDs.push_back(idIter.Key());
+  }
+
+  myIdGrid->SetPoints(aPoints);
+
+  aPoints->Delete();
+
+  myIdActor->GetMapper()->Update();
+}
+
+void SMESHGUI_IdPreview::SetElemsData( const std::vector<int> & theElemsIdMap,
+                                       const std::list<gp_XYZ> & aGrCentersXYZ )
+{
+  vtkPoints* aPoints = vtkPoints::New();
+  aPoints->SetNumberOfPoints( theElemsIdMap.size() );
+  myIDs = theElemsIdMap;
+
+  std::list<gp_XYZ>::const_iterator coordIt = aGrCentersXYZ.begin();
+  for( int i = 0; coordIt != aGrCentersXYZ.end(); coordIt++, i++ )
+    aPoints->SetPoint( i, coordIt->X(), coordIt->Y(), coordIt->Z() );
+
+  myIdGrid->SetPoints(aPoints);
+  aPoints->Delete();
+
+  myIdActor->GetMapper()->Update();
+}
+
+void SMESHGUI_IdPreview::AddToRender(vtkRenderer* theRenderer)
+{
+  myIdActor->AddToRender(theRenderer);
+
+  myPtsSelectVisiblePoints->SetRenderer(theRenderer);
+  theRenderer->AddActor2D(myPointLabels);
+}
+
+void SMESHGUI_IdPreview::RemoveFromRender(vtkRenderer* theRenderer)
+{
+  myIdActor->RemoveFromRender(theRenderer);
+
+  myPtsSelectVisiblePoints->SetRenderer(theRenderer);
+  theRenderer->RemoveActor(myPointLabels);
+}
+
+void SMESHGUI_IdPreview::SetPointsLabeled( bool theIsPointsLabeled, bool theIsActorVisible )
+{
+  myIsPointsLabeled = theIsPointsLabeled && myIdGrid->GetNumberOfPoints();
+
+  if ( myIsPointsLabeled ) {
+    myPointsNumDataSet->ShallowCopy(myIdGrid);
+    vtkDataSet *aDataSet = myPointsNumDataSet;
+    int aNbElem = myIDs.size();
+    vtkIntArray *anArray = vtkIntArray::New();
+    anArray->SetNumberOfValues( aNbElem );
+    for ( int i = 0; i < aNbElem; i++ )
+      anArray->SetValue( i, myIDs[i] );
+    aDataSet->GetPointData()->SetScalars( anArray );
+    anArray->Delete();
+    myPtsMaskPoints->SetInputData( aDataSet );
+    myPointLabels->SetVisibility( theIsActorVisible );
+  }
+  else {
+    myPointLabels->SetVisibility( false );
+  }
+}
+
+SMESHGUI_IdPreview::~SMESHGUI_IdPreview()
+{
+  RemoveFromRender(myViewWindow->getRenderer());
+
+  myIdGrid->Delete();
+
+  myViewWindow->RemoveActor(myIdActor);
+  myIdActor->Delete();
+
+  //Deleting of points numbering pipeline
+  //---------------------------------------
+  myPointsNumDataSet->Delete();
+
+  //myPtsLabeledDataMapper->RemoveAllInputs();        //vtk 5.0 porting
+  myPtsLabeledDataMapper->Delete();
+
+  //myPtsSelectVisiblePoints->UnRegisterAllOutputs(); //vtk 5.0 porting
+  myPtsSelectVisiblePoints->Delete();
+
+  //myPtsMaskPoints->UnRegisterAllOutputs();          //vtk 5.0 porting
+  myPtsMaskPoints->Delete();
+
+  myPointLabels->Delete();
+
+  //       myTimeStamp->Delete();
+}
diff --git a/src/SMESHGUI/SMESHGUI_IdPreview.h b/src/SMESHGUI/SMESHGUI_IdPreview.h
new file mode 100644 (file)
index 0000000..ac547ee
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef SMESHGUI_IdPreview_H
+#define SMESHGUI_IdPreview_H
+
+#include "SMESH_SMESHGUI.hxx"
+
+#include <list>
+#include <vector>
+
+#include <gp_XYZ.hxx>
+
+class SALOME_Actor;
+class SMDS_Mesh;
+class SVTK_ViewWindow;
+class TColStd_MapOfInteger;
+class vtkActor2D;
+class vtkLabeledDataMapper;
+class vtkMaskPoints;
+class vtkRenderer;
+class vtkSelectVisiblePoints;
+class vtkTextProperty;
+class vtkUnstructuredGrid;
+
+/*!
+ * \brief To display in the viewer IDs of selected elements or nodes
+ */
+class SMESHGUI_IdPreview
+{
+public:
+  SMESHGUI_IdPreview(SVTK_ViewWindow* theViewWindow);
+  ~SMESHGUI_IdPreview();
+
+  void SetPointsData( SMDS_Mesh* theMesh, const TColStd_MapOfInteger & theNodesIdMap );
+  void SetElemsData ( const std::vector<int> &  theElemsIdMap,
+                      const std::list<gp_XYZ> & theGrCentersXYZ );
+  void SetPointsLabeled( bool theIsPointsLabeled, bool theIsActorVisible = true );
+
+  void AddToRender     ( vtkRenderer* theRenderer );
+  void RemoveFromRender( vtkRenderer* theRenderer );
+
+protected:
+
+  SVTK_ViewWindow*        myViewWindow;
+
+  vtkUnstructuredGrid*    myIdGrid;
+  SALOME_Actor*           myIdActor;
+
+  vtkUnstructuredGrid*    myPointsNumDataSet;
+  vtkMaskPoints*          myPtsMaskPoints;
+  vtkSelectVisiblePoints* myPtsSelectVisiblePoints;
+  vtkLabeledDataMapper*   myPtsLabeledDataMapper;
+  bool                    myIsPointsLabeled;
+  vtkActor2D*             myPointLabels;
+
+  std::vector<int>        myIDs;
+};
+
+#endif
index 92642d3..ec44221 100644 (file)
 #include "SMESHGUI_MergeDlg.h"
 
 #include "SMESHGUI.h"
-#include "SMESHGUI_Utils.h"
-#include "SMESHGUI_VTKUtils.h"
+#include "SMESHGUI_IdPreview.h"
 #include "SMESHGUI_MeshUtils.h"
 #include "SMESHGUI_SpinBox.h"
+#include "SMESHGUI_Utils.h"
+#include "SMESHGUI_VTKUtils.h"
 
 #include <SMESH_Actor.h>
 #include <SMESH_TypeFilter.hxx>
 #include CORBA_SERVER_HEADER(SMESH_Group)
 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
 
-// VTK includes
-#include <vtkUnstructuredGrid.h>
-#include <vtkRenderer.h>
-#include <vtkActor2D.h>
-#include <vtkPoints.h>
-#include <vtkDataSetMapper.h>
-#include <vtkMaskPoints.h>
-#include <vtkSelectVisiblePoints.h>
-#include <vtkLabeledDataMapper.h>
-#include <vtkTextProperty.h>
-#include <vtkIntArray.h>
-#include <vtkProperty2D.h>
-#include <vtkPointData.h>
-
 // Qt includes
 #include <QApplication>
+#include <QButtonGroup>
+#include <QCheckBox>
+#include <QGridLayout>
 #include <QGroupBox>
+#include <QHBoxLayout>
+#include <QKeyEvent>
 #include <QLabel>
 #include <QLineEdit>
 #include <QListWidget>
 #include <QPushButton>
 #include <QRadioButton>
-#include <QCheckBox>
-#include <QHBoxLayout>
 #include <QVBoxLayout>
-#include <QGridLayout>
-#include <QKeyEvent>
-#include <QButtonGroup>
 
 #define SPACING 6
 #define MARGIN  11
@@ -97,208 +84,27 @@ namespace
 {
   enum ActionType { MERGE_NODES, MERGE_ELEMENTS, TYPE_AUTO=0, TYPE_MANUAL };
 }
-namespace SMESH
-{
-  class TIdPreview
-  { // to display in the viewer IDs of the selected elements
-    SVTK_ViewWindow* myViewWindow;
-
-    vtkUnstructuredGrid* myIdGrid;
-    SALOME_Actor* myIdActor;
-
-    vtkUnstructuredGrid* myPointsNumDataSet;
-    vtkMaskPoints* myPtsMaskPoints;
-    vtkSelectVisiblePoints* myPtsSelectVisiblePoints;
-    vtkLabeledDataMapper* myPtsLabeledDataMapper;
-    vtkTextProperty* aPtsTextProp;
-    bool myIsPointsLabeled;
-    vtkActor2D* myPointLabels;
-
-    std::vector<int> myIDs;
-
-  public:
-    TIdPreview(SVTK_ViewWindow* theViewWindow):
-      myViewWindow(theViewWindow)
-    {
-      myIdGrid = vtkUnstructuredGrid::New();
-
-      // Create and display actor
-      vtkDataSetMapper* aMapper = vtkDataSetMapper::New();
-      aMapper->SetInputData( myIdGrid );
-
-      myIdActor = SALOME_Actor::New();
-      myIdActor->SetInfinitive(true);
-      myIdActor->VisibilityOff();
-      myIdActor->PickableOff();
-
-      myIdActor->SetMapper( aMapper );
-      aMapper->Delete();
-
-      myViewWindow->AddActor(myIdActor);
-
-      //Definition of points numbering pipeline
-      myPointsNumDataSet = vtkUnstructuredGrid::New();
-
-      myPtsMaskPoints = vtkMaskPoints::New();
-      myPtsMaskPoints->SetInputData(myPointsNumDataSet);
-      myPtsMaskPoints->SetOnRatio(1);
-
-      myPtsSelectVisiblePoints = vtkSelectVisiblePoints::New();
-      myPtsSelectVisiblePoints->SetInputConnection(myPtsMaskPoints->GetOutputPort());
-      myPtsSelectVisiblePoints->SelectInvisibleOff();
-      myPtsSelectVisiblePoints->SetTolerance(0.1);
-    
-      myPtsLabeledDataMapper = vtkLabeledDataMapper::New();
-      myPtsLabeledDataMapper->SetInputConnection(myPtsSelectVisiblePoints->GetOutputPort());
-      myPtsLabeledDataMapper->SetLabelModeToLabelScalars();
-    
-      vtkTextProperty* aPtsTextProp = vtkTextProperty::New();
-      aPtsTextProp->SetFontFamilyToTimes();
-      static int aPointsFontSize = 12;
-      aPtsTextProp->SetFontSize(aPointsFontSize);
-      aPtsTextProp->SetBold(1);
-      aPtsTextProp->SetItalic(0);
-      aPtsTextProp->SetShadow(0);
-      myPtsLabeledDataMapper->SetLabelTextProperty(aPtsTextProp);
-      aPtsTextProp->Delete();
-  
-      myIsPointsLabeled = false;
-
-      myPointLabels = vtkActor2D::New();
-      myPointLabels->SetMapper(myPtsLabeledDataMapper);
-      myPointLabels->GetProperty()->SetColor(1,1,1);
-      myPointLabels->SetVisibility(myIsPointsLabeled);
-
-      AddToRender(myViewWindow->getRenderer());
-    }
-
-    void SetPointsData ( SMDS_Mesh* theMesh, 
-                         TColStd_MapOfInteger & theNodesIdMap )
-    {
-      vtkPoints* aPoints = vtkPoints::New();
-      aPoints->SetNumberOfPoints(theNodesIdMap.Extent());
-      myIDs.clear();
-      
-      TColStd_MapIteratorOfMapOfInteger idIter( theNodesIdMap );
-      for( int i = 0; idIter.More(); idIter.Next(), i++ ) {
-        const SMDS_MeshNode* aNode = theMesh->FindNode(idIter.Key());
-        aPoints->SetPoint( i, aNode->X(), aNode->Y(), aNode->Z() );
-        myIDs.push_back(idIter.Key());
-      }
 
-      myIdGrid->SetPoints(aPoints);
 
-      aPoints->Delete();
-
-      myIdActor->GetMapper()->Update();
-    }
-
-    void SetElemsData( TColStd_MapOfInteger & theElemsIdMap, 
-                       std::list<gp_XYZ> & aGrCentersXYZ )
-    {
-      vtkPoints* aPoints = vtkPoints::New();
-      aPoints->SetNumberOfPoints(theElemsIdMap.Extent());
-      myIDs.clear();
-      
-      TColStd_MapIteratorOfMapOfInteger idIter( theElemsIdMap );
-      for( ; idIter.More(); idIter.Next() ) {
-        myIDs.push_back(idIter.Key());
-      }
-
-      gp_XYZ aXYZ;
-      std::list<gp_XYZ>::iterator coordIt = aGrCentersXYZ.begin();
-      for( int i = 0; coordIt != aGrCentersXYZ.end(); coordIt++, i++ ) {
-        aXYZ = *coordIt;
-        aPoints->SetPoint( i, aXYZ.X(), aXYZ.Y(), aXYZ.Z() );
-      }
-      myIdGrid->SetPoints(aPoints);
-      aPoints->Delete();
-      
-      myIdActor->GetMapper()->Update();
-    }
-
-    void AddToRender(vtkRenderer* theRenderer)
-    {
-      myIdActor->AddToRender(theRenderer);
-
-      myPtsSelectVisiblePoints->SetRenderer(theRenderer);
-      theRenderer->AddActor2D(myPointLabels);
-    }
-
-    void RemoveFromRender(vtkRenderer* theRenderer)
-    {
-      myIdActor->RemoveFromRender(theRenderer);
-
-      myPtsSelectVisiblePoints->SetRenderer(theRenderer);
-      theRenderer->RemoveActor(myPointLabels);
-    }
-
-    void SetPointsLabeled( bool theIsPointsLabeled, bool theIsActorVisible = true )
-    {
-      myIsPointsLabeled = theIsPointsLabeled && myIdGrid->GetNumberOfPoints();
-      
-      if ( myIsPointsLabeled ) {
-        myPointsNumDataSet->ShallowCopy(myIdGrid);
-        vtkDataSet *aDataSet = myPointsNumDataSet;
-        int aNbElem = myIDs.size();
-        vtkIntArray *anArray = vtkIntArray::New();
-        anArray->SetNumberOfValues( aNbElem );
-        for ( int i = 0; i < aNbElem; i++ )
-          anArray->SetValue( i, myIDs[i] );
-        aDataSet->GetPointData()->SetScalars( anArray );
-        anArray->Delete();
-        myPtsMaskPoints->SetInputData( aDataSet );
-        myPointLabels->SetVisibility( theIsActorVisible );
-      }
-      else {
-        myPointLabels->SetVisibility( false );
-      }
-    }
-    
-    ~TIdPreview()
-    {
-      RemoveFromRender(myViewWindow->getRenderer());
-
-      myIdGrid->Delete();
-
-      myViewWindow->RemoveActor(myIdActor);
-      myIdActor->Delete();
-
-      //Deleting of points numbering pipeline
-      //---------------------------------------
-      myPointsNumDataSet->Delete();
-      
-      //myPtsLabeledDataMapper->RemoveAllInputs();        //vtk 5.0 porting
-      myPtsLabeledDataMapper->Delete();
-
-      //myPtsSelectVisiblePoints->UnRegisterAllOutputs(); //vtk 5.0 porting
-      myPtsSelectVisiblePoints->Delete();
-
-      //myPtsMaskPoints->UnRegisterAllOutputs();          //vtk 5.0 porting
-      myPtsMaskPoints->Delete();
-
-      myPointLabels->Delete();
-
-//       myTimeStamp->Delete();
-    }
-  };
+QPixmap SMESHGUI_MergeDlg::IconFirst()
+{
+  static const char * iconFirst[] = {
+    "18 10 2 1",
+    "       g None",
+    ".      g #000000",
+    "         .     .  ",
+    "  ..    ..    ..  ",
+    "  ..   ...   ...  ",
+    "  ..  ....  ....  ",
+    "  .. ..... .....  ",
+    "  .. ..... .....  ",
+    "  ..  ....  ....  ",
+    "  ..   ...   ...  ",
+    "  ..    ..    ..  ",
+    "         .     .  "};
+  return iconFirst;
 }
 
-static const char * IconFirst[] = {
-"18 10 2 1",
-"       g None",
-".      g #000000",
-"         .     .  ",
-"  ..    ..    ..  ",
-"  ..   ...   ...  ",
-"  ..  ....  ....  ",
-"  .. ..... .....  ",
-"  .. ..... .....  ",
-"  ..  ....  ....  ",
-"  ..   ...   ...  ",
-"  ..    ..    ..  ",
-"         .     .  "};
-
 //=================================================================================
 // class    : SMESHGUI_MergeDlg()
 // purpose  :
@@ -313,7 +119,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   setAttribute(Qt::WA_DeleteOnClose, true);
   setWindowTitle(myAction == MERGE_ELEMENTS ? tr("SMESH_MERGE_ELEMENTS") : tr("SMESH_MERGE_NODES"));
 
-  myIdPreview = new SMESH::TIdPreview(SMESH::GetViewWindow( mySMESHGUI ));
+  myIdPreview = new SMESHGUI_IdPreview(SMESH::GetViewWindow( mySMESHGUI ));
 
   SUIT_ResourceMgr* aResMgr = SMESH::GetResourceMgr( mySMESHGUI );
   QPixmap IconMergeNodes (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_MERGE_NODES")));
@@ -511,7 +317,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction)
   RemoveElemButton = new QPushButton(GroupEdit);
   RemoveElemButton->setIcon(IconRemove);
   SetFirstButton = new QPushButton(GroupEdit);
-  SetFirstButton->setIcon(QPixmap(IconFirst));
+  SetFirstButton->setIcon(IconFirst());
 
   GroupEditLayout->addWidget(ListEdit,         0, 0, 2, 1);
   GroupEditLayout->addWidget(AddElemButton,    0, 1);
@@ -645,8 +451,9 @@ void SMESHGUI_MergeDlg::Init()
 // function : FindGravityCenter()
 // purpose  :
 //=================================================================================
-void SMESHGUI_MergeDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap, 
-                                          std::list< gp_XYZ > & theGrCentersXYZ)
+void SMESHGUI_MergeDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap,
+                                          std::vector<int>&      theIDs,
+                                          std::list< gp_XYZ > &  theGrCentersXYZ)
 {
   if (!myActor)
     return;
@@ -658,11 +465,13 @@ void SMESHGUI_MergeDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap,
 
   int nbNodes;
 
+  theIDs.reserve( theElemsIdMap.Extent() );
   TColStd_MapIteratorOfMapOfInteger idIter( theElemsIdMap );
   for( ; idIter.More(); idIter.Next() ) {
     const SMDS_MeshElement* anElem = aMesh->FindElement(idIter.Key());
     if ( !anElem )
       continue;
+    theIDs.push_back( idIter.Key() );
 
     gp_XYZ anXYZ(0., 0., 0.);
     SMDS_ElemIteratorPtr nodeIt = anElem->nodesIterator();
@@ -948,7 +757,7 @@ void SMESHGUI_MergeDlg::onDetect()
 
     SMESH::SMESH_IDSource_var src;
     if ( mySubMeshOrGroup->_is_nil() ) src = SMESH::SMESH_IDSource::_duplicate( myMesh );
-    else src = SMESH::SMESH_IDSource::_duplicate( mySubMeshOrGroup );
+    else                               src = SMESH::SMESH_IDSource::_duplicate( mySubMeshOrGroup );
 
     switch (myAction) {
     case MERGE_NODES :
@@ -1034,8 +843,9 @@ void SMESHGUI_MergeDlg::onSelectGroup()
     }
     else {
       std::list< gp_XYZ > aGrCentersXYZ;
-      FindGravityCenter(anIndices, aGrCentersXYZ);
-      myIdPreview->SetElemsData( anIndices, aGrCentersXYZ);
+      std::vector<int>    anIDs;
+      FindGravityCenter(anIndices, anIDs, aGrCentersXYZ);
+      myIdPreview->SetElemsData( anIDs, aGrCentersXYZ );
       myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
     }
   else
@@ -1087,8 +897,9 @@ void SMESHGUI_MergeDlg::onSelectElementFromGroup()
     }
     else {
       std::list< gp_XYZ > aGrCentersXYZ;
-      FindGravityCenter(anIndices, aGrCentersXYZ);
-      myIdPreview->SetElemsData(anIndices, aGrCentersXYZ);
+      std::vector<int>    anIDs;
+      FindGravityCenter(anIndices, anIDs, aGrCentersXYZ);
+      myIdPreview->SetElemsData(anIDs, aGrCentersXYZ);
       myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility());
     }
   else 
index 754dde0..52fd3d5 100644 (file)
 
 // STL includes
 #include <list>
+#include <vector>
 
 // IDL includes
 #include <SALOMEconfig.h>
 #include CORBA_SERVER_HEADER(SMESH_Mesh)
 
+class LightApp_SelectionMgr;
+class QButtonGroup;
+class QCheckBox;
 class QGroupBox;
 class QLabel;
 class QLineEdit;
+class QListWidget;
 class QPushButton;
 class QRadioButton;
-class QCheckBox;
-class QListWidget;
-class QButtonGroup;
 class SMESHGUI;
+class SMESHGUI_IdPreview;
 class SMESHGUI_SpinBox;
 class SMESH_Actor;
-class SVTK_Selector;
-class LightApp_SelectionMgr;
 class SUIT_SelectionFilter;
+class SVTK_Selector;
 class TColStd_MapOfInteger;
 
 namespace SMESH
@@ -76,6 +78,8 @@ public:
   SMESHGUI_MergeDlg( SMESHGUI*, int );
   ~SMESHGUI_MergeDlg();
 
+  static QPixmap IconFirst();
+
 private:
   void                      Init();
   void                      enterEvent( QEvent* );              /* mouse enter the QWidget */
@@ -84,7 +88,8 @@ private:
   bool                      isKeepNodesIDsSelection();
   bool                      isNewKeepNodesGroup( const char* entry );
 
-  void                      FindGravityCenter( TColStd_MapOfInteger&, 
+  void                      FindGravityCenter( TColStd_MapOfInteger&,
+                                               std::vector<int>& , 
                                                std::list<gp_XYZ>& );
   // add the centers of gravity of ElemsIdMap elements to the GrCentersXYZ list
 
@@ -103,7 +108,7 @@ private:
   SUIT_SelectionFilter*     myMeshOrSubMeshOrGroupFilter;
   SUIT_SelectionFilter*     mySubMeshOrGroupFilter;
 
-  SMESH::TIdPreview*        myIdPreview;
+  SMESHGUI_IdPreview*       myIdPreview;
 
   int                       myAction;
   bool                      myIsBusy;
diff --git a/src/SMESHGUI/SMESHGUI_PreVisualObj.cxx b/src/SMESHGUI/SMESHGUI_PreVisualObj.cxx
new file mode 100644 (file)
index 0000000..3e05490
--- /dev/null
@@ -0,0 +1,142 @@
+// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SMESHGUI_PreVisualObj.h"
+
+#include <SMDS_Mesh.hxx>
+#include <SMESH_Actor.h>
+
+SMESHGUI_PreVisualObj::SMESHGUI_PreVisualObj()
+{
+  myMesh = new SMDS_Mesh();
+}
+
+bool SMESHGUI_PreVisualObj::Update( int theIsClear = true )
+{
+  return false;
+}
+
+void SMESHGUI_PreVisualObj::UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor )
+{
+  if ( theFunctor ) theFunctor->SetMesh( GetMesh() );
+}
+
+int SMESHGUI_PreVisualObj::GetElemDimension( const int theObjId )
+{
+  if ( const SMDS_MeshElement* anElem = myMesh->FindElement( theObjId ))
+  {
+    switch ( anElem->GetType() )
+    {
+    case SMDSAbs_Edge  :     return 1;
+    case SMDSAbs_Face  :     return 2;
+    case SMDSAbs_Volume:     return 3;
+    // case SMDSAbs_0DElement : return 0;
+    // case SMDSAbs_Ball :      return 0;
+    default            :     return 0;
+    }
+  }
+  return -1;
+}
+
+int SMESHGUI_PreVisualObj::GetNbEntities( const SMDSAbs_ElementType theType ) const
+{
+  myMesh->GetMeshInfo().NbElements( theType );
+}
+
+SMESH::SMESH_Mesh_ptr SMESHGUI_PreVisualObj::GetMeshServer()
+{
+  return SMESH::SMESH_Mesh::_nil();
+}
+
+//=================================================================================
+// function : GetEdgeNodes
+// purpose  : Retrieve ids of nodes from edge of elements ( edge is numbered from 1 )
+//=================================================================================
+
+bool SMESHGUI_PreVisualObj::GetEdgeNodes( const int theElemId,
+                                          const int theEdgeNum,
+                                          int&      theNodeId1,
+                                          int&      theNodeId2 ) const
+{
+  const SMDS_MeshElement* e = myMesh->FindElement( theElemId );
+  if ( !e || e->GetType() != SMDSAbs_Face )
+    return false;
+
+  int nbNodes = e->NbCornerNodes();
+  if ( theEdgeNum < 0 || theEdgeNum > nbNodes )
+    return false;
+
+  theNodeId1 = e->GetNode( theEdgeNum-1 )->GetID();
+  theNodeId2 = e->GetNode( theEdgeNum % nbNodes )->GetID();
+
+  return true;
+}
+
+bool SMESHGUI_PreVisualObj::IsValid() const
+{
+  return GetNbEntities( SMDSAbs_All ) > 0;
+}
+
+vtkUnstructuredGrid* SMESHGUI_PreVisualObj::GetUnstructuredGrid()
+{
+  return myMesh->getGrid();
+}
+
+
+vtkIdType SMESHGUI_PreVisualObj::GetNodeObjId( int theVTKID )
+{
+  const SMDS_MeshNode* aNode = myMesh->FindNodeVtk( theVTKID );
+  return aNode ? aNode->GetID() : -1;
+}
+
+vtkIdType SMESHGUI_PreVisualObj::GetNodeVTKId( int theObjID )
+{
+  const SMDS_MeshNode* aNode = myMesh->FindNode( theObjID );
+  return aNode ? aNode->GetID() : -1;
+}
+
+vtkIdType SMESHGUI_PreVisualObj::GetElemObjId( int theVTKID )
+{
+  return this->GetMesh()->fromVtkToSmds(theVTKID);
+}
+
+vtkIdType SMESHGUI_PreVisualObj::GetElemVTKId( int theObjID )
+{
+  const SMDS_MeshElement* e = myMesh->FindElement(theObjID);
+  return e ? e->getVtkId() : -1;
+}
+
+void SMESHGUI_PreVisualObj::ClearEntitiesFlags()
+{
+  myEntitiesState = SMESH_Actor::eAllEntity;
+  myEntitiesFlag = false;
+}
+
+bool SMESHGUI_PreVisualObj::GetEntitiesFlag()
+{
+  return myEntitiesFlag;
+}
+
+unsigned int SMESHGUI_PreVisualObj::GetEntitiesState()
+{
+  return myEntitiesState;
+}
diff --git a/src/SMESHGUI/SMESHGUI_PreVisualObj.h b/src/SMESHGUI/SMESHGUI_PreVisualObj.h
new file mode 100644 (file)
index 0000000..dcbfac9
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  File   : SMESHGUI_PreVisualObj.h
+//  Module : SMESH
+//
+#ifndef SMESHGUI_PreVisualObj_H
+#define SMESHGUI_PreVisualObj_H
+
+#include "SMESH_SMESHGUI.hxx"
+
+#include "SMESH_Object.h"
+
+/*!
+ * \brief Incarnation of SMESH_VisualObj allowing usage of SMESH_Actor
+ *        to show arbitrary mesh data. SMESHGUI_PreVisualObj encapsulates
+ *        a instance of SMDS_Mesh that can be filled by its user.
+ *        Main usage: to initialize a SMESH_Actor to display some preview
+ */
+class SMESHGUI_EXPORT SMESHGUI_PreVisualObj : public SMESH_VisualObj
+{
+  mutable SMDS_Mesh* myMesh;
+  bool               myEntitiesFlag;
+  unsigned int       myEntitiesState;
+
+ public:
+  SMESHGUI_PreVisualObj();
+  virtual SMDS_Mesh* GetMesh() const { return myMesh; }
+
+  virtual bool Update( int theIsClear );
+  virtual bool NulData() { return false; }
+  virtual void UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor );
+  virtual int  GetElemDimension( const int theObjId );
+  virtual int  GetNbEntities( const SMDSAbs_ElementType theType) const;
+  virtual bool IsValid() const;
+  virtual bool GetEdgeNodes( const int theElemId,
+                             const int theEdgeNum,
+                             int&      theNodeId1,
+                             int&      theNodeId2 ) const;
+
+  virtual vtkIdType GetNodeObjId( int theVTKID );
+  virtual vtkIdType GetNodeVTKId( int theObjID );
+  virtual vtkIdType GetElemObjId( int theVTKID );
+  virtual vtkIdType GetElemVTKId( int theObjID );
+  virtual void                  ClearEntitiesFlags();
+  virtual bool                  GetEntitiesFlag();
+  virtual unsigned int          GetEntitiesState();
+
+  virtual SMESH::SMESH_Mesh_ptr GetMeshServer();
+  virtual vtkUnstructuredGrid*  GetUnstructuredGrid();
+};
+
+#endif
index 19b8a1d..6979a07 100644 (file)
 #include "SMESHGUI_SewingDlg.h"
 
 #include "SMESHGUI.h"
+#include "SMESHGUI_IdPreview.h"
+#include "SMESHGUI_IdValidator.h"
+#include "SMESHGUI_MergeDlg.h"
+#include "SMESHGUI_MeshUtils.h"
+#include "SMESHGUI_PreVisualObj.h"
+#include "SMESHGUI_SpinBox.h"
 #include "SMESHGUI_Utils.h"
 #include "SMESHGUI_VTKUtils.h"
-#include "SMESHGUI_MeshUtils.h"
-#include "SMESHGUI_IdValidator.h"
 
-#include <SMESH_Actor.h>
 #include <SMDS_Mesh.hxx>
+#include <SMESH_Actor.h>
+#include <SMESH_TypeDefs.hxx>
 
 // SALOME GUI includes
-#include <SUIT_Session.h>
-#include <SUIT_ResourceMgr.h>
+#include <LightApp_Application.h>
+#include <LightApp_SelectionMgr.h>
+#include <SALOME_ListIO.hxx>
 #include <SUIT_Desktop.h>
 #include <SUIT_MessageBox.h>
 #include <SUIT_OverrideCursor.h>
-
-#include <LightApp_Application.h>
-#include <LightApp_SelectionMgr.h>
-
+#include <SUIT_ResourceMgr.h>
+#include <SUIT_Session.h>
 #include <SVTK_ViewModel.h>
 #include <SVTK_ViewWindow.h>
-#include <SALOME_ListIO.hxx>
+#include <SalomeApp_IntSpinBox.h>
 
 // OCCT includes
 #include <TColStd_MapOfInteger.hxx>
 // Qt includes
 #include <QApplication>
 #include <QButtonGroup>
+#include <QCheckBox>
+#include <QGridLayout>
 #include <QGroupBox>
+#include <QHBoxLayout>
+#include <QKeyEvent>
 #include <QLabel>
 #include <QLineEdit>
+#include <QListWidget>
 #include <QPushButton>
 #include <QRadioButton>
-#include <QCheckBox>
-#include <QHBoxLayout>
+#include <QToolButton>
 #include <QVBoxLayout>
-#include <QGridLayout>
-#include <QKeyEvent>
-
-// IDL includes
-#include <SALOMEconfig.h>
-#include CORBA_SERVER_HEADER(SMESH_MeshEditor)
 
 #define SPACING 6
 #define MARGIN  11
 
+namespace
+{
+  enum ActionType { MODE_AUTO=0, MODE_MANUAL,
+                    MOVE_LEFT_1=0, MOVE_RIGHT_1, MOVE_LEFT_2, MOVE_RIGHT_2,
+                    GROUP_COLOR=Qt::UserRole, GROUP_INDEX };
+}
+
+//=================================================================================
+/*!
+ * \brief Dispalayer of free borders
+ */
+//=================================================================================
+
+struct SMESHGUI_SewingDlg::BorderGroupDisplayer
+{
+  const SMESH::ListOfFreeBorders& myBorders;
+  const SMESH::FreeBordersGroup&  myGroup;
+  QColor                          myColor;
+  SMESH::SMESH_Mesh_ptr           myMesh;
+
+  std::vector< SMESH_Actor* >     myPartActors;
+  SVTK_ViewWindow*                myViewWindow;
+  SMESHGUI_IdPreview              myIdPreview;
+
+  BorderGroupDisplayer( const SMESH::CoincidentFreeBorders& borders,
+                        int                                 groupIndex,
+                        QColor                              color,
+                        SMESH::SMESH_Mesh_ptr               mesh);
+  ~BorderGroupDisplayer();
+  void Hide();
+  void ShowGroup( bool wholeBorders );
+  void ShowPart( int partIndex, bool toEdit );
+  void Update();
+
+private:
+  void getPartEnds( int partIndex, std::vector<int> & ids, std::list<gp_XYZ>& coords);
+};
+
 //=================================================================================
 // class    : SMESHGUI_SewingDlg()
 // purpose  :
@@ -89,6 +129,7 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
   QPixmap image2 (mgr->loadPixmap("SMESH", tr("ICON_SMESH_SEWING_BORDERTOSIDE")));
   QPixmap image3 (mgr->loadPixmap("SMESH", tr("ICON_SMESH_SEWING_SIDEELEMENTS")));
   QPixmap image4 (mgr->loadPixmap("SMESH", tr("ICON_SELECT")));
+  QPixmap IconRemove(mgr->loadPixmap("SMESH", tr("ICON_REMOVE")));
 
   setModal(false);
   setAttribute(Qt::WA_DeleteOnClose, true);
@@ -203,9 +244,162 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
   // Control for the polyedres creation to obtain conform mesh
   CheckBoxPolyedrs = new QCheckBox(tr("CREATE_POLYEDRS_NEAR_BOUNDARY"), GroupArguments);
 
+  /***************************************************************/
+  // Controls to switch free borders mode ( auto || manual )
+
+  ModeGroup = new QGroupBox( tr( "SMESH_MODE" ), GroupArguments );
+  ModeButGrp = new QButtonGroup( ModeGroup );
+  QHBoxLayout* aModeGroupLayout = new QHBoxLayout( ModeGroup );
+  aModeGroupLayout->setMargin( MARGIN );
+  aModeGroupLayout->setSpacing( SPACING );
+
+  QRadioButton* rb1 = new QRadioButton( tr( "SMESH_AUTOMATIC" ), ModeGroup );
+  QRadioButton* rb2 = new QRadioButton( tr( "SMESH_MANUAL"    ), ModeGroup );
+  ModeButGrp->addButton( rb1, MODE_AUTO );
+  ModeButGrp->addButton( rb2, MODE_MANUAL );
+  aModeGroupLayout->addWidget( rb1 );
+  aModeGroupLayout->addWidget( rb2 );
+  rb1->setChecked(true);
+
+  /***************************************************************/
+  // Controls for detecting coincident free borders
+
+  SewFreeBordersWidget = new QWidget( GroupArguments );
+  QVBoxLayout* aSewFreeBordersLayout = new QVBoxLayout( SewFreeBordersWidget );
+  aSewFreeBordersLayout->setMargin( 0 );
+  aSewFreeBordersLayout->setSpacing( SPACING );
+
+  // Tolerance
+  QWidget* TolAndAuto = new QWidget(SewFreeBordersWidget);
+  QLabel* TextLabelTolerance = new QLabel(tr("SMESH_TOLERANCE"), TolAndAuto);
+  SpinBoxTolerance = new SMESHGUI_SpinBox(TolAndAuto);
+  SpinBoxTolerance->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
+  SpinBoxTolerance->RangeStepAndValidator(0.0, COORD_MAX, 0.00001, "len_tol_precision");
+  SpinBoxTolerance->SetValue(0.); // auto-tolerance
+
+  // Auto Sewing
+  AutoSewCheck = new QCheckBox(tr("AUTO_SEWING"), TolAndAuto);
+  AutoSewCheck->setChecked( true );
+
+  // mesh
+  QGroupBox* GroupMesh = new QGroupBox(tr("SMESH_SELECT_WHOLE_MESH"), SewFreeBordersWidget);
+  QHBoxLayout* GroupMeshLayout = new QHBoxLayout(GroupMesh);
+  GroupMeshLayout->setSpacing(SPACING);
+  GroupMeshLayout->setMargin(MARGIN);
+
+  QLabel* TextLabelName = new QLabel(tr("SMESH_NAME"), GroupMesh);
+  //SelectMeshButton = new QPushButton(GroupMesh);
+  //SelectMeshButton->setIcon(IconSelect);
+  LineEditMesh = new QLineEdit(GroupMesh);
+  LineEditMesh->setReadOnly(true);
+
+  GroupMeshLayout->addWidget(TextLabelName);
+  //GroupMeshLayout->addWidget(SelectMeshButton);
+  GroupMeshLayout->addWidget(LineEditMesh);
+
+  QGridLayout* TolAndAutoLayout = new QGridLayout( TolAndAuto );
+  TolAndAutoLayout->setSpacing(SPACING);
+  TolAndAutoLayout->setMargin(0);
+  TolAndAutoLayout->addWidget(GroupMesh,          0, 0, 1, 2 );
+  TolAndAutoLayout->addWidget(TextLabelTolerance, 1, 0 );
+  TolAndAutoLayout->addWidget(SpinBoxTolerance,   1, 1 );
+  TolAndAutoLayout->addWidget(AutoSewCheck,       2, 0 );
+
+  aSewFreeBordersLayout->addWidget( TolAndAuto );
+
+  /******************/
+  // Coincident group
+  GroupCoincidentWidget = new QWidget(SewFreeBordersWidget);
+  QGridLayout* GroupCoincidentLayout = new QGridLayout(GroupCoincidentWidget);
+  GroupCoincidentLayout->setSpacing(SPACING);
+  GroupCoincidentLayout->setMargin(0);
+
+  QGroupBox* GroupCoincident = new QGroupBox(tr("COINCIDENT_FREE_BORDERS"), GroupCoincidentWidget);
+  QGridLayout* aCoincidentLayout = new QGridLayout(GroupCoincident);
+  aCoincidentLayout->setSpacing(SPACING);
+  aCoincidentLayout->setMargin(MARGIN);
+
+  /*******/
+  // borders
+  ListCoincident = new QListWidget(GroupCoincident);
+  ListCoincident->setSelectionMode(QListWidget::ExtendedSelection);
+
+  DetectButton      = new QPushButton(tr("DETECT"),           GroupCoincident);
+  RemoveGroupButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupCoincident);
+
+  SelectAllCheck = new QCheckBox(tr("SELECT_ALL"), GroupCoincident);
+
+  aCoincidentLayout->addWidget(ListCoincident,    0, 0, 4, 2);
+  aCoincidentLayout->addWidget(DetectButton,      1, 2);
+  aCoincidentLayout->addWidget(RemoveGroupButton, 3, 2);
+  aCoincidentLayout->addWidget(SelectAllCheck,    4, 0);
+  aCoincidentLayout->setRowMinimumHeight(1, 10);
+  aCoincidentLayout->setRowStretch      (1, 5);
+
+  GroupCoincidentLayout->addWidget( GroupCoincident );
+
+  /*****************************************/
+  // Controls for editing the selected group
+
+  QGroupBox* GroupEdit = new QGroupBox(tr("EDIT_SELECTED_GROUP"), GroupCoincidentWidget);
+  QGridLayout* GroupEditLayout = new QGridLayout(GroupEdit);
+  GroupEditLayout->setSpacing(SPACING);
+  GroupEditLayout->setMargin(MARGIN);
+
+  ListEdit = new QListWidget(GroupEdit);
+  ListEdit->setFlow( QListView::LeftToRight );
+  ListEdit->setSelectionMode(QListWidget::ExtendedSelection);
+  SetFirstButton = new QPushButton(GroupEdit);
+  SetFirstButton->setIcon(QPixmap(SMESHGUI_MergeDlg::IconFirst()));
+  RemoveElemButton = new QPushButton(GroupEdit);
+  RemoveElemButton->setIcon(IconRemove);
+
+  MoveBorderEndsButGrp = new QButtonGroup( GroupEdit );
+  QToolButton* moveBut1 = new QToolButton( GroupEdit );
+  QToolButton* moveBut2 = new QToolButton( GroupEdit );
+  QToolButton* moveBut3 = new QToolButton( GroupEdit );
+  QToolButton* moveBut4 = new QToolButton( GroupEdit );
+  moveBut1->setArrowType( Qt::LeftArrow );
+  moveBut2->setArrowType( Qt::RightArrow );
+  moveBut3->setArrowType( Qt::LeftArrow );
+  moveBut4->setArrowType( Qt::RightArrow );
+  MoveBorderEndsButGrp->addButton( moveBut1, MOVE_LEFT_1 );
+  MoveBorderEndsButGrp->addButton( moveBut2, MOVE_RIGHT_1 );
+  MoveBorderEndsButGrp->addButton( moveBut3, MOVE_LEFT_2 );
+  MoveBorderEndsButGrp->addButton( moveBut4, MOVE_RIGHT_2 );
+
+  SwapBut  = new QPushButton( "<->", GroupEdit );
+  BorderEndLine[0] = new QLineEdit( GroupEdit );
+  BorderEndLine[1] = new QLineEdit( GroupEdit );
+  BorderEndLine[0]->setReadOnly(true);
+  BorderEndLine[1]->setReadOnly(true);
+  QLabel* StepLabel = new QLabel(tr("STEP"), GroupEdit );
+  StepSpin = new SalomeApp_IntSpinBox( 1, 100000, 1, GroupEdit,
+                                       /*acceptNames=*/false, /*showTip=*/false );
+  StepSpin->setValue( 1 );
+
+  GroupEditLayout->addWidget(ListEdit,         0, 0, 1, 8);
+  GroupEditLayout->addWidget(SetFirstButton,   0, 8);
+  GroupEditLayout->addWidget(RemoveElemButton, 0, 9);
+  GroupEditLayout->addWidget(moveBut1,         1, 0);
+  GroupEditLayout->addWidget(BorderEndLine[0], 1, 1);
+  GroupEditLayout->addWidget(moveBut2,         1, 2);
+  GroupEditLayout->addWidget(moveBut3,         1, 3);
+  GroupEditLayout->addWidget(BorderEndLine[1], 1, 4);
+  GroupEditLayout->addWidget(moveBut4,         1, 5);
+  GroupEditLayout->setColumnStretch(              6, 5 );
+  GroupEditLayout->addWidget(SwapBut,          1, 7);
+  GroupEditLayout->addWidget(StepLabel,        1, 8);
+  GroupEditLayout->addWidget(StepSpin,         1, 9);
+
+  GroupCoincidentLayout->addWidget( GroupEdit );
+  aSewFreeBordersLayout->addWidget( GroupCoincidentWidget );
+
   // layout
+  GroupArgumentsLayout->addWidget(ModeGroup);
   GroupArgumentsLayout->addWidget(SubGroup1);
   GroupArgumentsLayout->addWidget(SubGroup2);
+  GroupArgumentsLayout->addWidget(SewFreeBordersWidget);
   GroupArgumentsLayout->addWidget(CheckBoxMerge);
   GroupArgumentsLayout->addWidget(CheckBoxPolygons);
   GroupArgumentsLayout->addWidget(CheckBoxPolyedrs);
@@ -238,6 +432,7 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
   SMESHGUI_SewingDlgLayout->addWidget(ConstructorsBox);
   SMESHGUI_SewingDlgLayout->addWidget(GroupArguments);
   SMESHGUI_SewingDlgLayout->addWidget(GroupButtons);
+  //SMESHGUI_SewingDlgLayout->setStretch( 2, 10 );
 
   /* Initialisations */
   RadioButton1->setChecked(true);
@@ -253,6 +448,9 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
 
   myHelpFileName = "sewing_meshes_page.html";
 
+  myActor = 0;
+  setDisplayMode();
+
   Init();
 
   /* signals and slots connections */
@@ -283,6 +481,18 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
   connect(LineEdit5, SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&)));
   connect(LineEdit6, SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&)));
 
+  connect(ModeButGrp,           SIGNAL(buttonClicked(int)),     SLOT(onModeChange(int)));
+  connect(AutoSewCheck,         SIGNAL(stateChanged(int)),      SLOT(onAutoSew(int)));
+  connect(DetectButton,         SIGNAL(clicked()),              SLOT(onDetectClicked()));
+  connect(RemoveGroupButton,    SIGNAL(clicked()),              SLOT(onRemoveGroupClicked()));
+  connect(ListCoincident,       SIGNAL(itemSelectionChanged()), SLOT(onSelectGroup()));
+  connect(SelectAllCheck,       SIGNAL(stateChanged(int)),      SLOT(onSelectAll(int)));
+  connect(ListEdit,             SIGNAL(itemSelectionChanged()), SLOT(onSelectBorderPartFromGroup()));
+  connect(SetFirstButton,       SIGNAL(clicked()),              SLOT(onSetFirstClicked()));
+  connect(RemoveElemButton,     SIGNAL(clicked()),              SLOT(onRemoveElemClicked()));
+  connect(MoveBorderEndsButGrp, SIGNAL(buttonClicked(int)),     SLOT(onMoveBorderEnd(int)));
+  connect(SwapBut,              SIGNAL(clicked()),              SLOT(onSwapClicked()));
+
   ConstructorsClicked(0);
 }
 
@@ -292,6 +502,12 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
 //=================================================================================
 SMESHGUI_SewingDlg::~SMESHGUI_SewingDlg()
 {
+  for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
+  {
+    delete myBorderDisplayers[ i ];
+    myBorderDisplayers[ i ] = 0;
+  }
+  myBorderDisplayers.clear();
 }
 
 //=================================================================================
@@ -302,13 +518,16 @@ void SMESHGUI_SewingDlg::Init()
 {
   myBusy = false;
 
-  myEditCurrentArgument = LineEdit1;
-  LineEdit1->setFocus();
-  myActor = 0;
+  if ( LineEdit1->isVisible() )
+    myEditCurrentArgument = LineEdit1;
+  else
+    myEditCurrentArgument = LineEditMesh;
+  myEditCurrentArgument->setFocus();
+  //myActor = 0;
   myMesh = SMESH::SMESH_Mesh::_nil();
-  CheckBoxMerge->setChecked(false);
-  CheckBoxPolygons->setChecked(false);
-  CheckBoxPolyedrs->setChecked(false);
+  // CheckBoxMerge->setChecked(false);
+  // CheckBoxPolygons->setChecked(false);
+  // CheckBoxPolyedrs->setChecked(false);
   SelectionIntoArgument();
 }
 
@@ -349,75 +568,97 @@ void SMESHGUI_SewingDlg::ConstructorsClicked (int constructorId)
       CheckBoxPolyedrs->hide();
   }
 
+  if (( !SubGroup1->isVisible() ) &&
+      ( constructorId != 0 || ModeButGrp->checkedId() == MODE_MANUAL ))
+  {
+    SubGroup1->show();
+    SubGroup2->show();
+  }
+
+  if ( constructorId != 0 )
+  {
+    ModeGroup->hide();
+    SewFreeBordersWidget->hide();
+  }
+
+  bool isNodeSelection = true;
+
   switch (constructorId) {
   case 0:
-    {
-      GroupArguments->setTitle(tr("SEW_FREE_BORDERS"));
-      SubGroup1->setTitle(tr("BORDER_1"));
-      SubGroup2->setTitle(tr("BORDER_2"));
+  {
+    GroupArguments->setTitle(tr("SEW_FREE_BORDERS"));
+    SubGroup1->setTitle(tr("BORDER_1"));
+    SubGroup2->setTitle(tr("BORDER_2"));
 
-        if (!CheckBoxPolygons->isVisible())
-          CheckBoxPolygons->show();
-        if (!CheckBoxPolyedrs->isVisible())
-          CheckBoxPolyedrs->show();
+    if (!CheckBoxPolygons->isVisible())
+      CheckBoxPolygons->show();
+    if (!CheckBoxPolyedrs->isVisible())
+      CheckBoxPolyedrs->show();
 
-      break;
+    if ( !ModeGroup->isVisible() )
+    {
+      ModeGroup->show();
     }
+    onModeChange( ModeButGrp->checkedId() );
+
+    isNodeSelection = ( ModeButGrp->checkedId() == MODE_MANUAL );
+
+    break;
+  }
   case 1:
-    {
-      GroupArguments->setTitle(tr("SEW_CONFORM_FREE_BORDERS"));
-      SubGroup1->setTitle(tr("BORDER_1"));
-      SubGroup2->setTitle(tr("BORDER_2"));
+  {
+    GroupArguments->setTitle(tr("SEW_CONFORM_FREE_BORDERS"));
+    SubGroup1->setTitle(tr("BORDER_1"));
+    SubGroup2->setTitle(tr("BORDER_2"));
 
-      TextLabel6->setEnabled(false);
-      SelectButton6->setEnabled(false);
-      LineEdit6->setEnabled(false);
+    TextLabel6->setEnabled(false);
+    SelectButton6->setEnabled(false);
+    LineEdit6->setEnabled(false);
 
-      myOk6 = true;
+    myOk6 = true;
 
-      break;
-    }
+    break;
+  }
   case 2:
-    {
-      GroupArguments->setTitle(tr("SEW_BORDER_TO_SIDE"));
-      SubGroup1->setTitle(tr("BORDER"));
-      SubGroup2->setTitle(tr("SIDE"));
-
-      TextLabel5->setEnabled(false);
-      SelectButton5->setEnabled(false);
-      LineEdit5->setEnabled(false);
-
-      if (!CheckBoxPolygons->isVisible())
-        CheckBoxPolygons->show();
-      if (!CheckBoxPolyedrs->isVisible())
-        CheckBoxPolyedrs->show();
-      
-      myOk5 = true;
-
-      break;
-    }
-  case 3:
-    {
-      GroupArguments->setTitle(tr("SEW_SIDE_ELEMENTS"));
-      SubGroup1->setTitle(tr("SIDE_1"));
-      SubGroup2->setTitle(tr("SIDE_2"));
+  {
+    GroupArguments->setTitle(tr("SEW_BORDER_TO_SIDE"));
+    SubGroup1->setTitle(tr("BORDER"));
+    SubGroup2->setTitle(tr("SIDE"));
 
-      TextLabel1->setText(tr("SMESH_ID_ELEMENTS"));
-      TextLabel2->setText(tr("NODE1_TO_MERGE"));
-      TextLabel3->setText(tr("NODE2_TO_MERGE"));
-      TextLabel4->setText(tr("SMESH_ID_ELEMENTS"));
-      TextLabel5->setText(tr("NODE1_TO_MERGE"));
-      TextLabel6->setText(tr("NODE2_TO_MERGE"));
+    TextLabel5->setEnabled(false);
+    SelectButton5->setEnabled(false);
+    LineEdit5->setEnabled(false);
 
-      LineEdit1->setValidator(new SMESHGUI_IdValidator(this));
-      LineEdit4->setValidator(new SMESHGUI_IdValidator(this));
+    if (!CheckBoxPolygons->isVisible())
+      CheckBoxPolygons->show();
+    if (!CheckBoxPolyedrs->isVisible())
+      CheckBoxPolyedrs->show();
 
-      SMESH::SetPointRepresentation(false);
+    myOk5 = true;
 
-      if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
-        aViewWindow->SetSelectionMode(CellSelection);
-      break;
-    }
+    break;
+  }
+  case 3:
+  {
+    GroupArguments->setTitle(tr("SEW_SIDE_ELEMENTS"));
+    SubGroup1->setTitle(tr("SIDE_1"));
+    SubGroup2->setTitle(tr("SIDE_2"));
+
+    TextLabel1->setText(tr("SMESH_ID_ELEMENTS"));
+    TextLabel2->setText(tr("NODE1_TO_MERGE"));
+    TextLabel3->setText(tr("NODE2_TO_MERGE"));
+    TextLabel4->setText(tr("SMESH_ID_ELEMENTS"));
+    TextLabel5->setText(tr("NODE1_TO_MERGE"));
+    TextLabel6->setText(tr("NODE2_TO_MERGE"));
+
+    LineEdit1->setValidator(new SMESHGUI_IdValidator(this));
+    LineEdit4->setValidator(new SMESHGUI_IdValidator(this));
+
+    isNodeSelection = false;
+    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+      aViewWindow->SetSelectionMode(CellSelection);
+    break;
+  }
   }
 
   if (constructorId != 3) {
@@ -430,21 +671,581 @@ void SMESHGUI_SewingDlg::ConstructorsClicked (int constructorId)
 
     LineEdit1->setValidator(new SMESHGUI_IdValidator(this, 1));
     LineEdit4->setValidator(new SMESHGUI_IdValidator(this, 1));
+  }
 
+  if ( isNodeSelection )
+  {
     SMESH::SetPointRepresentation(true);
-
     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
       aViewWindow->SetSelectionMode(NodeSelection);
   }
 
+  UpdateButtons();
+
   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument()));
   mySelectionMgr->setSelectedObjects( io );
 
   QApplication::instance()->processEvents();
   updateGeometry();
+
+  resize(100,100);
+}
+
+//=======================================================================
+//function : storeDisplayMode
+//purpose  : save representation of a mesh and switch it to wireframe mode
+//=======================================================================
+
+void SMESHGUI_SewingDlg::setDisplayMode()
+{
+  myStoredEntityMode = 0;
+  myStoredRepresentation = -1;
+  if ( myActor )
+  {
+    myStoredEntityMode     = myActor->GetEntityMode();
+    myStoredRepresentation = myActor->GetRepresentation();
+
+    myActor->SetEntityMode( myStoredEntityMode & ~SMESH_Actor::eVolumes );
+    myActor->SetRepresentation( SMESH_Actor::eEdge );
+  }
+}
+
+//=======================================================================
+//function : restoreDisplayMode
+//purpose  : restore representation of a mesh
+//=======================================================================
+
+void SMESHGUI_SewingDlg::restoreDisplayMode()
+{
+  if ( myActor && myStoredEntityMode )
+  {
+    if ( myActor->GetEntityMode() == ( myStoredEntityMode & ~SMESH_Actor::eVolumes ))
+      myActor->SetEntityMode( myStoredEntityMode );
+
+    if ( myActor->GetRepresentation() == SMESH_Actor::eEdge )
+      myActor->SetRepresentation( myStoredRepresentation );
+
+    myStoredEntityMode = 0;
+    myStoredRepresentation = -1;
+  }
+}
+
+//=======================================================================
+//function : onModeChange
+//purpose  : SLOT called when mode (auto or manual) of Sew free borders change
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onModeChange( int mode )
+{
+  if ( mode == MODE_MANUAL )
+  {
+    myEditCurrentArgument = LineEdit1;
+    if ( !SubGroup1->isVisible() )
+      SubGroup1->show(), SubGroup2->show();
+    SewFreeBordersWidget->hide();
+  }
+  else
+  {
+    myEditCurrentArgument = LineEditMesh;
+    SubGroup1->hide(), SubGroup2->hide();
+    if ( !SewFreeBordersWidget->isVisible() )
+      SewFreeBordersWidget->show();
+  }
+  onAutoSew( AutoSewCheck->isChecked() );
+
+  QApplication::instance()->processEvents();
+  updateGeometry();
+
   resize(100,100);
 }
 
+//=======================================================================
+//function : onAutoSew
+//purpose  : SLOT called when Auto Sewing check box is checked
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onAutoSew( int isAuto )
+{
+  GroupCoincidentWidget->setVisible( !isAuto );
+
+  QApplication::instance()->processEvents();
+
+  SewFreeBordersWidget->hide();
+  if ( ModeButGrp->checkedId() == MODE_AUTO )
+    SewFreeBordersWidget->show();
+
+  UpdateButtons();
+
+  updateGeometry();
+  resize(minimumSizeHint());
+}
+
+//=======================================================================
+//function : haveBorders
+//purpose  : Returns true if myBorders have been initialized
+//=======================================================================
+
+bool SMESHGUI_SewingDlg::haveBorders()
+{
+  return ( & myBorders.in() &&
+           myBorders->borders.length() &&
+           myBorders->coincidentGroups.length() );
+}
+
+//=======================================================================
+//function : getGroupText
+//purpose  : Returns a text of a given group of coincident free borders
+//=======================================================================
+
+QString SMESHGUI_SewingDlg::getPartText(const SMESH::FreeBorderPart& aPART)
+{
+  QString text;
+  if ( 0 <= aPART.border && aPART.border < myBorders->borders.length() )
+  {
+    const SMESH::FreeBorder& aBRD = myBorders->borders[ aPART.border ];
+    if ( 0 <= aPART.node1    && aPART.node1 < aBRD.nodeIDs.length() &&
+         0 <= aPART.nodeLast && aPART.nodeLast < aBRD.nodeIDs.length() )
+    {
+      text += QString("( %1 %2 ) ")
+        .arg( aBRD.nodeIDs[ aPART.node1 ] )
+        .arg( aBRD.nodeIDs[ aPART.nodeLast ] );
+    }
+  }
+  return text;
+}
+
+//=======================================================================
+//function : getGroupText
+//purpose  : Returns a text of a given group of coincident free borders
+//=======================================================================
+
+QString SMESHGUI_SewingDlg::getGroupText(int groupIndex)
+{
+  QString text;
+
+  if ( haveBorders()   &&
+       groupIndex >= 0 &&
+       groupIndex < myBorders->coincidentGroups.length() )
+  {
+    const SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ groupIndex ];
+
+    for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
+    {
+      QString partText = getPartText( aGRP[ iP ]);
+      if ( partText.isEmpty() )
+        return "";
+      text += partText;
+    }
+  }
+  return text;
+}
+
+//=======================================================================
+//function : onDetectClicked
+//purpose  : SLOT called when [Detect] is clicked
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onDetectClicked()
+{
+  ListCoincident->clear();
+
+  if ( myMesh->_is_nil() )
+    return;
+
+  SUIT_OverrideCursor wc;
+
+  SMESH::SMESH_MeshEditor_var editor = myMesh->GetMeshEditor();
+  myBorders = editor->FindCoincidentFreeBorders( SpinBoxTolerance->GetValue() );
+  if ( !haveBorders() )
+    return;
+
+  for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
+  {
+    delete myBorderDisplayers[ i ];
+    myBorderDisplayers[ i ] = 0;
+  }
+  myBorderDisplayers.resize( myBorders->coincidentGroups.length(), 0 );
+
+  for ( CORBA::ULong i = 0; i < myBorders->coincidentGroups.length(); ++i )
+  {
+    QString groupText = getGroupText( i );
+    if ( groupText.isEmpty() )
+      continue;
+
+    QColor groupColor;
+    groupColor.setHsvF( float(i) / myBorders->coincidentGroups.length(), 1., 1. );
+    QPixmap icon( QSize( 20, 20 ));
+    icon.fill( groupColor );
+
+    QListWidgetItem * item = new QListWidgetItem( icon, groupText, ListCoincident );
+    item->setData( GROUP_COLOR, groupColor );
+    item->setData( GROUP_INDEX, i );
+  }
+
+  onSelectGroup();
+
+  UpdateButtons();
+}
+
+//=======================================================================
+//function : onRemoveGroupClicked
+//purpose  :
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onRemoveGroupClicked()
+{
+  QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
+  for ( int i = 0; i < selItems.count(); ++i )
+  {
+    QListWidgetItem* item = selItems[ i ];
+    item->setSelected( false );
+    int groupIndex = item->data( GROUP_INDEX ).toInt();
+    delete item;
+    myBorderDisplayers[ groupIndex ]->Hide();
+    SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
+    aGRP.length( 0 );
+  }
+  UpdateButtons();
+}
+
+//=======================================================================
+//function : showGroup
+//purpose  : display a group of coincident free borders in the Viewer
+//=======================================================================
+
+void SMESHGUI_SewingDlg::showGroup( QListWidgetItem* item )
+{
+  if ( !item ||
+       item->listWidget() != ListCoincident ||
+       !haveBorders() )
+    return;
+
+  int    groupIndex = item->data( GROUP_INDEX ).toInt();
+  QColor groupColor = item->data( GROUP_COLOR ).value<QColor>();
+  if ( groupIndex >= 0       &&
+       groupIndex < myBorders->coincidentGroups.length() )
+  {
+    if ( !myBorderDisplayers[ groupIndex ])
+      myBorderDisplayers[ groupIndex ] = new BorderGroupDisplayer( myBorders, groupIndex, groupColor, myMesh );
+    bool wholeBorders = setCurrentGroup();
+    myBorderDisplayers[ groupIndex ]->ShowGroup( wholeBorders );
+  }
+}
+
+//=======================================================================
+//function : setCurrentGroup
+//purpose  : set index of a current free border group to myCurGroupIndex
+//=======================================================================
+
+bool SMESHGUI_SewingDlg::setCurrentGroup()
+{
+  if ( !haveBorders() )
+    return false;
+
+  QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
+  if ( selItems.count() != 1 )
+    return false;
+  
+  myCurGroupIndex = selItems[0]->data( GROUP_INDEX ).toInt();
+
+  return ( myCurGroupIndex >= 0 && myCurGroupIndex < myBorders->coincidentGroups.length() );
+}
+
+//=======================================================================
+//function : setCurrentPart
+//purpose  : set index of a current free border of a current group to myCurPartIndex
+//=======================================================================
+
+bool SMESHGUI_SewingDlg::setCurrentPart()
+{
+  if ( !setCurrentGroup() )
+    return false;
+
+  if ( ListEdit->selectedItems().count() != 1 )
+    return false;
+
+  myCurPartIndex = ListEdit->currentRow();
+  const SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
+
+  return ( myCurPartIndex >= 0 && myCurPartIndex < aGRP.length() );
+}
+
+//=======================================================================
+//function : onSelectGroup
+//purpose  : SLOT called when selection of coincident free borders change
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onSelectGroup()
+{
+  if ( myBusy )
+    return;
+  ListEdit->clear();
+  BorderEndLine[0]->clear();
+  BorderEndLine[1]->clear();
+  for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
+    if ( myBorderDisplayers[ i ])
+      myBorderDisplayers[ i ]->Hide();
+
+  QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
+
+  RemoveGroupButton->setEnabled( selItems.count() > 0 );
+
+  onSelectBorderPartFromGroup(); // enable buttons
+
+  if ( !haveBorders() )
+    return;
+
+  SelectAllCheck->blockSignals( true );
+  if ( ListCoincident->count() != selItems.count() )
+    SelectAllCheck->setChecked( false );
+  SelectAllCheck->blockSignals( false );
+
+  if ( selItems.empty() ) // nothing selected - show all
+    for ( int i = 0; i < ListCoincident->count(); ++i )
+      showGroup( ListCoincident->item( i ));
+  else
+    for ( int i = 0; i < selItems.count(); ++i )
+      showGroup( selItems[ i ]);
+
+  if ( setCurrentGroup() ) // edit a selected group
+  {
+    const SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
+    for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
+      new QListWidgetItem( getPartText( aGRP[ iP ]), ListEdit );
+  }
+  SMESH::RepaintCurrentView();
+}
+
+//=======================================================================
+//function : onSelectAll
+//purpose  : SLOT called when Select All is checked
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onSelectAll(int isOn)
+{
+  if ( isOn )
+    ListCoincident->selectAll();
+  else
+    ListCoincident->clearSelection();
+}
+
+//=======================================================================
+//function : onSelectBorderPartFromGroup
+//purpose  : SLOT called when selection of borders in an edited group changes
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onSelectBorderPartFromGroup()
+{
+  if ( myBusy ) return;
+  BorderEndLine[0]->setText("");
+  BorderEndLine[1]->setText("");
+  MoveBorderEndsButGrp->button( MOVE_LEFT_1  )->setEnabled( false );
+  MoveBorderEndsButGrp->button( MOVE_RIGHT_1 )->setEnabled( false );
+  MoveBorderEndsButGrp->button( MOVE_LEFT_2  )->setEnabled( false );
+  MoveBorderEndsButGrp->button( MOVE_RIGHT_2 )->setEnabled( false );
+  SwapBut->setEnabled( false );
+  SetFirstButton->setEnabled( false );
+  RemoveElemButton->setEnabled ( ListEdit->count() > 2 );
+
+  if ( !setCurrentGroup() )
+    return;
+
+  if ( !myBorderDisplayers[ myCurGroupIndex ]) return;
+  myBorderDisplayers[ myCurGroupIndex ]->Hide();
+
+  QList<QListWidgetItem*> selItems = ListEdit->selectedItems();
+  bool editPart = ( setCurrentPart() );
+  for ( int i = 0; i < selItems.count(); ++i )
+    myBorderDisplayers[ myCurGroupIndex ]->ShowPart( ListEdit->row( selItems[i] ), editPart );
+
+  if ( selItems.isEmpty() )
+    myBorderDisplayers[ myCurGroupIndex ]->ShowGroup( /*wholeBorders=*/ true );
+
+  if ( editPart )
+  {
+    SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
+    SMESH::FreeBorderPart&   aPRT = aGRP[ myCurPartIndex ];
+    SMESH::FreeBorder&       aBRD = myBorders->borders[ aPRT.border ];
+
+    BorderEndLine[0]->setText( QString::number( aBRD.nodeIDs[ aPRT.node1 ]));
+    BorderEndLine[1]->setText( QString::number( aBRD.nodeIDs[ aPRT.nodeLast ]));
+    SwapBut->setEnabled( true );
+    SetFirstButton->setEnabled( myCurPartIndex > 0 );
+
+    int      size = (int) aBRD.nodeIDs.length();
+    bool isClosed = ( aBRD.nodeIDs[0] == aBRD.nodeIDs[ size-1 ]);
+    if ( !isClosed )
+    {
+      bool isFwd = ( Abs( aPRT.node2 - aPRT.node1 ) == 1 ) ? aPRT.node2 > aPRT.node1 : aPRT.node2 < aPRT.node1;
+      int dn     = ( isFwd ? +1 : -1 ) * StepSpin->value();
+      MoveBorderEndsButGrp->button( MOVE_LEFT_1  )->
+        setEnabled( 0 <= aPRT.node1-dn && aPRT.node1-dn < size );
+      MoveBorderEndsButGrp->button( MOVE_RIGHT_1 )->
+        setEnabled( 0 <= aPRT.node1+dn && aPRT.node1+dn < size );
+      MoveBorderEndsButGrp->button( MOVE_LEFT_2  )->
+        setEnabled( 0 <= aPRT.nodeLast-dn && aPRT.nodeLast-dn < size );
+      MoveBorderEndsButGrp->button( MOVE_RIGHT_2  )->
+        setEnabled( 0 <= aPRT.nodeLast+dn && aPRT.nodeLast+dn < size );
+    }
+    else
+    {
+      MoveBorderEndsButGrp->button( MOVE_LEFT_1  )->setEnabled( true );
+      MoveBorderEndsButGrp->button( MOVE_RIGHT_1 )->setEnabled( true );
+      MoveBorderEndsButGrp->button( MOVE_LEFT_2  )->setEnabled( true );
+      MoveBorderEndsButGrp->button( MOVE_RIGHT_2 )->setEnabled( true );
+    }
+  }
+  SMESH::RepaintCurrentView();
+}
+
+//=======================================================================
+//function : onGroupChange
+//purpose  : Update after modification of a current group by the user
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onGroupChange( bool partChange )
+{
+  ListCoincident->currentItem()->setText( getGroupText( myCurGroupIndex ));
+
+  const SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
+  for ( int i = 0; i < ListEdit->count(); ++i )
+    ListEdit->item( i )->setText( getPartText( aGRP[ i ]));
+
+  myBorderDisplayers[ myCurGroupIndex ]->Update();
+
+  if ( partChange )
+    onSelectBorderPartFromGroup();
+}
+
+//=======================================================================
+//function : onSetFirstClicked
+//purpose  : STOL called when |<< is clicked
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onSetFirstClicked()
+{
+  if ( !setCurrentPart() || myCurPartIndex == 0 || ListEdit->count() == 0 )
+    return;
+
+  SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
+
+  SMESH::FreeBorderPart new1st = aGRP[ myCurPartIndex ];
+  for ( ; myCurPartIndex > 0; --myCurPartIndex )
+    aGRP[ myCurPartIndex ] = aGRP[ myCurPartIndex - 1 ];
+
+  aGRP[ 0 ] = new1st;
+
+  onGroupChange();
+
+  myBusy = true;
+  ListEdit->clearSelection();
+  myBusy = false;
+  ListEdit->setCurrentItem( ListEdit->item(0) );//ListEdit->item(0)->setSelected(true);
+}
+
+//=======================================================================
+//function : onRemoveElemClicked
+//purpose  : 
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onRemoveElemClicked()
+{
+  if ( !setCurrentGroup() )
+    return;
+
+  SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
+
+  QList<QListWidgetItem*> selItems = ListEdit->selectedItems();
+  for ( int i = 0; i < selItems.count(); ++i )
+  {
+    int part = ListEdit->row( selItems[i] );
+    for ( ; part + 1 < aGRP.length(); ++part )
+      aGRP[ part ] = aGRP[ part + 1 ];
+    aGRP.length( aGRP.length() - 1 );
+    delete selItems[i];
+  }
+
+  if ( aGRP.length() == 0 )
+    onRemoveGroupClicked();
+  else
+    onGroupChange( /*partChange=*/true );
+}
+
+//=======================================================================
+//function : onMoveBorderEnd
+//purpose  : 
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onMoveBorderEnd(int button)
+{
+  if ( !setCurrentPart() )
+    return;
+
+  SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
+  SMESH::FreeBorderPart&   aPRT = aGRP[ myCurPartIndex ];
+  SMESH::FreeBorder&       aBRD = myBorders->borders[ aPRT.border ];
+  int size = (int) aBRD.nodeIDs.length();
+
+  bool isClosed = ( aBRD.nodeIDs[0] == aBRD.nodeIDs[ size-1 ]);
+  if ( isClosed ) --size;
+
+  bool isFwd = ( Abs( aPRT.node2 - aPRT.node1 ) == 1 ) ? aPRT.node2 > aPRT.node1 : aPRT.node2 < aPRT.node1;
+  int dn     = ( isFwd ? +1 : -1 ) * StepSpin->value();
+  if ( button == MOVE_LEFT_1 || button == MOVE_LEFT_2 )
+    dn *= -1;
+
+  switch ( button ) {
+  case MOVE_LEFT_1:
+  case MOVE_RIGHT_1:
+    if (( isClosed ) ||
+        ( 0 <= aPRT.node1+dn && aPRT.node1+dn < size ))
+    {
+      aPRT.node1 = ( aPRT.node1 + size + dn ) % size;
+      aPRT.node2 = ( aPRT.node2 + size + dn ) % size;
+      break;
+    }
+  case MOVE_LEFT_2:
+  case MOVE_RIGHT_2:
+    if (( isClosed ) ||
+        ( 0 <= aPRT.nodeLast+dn && aPRT.nodeLast+dn < size ))
+    {
+      aPRT.nodeLast = ( aPRT.nodeLast + size + dn ) % size;
+      break;
+    }
+  default:
+    return; // impossible to move
+  }
+  
+  onGroupChange( /*partChange=*/true );
+}
+
+//=======================================================================
+//function : onSwapClicked
+//purpose  : SLOT called when <-> is clicked
+//=======================================================================
+
+void SMESHGUI_SewingDlg::onSwapClicked()
+{
+  if ( !setCurrentPart() )
+    return;
+
+  SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
+  SMESH::FreeBorderPart&   aPRT = aGRP[ myCurPartIndex ];
+  SMESH::FreeBorder&       aBRD = myBorders->borders[ aPRT.border ];
+  int size = (int) aBRD.nodeIDs.length();
+
+  bool isClosed = ( aBRD.nodeIDs[0] == aBRD.nodeIDs[ size-1 ]);
+  if ( isClosed ) --size;
+
+  bool isFwd = ( Abs( aPRT.node2 - aPRT.node1 ) == 1 ) ? aPRT.node2 > aPRT.node1 : aPRT.node2 < aPRT.node1;
+
+  std::swap( aPRT.nodeLast, aPRT.node1 );
+
+  aPRT.node2 = ( aPRT.node1 + ( isFwd ? -1 : +1 ) + size ) % size;
+
+  onGroupChange( /*partChange=*/true );
+}
+
 //=================================================================================
 // function : ClickOnApply()
 // purpose  :
@@ -456,11 +1257,11 @@ bool SMESHGUI_SewingDlg::ClickOnApply()
 
   bool aResult = false;
 
-  if (IsValid()) {
-    bool toMerge = CheckBoxMerge->isChecked();
+  if (IsValid())
+  {
+    bool toMerge          = CheckBoxMerge->isChecked();
     bool toCreatePolygons = CheckBoxPolygons->isChecked();
     bool toCreatePolyedrs = CheckBoxPolyedrs->isChecked();
-
     try {
       SUIT_OverrideCursor aWaitCursor;
       SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor();
@@ -469,21 +1270,51 @@ bool SMESHGUI_SewingDlg::ClickOnApply()
       SMESH::SMESH_MeshEditor::Sew_Error anError;
 
       if (aConstructorId == 0)
-        anError = aMeshEditor->SewFreeBorders(LineEdit1->text().toLong(),
-                                              LineEdit2->text().toLong(),
-                                              LineEdit3->text().toLong(),
-                                              LineEdit4->text().toLong(),
-                                              LineEdit5->text().toLong(),
-                                              LineEdit6->text().toLong(),
-                                              toCreatePolygons,
-                                              toCreatePolyedrs);
+      {
+        if ( ModeButGrp->checkedId() == MODE_MANUAL )
+        {
+          anError = aMeshEditor->SewFreeBorders(LineEdit1->text().toLong(),
+                                                LineEdit2->text().toLong(),
+                                                LineEdit3->text().toLong(),
+                                                LineEdit4->text().toLong(),
+                                                LineEdit5->text().toLong(),
+                                                LineEdit6->text().toLong(),
+                                                toCreatePolygons,
+                                                toCreatePolyedrs);
+        }
+        else
+        {
+          int nbCoincGroups = ListCoincident->count();
+          if ( AutoSewCheck->isChecked() )
+          {
+            myBorders     = aMeshEditor->FindCoincidentFreeBorders( SpinBoxTolerance->GetValue() );
+            nbCoincGroups = myBorders->coincidentGroups.length();
+          }
+          CORBA::Short nbSewed = aMeshEditor->SewCoincidentFreeBorders( myBorders.inout(),
+                                                                        toCreatePolygons,
+                                                                        toCreatePolyedrs);
+          QString msg;
+          if ( nbCoincGroups == 0 )
+            msg = tr("NO_BORDERS_TO_SEW");
+          else if ( nbSewed < nbCoincGroups )
+            msg = tr("NOT_ALL_BORDERS_SEWED").arg( nbSewed ).arg( nbCoincGroups );
+          else
+            msg = tr("ALL_BORDERS_SEWED").arg( nbSewed );
+          SUIT_MessageBox::information( this, tr("SMESH_INFORMATION"), msg );
+
+          anError = SMESH::SMESH_MeshEditor::SEW_OK;
+        }
+      }
       else if (aConstructorId == 1)
+      {
         anError = aMeshEditor->SewConformFreeBorders(LineEdit1->text().toLong(),
                                                      LineEdit2->text().toLong(),
                                                      LineEdit3->text().toLong(),
                                                      LineEdit4->text().toLong(),
                                                      LineEdit5->text().toLong());
+      }
       else if (aConstructorId == 2)
+      {
         anError = aMeshEditor->SewBorderToSide(LineEdit1->text().toLong(),
                                                LineEdit2->text().toLong(),
                                                LineEdit3->text().toLong(),
@@ -491,6 +1322,7 @@ bool SMESHGUI_SewingDlg::ClickOnApply()
                                                LineEdit6->text().toLong(),
                                                toCreatePolygons,
                                                toCreatePolyedrs);
+      }
       else if (aConstructorId == 3) {
         QStringList aListElementsId1 = LineEdit1->text().split(" ", QString::SkipEmptyParts);
         QStringList aListElementsId2 = LineEdit4->text().split(" ", QString::SkipEmptyParts);
@@ -526,13 +1358,15 @@ bool SMESHGUI_SewingDlg::ClickOnApply()
     }
 
     if (aResult) {
-      Handle(SALOME_InteractiveObject) anIO = myActor->getIO();
-
-      SALOME_ListIO aList;
-      aList.Append(anIO);
-      mySelectionMgr->setSelectedObjects(aList, false);
-      SMESH::UpdateView();
 
+      if ( myActor )
+      {
+        Handle(SALOME_InteractiveObject) anIO = myActor->getIO();
+        SALOME_ListIO aList;
+        aList.Append(anIO);
+        mySelectionMgr->setSelectedObjects(aList, false);
+        SMESH::UpdateView();
+      }
       Init();
       ConstructorsClicked(GetConstructorId());
 
@@ -576,6 +1410,13 @@ void SMESHGUI_SewingDlg::onCloseView()
 {
   DeactivateActiveDialog();
   mySelector = 0;
+
+  for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
+  {
+    delete myBorderDisplayers[ i ];
+    myBorderDisplayers[ i ] = 0;
+  }
+  myBorderDisplayers.clear();
 }
 
 //=================================================================================
@@ -584,6 +1425,7 @@ void SMESHGUI_SewingDlg::onCloseView()
 //=================================================================================
 void SMESHGUI_SewingDlg::reject()
 {
+  restoreDisplayMode();
   //mySelectionMgr->clearSelected();
   SMESH::SetPointRepresentation(false);
   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
@@ -644,9 +1486,6 @@ void SMESHGUI_SewingDlg::onTextChange (const QString& theNewText)
   else if (send == LineEdit6)
     myOk6 = false;
 
-  buttonOk->setEnabled(false);
-  buttonApply->setEnabled(false);
-
   // hilight entered elements/nodes
   SMDS_Mesh* aMesh = 0;
 
@@ -718,10 +1557,7 @@ void SMESHGUI_SewingDlg::onTextChange (const QString& theNewText)
     }
   }
 
-  if (IsValid()) {
-    buttonOk->setEnabled(true);
-    buttonApply->setEnabled(true);
-  }
+  UpdateButtons();
 
   myBusy = false;
 }
@@ -735,6 +1571,7 @@ void SMESHGUI_SewingDlg::SelectionIntoArgument (bool isSelectionChanged)
   if (myBusy) return;
 
   // clear
+  restoreDisplayMode();
   if (isSelectionChanged)
     myActor = 0;
 
@@ -742,13 +1579,18 @@ void SMESHGUI_SewingDlg::SelectionIntoArgument (bool isSelectionChanged)
 
   myBusy = true;
   myEditCurrentArgument->setText(aString);
+  ListCoincident->clear();
+  ListEdit->clear();
   myBusy = false;
 
+  onSelectGroup(); // erase preview
+
   if (!GroupButtons->isEnabled()) // inactive
     return;
 
   buttonOk->setEnabled(false);
   buttonApply->setEnabled(false);
+  DetectButton->setEnabled(false);
 
   // get selected mesh
   SALOME_ListIO aList;
@@ -759,20 +1601,40 @@ void SMESHGUI_SewingDlg::SelectionIntoArgument (bool isSelectionChanged)
     return;
 
   Handle(SALOME_InteractiveObject) IO = aList.First();
-  myMesh = SMESH::GetMeshByIO(IO); //@ SMESH::IObjectToInterface<SMESH::SMESH_Mesh>(IO);
+  myMesh  = SMESH::GetMeshByIO(IO);
   myActor = SMESH::FindActorByEntry(aList.First()->getEntry());
+  if (myMesh->_is_nil())
+    return;
+
+  CheckBoxPolyedrs->setEnabled( myMesh->NbVolumes() > 0 );
+
+  if ( myEditCurrentArgument == LineEditMesh )
+  {
+    LineEditMesh->setText( IO->getName() );
+    ListCoincident->clear();
+    if ( AutoSewCheck->isChecked() )
+    {
+      buttonOk->setEnabled(true);
+      buttonApply->setEnabled(true);
+    }
+    DetectButton->setEnabled( myMesh->NbFaces() > 0 );
+    setDisplayMode();
+    return;
+  }
 
-  if (myMesh->_is_nil() || !myActor)
+  if (!myActor)
     return;
 
   // get selected elements/nodes
   int aNbUnits = 0;
-  if (GetConstructorId() != 3 ||
-      (myEditCurrentArgument != LineEdit1 && myEditCurrentArgument != LineEdit4)) {
+  if (( GetConstructorId() != 3 ) ||
+      ( myEditCurrentArgument != LineEdit1 && myEditCurrentArgument != LineEdit4))
+  {
     aNbUnits = SMESH::GetNameOfSelectedNodes(mySelector, IO, aString);
     if (aNbUnits != 1)
       return;
-  } else {
+  }
+  else {
     aNbUnits = SMESH::GetNameOfSelectedElements(mySelector, IO, aString);
     if (aNbUnits < 1)
       return;
@@ -796,10 +1658,7 @@ void SMESHGUI_SewingDlg::SelectionIntoArgument (bool isSelectionChanged)
   else if (myEditCurrentArgument == LineEdit6)
     myOk6 = true;
 
-  if (IsValid()) {
-    buttonOk->setEnabled(true);
-    buttonApply->setEnabled(true);
-  }
+  UpdateButtons();
 }
 
 //=================================================================================
@@ -918,9 +1777,38 @@ int SMESHGUI_SewingDlg::GetConstructorId()
 //=================================================================================
 bool SMESHGUI_SewingDlg::IsValid()
 {
+  if ( myMesh->_is_nil() )
+    return false;
+
+  if ( GetConstructorId() == 0 && ModeButGrp->checkedId() == MODE_AUTO )
+  {
+    if ( AutoSewCheck->isChecked() )
+      return true;
+
+    int nbGroups = 0;
+    if ( haveBorders() )
+      for ( int i = 0; i < ListCoincident->count(); ++i )
+      {
+        int groupIndex = ListCoincident->item(i)->data( GROUP_INDEX ).toInt();
+        nbGroups += ( !getGroupText( groupIndex ).isEmpty() );
+      }
+    return nbGroups > 0;
+  }
   return (myOk1 && myOk2 && myOk3 && myOk4 && myOk5 && myOk6);
 }
 
+//=======================================================================
+//function : UpdateButtons
+//purpose  : activate [Apply] buttons
+//=======================================================================
+
+void SMESHGUI_SewingDlg::UpdateButtons()
+{
+  bool ok = IsValid();
+  buttonOk->setEnabled( ok );
+  buttonApply->setEnabled( ok );
+}
+
 //=================================================================================
 // function : keyPressEvent()
 // purpose  :
@@ -936,3 +1824,157 @@ void SMESHGUI_SewingDlg::keyPressEvent( QKeyEvent* e )
     ClickOnHelp();
   }
 }
+
+SMESHGUI_SewingDlg::
+BorderGroupDisplayer::BorderGroupDisplayer( const SMESH::CoincidentFreeBorders& borders,
+                                            int                                 groupIndex,
+                                            QColor                              color,
+                                            SMESH::SMESH_Mesh_ptr               mesh):
+  myBorders   ( borders.borders ),
+  myGroup     ( borders.coincidentGroups[ groupIndex ]),
+  myColor     ( color ),
+  myMesh      ( mesh ),
+  myViewWindow( SMESH::GetCurrentVtkView() ),
+  myIdPreview ( myViewWindow )
+{
+  Update();
+}
+
+SMESHGUI_SewingDlg::BorderGroupDisplayer::~BorderGroupDisplayer()
+{
+  for ( size_t i = 0; i < myPartActors.size(); ++i )
+  {
+    if ( myPartActors[ i ]) {
+      myViewWindow->RemoveActor( myPartActors[i] );
+      myPartActors[i]->Delete();
+    }
+  }
+  myIdPreview.SetPointsLabeled(false);
+  //myViewWindow->Repaint();
+}
+
+void SMESHGUI_SewingDlg::BorderGroupDisplayer::Hide()
+{
+  for ( size_t i = 0; i < myPartActors.size(); ++i )
+    if ( myPartActors[ i ])
+      myPartActors[ i ]->SetVisibility(false);
+
+  myIdPreview.SetPointsLabeled(false);
+}
+
+void SMESHGUI_SewingDlg::BorderGroupDisplayer::ShowGroup( bool wholeBorders )
+{
+  std::vector<int> ids;
+  std::list<gp_XYZ> coords;
+  for ( size_t i = 0; i < myPartActors.size(); ++i )
+    if ( myPartActors[ i ])
+    {
+      myPartActors[ i ]->SetPointRepresentation( wholeBorders );
+      myPartActors[ i ]->SetVisibility( true );
+      if ( wholeBorders )
+        getPartEnds( i, ids, coords );
+    }
+  if ( wholeBorders )
+    myIdPreview.SetElemsData( ids, coords );
+  myIdPreview.SetPointsLabeled( wholeBorders, true );
+}
+
+void SMESHGUI_SewingDlg::BorderGroupDisplayer::ShowPart( int partIndex, bool toEdit )
+{
+  if ( partIndex < (int) myPartActors.size() )
+  {
+    myPartActors[partIndex]->SetVisibility(true);
+    myPartActors[partIndex]->SetPointRepresentation(toEdit);
+
+    if ( toEdit )
+    {
+      std::vector<int> ids;
+      std::list<gp_XYZ> coords;
+      getPartEnds( partIndex, ids, coords );
+
+      myIdPreview.SetElemsData( ids, coords );
+      myIdPreview.SetPointsLabeled( true, /*show=*/true );
+    }
+  }
+}
+
+void SMESHGUI_SewingDlg::BorderGroupDisplayer::getPartEnds( int                partIndex,
+                                                            std::vector<int> & ids,
+                                                            std::list<gp_XYZ>& coords)
+{
+  const SMESH::FreeBorderPart& aPART = myGroup  [ partIndex ];
+  const SMESH::FreeBorder&      aBRD = myBorders[ aPART.border ];
+
+  ids.push_back( aBRD.nodeIDs[ aPART.node1 ]);
+  ids.push_back( aBRD.nodeIDs[ aPART.nodeLast ]);
+
+  SMDS_Mesh* mesh = myPartActors[ partIndex ]->GetObject()->GetMesh();
+
+  coords.push_back( SMESH_TNodeXYZ( mesh->FindNode( aPART.node1+1 )));
+  coords.push_back( SMESH_TNodeXYZ( mesh->FindNode( aPART.nodeLast+1 )));
+}
+
+void SMESHGUI_SewingDlg::BorderGroupDisplayer::Update()
+{
+  Hide();
+  myPartActors.resize( myGroup.length(), 0 );
+
+  for ( size_t i = 0; i < myPartActors.size(); ++i )
+  {
+    TVisualObjPtr obj;
+    if ( myPartActors[ i ])
+      obj = myPartActors[ i ]->GetObject();
+    else
+      obj = TVisualObjPtr( new SMESHGUI_PreVisualObj() );
+    SMDS_Mesh* mesh = obj->GetMesh();
+    mesh->Clear();
+
+    // add nodes
+    const SMESH::FreeBorderPart& aPRT = myGroup[ i ];
+    const SMESH::FreeBorder&     aBRD = myBorders[ aPRT.border ];
+    for ( CORBA::ULong iN = 0; iN < aBRD.nodeIDs.length(); ++iN )
+    {
+      SMESH::double_array_var xyz = myMesh->GetNodeXYZ( aBRD.nodeIDs[ iN ]);
+      if ( xyz->length() == 3 )
+        mesh->AddNode( xyz[0], xyz[1], xyz[2] );
+    }
+
+    // add edges
+    bool isFwd = ( Abs( aPRT.node2 - aPRT.node1 ) == 1 ) ? aPRT.node2 > aPRT.node1 : aPRT.node2 < aPRT.node1;
+    int dn     = isFwd ? +1 : -1;
+    int size   = (int) aBRD.nodeIDs.length();
+    int n2, n1 = aPRT.node1;
+    for ( n2 = n1 + dn; ( n2 >= 0 && n2 < size ); n2 += dn )
+    {
+      mesh->AddEdgeWithID( n1+1, n2+1, mesh->NbEdges() + 1 );
+      n1 = n2;
+      if ( n2 == aPRT.nodeLast )
+        break;
+    }
+    if ( n2 % size != aPRT.nodeLast )
+    {
+      if ( n2 < 0 ) n1 = size;
+      else          n1 = 0;
+      for ( n2 = n1 + dn; ( n2 >= 0 && n2 < size ); n2 += dn )
+      {
+        mesh->AddEdgeWithID( n1+1, n2+1, mesh->NbEdges() + 1 );
+        n1 = n2;
+        if ( n2 == aPRT.nodeLast )
+          break;
+      }
+    }
+
+    if ( !myPartActors[ i ]) // TVisualObj must be filled before actor creation
+    {
+      myPartActors[ i ] = SMESH_Actor::New( obj, "", "", 1 );
+      myPartActors[ i ]->SetEdgeColor( myColor.redF(), myColor.greenF(), myColor.blueF() );
+      myPartActors[ i ]->SetLineWidth( 3 * SMESH::GetFloat("SMESH:element_width",1));
+      myPartActors[ i ]->SetPickable( false );
+      myPartActors[ i ]->SetNodeColor( myColor.redF(), myColor.greenF(), myColor.blueF() );
+      myPartActors[ i ]->SetMarkerStd( VTK::MT_POINT, 13 );
+      myViewWindow->AddActor( myPartActors[ i ]);
+      myViewWindow->Repaint();
+    }
+  }
+}
+
index 3d2b91f..2bf5c59 100644 (file)
@@ -36,6 +36,9 @@
 // IDL includes
 #include <SALOMEconfig.h>
 #include CORBA_SERVER_HEADER(SMESH_Mesh)
+#include CORBA_SERVER_HEADER(SMESH_MeshEditor)
+
+#include <vector>
 
 class QButtonGroup;
 class QGroupBox;
@@ -48,6 +51,10 @@ class SMESHGUI;
 class SMESH_Actor;
 class SVTK_Selector;
 class LightApp_SelectionMgr;
+class SMESHGUI_SpinBox;
+class SalomeApp_IntSpinBox;
+class QListWidget;
+class QListWidgetItem;
 
 //=================================================================================
 // class    : SMESHGUI_SewingDlg
@@ -67,7 +74,8 @@ private:
   void                    keyPressEvent( QKeyEvent* );
   int                     GetConstructorId();
   bool                    IsValid();
-  
+  void                    UpdateButtons();
+
   SMESHGUI*               mySMESHGUI;              /* Current SMESHGUI object */
   LightApp_SelectionMgr*  mySelectionMgr;          /* User shape selection */
   int                     myOk1, myOk2, myOk3, myOk4, myOk5, myOk6;    
@@ -114,13 +122,67 @@ private:
   QCheckBox*              CheckBoxPolygons;
   QCheckBox*              CheckBoxPolyedrs;
 
+  QWidget*                SewFreeBordersWidget;
+  QGroupBox*              ModeGroup;
+  QButtonGroup*           ModeButGrp;
+  //QPushButton*            SelectMeshButton;
+  QLineEdit*              LineEditMesh;
+
+  SMESHGUI_SpinBox*       SpinBoxTolerance;
+  QCheckBox*              AutoSewCheck;
+
+  QWidget*                GroupCoincidentWidget;
+  QListWidget*            ListCoincident;
+  QPushButton*            DetectButton;
+  QPushButton*            RemoveGroupButton;
+  QCheckBox*              SelectAllCheck;
+
+  QListWidget*            ListEdit;
+  QButtonGroup*           MoveBorderEndsButGrp;
+  QLineEdit*              BorderEndLine[2];
+  QPushButton*            SwapBut;
+  QPushButton*            SetFirstButton;
+  QPushButton*            RemoveElemButton;
+  SalomeApp_IntSpinBox*   StepSpin;
+
   QString                 myHelpFileName;
 
-protected slots:
+
+  struct BorderGroupDisplayer;
+  std::vector< BorderGroupDisplayer* > myBorderDisplayers;
+  SMESH::CoincidentFreeBorders_var     myBorders;
+  int                                  myCurGroupIndex;
+  int                                  myCurPartIndex;
+  int                                  myStoredRepresentation;
+  unsigned int                         myStoredEntityMode;
+
+  bool                    haveBorders();
+  QString                 getGroupText( int groupIndex );
+  QString                 getPartText( const SMESH::FreeBorderPart& part );
+  void                    showGroup( QListWidgetItem* item );
+  bool                    setCurrentGroup();
+  bool                    setCurrentPart();
+  void                    onGroupChange(bool partChange=false);
+  void                    setDisplayMode();
+  void                    restoreDisplayMode();
+
+
+ protected slots:
   virtual void            reject();
 
-private slots:
+ private slots:
   void                    ConstructorsClicked( int );
+  void                    onModeChange( int );
+  void                    onAutoSew( int );
+  void                    onDetectClicked();
+  void                    onRemoveGroupClicked();
+  void                    onSelectGroup();
+  void                    onSelectAll(int);
+  void                    onSelectBorderPartFromGroup();
+  void                    onSetFirstClicked();
+  void                    onRemoveElemClicked();
+  void                    onMoveBorderEnd(int);
+  void                    onSwapClicked();
   void                    ClickOnOk();
   bool                    ClickOnApply();
   void                    ClickOnHelp();
index 8eb6265..36a4916 100644 (file)
@@ -5141,7 +5141,7 @@ Please select a group and try again</translation>
     </message>
     <message>
         <source>SEPARATE_CORNERS_AND_MEDIUM</source>
-        <translation>No merge of corner and medium nodes</translation>
+        <translation>No merge of corner and medium nodes of quadratic cells</translation>
     </message>
     <message>
         <source>KEEP_NODES</source>
@@ -5155,10 +5155,6 @@ Please select a group and try again</translation>
         <source>SELECT</source>
         <translation>Select: </translation>
     </message>
-    <message>
-        <source></source>
-        <translation></translation>
-    </message>
 </context>
 <context>
     <name>SMESHGUI_ExtrusionAlongPathDlg</name>
@@ -6665,6 +6661,42 @@ It is impossible to read point coordinates from file</translation>
         <source>SIDE_2</source>
         <translation>Side 2</translation>
     </message>
+    <message>
+        <source>AUTO_SEWING</source>
+        <translation>Auto Sewing</translation>
+    </message>
+    <message>
+        <source>COINCIDENT_FREE_BORDERS</source>
+        <translation>Coincident Free Borders</translation>
+    </message>
+    <message>
+        <source>DETECT</source>
+        <translation>Detect</translation>
+    </message>
+    <message>
+        <source>SELECT_ALL</source>
+        <translation>Select all</translation>
+    </message>
+    <message>
+        <source>EDIT_SELECTED_GROUP</source>
+        <translation>Edit Selected Group</translation>
+    </message>
+    <message>
+        <source>STEP</source>
+        <translation>Step</translation>
+    </message>
+    <message>
+        <source>NO_BORDERS_TO_SEW</source>
+        <translation>No free borders to sew found</translation>
+    </message>
+    <message>
+        <source>NOT_ALL_BORDERS_SEWED</source>
+        <translation>%1 of %2 groups of borders sewed</translation>
+    </message>
+    <message>
+        <source>ALL_BORDERS_SEWED</source>
+        <translation>%1 group(s) of borders sewed</translation>
+    </message>
 </context>
 <context>
     <name>SMESHGUI_ShapeByMeshDlg</name>
index 8bafe47..c79b29f 100644 (file)
@@ -79,6 +79,7 @@ SET(SMESHUtils_SOURCES
   SMESH_File.cxx
   SMESH_MeshAlgos.cxx
   SMESH_MAT2d.cxx
+  SMESH_FreeBorders.cxx
 )
 
 # --- rules ---
diff --git a/src/SMESHUtils/SMESH_FreeBorders.cxx b/src/SMESHUtils/SMESH_FreeBorders.cxx
new file mode 100644 (file)
index 0000000..8d5e8ca
--- /dev/null
@@ -0,0 +1,507 @@
+// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+// File      : SMESH_FreeBorders.cxx
+// Created   : Tue Sep  8 17:08:39 2015
+// Author    : Edward AGAPOV (eap)
+
+//================================================================================
+// Implementation of SMESH_MeshAlgos::FindCoincidentFreeBorders()
+//================================================================================
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include "SMDS_LinearEdge.hxx"
+#include "SMDS_Mesh.hxx"
+#include "SMDS_SetIterator.hxx"
+
+#include <algorithm>
+#include <limits>
+#include <set>
+#include <vector>
+
+#include <NCollection_DataMap.hxx>
+#include <gp_Pnt.hxx>
+
+using namespace SMESH_MeshAlgos;
+
+namespace
+{
+  struct BEdge;
+
+  /*!
+   * \brief Node on a free border
+   */
+  struct BNode
+  {
+    const SMDS_MeshNode *         myNode;
+    mutable std::vector< BEdge* > myLinkedEdges;
+    mutable std::vector< BEdge* > myCloseEdges;
+
+    BNode(const SMDS_MeshNode * node): myNode( node ) {}
+    void AddLinked( BEdge* e ) const;
+    void AddClose ( const BEdge* e ) const;
+    BEdge* FindCloseEdgeOfBorder( int borderID ) const;
+    bool operator<(const BNode& other) const { return myNode->GetID() < other.myNode->GetID(); }
+  };
+  /*!
+   * \brief Edge of a free border
+   */
+  struct BEdge : public SMDS_LinearEdge
+  {
+    const BNode*            myBNode1;
+    const BNode*            myBNode2;
+    int                     myBorderID;
+    int                     myID; // within a border
+    BEdge*                  myPrev;
+    BEdge*                  myNext;
+    const SMDS_MeshElement* myFace;
+    std::set< int >         myCloseBorders;
+    bool                    myInGroup;
+
+    BEdge():SMDS_LinearEdge( 0, 0 ), myBorderID(-1), myID(-1), myPrev(0), myNext(0), myInGroup(0) {}
+
+    void Set( const BNode *           node1,
+              const BNode *           node2,
+              const SMDS_MeshElement* face,
+              const int               ID)
+    {
+      myBNode1   = node1;
+      myBNode2   = node2;
+      myNodes[0] = node1->myNode;
+      myNodes[1] = node2->myNode;
+      myFace     = face;
+      setId( ID ); // mesh element ID
+    }
+    bool Contains( const BNode* n ) const
+    {
+      return ( n == myBNode1 || n == myBNode2 );
+    }
+    void AddLinked( BEdge* e )
+    {
+      if ( e->Contains( myBNode1 )) myPrev = e;
+      else                          myNext = e;
+    }
+    void RemoveLinked( BEdge* e )
+    {
+      if ( myPrev == e ) myPrev = 0;
+      if ( myNext == e ) myNext = 0;
+    }
+    void Reverse()
+    {
+      std::swap( myBNode1, myBNode2 );
+      myNodes[0] = myBNode1->myNode;
+      myNodes[1] = myBNode2->myNode;
+    }
+    void Orient()
+    {
+      if (( myPrev && !myPrev->Contains( myBNode1 )) ||
+          ( myNext && !myNext->Contains( myBNode2 )))
+        std::swap( myPrev, myNext );
+      if ( myPrev && myPrev->myBNode2 != myBNode1 ) myPrev->Reverse();
+      if ( myNext && myNext->myBNode1 != myBNode2 ) myNext->Reverse();
+    }
+    void SetID( int id )
+    {
+      if ( myID < 0 )
+      {
+        myID = id;
+        if ( myNext )
+          myNext->SetID( id + 1 );
+      }
+    }
+    void FindRangeOfSameCloseBorders(BEdge* eRange[2])
+    {
+      eRange[0] = this;
+      while ( eRange[0]->myPrev && eRange[0]->myPrev->myCloseBorders == this->myCloseBorders )
+      {
+        if ( eRange[0]->myPrev == this /*|| eRange[0]->myPrev->myInGroup*/ )
+          break;
+        eRange[0] = eRange[0]->myPrev;
+      }
+      eRange[1] = this;
+      if ( eRange[0]->myPrev != this ) // not closed range
+        while ( eRange[1]->myNext && eRange[1]->myNext->myCloseBorders == this->myCloseBorders )
+        {
+          if ( eRange[1]->myNext == this /*|| eRange[1]->myNext->myInGroup*/ )
+            break;
+          eRange[1] = eRange[1]->myNext;
+        }
+    }
+  };
+
+  void BNode::AddLinked( BEdge* e ) const
+  {
+    myLinkedEdges.reserve(2);
+    myLinkedEdges.push_back( e );
+    if ( myLinkedEdges.size() < 2 ) return;
+
+    if ( myLinkedEdges.size() == 2 )
+    {
+      myLinkedEdges[0]->AddLinked( myLinkedEdges[1] );
+      myLinkedEdges[1]->AddLinked( myLinkedEdges[0] );
+    }
+    else
+    {
+      for ( size_t i = 0; i < myLinkedEdges.size(); ++i )
+        for ( size_t j = 0; j < myLinkedEdges.size(); ++j )
+          if ( i != j )
+            myLinkedEdges[i]->RemoveLinked( myLinkedEdges[j] );
+    }
+  }
+  void BNode::AddClose ( const BEdge* e ) const
+  {
+    if ( ! e->Contains( this ))
+      myCloseEdges.push_back( const_cast< BEdge* >( e ));
+  }
+  BEdge* BNode::FindCloseEdgeOfBorder( int borderID ) const
+  {
+    for ( size_t i = 0; i < myCloseEdges.size(); ++i )
+      if ( borderID == myCloseEdges[ i ]->myBorderID )
+        return myCloseEdges[ i ];
+    return 0;
+  }
+
+  /// Accessor to SMDS_MeshElement* inherited by BEdge
+  struct ElemAcess
+  {
+    static const SMDS_MeshElement* value( std::vector< BEdge >::const_iterator it)
+    {
+      return & (*it);
+    }
+  };
+  /// Iterator over a vector of BEdge's
+  static SMDS_ElemIteratorPtr getElemIterator( const std::vector< BEdge > & bedges )
+  {
+    typedef SMDS_SetIterator
+      < const SMDS_MeshElement*, std::vector< BEdge >::const_iterator, ElemAcess > BEIter;
+    return SMDS_ElemIteratorPtr( new BEIter( bedges.begin(), bedges.end() ));
+  }
+
+} // namespace
+
+// struct needed for NCollection_Map
+struct TLinkHasher
+{
+  static int HashCode(const SMESH_TLink& link, int aLimit)
+  {
+    return ::HashCode( link.node1()->GetID() + link.node2()->GetID(), aLimit );
+  }
+  static Standard_Boolean IsEqual(const SMESH_TLink& l1, const SMESH_TLink& l2)
+  {
+    return ( l1.node1() == l2.node1() && l1.node2() == l2.node2() );
+  }
+};
+
+//================================================================================
+/*
+ * Returns groups of TFreeBorder's coincident within the given tolerance.
+ * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
+ * to free borders being compared is used.
+ */
+//================================================================================
+
+void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
+                                                double                  tolerance,
+                                                CoincidentFreeBorders & foundFreeBordes)
+{
+  // find free links
+  typedef NCollection_DataMap<SMESH_TLink, const SMDS_MeshElement*, TLinkHasher > TLink2FaceMap;
+  TLink2FaceMap linkMap;
+  SMDS_FaceIteratorPtr faceIt = mesh.facesIterator();
+  while ( faceIt->more() )
+  {
+    const SMDS_MeshElement* face = faceIt->next();
+    if ( !face ) continue;
+
+    const SMDS_MeshNode*     n0 = face->GetNode( face->NbNodes() - 1 );
+    SMDS_NodeIteratorPtr nodeIt = face->interlacedNodesIterator();
+    while ( nodeIt->more() )
+    {
+      const SMDS_MeshNode* n1 = nodeIt->next();
+      SMESH_TLink link( n0, n1 );
+      if ( !linkMap.Bind( link, face ))
+        linkMap.UnBind( link );
+      n0 = n1;
+    }
+  }
+  if ( linkMap.IsEmpty() )
+    return;
+
+  // form free borders
+  std::set   < BNode > bNodes;
+  std::vector< BEdge > bEdges( linkMap.Extent() );
+
+  TLink2FaceMap::Iterator linkIt( linkMap );
+  for ( int iEdge = 0; linkIt.More(); linkIt.Next(), ++iEdge )
+  {
+    const SMESH_TLink & link = linkIt.Key();
+    std::set< BNode >::iterator n1 = bNodes.insert( BNode( link.node1() )).first;
+    std::set< BNode >::iterator n2 = bNodes.insert( BNode( link.node2() )).first;
+    bEdges[ iEdge ].Set( &*n1, &*n2, linkIt.Value(), iEdge+1 );
+    n1->AddLinked( & bEdges[ iEdge ] );
+    n2->AddLinked( & bEdges[ iEdge ] );
+  }
+  linkMap.Clear();
+
+  // assign IDs to borders
+  std::vector< BEdge* > borders; // 1st of connected (via myPrev and myNext) edges
+  std::set< BNode >::iterator bn = bNodes.begin();
+  for ( ; bn != bNodes.end(); ++bn )
+  {
+    for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
+    {
+      if ( bn->myLinkedEdges[i]->myBorderID < 0 )
+      {
+        BEdge* be = bn->myLinkedEdges[i];
+        int borderID = borders.size();
+        borders.push_back( be );
+        for ( ; be && be->myBorderID < 0; be = be->myNext )
+        {
+          be->myBorderID = borderID;
+          be->Orient();
+        }
+        bool isClosed = ( be == bn->myLinkedEdges[i] );
+        be = bn->myLinkedEdges[i]->myPrev;
+        for ( ; be && be->myBorderID < 0; be = be->myPrev )
+        {
+          be->myBorderID = borderID;
+          be->Orient();
+        }
+        if ( !isClosed )
+          while ( borders.back()->myPrev )
+            borders.back() = borders.back()->myPrev;
+
+        borders.back()->SetID( 0 ); // set IDs to all edges of the border
+      }
+    }
+  }
+
+  // compute tolerance of each border
+  double maxTolerance = tolerance;
+  std::vector< double > bordToler( borders.size(), tolerance );
+  if ( maxTolerance < std::numeric_limits< double >::min() )
+  {
+    // no tolerance provided by the user; compute tolerance of each border
+    // as one tenth of an average size of faces adjacent to a border
+    for ( size_t i = 0; i < borders.size(); ++i )
+    {
+      double avgFaceSize = 0;
+      int    nbFaces     = 0;
+      BEdge* be = borders[ i ];
+      do {
+        double facePerimeter = 0;
+        gp_Pnt p0 = SMESH_TNodeXYZ( be->myFace->GetNode( be->myFace->NbNodes() - 1 ));
+        SMDS_NodeIteratorPtr nodeIt = be->myFace->interlacedNodesIterator();
+        while ( nodeIt->more() )
+        {
+          gp_Pnt p1 = SMESH_TNodeXYZ( nodeIt->next() );
+          facePerimeter += p0.Distance( p1 );
+          p0 = p1;
+        }
+        avgFaceSize += ( facePerimeter / be->myFace->NbCornerNodes() );
+        nbFaces++;
+
+        be = be->myNext;
+      }
+      while ( be && be != borders[i] );
+
+      bordToler[ i ] = 0.1 * avgFaceSize / nbFaces;
+      maxTolerance = Max( maxTolerance, bordToler[ i ]);
+    }
+  }
+
+  // for every border node find close border edges
+  SMESH_ElementSearcher* searcher =
+    GetElementSearcher( mesh, getElemIterator( bEdges ), maxTolerance );
+  SMESHUtils::Deleter< SMESH_ElementSearcher > searcherDeleter( searcher );
+  std::vector< const SMDS_MeshElement* > candidateEdges;
+  for ( bn = bNodes.begin(); bn != bNodes.end(); ++bn )
+  {
+    gp_Pnt point = SMESH_TNodeXYZ( bn->myNode );
+    searcher->FindElementsByPoint( point, SMDSAbs_Edge, candidateEdges );
+    if ( candidateEdges.size() <= bn->myLinkedEdges.size() )
+      continue;
+
+    double nodeTol = 0;
+    for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
+      nodeTol = Max( nodeTol, bordToler[ bn->myLinkedEdges[ i ]->myBorderID ]);
+
+    for ( size_t i = 0; i < candidateEdges.size(); ++i )
+    {
+      const BEdge* be = static_cast< const BEdge* >( candidateEdges[ i ]);
+      double      tol = Max( nodeTol, bordToler[ be->myBorderID ]);
+      if ( maxTolerance - tol < 1e-12 ||
+           !SMESH_MeshAlgos::IsOut( be, point, tol ))
+        bn->AddClose( be );
+    }
+  }
+
+  // for every border edge find close borders
+
+  std::vector< BEdge* > closeEdges;
+  for ( size_t i = 0; i < bEdges.size(); ++i )
+  {
+    BEdge& be = bEdges[i];
+    if ( be.myBNode1->myCloseEdges.empty() ||
+         be.myBNode2->myCloseEdges.empty() )
+      continue;
+
+    closeEdges.clear();
+    for ( size_t iE1 = 0; iE1 < be.myBNode1->myCloseEdges.size(); ++iE1 )
+    {
+      // find edges of the same border close to both nodes of the edge
+      BEdge* closeE1 = be.myBNode1->myCloseEdges[ iE1 ];
+      BEdge* closeE2 = be.myBNode2->FindCloseEdgeOfBorder( closeE1->myBorderID );
+      if ( !closeE2 )
+        continue;
+      // check that edges connecting closeE1 and closeE2 (if any) are also close to 'be'
+      if ( closeE1 != closeE2 )
+      {
+        bool coincide;
+        for ( int j = 0; j < 2; ++j ) // move closeE1 -> closeE2 or inversely
+        {
+          BEdge* ce = closeE1;
+          do {
+            coincide = ( ce->myBNode2->FindCloseEdgeOfBorder( be.myBorderID ));
+            ce       = ce->myNext;
+          } while ( coincide && ce && ce != closeE2 );
+
+          if ( coincide && ce == closeE2 )
+            break;
+          if ( j == 0 )
+            std::swap( closeE1, closeE2 );
+          coincide = false;
+        }
+        if ( !coincide )
+          continue;
+        closeEdges.push_back( closeE1 );
+        closeEdges.push_back( closeE2 );
+      }
+      else
+      {
+        closeEdges.push_back( closeE1 );
+      }
+      be.myCloseBorders.insert( closeE1->myBorderID );
+    }
+    if ( !closeEdges.empty() )
+    {
+      be.myCloseBorders.insert( be.myBorderID );
+      // for ( size_t iB = 0; iB < closeEdges.size(); ++iB )
+      //   closeEdges[ iB ]->myCloseBorders.insert( be.myCloseBorders.begin(),
+      //                                            be.myCloseBorders.end() );
+    }
+  }
+
+  // Fill in CoincidentFreeBorders
+
+  // save nodes of free borders
+  foundFreeBordes._borders.resize( borders.size() );
+  for ( size_t i = 0; i < borders.size(); ++i )
+  {
+    BEdge* be = borders[i];
+    foundFreeBordes._borders[i].push_back( be->myBNode1->myNode );
+    do {
+      foundFreeBordes._borders[i].push_back( be->myBNode2->myNode );
+      be = be->myNext;
+    }
+    while ( be && be != borders[i] );
+  }
+
+  // form groups of coincident parts of free borders
+
+  TFreeBorderPart  part;
+  TCoincidentGroup group;
+  for ( size_t i = 0; i < borders.size(); ++i )
+  {
+    BEdge* be = borders[i];
+
+    // look for an edge close to other borders
+    do {
+      if ( !be->myInGroup && !be->myCloseBorders.empty() )
+        break;
+      be = be->myNext;
+    } while ( be && be != borders[i] );
+
+    if ( !be || be->myInGroup || be->myCloseBorders.empty() )
+      continue; // all edges of a border treated or are non-coincident
+
+    group.clear();
+
+    // look for the 1st and last edge of a coincident group
+    BEdge* beRange[2];
+    be->FindRangeOfSameCloseBorders( beRange );
+    BEdge* be1st = beRange[0];
+
+    // fill in a group
+    part._border   = i;
+    part._node1    = beRange[0]->myID;
+    part._node2    = beRange[0]->myID + 1;
+    part._nodeLast = beRange[1]->myID + 1;
+    group.push_back( part );
+
+    be = beRange[0];
+    be->myInGroup = true;
+    while ( be != beRange[1] )
+    {
+      be->myInGroup = true;
+      be = be->myNext;
+    }
+    beRange[1]->myInGroup = true;
+
+    // add parts of other borders
+    std::set<int>::iterator closeBord = be1st->myCloseBorders.begin();
+    for ( ; closeBord != be1st->myCloseBorders.end(); ++closeBord )
+    {
+      be = be1st->myBNode2->FindCloseEdgeOfBorder( *closeBord );
+      if ( !be ) continue;
+
+      be->FindRangeOfSameCloseBorders( beRange );
+
+      // find out mutual orientation of borders
+      bool reverse = ( beRange[0]->myBNode1->FindCloseEdgeOfBorder( i ) != be1st &&
+                       beRange[0]->myBNode2->FindCloseEdgeOfBorder( i ) != be1st );
+
+      // fill in a group
+      part._border   = beRange[0]->myBorderID;
+      if ( reverse ) {
+        part._node1    = beRange[1]->myID + 1;
+        part._node2    = beRange[1]->myID;
+        part._nodeLast = beRange[0]->myID;
+      }
+      else  {
+        part._node1    = beRange[0]->myID;
+        part._node2    = beRange[0]->myID + 1;
+        part._nodeLast = beRange[1]->myID + 1;
+      }
+      group.push_back( part );
+
+      be = beRange[0];
+      be->myInGroup = true;
+      while ( be != beRange[1] )
+      {
+        be->myInGroup = true;
+        be = be->myNext;
+      }
+      beRange[1]->myInGroup = true;
+    }
+
+    foundFreeBordes._coincidentGroups.push_back( group );
+
+  } // loop on free borders
+}
index a16379b..dc157e7 100644 (file)
@@ -439,8 +439,10 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   bool                         _outerFacesFound;
   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
 
-  SMESH_ElementSearcherImpl( SMDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
-    : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
+  SMESH_ElementSearcherImpl( SMDS_Mesh&           mesh,
+                             double               tol=-1,
+                             SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
+    : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) {}
   virtual ~SMESH_ElementSearcherImpl()
   {
     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
@@ -1091,32 +1093,22 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
 
   // get ordered nodes
 
-  vector< gp_XYZ > xyz;
-  vector<const SMDS_MeshNode*> nodeList;
+  vector< SMESH_TNodeXYZ > xyz;
 
-  SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
-  if ( element->IsQuadratic() ) {
-    nodeIt = element->interlacedNodesElemIterator();
-    // if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
-    //   nodeIt = f->interlacedNodesElemIterator();
-    // else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
-    //   nodeIt = e->interlacedNodesElemIterator();
-  }
+  SMDS_ElemIteratorPtr nodeIt = element->interlacedNodesElemIterator();
   while ( nodeIt->more() )
   {
     SMESH_TNodeXYZ node = nodeIt->next();
     xyz.push_back( node );
-    nodeList.push_back(node._node);
   }
 
-  int i, nbNodes = (int) nodeList.size(); // central node of biquadratic is missing
+  int i, nbNodes = (int) xyz.size(); // central node of biquadratic is missing
 
   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
   {
     // compute face normal
     gp_Vec faceNorm(0,0,0);
     xyz.push_back( xyz.front() );
-    nodeList.push_back( nodeList.front() );
     for ( i = 0; i < nbNodes; ++i )
     {
       gp_Vec edge1( xyz[i+1], xyz[i]);
@@ -1129,7 +1121,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
       // degenerated face: point is out if it is out of all face edges
       for ( i = 0; i < nbNodes; ++i )
       {
-        SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
+        SMDS_LinearEdge edge( xyz[i]._node, xyz[i+1]._node );
         if ( !IsOut( &edge, point, tol ))
           return false;
       }
@@ -1216,13 +1208,28 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     // (we consider quadratic edge as being composed of two straight parts)
     for ( i = 1; i < nbNodes; ++i )
     {
-      gp_Vec edge( xyz[i-1], xyz[i]);
-      gp_Vec n1p ( xyz[i-1], point);
-      double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
-      if ( dist > tol )
+      gp_Vec edge( xyz[i-1], xyz[i] );
+      gp_Vec n1p ( xyz[i-1], point  );
+      // double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
+      // if ( dist > tol )
+      //   continue;
+      // gp_Vec n2p( xyz[i], point );
+      // if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
+      //   continue;
+      double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+      if ( u < 0. ) {
+        if ( n1p.SquareMagnitude() < tol * tol )
+          return false;
         continue;
-      gp_Vec n2p( xyz[i], point );
-      if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
+      }
+      if ( u > 1. ) {
+        if ( point.SquareDistance( xyz[i] ) < tol * tol )
+          return false;
+        continue;
+      }
+      gp_XYZ proj = ( 1. - u ) * xyz[i-1] + u * xyz[i]; // projection of the point on the edge
+      double dist2 = point.SquareDistance( proj );
+      if ( dist2 > tol * tol )
         continue;
       return false; // point is ON this part
     }
@@ -1231,7 +1238,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
   // Node or 0D element -------------------------------------------------------------------------
   {
     gp_Vec n2p ( xyz[0], point );
-    return n2p.Magnitude() <= tol;
+    return n2p.SquareMagnitude() <= tol * tol;
   }
   return true;
 }
@@ -1650,9 +1657,10 @@ SMESH_NodeSearcher* SMESH_MeshAlgos::GetNodeSearcher(SMDS_Mesh& mesh)
  */
 //=======================================================================
 
-SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh)
+SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh,
+                                                           double     tolerance)
 {
-  return new SMESH_ElementSearcherImpl( mesh );
+  return new SMESH_ElementSearcherImpl( mesh, tolerance );
 }
 
 //=======================================================================
@@ -1662,7 +1670,8 @@ SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh)
 //=======================================================================
 
 SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh&           mesh,
-                                                           SMDS_ElemIteratorPtr elemIt)
+                                                           SMDS_ElemIteratorPtr elemIt,
+                                                           double               tolerance)
 {
-  return new SMESH_ElementSearcherImpl( mesh, elemIt );
+  return new SMESH_ElementSearcherImpl( mesh, tolerance, elemIt );
 }
index fe5074e..9b860a6 100644 (file)
@@ -156,10 +156,45 @@ namespace SMESH_MeshAlgos
    * \brief Return SMESH_ElementSearcher. The caller is responsible for deleting it
    */
   SMESHUtils_EXPORT
-  SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh );
+  SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh,
+                                             double     tolerance=-1.);
   SMESHUtils_EXPORT
   SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh,
-                                             SMDS_ElemIteratorPtr elemIt );
-}
+                                             SMDS_ElemIteratorPtr elemIt,
+                                             double     tolerance=-1. );
+
+
+
+  typedef std::vector<const SMDS_MeshNode*> TFreeBorder;
+  typedef std::vector<TFreeBorder>          TFreeBorderVec;
+  struct TFreeBorderPart
+  {
+    int _border; // border index within a TFreeBorderVec
+    int _node1;  // node index within the border-th TFreeBorder
+    int _node2;
+    int _nodeLast;
+  };
+  typedef std::vector<TFreeBorderPart>  TCoincidentGroup;
+  typedef std::vector<TCoincidentGroup> TCoincidentGroupVec;
+  struct CoincidentFreeBorders
+  {
+    TFreeBorderVec      _borders;          // nodes of all free borders
+    TCoincidentGroupVec _coincidentGroups; // groups of coincident parts of borders
+  };
+
+  /*!
+   * Returns TFreeBorder's coincident within the given tolerance.
+   * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
+   * to free borders being compared is used.
+   *
+   * (Implemented in ./SMESH_FreeBorders.cxx)
+   */
+  SMESHUtils_EXPORT
+  void FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
+                                 double                  tolerance,
+                                 CoincidentFreeBorders & foundFreeBordes);
+  
+
+} // SMESH_MeshAlgos
 
 #endif
index 8b51e5b..bb9106f 100644 (file)
@@ -2414,6 +2414,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
       "Mirror","MirrorObject","Translate","TranslateObject","Rotate","RotateObject",
       "FindCoincidentNodes","MergeNodes","FindEqualElements",
       "MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders",
+      "FindCoincidentFreeBorders", "SewCoincidentFreeBorders",
       "SewBorderToSide","SewSideElements","ChangeElemNodes","GetLastCreatedNodes",
       "GetLastCreatedElems",
       "MirrorMakeMesh","MirrorObjectMakeMesh","TranslateMakeMesh","TranslateObjectMakeMesh",
index 20fea4a..a676b7a 100644 (file)
@@ -547,6 +547,39 @@ namespace SMESH
     DumpArray( theList, *this );
     return *this;
   }
+  TPythonDump& TPythonDump::operator<<(const SMESH::CoincidentFreeBorders& theCFB)
+  {
+    // dump CoincidentFreeBorders as a list of lists, each enclosed list
+    // contains node IDs of a group of coincident free borders where
+    // each consequent triple of IDs describe a free border: (n1, n2, nLast)
+    // For example [[1, 2, 10, 20, 21, 40], [11, 12, 15, 55, 54, 41]] describes
+    // two groups of coincident free borders, each group including two borders
+
+    myStream << "[";
+    for ( CORBA::ULong i = 0; i < theCFB.coincidentGroups.length(); ++i )
+    {
+      const SMESH::FreeBordersGroup& aGRP = theCFB.coincidentGroups[ i ];
+      if ( i ) myStream << ",";
+      myStream << "[";
+      for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
+      {
+        const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
+        if ( 0 <= aPART.border && aPART.border < theCFB.borders.length() )
+        {
+          if ( iP ) myStream << ", ";
+          const SMESH::FreeBorder& aBRD = theCFB.borders[ aPART.border ];
+          myStream << aBRD.nodeIDs[ aPART.node1    ] << ",";
+          myStream << aBRD.nodeIDs[ aPART.node2    ] << ",";
+          myStream << aBRD.nodeIDs[ aPART.nodeLast ];
+        }
+      }
+      myStream << "]";
+    }
+    myStream << "]";
+
+    return *this;
+  }
+
   const char* TPythonDump::NotPublishedObjectName()
   {
     return theNotPublishedObjectName;
index 206c73d..34f3109 100644 (file)
@@ -4573,6 +4573,182 @@ static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Se
 }
 
 //=======================================================================
+/*!
+ * Returns groups of FreeBorder's coincident within the given tolerance.
+ * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent
+ * to free borders being compared is used.
+ */
+//=======================================================================
+
+SMESH::CoincidentFreeBorders*
+SMESH_MeshEditor_i::FindCoincidentFreeBorders(CORBA::Double tolerance)
+{
+  SMESH::CoincidentFreeBorders_var aCFB = new SMESH::CoincidentFreeBorders;
+
+  SMESH_TRY;
+
+  SMESH_MeshAlgos::CoincidentFreeBorders cfb;
+  SMESH_MeshAlgos::FindCoincidentFreeBorders( *getMeshDS(), tolerance, cfb );
+
+  // copy free borders
+  aCFB->borders.length( cfb._borders.size() );
+  for ( size_t i = 0; i < cfb._borders.size(); ++i )
+  {
+    SMESH_MeshAlgos::TFreeBorder& nodes = cfb._borders[i];
+    SMESH::FreeBorder&             aBRD = aCFB->borders[i];
+    aBRD.nodeIDs.length( nodes.size() );
+    for ( size_t iN = 0; iN < nodes.size(); ++iN )
+      aBRD.nodeIDs[ iN ] = nodes[ iN ]->GetID();
+  }
+
+  // copy coincident parts
+  aCFB->coincidentGroups.length( cfb._coincidentGroups.size() );
+  for ( size_t i = 0; i < cfb._coincidentGroups.size(); ++i )
+  {
+    SMESH_MeshAlgos::TCoincidentGroup& grp = cfb._coincidentGroups[i];
+    SMESH::FreeBordersGroup&          aGRP = aCFB->coincidentGroups[i];
+    aGRP.length( grp.size() );
+    for ( size_t iP = 0; iP < grp.size(); ++iP )
+    {
+      SMESH_MeshAlgos::TFreeBorderPart& part = grp[ iP ];
+      SMESH::FreeBorderPart&           aPART = aGRP[ iP ];
+      aPART.border   = part._border;
+      aPART.node1    = part._node1;
+      aPART.node2    = part._node2;
+      aPART.nodeLast = part._nodeLast;
+    }
+  }
+  SMESH_CATCH( SMESH::doNothing );
+
+  TPythonDump() << "CoincidentFreeBorders = "
+                << this << ".FindCoincidentFreeBorders( " << tolerance << " )";
+
+  return aCFB._retn();
+}
+
+//=======================================================================
+/*!
+ * Sew FreeBorder's of each group
+ */
+//=======================================================================
+
+CORBA::Short SMESH_MeshEditor_i::
+SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
+                         CORBA::Boolean                      createPolygons,
+                         CORBA::Boolean                      createPolyhedra)
+  throw (SALOME::SALOME_Exception)
+{
+  CORBA::Short nbSewed = 0;
+
+  SMESH_MeshAlgos::TFreeBorderVec groups;
+  SMESH_MeshAlgos::TFreeBorder    borderNodes; // triples on nodes for every FreeBorderPart
+
+  // check the input
+  for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
+  {
+    const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
+    for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
+    {
+      const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
+      if ( aPART.border < 0 || aPART.border >= freeBorders.borders.length() )
+        THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::border index", SALOME::BAD_PARAM);
+
+      const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ];
+
+      if ( aPART.node1 < 0 || aPART.node1 > aBRD.nodeIDs.length() )
+        THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node1", SALOME::BAD_PARAM);
+      if ( aPART.node2 < 0 || aPART.node2 > aBRD.nodeIDs.length() )
+        THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node2", SALOME::BAD_PARAM);
+      if ( aPART.nodeLast < 0 || aPART.nodeLast > aBRD.nodeIDs.length() )
+        THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
+
+      // do not keep these nodes for further sewing as nodes can be removed by the sewing
+      const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1    ]);
+      const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2    ]);
+      const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]);
+      if ( !n1)
+        THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node1", SALOME::BAD_PARAM);
+      if ( !n2 )
+        THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM);
+      if ( !n3 )
+        THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
+    }
+  }
+
+  //TIDSortedElemSet dummy;
+
+  ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
+  for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
+  {
+    const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
+    if ( aGRP.length() < 2 )
+      continue;
+
+    //int n1bord2, n2bord2;
+
+    bool groupSewed = false;
+    for ( CORBA::ULong iP = 1; iP < aGRP.length(); ++iP )
+    {
+      const SMESH::FreeBorderPart& aPART_0 = aGRP[ 0 ];
+      const SMESH::FreeBorder&      aBRD_0 = freeBorders.borders[ aPART_0.border ];
+
+      const SMDS_MeshNode* n0 = getMeshDS()->FindNode( aBRD_0.nodeIDs[ aPART_0.node1    ]);
+      const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD_0.nodeIDs[ aPART_0.node2    ]);
+      const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD_0.nodeIDs[ aPART_0.nodeLast ]);
+
+      const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
+      const SMESH::FreeBorder&      aBRD = freeBorders.borders[ aPART.border ];
+
+      const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1    ]);
+      const SMDS_MeshNode* n4 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2    ]);
+      const SMDS_MeshNode* n5 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]);
+
+      if ( !n0 || !n1 || !n2 || !n3 || !n4 || !n5 )
+        continue;
+
+      // if ( iP == 1 )
+      // {
+      //   n1bord2 = aBRD.nodeIDs[ aPART.node1 ];
+      //   n2bord2 = aBRD.nodeIDs[ aPART.node2 ];
+      // }
+      // else if ( !SMESH_MeshAlgos::FindFaceInSet( n0, n1, dummy, dummy ))
+      // {
+      //   // a face including n0 and n1 was split;
+      //   // find a new face starting at n0 in order to get a new n1
+      //   const SMDS_MeshNode* n1test = getMeshDS()->FindNode( n1bord2 );
+      //   const SMDS_MeshNode* n2test = getMeshDS()->FindNode( n2bord2 );
+      //   if      ( n1test && SMESH_MeshAlgos::FindFaceInSet( n0, n1test, dummy, dummy ))
+      //     n1 = n1test;
+      //   else if ( n2test && SMESH_MeshAlgos::FindFaceInSet( n0, n2test, dummy, dummy ))
+      //     n1 = n2test;
+      //   // else continue; ??????
+      // }
+
+      if ( iP > 1 )
+      {
+        n1 = n2; // at border-to-side sewing only last side node (n1) is needed
+        n2 = 0;  //  and n2 is not used
+      }
+
+      // 1st border moves to 2nd
+      res = getEditor().SewFreeBorder( n3, n4, n5 ,// 1st
+                                       n0 ,n1 ,n2 ,// 2nd
+                                       /*2ndIsFreeBorder=*/ iP == 1,
+                                       createPolygons, createPolyhedra);
+      groupSewed = ( res == ok );
+    }
+    nbSewed += groupSewed;
+  }
+
+  TPythonDump() << "nbSewed = " << this << ".SewCoincidentFreeBorders( "
+                << freeBorders     << ", "
+                << createPolygons  << ", "
+                << createPolyhedra << " )";
+
+  return nbSewed;
+}
+
+//=======================================================================
 //function : SewFreeBorders
 //purpose  :
 //=======================================================================
@@ -4621,14 +4797,14 @@ SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1,
 
   SMESH::SMESH_MeshEditor::Sew_Error error =
     convError( getEditor().SewFreeBorder (aBorderFirstNode,
-                                       aBorderSecondNode,
-                                       aBorderLastNode,
-                                       aSide2FirstNode,
-                                       aSide2SecondNode,
-                                       aSide2ThirdNode,
-                                       true,
-                                       CreatePolygons,
-                                       CreatePolyedrs) );
+                                          aBorderSecondNode,
+                                          aBorderLastNode,
+                                          aSide2FirstNode,
+                                          aSide2SecondNode,
+                                          aSide2ThirdNode,
+                                          true,
+                                          CreatePolygons,
+                                          CreatePolyedrs) );
 
 
   declareMeshModified( /*isReComputeSafe=*/false );
@@ -4681,13 +4857,13 @@ SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1,
 
   SMESH::SMESH_MeshEditor::Sew_Error error =
     convError( getEditor().SewFreeBorder (aBorderFirstNode,
-                                       aBorderSecondNode,
-                                       aBorderLastNode,
-                                       aSide2FirstNode,
-                                       aSide2SecondNode,
-                                       aSide2ThirdNode,
-                                       true,
-                                       false, false) );
+                                          aBorderSecondNode,
+                                          aBorderLastNode,
+                                          aSide2FirstNode,
+                                          aSide2SecondNode,
+                                          aSide2ThirdNode,
+                                          true,
+                                          false, false) );
 
   declareMeshModified( /*isReComputeSafe=*/false );
   return error;
@@ -4743,14 +4919,14 @@ SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
 
   SMESH::SMESH_MeshEditor::Sew_Error error =
     convError( getEditor().SewFreeBorder (aBorderFirstNode,
-                                       aBorderSecondNode,
-                                       aBorderLastNode,
-                                       aSide2FirstNode,
-                                       aSide2SecondNode,
-                                       aSide2ThirdNode,
-                                       false,
-                                       CreatePolygons,
-                                       CreatePolyedrs) );
+                                          aBorderSecondNode,
+                                          aBorderLastNode,
+                                          aSide2FirstNode,
+                                          aSide2SecondNode,
+                                          aSide2ThirdNode,
+                                          false,
+                                          CreatePolygons,
+                                          CreatePolyedrs) );
 
   declareMeshModified( /*isReComputeSafe=*/false );
   return error;
index 97fe0ba..3c36508 100644 (file)
@@ -538,6 +538,12 @@ public:
   CORBA::Short GetPointState(CORBA::Double x, CORBA::Double y, CORBA::Double z)
     throw (SALOME::SALOME_Exception);
 
+  SMESH::CoincidentFreeBorders* FindCoincidentFreeBorders(CORBA::Double tolerance);
+  CORBA::Short SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
+                                        CORBA::Boolean                      createPolygons,
+                                        CORBA::Boolean                      createPolyedrs)
+    throw (SALOME::SALOME_Exception);
+
   SMESH::SMESH_MeshEditor::Sew_Error
   SewFreeBorders(CORBA::Long FirstNodeID1,
                  CORBA::Long SecondNodeID1,
@@ -546,15 +552,13 @@ public:
                  CORBA::Long SecondNodeID2,
                  CORBA::Long LastNodeID2,
                  CORBA::Boolean CreatePolygons,
-                 CORBA::Boolean CreatePolyedrs)
-    throw (SALOME::SALOME_Exception);
+                 CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
   SMESH::SMESH_MeshEditor::Sew_Error
   SewConformFreeBorders(CORBA::Long FirstNodeID1,
                         CORBA::Long SecondNodeID1,
                         CORBA::Long LastNodeID1,
                         CORBA::Long FirstNodeID2,
-                        CORBA::Long SecondNodeID2)
-    throw (SALOME::SALOME_Exception);
+                        CORBA::Long SecondNodeID2) throw (SALOME::SALOME_Exception);
   SMESH::SMESH_MeshEditor::Sew_Error
   SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder,
                   CORBA::Long SecondNodeIDOnFreeBorder,
@@ -562,16 +566,14 @@ public:
                   CORBA::Long FirstNodeIDOnSide,
                   CORBA::Long LastNodeIDOnSide,
                   CORBA::Boolean CreatePolygons,
-                  CORBA::Boolean CreatePolyedrs)
-    throw (SALOME::SALOME_Exception);
+                  CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception);
   SMESH::SMESH_MeshEditor::Sew_Error
   SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
                   const SMESH::long_array& IDsOfSide2Elements,
                   CORBA::Long NodeID1OfSide1ToMerge,
                   CORBA::Long NodeID1OfSide2ToMerge,
                   CORBA::Long NodeID2OfSide1ToMerge,
-                  CORBA::Long NodeID2OfSide2ToMerge)
-    throw (SALOME::SALOME_Exception);
+                  CORBA::Long NodeID2OfSide2ToMerge) throw (SALOME::SALOME_Exception);
 
   /*!
    * Set new nodes for given element.
index 4d4f6b7..6963762 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <SALOMEconfig.h>
 #include CORBA_SERVER_HEADER(SMESH_Mesh)
+#include CORBA_SERVER_HEADER(SMESH_MeshEditor)
 #include CORBA_SERVER_HEADER(GEOM_Gen)
 #include CORBA_SERVER_HEADER(SALOMEDS)
 
@@ -229,6 +230,9 @@ namespace SMESH
     TPythonDump&
     operator<<(const SMESH::ListOfIDSources& theList);
 
+    TPythonDump&
+    operator<<(const SMESH::CoincidentFreeBorders& theCFB);
+
     static const char* SMESHGenName() { return "smeshgen"; }
     static const char* MeshEditorName() { return "mesh_editor"; }
     static const char* NotPublishedObjectName();
index 1d6de9c..8f49d49 100644 (file)
@@ -4519,6 +4519,52 @@ class Mesh:
     def MergeEqualElements(self):
         self.editor.MergeEqualElements()
 
+    ## Returns groups of FreeBorder's coincident within the given tolerance.
+    #  @param tolerance the tolerance. If the tolerance <= 0.0 then one tenth of an average
+    #         size of elements adjacent to free borders being compared is used.
+    #  @return SMESH.CoincidentFreeBorders structure
+    #  @ingroup l2_modif_trsf
+    def FindCoincidentFreeBorders (self, tolerance=0.):
+        return self.editor.FindCoincidentFreeBorders( tolerance )
+        
+    ## Sew FreeBorder's of each group
+    #  @param freeBorders either a SMESH.CoincidentFreeBorders structure or a list of lists
+    #         where each enclosed list contains node IDs of a group of coincident free
+    #         borders such that each consequent triple of IDs within a group describes
+    #         a free border in a usual way: n1, n2, nLast - i.e. 1st node, 2nd node and
+    #         last node of a border.
+    #         For example [[1, 2, 10, 20, 21, 40], [11, 12, 15, 55, 54, 41]] describes two
+    #         groups of coincident free borders, each group including two borders.
+    #  @param createPolygons if @c True faces adjacent to free borders are converted to
+    #         polygons if a node of opposite border falls on a face edge, else such
+    #         faces are split into several ones.
+    #  @param createPolyhedra if @c True volumes adjacent to free borders are converted to
+    #         polyhedra if a node of opposite border falls on a volume edge, else such
+    #         volumes, if any, remain intact and the mesh becomes non-conformal.
+    #  @return a number of successfully sewed groups
+    #  @ingroup l2_modif_trsf
+    def SewCoincidentFreeBorders (self, freeBorders, createPolygons=False, createPolyhedra=False):
+        if freeBorders and isinstance( freeBorders, list ):
+            # construct SMESH.CoincidentFreeBorders
+            if isinstance( freeBorders[0], int ):
+                freeBorders = [freeBorders]
+            borders = []
+            coincidentGroups = []
+            for nodeList in freeBorders:
+                if not nodeList or len( nodeList ) % 3:
+                    raise ValueError, "Wrong number of nodes in this group: %s" % nodeList
+                group = []
+                while nodeList:
+                    group.append  ( SMESH.FreeBorderPart( len(borders), 0, 1, 2 ))
+                    borders.append( SMESH.FreeBorder( nodeList[:3] ))
+                    nodeList = nodeList[3:]
+                    pass
+                coincidentGroups.append( group )
+                pass
+            freeBorders = SMESH.CoincidentFreeBorders( borders, coincidentGroups )
+
+        return self.editor.SewCoincidentFreeBorders( freeBorders, createPolygons, createPolyhedra )
+
     ## Sews free borders
     #  @return SMESH::Sew_Error
     #  @ingroup l2_modif_trsf