Salome HOME
Implementation of new version ExtrusionAlongPath (20003 from Mantis).
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index b858c372f1249ad88d97ff39fb0c5659a2cc07d2..81d71320ccbb23c62700a92e213c0965101c03b9 100644 (file)
@@ -1,6 +1,6 @@
-//  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
+//  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
 //
-//  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  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
 //  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
-//
-//
+//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
+//  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
 // File      : SMESH_MeshEditor.cxx
 // Created   : Mon Apr 12 16:10:22 2004
 // Author    : Edward AGAPOV (eap)
-
-
+//
 #include "SMESH_MeshEditor.hxx"
 
 #include "SMDS_FaceOfNodes.hxx"
@@ -61,6 +59,7 @@
 #include <TopExp_Explorer.hxx>
 #include <TopTools_ListIteratorOfListOfShape.hxx>
 #include <TopTools_ListOfShape.hxx>
+#include <TopTools_SequenceOfShape.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Face.hxx>
 #include <gp.hxx>
@@ -92,22 +91,6 @@ struct TNodeXYZ : public gp_XYZ {
   TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {}
 };
 
-typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
-
-//=======================================================================
-/*!
- * \brief A sorted pair of nodes
- */
-//=======================================================================
-
-struct TLink: public NLink
-{
-  TLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ):NLink( n1, n2 )
-  { if ( n1->GetID() < n2->GetID() ) std::swap( first, second ); }
-  TLink(const NLink& link ):NLink( link )
-  { if ( first->GetID() < second->GetID() ) std::swap( first, second ); }
-};
-
 //=======================================================================
 //function : SMESH_MeshEditor
 //purpose  :
@@ -1171,11 +1154,13 @@ void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
                                         SMESHDS_Mesh *          aMesh)
 {
   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
-  set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
-  for ( ; grIt != groups.end(); grIt++ ) {
-    SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
-    if ( group && group->Contains( elemInGroups ))
-      group->SMDSGroup().Add( elemToAdd );
+  if (!groups.empty()) {
+    set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
+    for ( ; grIt != groups.end(); grIt++ ) {
+      SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+      if ( group && group->Contains( elemInGroups ))
+        group->SMDSGroup().Add( elemToAdd );
+    }
   }
 }
 
@@ -1200,6 +1185,25 @@ void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
   }
 }
 
+//=======================================================================
+//function : ReplaceElemInGroups
+//purpose  : replace elemToRm by elemToAdd in the all groups
+//=======================================================================
+
+void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
+                                            const SMDS_MeshElement* elemToAdd,
+                                            SMESHDS_Mesh *          aMesh)
+{
+  const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
+  if (!groups.empty()) {
+    set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
+    for ( ; grIt != groups.end(); grIt++ ) {
+      SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
+      if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
+        group->SMDSGroup().Add( elemToAdd );
+    }
+  }
+}
 
 //=======================================================================
 //function : QuadToTri
@@ -1460,10 +1464,10 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
   // 1. map of elements with their linkIDs
   // 2. map of linkIDs with their elements
 
-  map< TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
-  map< TLink, list< const SMDS_MeshElement* > >::iterator itLE;
-  map< const SMDS_MeshElement*, set< TLink > >  mapEl_setLi;
-  map< const SMDS_MeshElement*, set< TLink > >::iterator itEL;
+  map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
+  map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
+  map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
+  map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
 
   TIDSortedElemSet::iterator itElem;
   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
