Salome HOME
Debug 23078: [CEA 1498] Sewing of meshes without having to set the nodes ids
authoreap <eap@opencascade.com>
Wed, 23 Sep 2015 14:47:26 +0000 (17:47 +0300)
committereap <eap@opencascade.com>
Wed, 23 Sep 2015 14:47:26 +0000 (17:47 +0300)
16 files changed:
doc/salome/gui/SMESH/images/sewing1.png [changed mode: 0755->0644]
doc/salome/gui/SMESH/images/sewing_auto.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/sewing_manual.png [new file with mode: 0644]
doc/salome/gui/SMESH/images/swap.png [new file with mode: 0644]
doc/salome/gui/SMESH/input/cartesian_algo.doc
doc/salome/gui/SMESH/input/constructing_meshes.doc
doc/salome/gui/SMESH/input/sewing_meshes.doc
src/DriverDAT/DriverDAT_W_SMDS_Mesh.cxx
src/DriverMED/DriverMED_W_SMESHDS_Mesh.cxx
src/SMDS/SMDS_Mesh0DElement.cxx
src/SMDS/SMDS_Mesh0DElement.hxx
src/SMESH/SMESH_MeshEditor.cxx
src/SMESHGUI/SMESHGUI_SewingDlg.cxx
src/SMESHUtils/SMESH_FreeBorders.cxx
src/SMESHUtils/SMESH_MeshAlgos.cxx
src/SMESH_I/SMESH_MeshEditor_i.cxx

old mode 100755 (executable)
new mode 100644 (file)
index daef959..1e97dd2
Binary files a/doc/salome/gui/SMESH/images/sewing1.png and b/doc/salome/gui/SMESH/images/sewing1.png differ
diff --git a/doc/salome/gui/SMESH/images/sewing_auto.png b/doc/salome/gui/SMESH/images/sewing_auto.png
new file mode 100644 (file)
index 0000000..0bf19b4
Binary files /dev/null and b/doc/salome/gui/SMESH/images/sewing_auto.png differ
diff --git a/doc/salome/gui/SMESH/images/sewing_manual.png b/doc/salome/gui/SMESH/images/sewing_manual.png
new file mode 100644 (file)
index 0000000..ded90cf
Binary files /dev/null and b/doc/salome/gui/SMESH/images/sewing_manual.png differ
diff --git a/doc/salome/gui/SMESH/images/swap.png b/doc/salome/gui/SMESH/images/swap.png
new file mode 100644 (file)
index 0000000..6470710
Binary files /dev/null and b/doc/salome/gui/SMESH/images/swap.png differ
index 4d00c57..63b81ff 100644 (file)
@@ -41,11 +41,9 @@ To apply this algorithm when you define your mesh, select <b>Body
 This dialog allows to define
 <ul>
   <li>\b Name of the algorithm. </li>
-  
   <li> Minimal size of a cell truncated by the geometry boundary. If the
     size of a truncated grid cell is \b Threshold times less than a
     initial cell size, then a mesh element is not created. </li>
-       
   <li> <b> Implement Edges </b> check-box activates incorporation of
   geometrical edges in the mesh.
   
@@ -64,9 +62,10 @@ This dialog allows to define
         System.</li>
       <li> You can define the \b Spacing of a grid as an algebraic formula
         <em>f(t)</em> where \a t is a position along a grid axis
-        normalized at [0.0,1.0]. The whole range of geometry can be
-        divided into sub-ranges with their own spacing formulas to apply;
-        \a t varies between 0.0 and 1.0 within each sub-range. \b Insert button
+        normalized at [0.0,1.0]. <em>f(t)</em> must be non-negative
+        at 0. <= \a t <= 1. The whole extent of geometry can be
+        divided into ranges with their own spacing formulas to apply;
+        \a t varies between 0.0 and 1.0 within each \b Range. \b Insert button
         divides a selected range into two. \b Delete button adds the
         selected sub-range to the previous one. Double click on a range in
         the list enables edition of its right boundary. Double click on a
index 666cfca..f28be86 100644 (file)
@@ -16,8 +16,8 @@ and hypotheses.
 
 Mesh generation on the geometry is performed in the bottom-up
 flow: nodes on vertices are created first, then edges are divided into
-segments using nodes on vertices; the segments of edges are then
-used to mesh faces; then the mesh of faces is used to mesh
+segments using nodes on vertices; the node of segments are then
+used to mesh faces; then the nodes of faces are used to mesh
 solids. This automatically assures the conformity of the mesh.
 
 It is required to choose a meshing algorithm for every dimension of
index 8b7bb76..18be054 100644 (file)
@@ -20,9 +20,11 @@ and from its sub-menu select the \b Sewing item.</li>
 <li>Check in the dialog box one of the radio buttons corresponding to
 the type of sewing operation you would like to perform.</li>
 <li>Fill the other fields available in the dialog box.</li>
-<li>Click the \b Apply or <b>Apply and Close</b> button to perform the operation of sewing.</li>
+<li>Click the \b Apply or <b>Apply and Close</b> button to perform the
+  operation of sewing.</li>
 </ol>
 
+
 <br>
 \anchor free_borders_anchor
 <h2>Sew free borders</h2>
@@ -31,14 +33,69 @@ 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.
+specified tolerance and sews them. Optionally it is possible to
+visually check and correct is necessary the found free borders before
+sewing. <br>
+In the \b Manual mode you are to define borders to sew by picking
+three nodes of each of two borders.
 
 \image html sewing1.png