@@ -1482,7 +1486,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
 
     // fill maps
     for ( i = 0; i < 3; i++ ) {
-      TLink link( aNodes[i], aNodes[i+1] );
+      SMESH_TLink link( aNodes[i], aNodes[i+1] );
       // check if elements sharing a link can be fused
       itLE = mapLi_listEl.find( link );
       if ( itLE != mapLi_listEl.end() ) {
@@ -1508,7 +1512,7 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
     int nbElems = (*itLE).second.size();
     if ( nbElems < 2  ) {
       const SMDS_MeshElement* elem = (*itLE).second.front();
-      TLink link = (*itLE).first;
+      SMESH_TLink link = (*itLE).first;
       mapEl_setLi[ elem ].erase( link );
       if ( mapEl_setLi[ elem ].empty() )
         mapEl_setLi.erase( elem );
@@ -1534,11 +1538,11 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
 
     // search elements to fuse starting from startElem or links of elements
     // fused earlyer - startLinks
-    list< TLink > startLinks;
+    list< SMESH_TLink > startLinks;
     while ( startElem || !startLinks.empty() ) {
       while ( !startElem && !startLinks.empty() ) {
         // Get an element to start, by a link
-        TLink linkId = startLinks.front();
+        SMESH_TLink linkId = startLinks.front();
         startLinks.pop_front();
         itLE = mapLi_listEl.find( linkId );
         if ( itLE != mapLi_listEl.end() ) {
@@ -1554,15 +1558,15 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
       if ( startElem ) {
         // Get candidates to be fused
         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
-        const TLink *link12, *link13;
+        const SMESH_TLink *link12, *link13;
         startElem = 0;
         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
-        set< TLink >& setLi = mapEl_setLi[ tr1 ];
+        set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
         ASSERT( !setLi.empty() );
-        set< TLink >::iterator itLi;
+        set< SMESH_TLink >::iterator itLi;
         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
         {
-          const TLink & link = (*itLi);
+          const SMESH_TLink & link = (*itLi);
           itLE = mapLi_listEl.find( link );
           if ( itLE == mapLi_listEl.end() )
             continue;
@@ -1583,10 +1587,10 @@ bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
           }
 
           // add other links of elem to list of links to re-start from
-          set< TLink >& links = mapEl_setLi[ elem ];
-          set< TLink >::iterator it;
+          set< SMESH_TLink >& links = mapEl_setLi[ elem ];
+          set< SMESH_TLink >::iterator it;
           for ( it = links.begin(); it != links.end(); it++ ) {
-            const TLink& link2 = (*it);
+            const SMESH_TLink& link2 = (*it);
             if ( link2 != link )
               startLinks.push_back( link2 );
           }
@@ -2047,8 +2051,8 @@ void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
           }
-          linkedNodes.insert( elem->GetNode( iAfter ));
-          linkedNodes.insert( elem->GetNode( iBefore ));
+          linkedNodes.insert( elem->GetNodeWrap( iAfter ));
+          linkedNodes.insert( elem->GetNodeWrap( iBefore ));
         }
       }
     }
@@ -2443,9 +2447,8 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
     // fix nodes on mesh boundary
 
     if ( checkBoundaryNodes ) {
-      typedef pair<const SMDS_MeshNode*, const SMDS_MeshNode*> TLink;
-      map< TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
-      map< TLink, int >::iterator link_nb;
+      map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
+      map< NLink, int >::iterator link_nb;
       // put all elements links to linkNbMap
       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
@@ -2454,10 +2457,10 @@ void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
         if(elem->IsQuadratic())
           nbn = nbn/2;
         // loop on elem links: insert them in linkNbMap
-        const SMDS_MeshNode* curNode, *prevNode = elem->GetNode( nbn );
+        const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
         for ( int iN = 0; iN < nbn; ++iN ) {
           curNode = elem->GetNode( iN );
-          TLink link;
+          NLink link;
           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
           else                      link = make_pair( prevNode , curNode );
           prevNode = curNode;
@@ -2772,8 +2775,6 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
 
   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
   vector<int> sames(nbNodes);
-
-  //bool issimple[nbNodes];
   vector<bool> issimple(nbNodes);
 
   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
@@ -2783,12 +2784,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     if ( listNewNodes.empty() )
       return;
 
-    if(listNewNodes.size()==nbSteps) {
-      issimple[iNode] = true;
-    }
-    else {
-      issimple[iNode] = false;
-    }
+    issimple[iNode] = (listNewNodes.size()==nbSteps);
 
     itNN[ iNode ] = listNewNodes.begin();
     prevNod[ iNode ] = node;
@@ -2833,11 +2829,8 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     //MESSAGE("Reversed elem " << elem );
     i0 = 2;
     i2 = 0;
-    if ( nbSame > 0 ) {
-      int iAB = iAfterSame + iBeforeSame;
-      iBeforeSame = iAB - iBeforeSame;
-      iAfterSame  = iAB - iAfterSame;
-    }
+    if ( nbSame > 0 )
+      std::swap( iBeforeSame, iAfterSame );
   }
 
   // make new elements
@@ -2856,8 +2849,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
           nextNod[ iNode ] = *itNN[ iNode ];
           itNN[ iNode ]++;
         }
-        else if(!elem->IsQuadratic() ||
-           elem->IsQuadratic() && elem->IsMediumNode(prevNod[iNode]) ) {
+        else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
           // we have to use each second node
           itNN[ iNode ]++;
           nextNod[ iNode ] = *itNN[ iNode ];
@@ -3285,7 +3277,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
               if ( !f )
                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
-              else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+              else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
                 aMesh->ChangeElementNodes( f, nodes, nbn );
               break;
             }
@@ -3293,7 +3285,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
               if ( !f )
                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
-              else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+              else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
                 aMesh->ChangeElementNodes( f, nodes, nbn );
               break;
             }
@@ -3305,7 +3297,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                   if ( !f )
                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
                                                              nodes[1], nodes[3], nodes[5]));
-                  else if ( nodes[ 2 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+                  else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
                     aMesh->ChangeElementNodes( f, nodes, nbn );
                 }
                 else {       /////// quadratic quadrangle
@@ -3314,7 +3306,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                   if ( !f )
                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
-                  else if ( nodes[ 2 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+                  else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
                     aMesh->ChangeElementNodes( f, nodes, nbn );
                 }
               }
@@ -3323,7 +3315,7 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
                 if ( !f )
                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
-                else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
+                else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
                   aMesh->ChangeElementNodes( f, nodes, nbn );
               }
             }
@@ -3741,7 +3733,7 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
   return newGroupIDs;
 }
 
-
+/*
 //=======================================================================
 //class    : SMESH_MeshEditor_PathPoint
 //purpose  : auxiliary class
@@ -3785,6 +3777,7 @@ protected:
   double myAngle;
   double myPrm;
 };
+*/
 
 //=======================================================================
 //function : ExtrusionAlongTrack
@@ -3796,6 +3789,7 @@ SMESH_MeshEditor::Extrusion_Error
                                         const SMDS_MeshNode* theN1,
                                         const bool           theHasAngles,
                                         list<double>&        theAngles,
+                                        const bool           theLinearVariation,
                                         const bool           theHasRefPoint,
                                         const gp_Pnt&        theRefPoint,
                                          const bool           theMakeGroups)