+<center>Default mode is \a Automatic</center>
+
+To use \b Automatic sewing:
+<ul>
+<li>Specify a mesh you want to sew by selecting it or any its part
+  (group or sub-mesh) in the Object Browser or in the VTK Viewer.</li>
+<li>Specify the \b Tolerance within which free borders are considered
+  coincident. At the default zero \b Tolerance, the tolerance used by
+  the search algorithm is defined as one tenth of an average size of
+  elements adjacent to free borders being compared.</li>
+<li>To visually check the coincident free borders found by the
+  algorithm, switch off <b>Auto Sewing</b> check-box. Then controls
+  to adjust groups of coincident free borders will become available in
+  the dialog.</li>
+
+\image html sewing_auto.png
+<center>Controls to adjust groups of coincident free borders</center>
+
+<li>\b Detect button launches the algorithm of search of coincident
+  free borders.</li>
+<li>The found groups of <b>Coincident Free Borders</b> are shown in a
+  list, a group per a line. Each group has its own color which is used
+  to display the borders of the group in the VTK Viewer. A free border
+  within a group is designated by IDs of its first and last nodes within
+  parenthesis. All borders present in the list will be sewn upon \b
+  Apply.</li>
+<li>\b Remove button removes selected groups from the list.</li>
+<li><b>Select All</b> check-box selects all groups in the list.</li>
+<li>When a group is selected, its borders appear in <b>Edit Selected
+    Group</b> list that allows you to change this group.</li>
+<li>
+\image html sort.png
+<em>Set First</em> button moves the selected border to the
+  first position in the group, as a result other borders will be moved
+  to this border during sewing.
+</li><li>
+\image html remove.png
+<em>Remove Border</em> button removes selected borders from the
+  group. It is active if there are more than two borders in the group.
+</li>
+<li>Selection of a border in the list allows to change its first and
+  last nodes whose IDs appear in two fields below the list. \a Arrow
+  buttons near each field move the corresponding end node by
+  number of nodes defined by \b Step field.</li>
+<li>
+\image html swap.png
+<em>Swap</em> button swaps the first and last nodes of a
+  selected border.
+</li>
+</ul>
+
+For sewing free borders manually you should switch the \b Mode to \b
+Manual and define three points on each border: first, second and the
+last node:
 
-For sewing free borders you should define three points on each border:
-first, second and the last node:
+\image html sewing_manual.png
 <ul>
 <li>the first node specifies beginning of the border;</li>
 <li>the second node specifies the part of the border which should be
index 5205292..63de896 100644 (file)
@@ -38,7 +38,6 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform()
   Status aResult = DRS_OK;
 
   int nbNodes, nbCells;
-  //int i;
 
   char *file2Read = (char *)myFile.c_str();
   FILE* aFileId = fopen(file2Read, "w+");
@@ -55,7 +54,7 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform()
   nbNodes = myMesh->NbNodes();
 
   /* Combien de mailles, faces ou aretes ? */
-  int /*nb_of_nodes,*/ nb_of_edges, nb_of_faces, nb_of_volumes;
+  int nb_of_edges, nb_of_faces, nb_of_volumes;
   nb_of_edges = myMesh->NbEdges();
   nb_of_faces = myMesh->NbFaces();
   nb_of_volumes = myMesh->NbVolumes();
@@ -64,7 +63,7 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform()
   SCRUTE(nb_of_faces);
   SCRUTE(nb_of_volumes);
 