@@ -3803,20 +3797,11 @@ SMESH_MeshEditor::Extrusion_Error
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  // source elements for each generated one
-  SMESH_SequenceOfElemPtr srcElems, srcNodes;
-
-  int j, aNbTP, aNbE, aNb;
-  double aT1, aT2, aT, aAngle, aX, aY, aZ;
+  int aNbE;
   std::list<double> aPrms;
-  std::list<double>::iterator aItD;
   TIDSortedElemSet::iterator itElem;
 
-  Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
-  gp_Pnt aP3D, aV0;
-  gp_Vec aVec;
   gp_XYZ aGC;
-  Handle(Geom_Curve) aC3D;
   TopoDS_Edge aTrackEdge;
   TopoDS_Vertex aV1, aV2;
 
@@ -3825,11 +3810,6 @@ SMESH_MeshEditor::Extrusion_Error
   SMDSAbs_ElementType aTypeE;
 
   TNodeOfNodeListMap mapNewNodes;
-  TElemOfVecOfNnlmiMap mapElemNewNodes;
-  TElemOfElemListMap newElemsMap;
-
-  aTolVec=1.e-7;
-  aTolVec2=aTolVec*aTolVec;
 
   // 1. Check data
   aNbE = theElements.size();
@@ -3840,7 +3820,7 @@ SMESH_MeshEditor::Extrusion_Error
   // 1.1 Track Pattern
   ASSERT( theTrack );
 
-  SMESHDS_SubMesh* pSubMeshDS=theTrack->GetSubMeshDS();
+  SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
 
   aItE = pSubMeshDS->GetElements();
   while ( aItE->more() ) {
@@ -3851,63 +3831,325 @@ SMESH_MeshEditor::Extrusion_Error
       return EXTR_PATH_NOT_EDGE;
   }
 
+  list<SMESH_MeshEditor_PathPoint> fullList;
+
   const TopoDS_Shape& aS = theTrack->GetSubShape();
-  // Sub shape for the Pattern must be an Edge
-  if ( aS.ShapeType() != TopAbs_EDGE )
+  // Sub shape for the Pattern must be an Edge or Wire
+  if( aS.ShapeType() == TopAbs_EDGE ) {
+    aTrackEdge = TopoDS::Edge( aS );
+    // the Edge must not be degenerated
+    if ( BRep_Tool::Degenerated( aTrackEdge ) )
+      return EXTR_BAD_PATH_SHAPE;
+    TopExp::Vertices( aTrackEdge, aV1, aV2 );
+    aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
+    const SMDS_MeshNode* aN1 = aItN->next();
+    aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
+    const SMDS_MeshNode* aN2 = aItN->next();
+    // starting node must be aN1 or aN2
+    if ( !( aN1 == theN1 || aN2 == theN1 ) )
+      return EXTR_BAD_STARTING_NODE;
+    aItN = pSubMeshDS->GetNodes();
+    while ( aItN->more() ) {
+      const SMDS_MeshNode* pNode = aItN->next();
+      const SMDS_EdgePosition* pEPos =
+       static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+      double aT = pEPos->GetUParameter();
+      aPrms.push_back( aT );
+    }
+    Extrusion_Error err = MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+  }
+  else if( aS.ShapeType() == TopAbs_WIRE ) {
+    list< SMESH_subMesh* > LSM;
+    TopTools_SequenceOfShape Edges;
+    SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
+    while(itSM->more()) {
+      SMESH_subMesh* SM = itSM->next();
+      LSM.push_back(SM);
+      const TopoDS_Shape& aS = SM->GetSubShape();
+      Edges.Append(aS);
+    }
+    list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
+    int startNid = theN1->GetID();
+    TColStd_MapOfInteger UsedNums;
+    int NbEdges = Edges.Length();
+    int i = 1;
+    for(; i<=NbEdges; i++) {
+      int k = 0;
+      list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
+      for(; itLSM!=LSM.end(); itLSM++) {
+       k++;
+       if(UsedNums.Contains(k)) continue;
+       aTrackEdge = TopoDS::Edge( Edges.Value(k) );
+       SMESH_subMesh* locTrack = *itLSM;
+       SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
+       TopExp::Vertices( aTrackEdge, aV1, aV2 );
+       aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
+       const SMDS_MeshNode* aN1 = aItN->next();
+       aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
+       const SMDS_MeshNode* aN2 = aItN->next();
+       // starting node must be aN1 or aN2
+       if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
+       // 2. Collect parameters on the track edge
+       aPrms.clear();
+       aItN = locMeshDS->GetNodes();
+       while ( aItN->more() ) {
+         const SMDS_MeshNode* pNode = aItN->next();
+         const SMDS_EdgePosition* pEPos =
+           static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+         double aT = pEPos->GetUParameter();
+         aPrms.push_back( aT );
+       }
+       list<SMESH_MeshEditor_PathPoint> LPP;
+       Extrusion_Error err = MakeEdgePathPoints(aPrms, aTrackEdge,
+                                                (aN1->GetID()==startNid), LPP);
+       LLPPs.push_back(LPP);
+       UsedNums.Add(k);
+       // update startN for search following egde
+       if( aN1->GetID() == startNid ) startNid = aN2->GetID();
+       else startNid = aN1->GetID();
+       break;
+      }
+    }
+    list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
+    list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
+    list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
+    for(; itPP!=firstList.end(); itPP++) {
+      fullList.push_back( *itPP );
+    }
+    SMESH_MeshEditor_PathPoint PP1 = fullList.back();
+    fullList.pop_back();
+    itLLPP++;
+    for(; itLLPP!=LLPPs.end(); itLLPP++) {
+      list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
+      itPP = currList.begin();
+      SMESH_MeshEditor_PathPoint PP2 = currList.front();
+      gp_Dir D1 = PP1.Tangent();
+      gp_Dir D2 = PP2.Tangent();
+      gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
+                          (D1.Z()+D2.Z())/2 ) );
+      PP1.SetTangent(Dnew);
+      fullList.push_back(PP1);
+      itPP++;
+      for(; itPP!=firstList.end(); itPP++) {
+       fullList.push_back( *itPP );
+      }
+      PP1 = fullList.back();
+      fullList.pop_back();
+    }
+    // if wire not closed
+    fullList.push_back(PP1);
+    // else ???
+  }
+  else {
     return EXTR_BAD_PATH_SHAPE;
+  }
 
-  aTrackEdge = TopoDS::Edge( aS );
-  // the Edge must not be degenerated
-  if ( BRep_Tool::Degenerated( aTrackEdge ) )
-    return EXTR_BAD_PATH_SHAPE;
+  return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+                         theHasRefPoint, theRefPoint, theMakeGroups);
+}
 
-  TopExp::Vertices( aTrackEdge, aV1, aV2 );
-  aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
-  aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
 
-  aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
-  const SMDS_MeshNode* aN1 = aItN->next();
+//=======================================================================
+//function : ExtrusionAlongTrack
+//purpose  :
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+  SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
+                                        SMESH_Mesh*          theTrack,
+                                        const SMDS_MeshNode* theN1,
+                                        const bool           theHasAngles,
+                                        list<double>&        theAngles,
+                                        const bool           theLinearVariation,
+                                        const bool           theHasRefPoint,
+                                        const gp_Pnt&        theRefPoint,
+                                         const bool           theMakeGroups)
+{
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
 
-  aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
-  const SMDS_MeshNode* aN2 = aItN->next();
+  int aNbE;
+  std::list<double> aPrms;
+  TIDSortedElemSet::iterator itElem;
 
-  // starting node must be aN1 or aN2
-  if ( !( aN1 == theN1 || aN2 == theN1 ) )
-    return EXTR_BAD_STARTING_NODE;
+  gp_XYZ aGC;
+  TopoDS_Edge aTrackEdge;
+  TopoDS_Vertex aV1, aV2;
 
-  aNbTP = pSubMeshDS->NbNodes() + 2;
+  SMDS_ElemIteratorPtr aItE;
+  SMDS_NodeIteratorPtr aItN;
+  SMDSAbs_ElementType aTypeE;
 
-  // 1.2. Angles
-  vector<double> aAngles( aNbTP );
+  TNodeOfNodeListMap mapNewNodes;
 
-  for ( j=0; j < aNbTP; ++j ) {
-    aAngles[j] = 0.;
+  // 1. Check data
+  aNbE = theElements.size();
+  // nothing to do
+  if ( !aNbE )
+    return EXTR_NO_ELEMENTS;
+
+  // 1.1 Track Pattern
+  ASSERT( theTrack );
+
+  SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
+
+  aItE = pMeshDS->elementsIterator();
+  while ( aItE->more() ) {
+    const SMDS_MeshElement* pE = aItE->next();
+    aTypeE = pE->GetType();
+    // Pattern must contain links only
+    if ( aTypeE != SMDSAbs_Edge )
+      return EXTR_PATH_NOT_EDGE;
   }
 
-  if ( theHasAngles ) {
-    aItD = theAngles.begin();
-    for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
-      aAngle = *aItD;
-      aAngles[j] = aAngle;
+  list<SMESH_MeshEditor_PathPoint> fullList;
+
+  const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
+  // Sub shape for the Pattern must be an Edge or Wire
+  if( aS.ShapeType() == TopAbs_EDGE ) {
+    aTrackEdge = TopoDS::Edge( aS );
+    // the Edge must not be degenerated
+    if ( BRep_Tool::Degenerated( aTrackEdge ) )
+      return EXTR_BAD_PATH_SHAPE;
+    TopExp::Vertices( aTrackEdge, aV1, aV2 );
+    aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
+    const SMDS_MeshNode* aN1 = aItN->next();
+    aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
+    const SMDS_MeshNode* aN2 = aItN->next();
+    // starting node must be aN1 or aN2
+    if ( !( aN1 == theN1 || aN2 == theN1 ) )
+      return EXTR_BAD_STARTING_NODE;
+    aItN = pMeshDS->nodesIterator();
+    while ( aItN->more() ) {
+      const SMDS_MeshNode* pNode = aItN->next();
+      if( pNode==aN1 || pNode==aN2 ) continue;
+      const SMDS_EdgePosition* pEPos =
+       static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+      double aT = pEPos->GetUParameter();
+      aPrms.push_back( aT );
+    }
+    Extrusion_Error err = MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+  }
+  else if( aS.ShapeType() == TopAbs_WIRE ) {
+    list< SMESH_subMesh* > LSM;
+    TopTools_SequenceOfShape Edges;
+    TopExp_Explorer eExp(aS, TopAbs_EDGE);
+    for(; eExp.More(); eExp.Next()) {
+      TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
+      if( BRep_Tool::Degenerated(E) ) continue;
+      SMESH_subMesh* SM = theTrack->GetSubMesh(E);
+      if(SM) {
+       LSM.push_back(SM);
+       Edges.Append(E);
+      }
+    }
+    list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
+    int startNid = theN1->GetID();
+    TColStd_MapOfInteger UsedNums;
+    int NbEdges = Edges.Length();
+    int i = 1;
+    for(; i<=NbEdges; i++) {
+      int k = 0;
+      list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
+      for(; itLSM!=LSM.end(); itLSM++) {
+       k++;
+       if(UsedNums.Contains(k)) continue;
+       aTrackEdge = TopoDS::Edge( Edges.Value(k) );
+       SMESH_subMesh* locTrack = *itLSM;
+       SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
+       TopExp::Vertices( aTrackEdge, aV1, aV2 );
+       aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
+       const SMDS_MeshNode* aN1 = aItN->next();
+       aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
+       const SMDS_MeshNode* aN2 = aItN->next();
+       // starting node must be aN1 or aN2
+       if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
+       // 2. Collect parameters on the track edge
+       aPrms.clear();
+       aItN = locMeshDS->GetNodes();
+       while ( aItN->more() ) {
+         const SMDS_MeshNode* pNode = aItN->next();
+         const SMDS_EdgePosition* pEPos =
+           static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
+         double aT = pEPos->GetUParameter();
+         aPrms.push_back( aT );
+       }
+       list<SMESH_MeshEditor_PathPoint> LPP;
+       Extrusion_Error err = MakeEdgePathPoints(aPrms, aTrackEdge,
+                                                (aN1->GetID()==startNid), LPP);
+       LLPPs.push_back(LPP);
+       UsedNums.Add(k);
+       // update startN for search following egde
+       if( aN1->GetID() == startNid ) startNid = aN2->GetID();
+       else startNid = aN1->GetID();
+       break;
+      }
     }
+    list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
+    list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
+    list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
+    for(; itPP!=firstList.end(); itPP++) {
+      fullList.push_back( *itPP );
+    }
+    SMESH_MeshEditor_PathPoint PP1 = fullList.back();
+    fullList.pop_back();
+    itLLPP++;
+    for(; itLLPP!=LLPPs.end(); itLLPP++) {
+      list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
+      itPP = currList.begin();
+      SMESH_MeshEditor_PathPoint PP2 = currList.front();
+      gp_Pnt P1 = PP1.Pnt();
+      //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
+      gp_Pnt P2 = PP2.Pnt();
+      gp_Dir D1 = PP1.Tangent();
+      gp_Dir D2 = PP2.Tangent();
+      gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
+                          (D1.Z()+D2.Z())/2 ) );
+      PP1.SetTangent(Dnew);
+      fullList.push_back(PP1);
+      itPP++;
+      for(; itPP!=currList.end(); itPP++) {
+       fullList.push_back( *itPP );
+      }
+      PP1 = fullList.back();
+      fullList.pop_back();
+    }
+    // if wire not closed
+    fullList.push_back(PP1);
+    // else ???
+  }
+  else {
+    return EXTR_BAD_PATH_SHAPE;
   }
 
-  // 2. Collect parameters on the track edge
-  aPrms.push_back( aT1 );
-  aPrms.push_back( aT2 );
+  return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
+                         theHasRefPoint, theRefPoint, theMakeGroups);
+}
 