-  fprintf(stdout, "%d %d\n", nbNodes, nbCells);
+  //fprintf(stdout, "%d %d\n", nbNodes, nbCells);
   fprintf(aFileId, "%d %d\n", nbNodes, nbCells);
 
   /****************************************************************************
@@ -74,7 +73,7 @@ Driver_Mesh::Status DriverDAT_W_SMDS_Mesh::Perform()
   SMDS_NodeIteratorPtr itNodes=myMesh->nodesIterator();
   while(itNodes->more()){               
     const SMDS_MeshNode * node = itNodes->next();
-    fprintf(aFileId, "%d %e %e %e\n", node->GetID(), node->X(), node->Y(), node->Z());
+    fprintf(aFileId, "%d %.14e %.14e %.14e\n", node->GetID(), node->X(), node->Y(), node->Z());
   }
         
   /****************************************************************************
index fa974f7..b4ab8db 100644 (file)
@@ -56,7 +56,8 @@ DriverMED_W_SMESHDS_Mesh::DriverMED_W_SMESHDS_Mesh():
   myDoGroupOfVolumes (false),
   myDoGroupOf0DElems(false),
   myDoGroupOfBalls(false),
-  myAutoDimension(true)
+  myAutoDimension(true),
+  myAddODOnVertices(false)
 {}
 
 void DriverMED_W_SMESHDS_Mesh::SetFile(const std::string& theFileName, 
index be38ce1..05dd4e4 100644 (file)
@@ -139,8 +139,12 @@ const SMDS_MeshNode* SMDS_Mesh0DElement::GetNode(const int ind) const
 //function : ChangeNode
 //purpose  :
 //=======================================================================
-bool SMDS_Mesh0DElement::ChangeNode (const SMDS_MeshNode * node)
+bool SMDS_Mesh0DElement::ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes)
 {
-  myNode = node;
-  return true;
+  if ( nbNodes == 1 )
+  {
+    myNode = nodes[0];
+    return true;
+  }
+  return false;
 }
index b499871..d0c0769 100644 (file)
@@ -34,8 +34,7 @@ class SMDS_EXPORT SMDS_Mesh0DElement: public SMDS_MeshCell
 {
  public:
   SMDS_Mesh0DElement (const SMDS_MeshNode * node);
-  bool ChangeNode (const SMDS_MeshNode * node);
-  virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes) {return false;};
+  virtual bool ChangeNodes(const SMDS_MeshNode* nodes[], const int nbNodes);
   virtual void Print (std::ostream & OS) const;
 
   virtual SMDSAbs_ElementType  GetType() const;
index c3a62bf..89e85dc 100644 (file)
@@ -7371,8 +7371,8 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
   for ( ; eIt != elems.end(); eIt++ )
   {
     const SMDS_MeshElement* elem = *eIt;
-    int nbNodes = elem->NbNodes();
-    int aShapeId = FindShape( elem );
+    const           int  nbNodes = elem->NbNodes();
+    const           int aShapeId = FindShape( elem );
 
     nodeSet.clear();
     curNodes.resize( nbNodes );
@@ -7912,17 +7912,24 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
 
     if ( isOk ) // the non-poly elem remains valid after sticking nodes
     {
-      elemType.Init( elem ).SetID( elem->GetID() );
+      if ( nbNodes != nbUniqueNodes )
+      {
+        elemType.Init( elem ).SetID( elem->GetID() );
 
-      SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
-      aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
+        SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
+        aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
 
-      uniqueNodes.resize(nbUniqueNodes);
-      SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType );
-      if ( sm && newElem )
-        sm->AddElement( newElem );
-      if ( elem != newElem )
-        ReplaceElemInGroups( elem, newElem, aMesh );
+        uniqueNodes.resize(nbUniqueNodes);
+        SMDS_MeshElement* newElem = this->AddElement( uniqueNodes, elemType );
+        if ( sm && newElem )
+          sm->AddElement( newElem );
+        if ( elem != newElem )
+          ReplaceElemInGroups( elem, newElem, aMesh );
+      }
+      else
+      {
+        aMesh->ChangeElementNodes( elem, & curNodes[0], nbNodes );
+      }
     }
     else {
       // Remove invalid regular element or invalid polygon
@@ -8749,7 +8756,8 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
   }
   // find coincident
   TListOfListOfElementsID equalGroups;
-  FindEqualElements( segments, equalGroups );
+  if ( !segments.empty() )
+    FindEqualElements( segments, equalGroups );
   if ( !equalGroups.empty() )
   {
     // remove from segments those that will be removed
index 6979a07..d0a5cc5 100644 (file)
@@ -329,14 +329,13 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
 
   SelectAllCheck = new QCheckBox(tr("SELECT_ALL"), GroupCoincident);
 
-  aCoincidentLayout->addWidget(ListCoincident,    0, 0, 4, 2);
+  aCoincidentLayout->addWidget(ListCoincident,    0, 0, 5, 2);
   aCoincidentLayout->addWidget(DetectButton,      1, 2);
   aCoincidentLayout->addWidget(RemoveGroupButton, 3, 2);
-  aCoincidentLayout->addWidget(SelectAllCheck,    4, 0);
+  aCoincidentLayout->addWidget(SelectAllCheck,    5, 0);
   aCoincidentLayout->setRowMinimumHeight(1, 10);
-  aCoincidentLayout->setRowStretch      (1, 5);
-
-  GroupCoincidentLayout->addWidget( GroupCoincident );
+  aCoincidentLayout->setRowStretch      (4, 5);
+  aCoincidentLayout->setRowStretch      (5, 0);
 
   /*****************************************/
   // Controls for editing the selected group
@@ -391,8 +390,13 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule )
   GroupEditLayout->addWidget(SwapBut,          1, 7);
   GroupEditLayout->addWidget(StepLabel,        1, 8);
   GroupEditLayout->addWidget(StepSpin,         1, 9);
+  GroupEditLayout->setRowStretch( 0, 1 );
 
+  GroupCoincidentLayout->addWidget( GroupCoincident );
   GroupCoincidentLayout->addWidget( GroupEdit );
+  GroupCoincidentLayout->setRowStretch( 0, 10 );
+  GroupCoincidentLayout->setRowStretch( 1, 1 );
+
   aSewFreeBordersLayout->addWidget( GroupCoincidentWidget );
 
   // layout
@@ -579,6 +583,7 @@ void SMESHGUI_SewingDlg::ConstructorsClicked (int constructorId)
   {
     ModeGroup->hide();
     SewFreeBordersWidget->hide();
+    restoreDisplayMode();
   }
 
   bool isNodeSelection = true;
@@ -673,12 +678,11 @@ void SMESHGUI_SewingDlg::ConstructorsClicked (int constructorId)
     LineEdit4->setValidator(new SMESHGUI_IdValidator(this, 1));
   }
 
-  if ( isNodeSelection )
-  {
-    SMESH::SetPointRepresentation(true);
-    if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
-      aViewWindow->SetSelectionMode(NodeSelection);
-  }
+  if ( myActor )
+    myActor->SetPointRepresentation( isNodeSelection );
+
+  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
+    aViewWindow->SetSelectionMode( isNodeSelection ? NodeSelection : ActorSelection );
 
   UpdateButtons();
 
@@ -700,7 +704,8 @@ void SMESHGUI_SewingDlg::setDisplayMode()
 {
   myStoredEntityMode = 0;
   myStoredRepresentation = -1;
-  if ( myActor )
+
+  if ( myActor && AutoSewCheck->isVisible() && !AutoSewCheck->isChecked() )
   {
     myStoredEntityMode     = myActor->GetEntityMode();
     myStoredRepresentation = myActor->GetRepresentation();
@@ -728,6 +733,9 @@ void SMESHGUI_SewingDlg::restoreDisplayMode()
     myStoredEntityMode = 0;
     myStoredRepresentation = -1;
   }
+  for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
+    if ( myBorderDisplayers[ i ])
+      myBorderDisplayers[ i ]->Hide();
 }
 
 //=======================================================================
@@ -751,6 +759,12 @@ void SMESHGUI_SewingDlg::onModeChange( int mode )
     if ( !SewFreeBordersWidget->isVisible() )
       SewFreeBordersWidget->show();
   }
+  if ( myActor )
+    myActor->SetPointRepresentation( mode == MODE_MANUAL );
+
+  if ( SVTK_ViewWindow* aViewWindow = SMESH::GetCurrentVtkView() )
+    aViewWindow->SetSelectionMode( mode == MODE_MANUAL ? NodeSelection : ActorSelection );
+
   onAutoSew( AutoSewCheck->isChecked() );
 
   QApplication::instance()->processEvents();
@@ -774,6 +788,12 @@ void SMESHGUI_SewingDlg::onAutoSew( int isAuto )
   if ( ModeButGrp->checkedId() == MODE_AUTO )
     SewFreeBordersWidget->show();
 
+  if ( isAuto )
+    restoreDisplayMode();
+  else
+    setDisplayMode();
+  SMESH::RepaintCurrentView();
+
   UpdateButtons();
 
   updateGeometry();
@@ -847,6 +867,7 @@ QString SMESHGUI_SewingDlg::getGroupText(int groupIndex)
 
 void SMESHGUI_SewingDlg::onDetectClicked()
 {
+  myBusy = true;
   ListCoincident->clear();
 
   if ( myMesh->_is_nil() )
@@ -881,6 +902,7 @@ void SMESHGUI_SewingDlg::onDetectClicked()
     item->setData( GROUP_COLOR, groupColor );
     item->setData( GROUP_INDEX, i );
   }
+  myBusy = false;
 
   onSelectGroup();
 
@@ -894,6 +916,7 @@ void SMESHGUI_SewingDlg::onDetectClicked()
 
 void SMESHGUI_SewingDlg::onRemoveGroupClicked()
 {
+  myBusy = true;
   QList<QListWidgetItem*> selItems = ListCoincident->selectedItems();
   for ( int i = 0; i < selItems.count(); ++i )
   {
@@ -901,10 +924,14 @@ void SMESHGUI_SewingDlg::onRemoveGroupClicked()
     item->setSelected( false );
     int groupIndex = item->data( GROUP_INDEX ).toInt();
     delete item;
-    myBorderDisplayers[ groupIndex ]->Hide();
+    if ( myBorderDisplayers[ groupIndex ])
+      myBorderDisplayers[ groupIndex ]->Hide();
     SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ];
     aGRP.length( 0 );
   }
+  myBusy = false;
+
+  onSelectGroup();
   UpdateButtons();
 }
 
@@ -917,7 +944,7 @@ void SMESHGUI_SewingDlg::showGroup( QListWidgetItem* item )
 {
   if ( !item ||
        item->listWidget() != ListCoincident ||
-       !haveBorders() )
+       !haveBorders())
     return;
 
   int    groupIndex = item->data( GROUP_INDEX ).toInt();
@@ -925,10 +952,11 @@ void SMESHGUI_SewingDlg::showGroup( QListWidgetItem* item )
   if ( groupIndex >= 0       &&
        groupIndex < myBorders->coincidentGroups.length() )
   {
-    if ( !myBorderDisplayers[ groupIndex ])
+    if ( !myBorderDisplayers[ groupIndex ] && SMESH::GetCurrentVtkView())
       myBorderDisplayers[ groupIndex ] = new BorderGroupDisplayer( myBorders, groupIndex, groupColor, myMesh );
     bool wholeBorders = setCurrentGroup();
-    myBorderDisplayers[ groupIndex ]->ShowGroup( wholeBorders );
+    if ( myBorderDisplayers[ groupIndex ])
+      myBorderDisplayers[ groupIndex ]->ShowGroup( wholeBorders );
   }
 }
 
@@ -1111,7 +1139,8 @@ void SMESHGUI_SewingDlg::onGroupChange( bool partChange )
   for ( int i = 0; i < ListEdit->count(); ++i )
     ListEdit->item( i )->setText( getPartText( aGRP[ i ]));
 
-  myBorderDisplayers[ myCurGroupIndex ]->Update();
+  if ( myBorderDisplayers[ myCurGroupIndex ])
+    myBorderDisplayers[ myCurGroupIndex ]->Update();
 
   if ( partChange )
     onSelectBorderPartFromGroup();
@@ -1410,6 +1439,7 @@ void SMESHGUI_SewingDlg::onCloseView()
 {
   DeactivateActiveDialog();
   mySelector = 0;
+  myActor = 0;
 
   for ( size_t i = 0; i < myBorderDisplayers.size(); ++i )
   {
@@ -1969,11 +1999,11 @@ void SMESHGUI_SewingDlg::BorderGroupDisplayer::Update()
       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 );
+      myPartActors[ i ]->SetPickable ( false );
       myViewWindow->AddActor( myPartActors[ i ]);
-      myViewWindow->Repaint();
+      //myViewWindow->Repaint();
     }
   }
 }