-  aItN = pSubMeshDS->GetNodes();
-  while ( aItN->more() ) {
-    const SMDS_MeshNode* pNode = aItN->next();
-    const SMDS_EdgePosition* pEPos =
-      static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
-    aT = pEPos->GetUParameter();
-    aPrms.push_back( aT );
-  }
 
+//=======================================================================
+//function : MakeEdgePathPoints
+//purpose  : auxilary for ExtrusionAlongTrack
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
+                                    const TopoDS_Edge& aTrackEdge,
+                                    bool FirstIsStart,
+                                    list<SMESH_MeshEditor_PathPoint>& LPP)
+{
+  Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
+  aTolVec=1.e-7;
+  aTolVec2=aTolVec*aTolVec;
+  double aT1, aT2;
+  TopoDS_Vertex aV1, aV2;
+  TopExp::Vertices( aTrackEdge, aV1, aV2 );
+  aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
+  aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
+  // 2. Collect parameters on the track edge
+  aPrms.push_front( aT1 );
+  aPrms.push_back( aT2 );
   // sort parameters
   aPrms.sort();
-  if ( aN1 == theN1 ) {
+  if( FirstIsStart ) {
     if ( aT1 > aT2 ) {
       aPrms.reverse();
     }
@@ -3917,48 +4159,100 @@ SMESH_MeshEditor::Extrusion_Error
       aPrms.reverse();
     }
   }
-
   // 3. Path Points
   SMESH_MeshEditor_PathPoint aPP;
-  vector<SMESH_MeshEditor_PathPoint> aPPs( aNbTP );
-  //
-  aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
-  //
-  aItD = aPrms.begin();
-  for ( j=0; aItD != aPrms.end(); ++aItD, ++j ) {
-    aT = *aItD;
+  Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
+  std::list<double>::iterator aItD = aPrms.begin();
+  for(; aItD != aPrms.end(); ++aItD) {
+    double aT = *aItD;
+    gp_Pnt aP3D;
+    gp_Vec aVec;
     aC3D->D1( aT, aP3D, aVec );
     aL2 = aVec.SquareMagnitude();
     if ( aL2 < aTolVec2 )
       return EXTR_CANT_GET_TANGENT;
-
     gp_Dir aTgt( aVec );
-    aAngle = aAngles[j];
-
     aPP.SetPnt( aP3D );
     aPP.SetTangent( aTgt );
-    aPP.SetAngle( aAngle );
     aPP.SetParameter( aT );
-    aPPs[j]=aPP;
+    LPP.push_back(aPP);
   }
+}
+
+
+//=======================================================================
+//function : MakeExtrElements
+//purpose  : auxilary for ExtrusionAlongTrack
+//=======================================================================
+SMESH_MeshEditor::Extrusion_Error
+SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
+                                  list<SMESH_MeshEditor_PathPoint>& fullList,
+                                  const bool theHasAngles,
+                                  list<double>& theAngles,
+                                  const bool theLinearVariation,
+                                  const bool theHasRefPoint,
+                                  const gp_Pnt& theRefPoint,
+                                  const bool theMakeGroups)
+{
+  //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
+  int aNbTP = fullList.size();
+  vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
+  // Angles
+  if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
+    LinearAngleVariation(aNbTP-1, theAngles);
+  }
+  vector<double> aAngles( aNbTP );
+  int j = 0;
+  for(; j<aNbTP; ++j) {
+    aAngles[j] = 0.;
+  }
+  if ( theHasAngles ) {
+    double anAngle;;
+    std::list<double>::iterator aItD = theAngles.begin();
+    for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
+      anAngle = *aItD;
+      aAngles[j] = anAngle;
+    }
+  }
+  // fill vector of path points with angles
+  //aPPs.resize(fullList.size());
+  j = -1;
+  list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
+  for(; itPP!=fullList.end(); itPP++) {
+    j++;
+    SMESH_MeshEditor_PathPoint PP = *itPP;
+    PP.SetAngle(aAngles[j]);
+    aPPs[j] = PP;
+  }
+
+  TNodeOfNodeListMap mapNewNodes;
+  TElemOfVecOfNnlmiMap mapElemNewNodes;
+  TElemOfElemListMap newElemsMap;
+  TIDSortedElemSet::iterator itElem;
+  double aX, aY, aZ;
+  int aNb;
+  SMDSAbs_ElementType aTypeE;
+  // source elements for each generated one
+  SMESH_SequenceOfElemPtr srcElems, srcNodes;
 
   // 3. Center of rotation aV0