index 8d5e8ca..939178f 100644 (file)
@@ -47,17 +47,20 @@ namespace
   /*!
    * \brief Node on a free border
    */
-  struct BNode
+  struct BNode : public SMESH_TNodeXYZ
   {
-    const SMDS_MeshNode *         myNode;
     mutable std::vector< BEdge* > myLinkedEdges;
-    mutable std::vector< BEdge* > myCloseEdges;
+    mutable std::vector< std::pair < BEdge*, double > > myCloseEdges; // edge & U
 
-    BNode(const SMDS_MeshNode * node): myNode( node ) {}
+    BNode(const SMDS_MeshNode * node): SMESH_TNodeXYZ( node ) {}
+    const SMDS_MeshNode * Node() const { return _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(); }
+    void AddClose ( const BEdge* e, double u ) const;
+    BEdge* GetCloseEdge( size_t i ) const { return myCloseEdges[i].first; }
+    double GetCloseU( size_t i ) const { return myCloseEdges[i].second; }
+    BEdge* GetCloseEdgeOfBorder( int borderID, double * u = 0 ) const;
+    bool IsCloseEdge( const BEdge* ) const;
+    bool operator<(const BNode& other) const { return Node()->GetID() < other.Node()->GetID(); }
   };
   /*!
    * \brief Edge of a free border
@@ -72,9 +75,9 @@ namespace
     BEdge*                  myNext;
     const SMDS_MeshElement* myFace;
     std::set< int >         myCloseBorders;
-    bool                    myInGroup;
+    int                     myInGroup;
 
-    BEdge():SMDS_LinearEdge( 0, 0 ), myBorderID(-1), myID(-1), myPrev(0), myNext(0), myInGroup(0) {}
+    BEdge():SMDS_LinearEdge( 0, 0 ), myBorderID(-1), myID(-1), myPrev(0), myNext(0), myInGroup(-1) {}
 
     void Set( const BNode *           node1,
               const BNode *           node2,
@@ -83,11 +86,15 @@ namespace
     {
       myBNode1   = node1;
       myBNode2   = node2;
-      myNodes[0] = node1->myNode;
-      myNodes[1] = node2->myNode;
+      myNodes[0] = node1->Node();
+      myNodes[1] = node2->Node();
       myFace     = face;
       setId( ID ); // mesh element ID
     }
+    bool IsInGroup() const
+    {
+      return myInGroup >= 0;
+    }
     bool Contains( const BNode* n ) const
     {
       return ( n == myBNode1 || n == myBNode2 );
@@ -105,8 +112,8 @@ namespace
     void Reverse()
     {
       std::swap( myBNode1, myBNode2 );
-      myNodes[0] = myBNode1->myNode;
-      myNodes[1] = myBNode2->myNode;
+      myNodes[0] = myBNode1->Node();
+      myNodes[1] = myBNode2->Node();
     }
     void Orient()
     {
@@ -125,25 +132,95 @@ namespace
           myNext->SetID( id + 1 );
       }
     }
-    void FindRangeOfSameCloseBorders(BEdge* eRange[2])
+    bool IsOut( const gp_XYZ& point, const double tol, double& u ) const
     {
+      gp_XYZ  me = *myBNode2 - *myBNode1;
+      gp_XYZ n1p = point     - *myBNode1;
+      u = ( me * n1p ) / me.SquareModulus(); // param [0,1] on this
+      if ( u < 0. ) return ( n1p.SquareModulus() > tol * tol );
+      if ( u > 1. ) return ( ( point - *myBNode2 ).SquareModulus() > tol * tol );
+
+      gp_XYZ  proj = ( 1. - u ) * *myBNode1 + u * *myBNode2; // projection of the point on this
+      double dist2 = ( point - proj ).SquareModulus();
+      return ( dist2 > tol * tol );
+    }
+    bool IsOverlappingProjection( const BEdge* toE, const double u, bool is1st ) const
+    {
+      // is1st shows which end of toE is projected on this at u
+      double u2;
+      const double eps = 0.1;
+      if ( toE == myBNode1->GetCloseEdgeOfBorder( toE->myBorderID, &u2 ) ||
+           toE == myBNode2->GetCloseEdgeOfBorder( toE->myBorderID, &u2 ))
+        return (( 0 < u2 && u2 < 1 ) &&     // u2 is proj param of myBNode's on toE
+                ( Abs( u2 - int( !is1st )) > eps ));
+
+      const BNode* n = is1st ? toE->myBNode2 : toE->myBNode1;
+      if ( this == n->GetCloseEdgeOfBorder( this->myBorderID, &u2 ))
+        return Abs( u - u2 ) > eps;
+      return false;
+    }
+    bool GetRangeOfSameCloseBorders(BEdge* eRange[2], const std::set< int >& bordIDs)
+    {
+      if ( this->myCloseBorders != bordIDs )
+        return false;
+
       eRange[0] = this;
-      while ( eRange[0]->myPrev && eRange[0]->myPrev->myCloseBorders == this->myCloseBorders )
+      while ( eRange[0]->myPrev && eRange[0]->myPrev->myCloseBorders == bordIDs )
       {
         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 )
+        while ( eRange[1]->myNext && eRange[1]->myNext->myCloseBorders == bordIDs )
         {
           if ( eRange[1]->myNext == this /*|| eRange[1]->myNext->myInGroup*/ )
             break;
           eRange[1] = eRange[1]->myNext;
         }