-  aV0 = theRefPoint;
+  gp_Pnt aV0 = theRefPoint;
+  gp_XYZ aGC;
   if ( !theHasRefPoint ) {
     aNb = 0;
     aGC.SetCoord( 0.,0.,0. );
-
+    
     itElem = theElements.begin();
     for ( ; itElem != theElements.end(); itElem++ ) {
       const SMDS_MeshElement* elem = *itElem;
-
+      
       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
       while ( itN->more() ) {
        const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
        aX = node->X();
        aY = node->Y();
        aZ = node->Z();
-
+       
        if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
          list<const SMDS_MeshNode*> aLNx;
          mapNewNodes[node] = aLNx;
@@ -4017,6 +4311,7 @@ SMESH_MeshEditor::Extrusion_Error
        const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
        aP0x = aPP0.Pnt();
        aDT0x= aPP0.Tangent();
+       //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
 
        for ( j = 1; j < aNbTP; ++j ) {
          const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
@@ -4125,6 +4420,56 @@ SMESH_MeshEditor::Extrusion_Error
   return EXTR_OK;
 }
 
+
+//=======================================================================
+//function : LinearAngleVariation
+//purpose  : auxilary for ExtrusionAlongTrack
+//=======================================================================
+void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
+                                           list<double>& Angles)
+{
+  int nbAngles = Angles.size();
+  if( nbSteps > nbAngles ) {
+    vector<double> theAngles(nbAngles);
+    list<double>::iterator it = Angles.begin();
+    int i = -1;
+    for(; it!=Angles.end(); it++) {
+      i++;
+      theAngles[i] = (*it);
+    }
+    list<double> res;
+    double rAn2St = double( nbAngles ) / double( nbSteps );
+    double angPrev = 0, angle;
+    for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
+      double angCur = rAn2St * ( iSt+1 );
+      double angCurFloor  = floor( angCur );
+      double angPrevFloor = floor( angPrev );
+      if ( angPrevFloor == angCurFloor )
+       angle = rAn2St * theAngles[ int( angCurFloor ) ];
+      else {
+       int iP = int( angPrevFloor );
+       double angPrevCeil = ceil(angPrev);
+       angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
+          
+       int iC = int( angCurFloor );
+       if ( iC < nbAngles )
+         angle += ( angCur - angCurFloor ) * theAngles[ iC ];
+       
+       iP = int( angPrevCeil );
+       while ( iC-- > iP )
+         angle += theAngles[ iC ];
+      }
+      res.push_back(angle);
+      angPrev = angCur;
+    }
+    Angles.clear();
+    it = res.begin();
+    for(; it!=res.end(); it++)
+      Angles.push_back( *it );
+  }
+}
+
+
 //=======================================================================
 //function : Transform
 //purpose  :
@@ -4844,6 +5189,25 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
       if ( nnIt != nodeNodeMap.end() ) { // n sticks
         n = (*nnIt).second;
+        // BUG 0020185: begin
+        {
+          bool stopRecur = false;
+          set<const SMDS_MeshNode*> nodesRecur;
+          nodesRecur.insert(n);
+          while (!stopRecur) {
+            TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
+            if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
+              n = (*nnIt_i).second;
+              if (!nodesRecur.insert(n).second) {
+                // error: recursive dependancy
+                stopRecur = true;
+              }
+            }
+            else
+              stopRecur = true;
+          }
+        }
+        // BUG 0020185: end
         iRepl[ nbRepl++ ] = iCur;
       }
       curNodes[ iCur ] = n;
@@ -6610,11 +6974,13 @@ void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode
 //=======================================================================
 
 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
-                                              SMESH_MesherHelper& theHelper,
-                                             const bool          theForce3d)
+                                             SMESH_MesherHelper& theHelper,
+                                             const bool          theForce3d)
 {
   int nbElem = 0;
   if( !theSm ) return nbElem;
+
+  const bool notFromGroups = false;
   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
   while(ElemItr->more())
   {
@@ -6632,8 +6998,7 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
     }
     SMDSAbs_ElementType aType = elem->GetType();
 
-    theSm->RemoveElement(elem);
-    GetMeshDS()->SMDS_Mesh::RemoveFreeElement(elem);
+    GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
 
     const SMDS_MeshElement* NewElem = 0;
 
@@ -6664,14 +7029,14 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
       switch(nbNodes)
       {
       case 4:
-       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, true);
+       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
        break;
       case 6:
-       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, true);
+       NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
        break;
       case 8:
        NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
-                                      aNds[4], aNds[5], aNds[6], aNds[7], id, true);
+                                      aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
        break;
       default:
        continue;
@@ -6681,13 +7046,9 @@ int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
     default :
       continue;
     }
+    ReplaceElemInGroups( elem, NewElem, GetMeshDS());
     if( NewElem )
-    {
-      AddToSameGroups( NewElem, elem, GetMeshDS());
       theSm->AddElement( NewElem );
-    }
-    if ( NewElem != elem )
-      RemoveElemFromGroups (elem, GetMeshDS());
   }
   return nbElem;
 }
@@ -6702,6 +7063,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
 
   SMESH_MesherHelper aHelper(*myMesh);
   aHelper.SetIsQuadratic( true );
+  const bool notFromGroups = false;
 
   int nbCheckedElems = 0;
   if ( myMesh->HasShapeToMesh() )
@@ -6719,8 +7081,9 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
     }
   }
   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
-  if ( nbCheckedElems < totalNbElems ) // not all elements in submeshes
+  if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
   {
+    SMESHDS_SubMesh *smDS = 0;
     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
     while(aEdgeItr->more())
     {
@@ -6731,13 +7094,10 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
        const SMDS_MeshNode* n1 = edge->GetNode(0);
        const SMDS_MeshNode* n2 = edge->GetNode(1);
 
-       meshDS->SMDS_Mesh::RemoveFreeElement(edge);
+       meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
 
         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
-        if ( NewEdge )
-          AddToSameGroups(NewEdge, edge, meshDS);
-        if ( NewEdge != edge )
-          RemoveElemFromGroups (edge, meshDS);
+        ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
       }
     }
     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
@@ -6755,7 +7115,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
        aNds[i] = face->GetNode(i);
       }
 
-      meshDS->SMDS_Mesh::RemoveFreeElement(face);
+      meshDS->RemoveFreeElement(face, smDS, notFromGroups);
 
       SMDS_MeshFace * NewFace = 0;
       switch(nbNodes)
@@ -6769,10 +7129,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
       default:
        continue;
       }
-      if ( NewFace )
-        AddToSameGroups(NewFace, face, meshDS);
-      if ( NewFace != face )
-        RemoveElemFromGroups (face, meshDS);
+      ReplaceElemInGroups( face, NewFace, GetMeshDS());
     }
     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
     while(aVolumeItr->more())
@@ -6789,30 +7146,27 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
        aNds[i] = volume->GetNode(i);
       }
 
-      meshDS->SMDS_Mesh::RemoveFreeElement(volume);
+      meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
 
       SMDS_MeshVolume * NewVolume = 0;
       switch(nbNodes)
       {
       case 4:
        NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
-                                      aNds[3], id, true );
+                                      aNds[3], id, theForce3d );
        break;
       case 6:
        NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
-                                      aNds[3], aNds[4], aNds[5], id, true);
+                                      aNds[3], aNds[4], aNds[5], id, theForce3d);
        break;
       case 8:
        NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
-                                      aNds[4], aNds[5], aNds[6], aNds[7], id, true);
+                                      aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
        break;
       default:
        continue;
       }
-      if ( NewVolume )
-        AddToSameGroups(NewVolume, volume, meshDS);
-      if ( NewVolume != volume )
-        RemoveElemFromGroups (volume, meshDS);
+      ReplaceElemInGroups(volume, NewVolume, meshDS);
     }
   }
 }