+
+      return ( eRange[0] != eRange[1] );
+    }
+  }; // class BEdge
+
+  void extendPart( BEdge* & e1, BEdge* & e2, const std::set< int >& bordIDs, int groupID )
+  {
+    if (( e1->myPrev == e2 ) ||
+        ( e1 == e2 && e1->myPrev && e1->myPrev->myInGroup == groupID ))
+      return; // full free border already
+
+    double u;
+    BEdge* be;
+    std::set<int>::const_iterator bord;
+    if ( e1->myPrev )
+    {
+      for ( bord = bordIDs.begin(); bord != bordIDs.end(); ++bord )
+        if ((  *bord != e1->myBorderID ) &&
+            (( be = e1->myBNode1->GetCloseEdgeOfBorder( *bord, &u ))) &&
+            (  be->myInGroup == groupID ) &&
+            (  0 < u && u < 1 ) &&
+            (  be->IsOverlappingProjection( e1->myPrev, u, false )))
+        {
+          e1 = e1->myPrev;
+          break;
+        }
     }
-  };
+    if ( e2->myNext )
+    {
+      for ( bord = bordIDs.begin(); bord != bordIDs.end(); ++bord )
+        if ((  *bord != e2->myBorderID ) &&
+            (( be = e2->myBNode2->GetCloseEdgeOfBorder( *bord, &u ))) &&
+            (  be->myInGroup == groupID ) &&
+            (  0 < u && u < 1 ) &&
+            (  be->IsOverlappingProjection( e2->myNext, u, true )))
+        {
+          e2 = e2->myNext;
+          break;
+        }
+    }
+  }
 
   void BNode::AddLinked( BEdge* e ) const
   {
@@ -164,17 +241,32 @@ namespace
             myLinkedEdges[i]->RemoveLinked( myLinkedEdges[j] );
     }
   }
-  void BNode::AddClose ( const BEdge* e ) const
+  void BNode::AddClose ( const BEdge* e, double u ) const
   {
     if ( ! e->Contains( this ))
-      myCloseEdges.push_back( const_cast< BEdge* >( e ));
+      myCloseEdges.push_back( make_pair( const_cast< BEdge* >( e ), u ));
+  }
+  BEdge* BNode::GetCloseEdgeOfBorder( int borderID, double * uPtr ) const
+  {
+    BEdge* e = 0;
+    double u = 0;
+    for ( size_t i = 0; i < myCloseEdges.size(); ++i )
+      if ( borderID == GetCloseEdge( i )->myBorderID )
+      {
+        if ( e && Abs( u - 0.5 ) < Abs( GetCloseU( i ) - 0.5 ))
+          continue;
+        u = GetCloseU( i );
+        e = GetCloseEdge ( i );
+      }
+    if ( uPtr ) *uPtr = u;
+    return e;
   }
-  BEdge* BNode::FindCloseEdgeOfBorder( int borderID ) const
+  bool BNode::IsCloseEdge( const BEdge* e ) const
   {
     for ( size_t i = 0; i < myCloseEdges.size(); ++i )
-      if ( borderID == myCloseEdges[ i ]->myBorderID )
-        return myCloseEdges[ i ];
-    return 0;
+      if ( e == GetCloseEdge( i ) )
+        return true;
+    return false;
   }
 
   /// Accessor to SMDS_MeshElement* inherited by BEdge
@@ -333,12 +425,11 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
   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 );
+    searcher->FindElementsByPoint( *bn, SMDSAbs_Edge, candidateEdges );
     if ( candidateEdges.size() <= bn->myLinkedEdges.size() )
       continue;
 
-    double nodeTol = 0;
+    double nodeTol = 0, u;
     for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
       nodeTol = Max( nodeTol, bordToler[ bn->myLinkedEdges[ i ]->myBorderID ]);
 
@@ -346,9 +437,8 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
     {
       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 );
+      if ( !be->IsOut( *bn, tol, u ))
+        bn->AddClose( be, u );
     }
   }
 
@@ -366,8 +456,8 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
     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 );
+      BEdge* closeE1 = be.myBNode1->GetCloseEdge( iE1 );
+      BEdge* closeE2 = be.myBNode2->GetCloseEdgeOfBorder( closeE1->myBorderID );
       if ( !closeE2 )
         continue;
       // check that edges connecting closeE1 and closeE2 (if any) are also close to 'be'
@@ -378,7 +468,7 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
         {
           BEdge* ce = closeE1;
           do {
-            coincide = ( ce->myBNode2->FindCloseEdgeOfBorder( be.myBorderID ));
+            coincide = ( ce->myBNode2->GetCloseEdgeOfBorder( be.myBorderID ));
             ce       = ce->myNext;
           } while ( coincide && ce && ce != closeE2 );
 
@@ -415,9 +505,9 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
   for ( size_t i = 0; i < borders.size(); ++i )
   {
     BEdge* be = borders[i];
-    foundFreeBordes._borders[i].push_back( be->myBNode1->myNode );
+    foundFreeBordes._borders[i].push_back( be->myBNode1->Node() );
     do {
-      foundFreeBordes._borders[i].push_back( be->myBNode2->myNode );
+      foundFreeBordes._borders[i].push_back( be->myBNode2->Node() );
       be = be->myNext;
     }
     while ( be && be != borders[i] );
@@ -427,81 +517,158 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
 
   TFreeBorderPart  part;
   TCoincidentGroup group;
-  for ( size_t i = 0; i < borders.size(); ++i )
+  vector< BEdge* > ranges; // couples of edges delimiting parts
+  BEdge* be = 0; // a current edge
+  int skipGroup = bEdges.size(); // a group ID used to avoid repeating treatment of edges
+
+  for ( int i = 0, nbBords = borders.size(); i < nbBords; i += bool(!be) )
   {
-    BEdge* be = borders[i];
+    if ( !be )
+      be = borders[i];
 
     // look for an edge close to other borders
     do {
-      if ( !be->myInGroup && !be->myCloseBorders.empty() )
+      if ( !be->IsInGroup() && !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
-
+    if ( !be || be->IsInGroup() || be->myCloseBorders.empty() )
+    {
+      be = 0;
+      continue; // all edges of a border are treated or non-coincident
+    }
     group.clear();
+    ranges.clear();
 
     // look for the 1st and last edge of a coincident group
     BEdge* beRange[2];
-    be->FindRangeOfSameCloseBorders( beRange );
-    BEdge* be1st = beRange[0];
+    if ( !be->GetRangeOfSameCloseBorders( beRange, be->myCloseBorders ))
+    {
+      be->myInGroup = skipGroup;
+      be = be->myNext;
+      continue;
+    }
 
-    // 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 );
+    ranges.push_back( beRange[0] );
+    ranges.push_back( beRange[1] );
 
+    int groupID = foundFreeBordes._coincidentGroups.size();
     be = beRange[0];
-    be->myInGroup = true;
+    be->myInGroup = groupID;
     while ( be != beRange[1] )
     {
-      be->myInGroup = true;
+      be->myInGroup = groupID;
       be = be->myNext;
     }
-    beRange[1]->myInGroup = true;
+    beRange[1]->myInGroup = groupID;
 
     // add parts of other borders
+
+    BEdge* be1st = beRange[0];
+    closeEdges.clear();
     std::set<int>::iterator closeBord = be1st->myCloseBorders.begin();
     for ( ; closeBord != be1st->myCloseBorders.end(); ++closeBord )
+      closeEdges.push_back( be1st->myBNode2->GetCloseEdgeOfBorder( *closeBord ));
+
+    for ( size_t iE = 0; iE < closeEdges.size(); ++iE )
     {
-      be = be1st->myBNode2->FindCloseEdgeOfBorder( *closeBord );
+      be = closeEdges[ iE ];
       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 );
+      bool ok = be->GetRangeOfSameCloseBorders( beRange, be->myCloseBorders );
+      if ( !ok && be->myPrev )
+        ok = be->myPrev->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders );
+      if ( !ok && be->myNext )
+        ok = be->myNext->GetRangeOfSameCloseBorders( beRange, be1st->myCloseBorders );
+      if ( !ok )
+        continue;
 
-      // 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;
+      be = beRange[0];
+      if ( be->myCloseBorders != be1st->myCloseBorders )
+      {
+        //add missing edges to closeEdges
+        closeBord = be->myCloseBorders.begin();
+        for ( ; closeBord != be->myCloseBorders.end(); ++closeBord )
+          if ( !be1st->myCloseBorders.count( *closeBord ))
+            closeEdges.push_back( be->myBNode2->GetCloseEdgeOfBorder( *closeBord ));
       }
-      else  {
-        part._node1    = beRange[0]->myID;
-        part._node2    = beRange[0]->myID + 1;
-        part._nodeLast = beRange[1]->myID + 1;
+
+      ranges.push_back( beRange[0] );
+      ranges.push_back( beRange[1] );
+
+      be->myInGroup = groupID;
+      while ( be != beRange[1] )
+      {
+        be->myInGroup = groupID;
+        be = be->myNext;
       }
+      beRange[1]->myInGroup = groupID;
+    }
+
+    if ( ranges.size() > 2 )
+    {
+      for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
+        extendPart( ranges[ iR-1 ], ranges[ iR ], be1st->myCloseBorders, groupID );
+
+      // fill in a group
+      beRange[0] = ranges[0];
+      beRange[1] = ranges[1];
+
+      part._border   = i;
+      part._node1    = beRange[0]->myID;
+      part._node2    = beRange[0]->myID + 1;
+      part._nodeLast = beRange[1]->myID + 1;
       group.push_back( part );
 
+      be1st = beRange[0];
+      for ( size_t iR = 3; iR < ranges.size(); iR += 2 )
+      {
+        beRange[0] = ranges[iR-1];
+        beRange[1] = ranges[iR-0];
+
+        // find out mutual orientation of borders
+        double u1, u2;
+        be1st       ->IsOut( *beRange[ 0 ]->myBNode1, maxTolerance, u1 );
+        beRange[ 0 ]->IsOut( *be1st->myBNode1,        maxTolerance, u2 );
+        bool reverse = (( u1 < 0 || u1 > 1 ) && ( u2 < 0 || u2 > 1 ));
+
+        // 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 );
+      }
+      foundFreeBordes._coincidentGroups.push_back( group );
+    }
+    else
+    {
+      beRange[0] = ranges[0];
+      beRange[1] = ranges[1];
+
       be = beRange[0];
-      be->myInGroup = true;
+      be->myInGroup = skipGroup;
       while ( be != beRange[1] )
       {
-        be->myInGroup = true;
+        be->myInGroup = skipGroup;
         be = be->myNext;
       }
-      beRange[1]->myInGroup = true;
+      beRange[1]->myInGroup = skipGroup;
     }
 
-    foundFreeBordes._coincidentGroups.push_back( group );
+    be = ranges[1];
 
   } // loop on free borders
-}
+
+  return;
+
+} // SMESH_MeshAlgos::FindCoincidentFreeBorders()
+
index dc157e7..1a9dd65 100644 (file)
@@ -1210,19 +1210,13 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     {
       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 ( u <= 0. ) {
         if ( n1p.SquareMagnitude() < tol * tol )
           return false;
         continue;
       }
-      if ( u > 1. ) {
+      if ( u >= 1. ) {
         if ( point.SquareDistance( xyz[i] ) < tol * tol )
           return false;
         continue;
index 34f3109..e623eda 100644 (file)
@@ -4641,11 +4641,12 @@ SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
   CORBA::Short nbSewed = 0;
 
   SMESH_MeshAlgos::TFreeBorderVec groups;
-  SMESH_MeshAlgos::TFreeBorder    borderNodes; // triples on nodes for every FreeBorderPart
+  SMESH_MeshAlgos::TFreeBorder    borderNodes; // triples of nodes for every FreeBorderPart
 
-  // check the input
+  // check the input and collect nodes
   for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
   {
+    borderNodes.clear();
     const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ];
     for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP )
     {
@@ -4672,71 +4673,70 @@ SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM);
       if ( !n3 )
         THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM);
+
+      borderNodes.push_back( n1 );
+      borderNodes.push_back( n2 );
+      borderNodes.push_back( n3 );
     }
+    groups.push_back( borderNodes );
   }
 