@@ -6830,6 +7184,8 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
 {
   int nbElem = 0;
   SMESHDS_Mesh* meshDS = GetMeshDS();
+  const bool notFromGroups = false;
+
   while( theItr->more() )
   {
     const SMDS_MeshElement* elem = theItr->next();
@@ -6855,15 +7211,10 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
       SMDSAbs_ElementType aType = elem->GetType();
 
       //remove old quadratic element
-      meshDS->SMDS_Mesh::RemoveFreeElement( elem );
-      if ( theSm )
-        theSm->RemoveElement( elem );
+      meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
 
       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
-      if ( NewElem )
-        AddToSameGroups(NewElem, elem, meshDS);
-      if ( NewElem != elem )
-        RemoveElemFromGroups (elem, meshDS);
+      ReplaceElemInGroups(elem, NewElem, meshDS);
       if( theSm && NewElem )
        theSm->AddElement( NewElem );
 
@@ -6871,7 +7222,7 @@ int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
       for ( ; nIt != mediumNodes.end(); ++nIt ) {
         const SMDS_MeshNode* n = *nIt;
-        if ( n->NbInverseNodes() == 0 ) {
+        if ( n->NbInverseElements() == 0 ) {
           if ( n->GetPosition()->GetShapeId() != theShapeID )
             meshDS->RemoveFreeNode( n, meshDS->MeshElements
                                     ( n->GetPosition()->GetShapeId() ));
@@ -6906,7 +7257,7 @@ bool  SMESH_MeshEditor::ConvertFromQuadratic()
   
   int totalNbElems =
     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
-  if ( nbCheckedElems < totalNbElems ) // not all elements in submeshes
+  if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
   {
     SMESHDS_SubMesh *aSM = 0;
     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
@@ -7541,8 +7892,8 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
   if ( theSecondNode1 != theSecondNode2 )
     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
 
-  set< TLink > linkSet; // set of nodes where order of nodes is ignored
-  linkSet.insert( TLink( theFirstNode1, theSecondNode1 ));
+  set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
+  linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
 
   list< NLink > linkList[2];
   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
@@ -7633,10 +7984,9 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
       }
 #ifdef DEBUG_MATCHING_NODES
-      cout << " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
-           << " F 1: " << face[0];
-      cout << "| Link 2: " << link[1].first->GetID() <<" "<< link[1].second->GetID()
-           << " F 2: " << face[1] << " | Bind: "<<endl ;
+      MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
+             << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
+            << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
 #endif
       int nbN = nbNodes[0];
       {
@@ -7644,7 +7994,7 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
         for ( int i = 0 ; i < nbN - 2; ++i ) {
 #ifdef DEBUG_MATCHING_NODES
-          cout << (*n1)->GetID() << " to " << (*n2)->GetID() << endl;
+          MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
 #endif
           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
         }
@@ -7658,16 +8008,16 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
       for ( int i = 0; i < nbN; i++ )
       {
         const SMDS_MeshNode* n2 = f0->GetNode( i );
-        pair< set< TLink >::iterator, bool > iter_isnew =
-          linkSet.insert( TLink( n1, n2 ));
+        pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
+          linkSet.insert( SMESH_TLink( n1, n2 ));
         if ( !iter_isnew.second ) { // already in a set: no need to process
           linkSet.erase( iter_isnew.first );
         }
         else // new in set == encountered for the first time: add
         {
 #ifdef DEBUG_MATCHING_NODES
-          cout << "Add link 1: " << n1->GetID() << " " << n2->GetID() << " ";
-          cout << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " << endl;
+          MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
+         << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
 #endif
           linkList[0].push_back ( NLink( n1, n2 ));
           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
@@ -7679,3 +8029,92 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
 
   return SEW_OK;
 }
+
+/*!
+  \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+  \param theNodes - identifiers of nodes to be doubled
+  \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
+         nodes. If list of element identifiers is empty then nodes are doubled but 
+         they not assigned to elements
+  \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
+                                    const std::list< int >& theListOfModifiedElems )
+{
+  myLastCreatedElems.Clear();
+  myLastCreatedNodes.Clear();
+
+  if ( theListOfNodes.size() == 0 )
+    return false;
+
+  SMESHDS_Mesh* aMeshDS = GetMeshDS();
+  if ( !aMeshDS )
+    return false;
+
+  // iterate through nodes and duplicate them
+
+  std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+
+  std::list< int >::const_iterator aNodeIter;
+  for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
+  {
+    int aCurr = *aNodeIter;
+    SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
+    if ( !aNode )
+      continue;
+
+    // duplicate node
+
+    const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
+    if ( aNewNode )
+    {
+      anOldNodeToNewNode[ aNode ] = aNewNode;
+      myLastCreatedNodes.Append( aNewNode );
+    }
+  }
+
+  // Create map of new nodes for modified elements
+
+  std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
+
+  std::list< int >::const_iterator anElemIter;
+  for ( anElemIter = theListOfModifiedElems.begin(); 
+        anElemIter != theListOfModifiedElems.end(); ++anElemIter )
+  {
+    int aCurr = *anElemIter;
+    SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
+    if ( !anElem )
+      continue;
+
+    vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
+
+    SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
+    int ind = 0;
+    while ( anIter->more() ) 
+    { 
+      SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
+      if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
+      {
+        const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
+        aNodeArr[ ind++ ] = aNewNode;
+      }
+      else
+        aNodeArr[ ind++ ] = aCurrNode;
+    }
+    anElemToNodes[ anElem ] = aNodeArr;
+  }
+
+  // Change nodes of elements  
+
+  std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
+    anElemToNodesIter = anElemToNodes.begin();
+  for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
+  {
+    const SMDS_MeshElement* anElem = anElemToNodesIter->first;
+    vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
+    if ( anElem )
+      aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
+  }
+
+  return true;
+}