-  //TIDSortedElemSet dummy;
+  // SewFreeBorder() can merge nodes, thus nodes stored in 'groups' can become dead;
+  // to get nodes that replace other nodes during merge we create 0D elements
+  // on each node and MergeNodes() will replace underlying nodes of 0D elements by
+  // new ones.
 
-  ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
-  for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i )
+  vector< const SMDS_MeshElement* > tmp0Delems;
+  for ( size_t i = 0; i < groups.size(); ++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 )
+    SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
+    for ( size_t iN = 0; iN < nodes.size(); ++iN )
     {
-      const SMESH::FreeBorderPart& aPART_0 = aGRP[ 0 ];
-      const SMESH::FreeBorder&      aBRD_0 = freeBorders.borders[ aPART_0.border ];
+      SMDS_ElemIteratorPtr it0D = nodes[iN]->GetInverseElementIterator(SMDSAbs_0DElement);
+      if ( it0D->more() )
+        tmp0Delems.push_back( it0D->next() );
+      else
+        tmp0Delems.push_back( getMeshDS()->Add0DElement( nodes[iN] ));
+    }
+  }
 
-      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 ]);
+  SMESH_TRY;
 
-      const SMESH::FreeBorderPart& aPART = aGRP[ iP ];
-      const SMESH::FreeBorder&      aBRD = freeBorders.borders[ aPART.border ];
+  ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK;
+  int i0D = 0;
+  for ( size_t i = 0; i < groups.size(); ++i )
+  {
+    bool isBordToBord = true;
+    bool   groupSewed = false;
+    SMESH_MeshAlgos::TFreeBorder& nodes = groups[i];
+    for ( size_t iN = 3; iN+2 < nodes.size(); iN += 3 )
+    {
+      const SMDS_MeshNode* n0 = tmp0Delems[ i0D + 0 ]->GetNode( 0 );
+      const SMDS_MeshNode* n1 = tmp0Delems[ i0D + 1 ]->GetNode( 0 );
+      const SMDS_MeshNode* n2 = tmp0Delems[ i0D + 2 ]->GetNode( 0 );
 
-      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 ]);
+      const SMDS_MeshNode* n3 = tmp0Delems[ i0D + 0 + iN ]->GetNode( 0 );
+      const SMDS_MeshNode* n4 = tmp0Delems[ i0D + 1 + iN ]->GetNode( 0 );
+      const SMDS_MeshNode* n5 = tmp0Delems[ i0D + 2 + iN ]->GetNode( 0 );
 
       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 )
+      if ( !isBordToBord )
       {
         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,
+                                       /*2ndIsFreeBorder=*/ isBordToBord,
                                        createPolygons, createPolyhedra);
       groupSewed = ( res == ok );
+
+      isBordToBord = false;
     }
+    i0D += nodes.size();
     nbSewed += groupSewed;
   }
 
@@ -4745,6 +4745,20 @@ SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders,
                 << createPolygons  << ", "
                 << createPolyhedra << " )";
 
+  SMESH_CATCH( SMESH::doNothing );
+
+  declareMeshModified( /*isReComputeSafe=*/false );
+
+  // remove tmp 0D elements
+  SMESH_TRY;
+  set< const SMDS_MeshElement* > removed0D;
+  for ( size_t i = 0; i < tmp0Delems.size(); ++i )
+  {
+    if ( removed0D.insert( tmp0Delems[i] ).second )
+      getMeshDS()->RemoveFreeElement( tmp0Delems[i], /*sm=*/0, /*fromGroups=*/false );
+  }
+  SMESH_CATCH( SMESH::throwCorbaException );
+
   return nbSewed;
 }