Salome HOME
0019296: EDF 681 SMESH - Pre-evaluation of the number of elements before mesh
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
index 3e51f4a935c8435b976ddfbdf08c7d8be4741b81..09bc9e4cb09faec258cfcbddba3373c2de1a74df 100644 (file)
@@ -47,6 +47,7 @@
 #include "utilities.h"
 
 #include <BRep_Tool.hxx>
+#include <BRepClass3d_SolidClassifier.hxx>
 #include <ElCLib.hxx>
 #include <Extrema_GenExtPS.hxx>
 #include <Extrema_POnSurf.hxx>
 #include <GeomAdaptor_Surface.hxx>
 #include <Geom_Curve.hxx>
 #include <Geom_Surface.hxx>
+#include <Precision.hxx>
 #include <TColStd_ListOfInteger.hxx>
+#include <TopAbs_State.hxx>
 #include <TopExp.hxx>
 #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>
@@ -2050,8 +2054,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 ));
         }
       }
     }
@@ -2456,7 +2460,7 @@ 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 );
           NLink link;
@@ -2780,27 +2784,30 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
     const SMDS_MeshNode*                 node         = nnIt->first;
     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
-    if ( listNewNodes.empty() )
+    if ( listNewNodes.empty() ) {
       return;
+    }
 
     issimple[iNode] = (listNewNodes.size()==nbSteps);
 
     itNN[ iNode ] = listNewNodes.begin();
     prevNod[ iNode ] = node;
     nextNod[ iNode ] = listNewNodes.front();
-//cout<<"iNode="<<iNode<<endl;
-//cout<<" prevNod[iNode]="<< prevNod[iNode]<<" nextNod[iNode]="<< nextNod[iNode]<<endl;
-    if ( prevNod[ iNode ] != nextNod [ iNode ])
-      iNotSameNode = iNode;
-    else {
-      iSameNode = iNode;
-      //nbSame++;
-      sames[nbSame++] = iNode;
+    if( !issimple[iNode] ) {
+      if ( prevNod[ iNode ] != nextNod [ iNode ])
+       iNotSameNode = iNode;
+      else {
+       iSameNode = iNode;
+       //nbSame++;
+       sames[nbSame++] = iNode;
+      }
     }
   }
-//cout<<"1 nbSame="<<nbSame<<endl;
+
+  //cout<<"  nbSame = "<<nbSame<<endl;
   if ( nbSame == nbNodes || nbSame > 2) {
-    MESSAGE( " Too many same nodes of element " << elem->GetID() );
+    //MESSAGE( " Too many same nodes of element " << elem->GetID() );
+    INFOS( " Too many same nodes of element " << elem->GetID() );
     return;
   }
 
@@ -2810,9 +2817,10 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
 //  }
 
   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
+  int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
   if ( nbSame > 0 ) {
-    iBeforeSame = ( iSameNode == 0 ? nbNodes - 1 : iSameNode - 1 );
-    iAfterSame  = ( iSameNode + 1 == nbNodes ? 0 : iSameNode + 1 );
+    iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
+    iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
   }
 
@@ -2829,7 +2837,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
     i0 = 2;
     i2 = 0;
     if ( nbSame > 0 )
-      std::swap( iAfterSame, iAfterSame );
+      std::swap( iBeforeSame, iAfterSame );
   }
 
   // make new elements
@@ -2850,7 +2858,7 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
         }
         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
           // we have to use each second node
-          itNN[ iNode ]++;
+          //itNN[ iNode ]++;
           nextNod[ iNode ] = *itNN[ iNode ];
           itNN[ iNode ]++;
         }
@@ -2909,8 +2917,9 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
           }
           else if(nbSame==1) { // quadratic triangle
-            if(sames[0]==2)
+            if(sames[0]==2) {
               return; // medium node on axis
+           }
             else if(sames[0]==0) {
               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
                                         nextNod[2], midlNod[1], prevNod[2]);
@@ -2920,8 +2929,9 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
                                         midlNod[0], nextNod[2], prevNod[2]);
             }
           }
-          else
+          else {
             return;
+         }
         }
         break;
       }
@@ -2956,38 +2966,140 @@ void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
       }
       case 6: { // quadratic triangle
         // create pentahedron with 15 nodes
-        if(i0>0) { // reversed case
-          aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
-                                       nextNod[0], nextNod[2], nextNod[1],
-                                       prevNod[5], prevNod[4], prevNod[3],
-                                       nextNod[5], nextNod[4], nextNod[3],
-                                       midlNod[0], midlNod[2], midlNod[1]);
-        }
-        else { // not reversed case
-          aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
-                                       nextNod[0], nextNod[1], nextNod[2],
-                                       prevNod[3], prevNod[4], prevNod[5],
-                                       nextNod[3], nextNod[4], nextNod[5],
-                                       midlNod[0], midlNod[1], midlNod[2]);
-        }
+       if(nbSame==0) {
+         if(i0>0) { // reversed case
+           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
+                                        nextNod[0], nextNod[2], nextNod[1],
+                                        prevNod[5], prevNod[4], prevNod[3],
+                                        nextNod[5], nextNod[4], nextNod[3],
+                                        midlNod[0], midlNod[2], midlNod[1]);
+         }
+         else { // not reversed case
+           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
+                                        nextNod[0], nextNod[1], nextNod[2],
+                                        prevNod[3], prevNod[4], prevNod[5],
+                                        nextNod[3], nextNod[4], nextNod[5],
+                                        midlNod[0], midlNod[1], midlNod[2]);
+         }
+       }
+       else if(nbSame==1) {
+         // 2d order pyramid of 13 nodes
+         //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
+          //                                 int n12,int n23,int n34,int n41,
+          //                                 int n15,int n25,int n35,int n45, int ID);
+         int n5 = iSameNode;
+         int n1,n4,n41,n15,n45;
+         if(i0>0) { // reversed case
+           n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
+           n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
+           n41 = n1 + 3;
+           n15 = n5 + 3;
+           n45 = n4 + 3;
+         }
+         else {
+           n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
+           n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
+           n41 = n4 + 3;
+           n15 = n1 + 3;
+           n45 = n5 + 3;
+         }
+         aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
+                             nextNod[n4], prevNod[n4], prevNod[n5],
+                             midlNod[n1], nextNod[n41],
+                             midlNod[n4], prevNod[n41],
+                             prevNod[n15], nextNod[n15],
+                             nextNod[n45], prevNod[n45]);
+       }
+       else if(nbSame==2) {
+         // 2d order tetrahedron of 10 nodes
+         //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
+         //                                 int n12,int n23,int n31,
+         //                                 int n14,int n24,int n34, int ID);
+         int n1 = iNotSameNode;
+         int n2,n3,n12,n23,n31;
+         if(i0>0) { // reversed case
+           n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
+           n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
+           n12 = n2 + 3;
+           n23 = n3 + 3;
+           n31 = n1 + 3;
+         }
+         else {
+           n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
+           n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
+           n12 = n1 + 3;
+           n23 = n2 + 3;
+           n31 = n3 + 3;
+         }
+         aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
+                                      prevNod[n12], prevNod[n23], prevNod[n31],
+                                      midlNod[n1], nextNod[n12], nextNod[n31]);
+       }
         break;
       }
       case 8: { // quadratic quadrangle
-        // create hexahedron with 20 nodes
-        if(i0>0) { // reversed case
-          aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
-                                       nextNod[0], nextNod[3], nextNod[2], nextNod[1],
-                                       prevNod[7], prevNod[6], prevNod[5], prevNod[4],
-                                       nextNod[7], nextNod[6], nextNod[5], nextNod[4],
-                                       midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
-        }
-        else { // not reversed case
-          aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
-                                       nextNod[0], nextNod[1], nextNod[2], nextNod[3],
-                                       prevNod[4], prevNod[5], prevNod[6], prevNod[7],
-                                       nextNod[4], nextNod[5], nextNod[6], nextNod[7],
-                                       midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
-        }
+       if(nbSame==0) {
+         // create hexahedron with 20 nodes
+         if(i0>0) { // reversed case
+           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
+                                        nextNod[0], nextNod[3], nextNod[2], nextNod[1],
+                                        prevNod[7], prevNod[6], prevNod[5], prevNod[4],
+                                        nextNod[7], nextNod[6], nextNod[5], nextNod[4],
+                                        midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
+         }
+         else { // not reversed case
+           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
+                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
+                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
+                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
+                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
+         }
+       }
+       else if(nbSame==1) { 
+         // --- pyramid + pentahedron - can not be created since it is needed 
+         // additional middle node ot the center of face
+         INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
+         return;
+       }
+       else if(nbSame==2) {
+         // 2d order Pentahedron with 15 nodes
+         //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
+          //                                 int n12,int n23,int n31,int n45,int n56,int n64,
+          //                                 int n14,int n25,int n36, int ID);
+         int n1,n2,n4,n5;
+          if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
+            // iBeforeSame is same too
+           n1 = iBeforeSame;
+           n2 = iOpposSame;
+           n4 = iSameNode;
+           n5 = iAfterSame;
+         }
+         else {
+            // iAfterSame is same too
+           n1 = iSameNode;
+           n2 = iBeforeSame;
+           n4 = iAfterSame;
+           n5 = iOpposSame;
+         }
+         int n12,n45,n14,n25;
+         if(i0>0) { //reversed case
+           n12 = n1 + 4;
+           n45 = n5 + 4;
+           n14 = n4 + 4;
+           n25 = n2 + 4;
+         }
+         else {
+           n12 = n2 + 4;
+           n45 = n4 + 4;
+           n14 = n1 + 4;
+           n25 = n5 + 4;
+         }
+         aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
+                                      prevNod[n4], prevNod[n5], nextNod[n5],
+                                      prevNod[n12], midlNod[n2], nextNod[n12],
+                                      prevNod[n45], midlNod[n5], nextNod[n45],
+                                      prevNod[n14], prevNod[n25], nextNod[n25]);
+       }
         break;
       }
       default: {
@@ -3276,7 +3388,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;
             }
@@ -3284,7 +3396,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;
             }
@@ -3293,20 +3405,40 @@ void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
                 if(nbn==6) { /////// quadratic triangle
                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
                                                              nodes[1], nodes[3], nodes[5] );
-                  if ( !f )
+                  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 ))
-                    aMesh->ChangeElementNodes( f, nodes, nbn );
+                 }
+                  else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
+                   const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
+                   tmpnodes[0] = nodes[0];
+                   tmpnodes[1] = nodes[2];
+                   tmpnodes[2] = nodes[4];
+                   tmpnodes[3] = nodes[1];
+                   tmpnodes[4] = nodes[3];
+                   tmpnodes[5] = nodes[5];
+                    aMesh->ChangeElementNodes( f, tmpnodes, nbn );
+                 }
                 }
                 else {       /////// quadratic quadrangle
                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
-                  if ( !f )
+                  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 ))
-                    aMesh->ChangeElementNodes( f, nodes, nbn );
+                 }
+                  else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
+                   const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
+                   tmpnodes[0] = nodes[0];
+                   tmpnodes[1] = nodes[2];
+                   tmpnodes[2] = nodes[4];
+                   tmpnodes[3] = nodes[6];
+                   tmpnodes[4] = nodes[1];
+                   tmpnodes[5] = nodes[3];
+                   tmpnodes[6] = nodes[5];
+                   tmpnodes[7] = nodes[7];
+                    aMesh->ChangeElementNodes( f, tmpnodes, nbn );
+                 }
                 }
               }
               else { //////// polygon
@@ -3314,7 +3446,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 );
               }
             }
@@ -3427,20 +3559,25 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
 
     // loop on elem nodes
     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-    while ( itN->more() )
-    {
+    while ( itN->more() ) {
       // check if a node has been already sweeped
       const SMDS_MeshNode* node = cast2Node( itN->next() );
+
+      gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+      double coord[3];
+      aXYZ.Coord( coord[0], coord[1], coord[2] );
+      bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
+
       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
       if ( nIt == mapNewNodes.end() ) {
         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
 
         // make new nodes
-        gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
-        double coord[3];
-        aXYZ.Coord( coord[0], coord[1], coord[2] );
-        bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
+        //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+        //double coord[3];
+        //aXYZ.Coord( coord[0], coord[1], coord[2] );
+        //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
         const SMDS_MeshNode * newNode = node;
         for ( int i = 0; i < theNbSteps; i++ ) {
           if ( !isOnAxis ) {
@@ -3461,10 +3598,17 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
             myLastCreatedNodes.Append(newNode);
             srcNodes.Append( node );
+           listNewNodes.push_back( newNode );
           }
-          listNewNodes.push_back( newNode );
+         else {
+           listNewNodes.push_back( newNode );
+           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
+             listNewNodes.push_back( newNode );
+           }
+         }
         }
       }
+      /*
       else {
         // if current elem is quadratic and current node is not medium
         // we have to check - may be it is needed to insert additional nodes
@@ -3473,25 +3617,33 @@ SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
           if(listNewNodes.size()==theNbSteps) {
             listNewNodes.clear();
             // make new nodes
-            gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
-            double coord[3];
-            aXYZ.Coord( coord[0], coord[1], coord[2] );
+            //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
+            //double coord[3];
+            //aXYZ.Coord( coord[0], coord[1], coord[2] );
             const SMDS_MeshNode * newNode = node;
-            for(int i = 0; i<theNbSteps; i++) {
-              aTrsf2.Transforms( coord[0], coord[1], coord[2] );
-              newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-              myLastCreatedNodes.Append(newNode);
-              listNewNodes.push_back( newNode );
-              srcNodes.Append( node );
-              aTrsf2.Transforms( coord[0], coord[1], coord[2] );
-              newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-              myLastCreatedNodes.Append(newNode);
-              srcNodes.Append( node );
-              listNewNodes.push_back( newNode );
+           if ( !isOnAxis ) {
+             for(int i = 0; i<theNbSteps; i++) {
+               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+               cout<<"    3 AddNode:  "<<newNode;
+               myLastCreatedNodes.Append(newNode);
+               listNewNodes.push_back( newNode );
+               srcNodes.Append( node );
+               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
+               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
+               cout<<"    4 AddNode:  "<<newNode;
+               myLastCreatedNodes.Append(newNode);
+               srcNodes.Append( node );
+               listNewNodes.push_back( newNode );
+             }
             }
+           else {
+             listNewNodes.push_back( newNode );
+           }
           }
         }
       }
+      */
       newNodesItVec.push_back( nIt );
     }
     // make new elements
@@ -3732,7 +3884,7 @@ SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
   return newGroupIDs;
 }
 
-
+/*
 //=======================================================================
 //class    : SMESH_MeshEditor_PathPoint
 //purpose  : auxiliary class
@@ -3776,6 +3928,7 @@ protected:
   double myAngle;
   double myPrm;
 };
+*/
 
 //=======================================================================
 //function : ExtrusionAlongTrack
@@ -3787,6 +3940,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)
@@ -3794,20 +3948,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;
 
@@ -3816,11 +3961,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();
@@ -3831,7 +3971,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() ) {
@@ -3842,63 +3982,327 @@ 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();
     }
@@ -3908,48 +4312,101 @@ 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);
   }
+  return EXTR_OK;
+}
+
+
+//=======================================================================
+//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;
@@ -4008,6 +4465,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];
@@ -4116,6 +4574,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  :
@@ -4614,7 +5122,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
     list<const SMDS_MeshNode*> nodes;
     const double precision = 1e-6;
-    myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
+    //myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
 
     double minSqDist = DBL_MAX;
     Bnd_B3d box;
@@ -6721,6 +7229,7 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
         SMESH_subMesh* sm = smIt->next();
         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
           aHelper.SetSubShape( sm->GetSubShape() );
+          if ( !theForce3d) aHelper.SetCheckNodePosition(true);
           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
         }
       }
@@ -6815,6 +7324,10 @@ void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
       ReplaceElemInGroups(volume, NewVolume, meshDS);
     }
   }
+  if ( !theForce3d ) {
+    aHelper.SetSubShape(0); // apply to the whole mesh
+    aHelper.FixQuadraticElements();
+  }
 }
 
 //=======================================================================
@@ -7678,89 +8191,166 @@ SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
 
 /*!
   \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
+  \param theElems - the list of elements (edges or faces) to be replicated
+        The nodes for duplication could be found from these elements
+  \param theNodesNot - list of nodes to NOT replicate
+  \param theAffectedElems - the list of elements (cells and edges) to which the 
+        replicated nodes should be associated to.
   \return TRUE if operation has been completed successfully, FALSE otherwise
 */
-bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
-                                    const std::list< int >& theListOfModifiedElems )
+bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
+                                    const TIDSortedElemSet& theNodesNot,
+                                    const TIDSortedElemSet& theAffectedElems )
 {
   myLastCreatedElems.Clear();
   myLastCreatedNodes.Clear();
 
-  if ( theListOfNodes.size() == 0 )
+  if ( theElems.size() == 0 )
     return false;
 
   SMESHDS_Mesh* aMeshDS = GetMeshDS();
   if ( !aMeshDS )
     return false;
 
-  // iterate through nodes and duplicate them
-
+  bool res = false;
   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
+  // duplicate elements and nodes
+  res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
+  // replce nodes by duplications
+  res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
+  return res;
+}
 
-  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 )
+/*!
+  \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+  \param theMeshDS - mesh instance
+  \param theElems - the elements replicated or modified (nodes should be changed)
+  \param theNodesNot - nodes to NOT replicate
+  \param theNodeNodeMap - relation of old node to new created node
+  \param theIsDoubleElem - flag os to replicate element or modify
+  \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
+                                    const TIDSortedElemSet& theElems,
+                                    const TIDSortedElemSet& theNodesNot,
+                                    std::map< const SMDS_MeshNode*,
+                                    const SMDS_MeshNode* >& theNodeNodeMap,
+                                    const bool theIsDoubleElem )
+{
+  // iterate on through element and duplicate them (by nodes duplication)
+  bool res = false;
+  TIDSortedElemSet::iterator elemItr = theElems.begin();
+  for ( ;  elemItr != theElems.end(); ++elemItr )
   {
-    int aCurr = *anElemIter;
-    SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
-    if ( !anElem )
+    const SMDS_MeshElement* anElem = *elemItr;
+    if (!anElem)
       continue;
 
-    vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
-
+    bool isDuplicate = false;
+    // duplicate nodes to duplicate element
+    std::vector<const SMDS_MeshNode*> newNodes( 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() )
+      SMDS_MeshNode* aNewNode = aCurrNode;
+      if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
+        aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
+      else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
       {
-        const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
-        aNodeArr[ ind++ ] = aNewNode;
+        // duplicate node
+        aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
+        theNodeNodeMap[ aCurrNode ] = aNewNode;
+        myLastCreatedNodes.Append( aNewNode );
       }
-      else
-        aNodeArr[ ind++ ] = aCurrNode;
+      isDuplicate |= (aCurrNode == aNewNode);
+      newNodes[ ind++ ] = aNewNode;
     }
-    anElemToNodes[ anElem ] = aNodeArr;
+    if ( !isDuplicate )
+      continue;
+  
+    if ( theIsDoubleElem )
+      myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
+    else
+      theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
+          
+    res = true;
   }
+  return res;
+}
 
-  // Change nodes of elements  
+/*!
+  \brief Check if element located inside shape
+  \return TRUE if IN or ON shape, FALSE otherwise
+*/
 
-  std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
-    anElemToNodesIter = anElemToNodes.begin();
-  for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
+static bool isInside(const SMDS_MeshElement* theElem,
+                     BRepClass3d_SolidClassifier& theBsc3d,
+                     const double theTol)
+{
+  gp_XYZ centerXYZ (0, 0, 0);
+  SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
+  while (aNodeItr->more())
   {
-    const SMDS_MeshElement* anElem = anElemToNodesIter->first;
-    vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
-    if ( anElem )
-      aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
+    SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
+    centerXYZ += gp_XYZ(aNode->X(), aNode->Y(), aNode->Z());
   }
+  gp_Pnt aPnt(centerXYZ);
+  theBsc3d.Perform(aPnt, theTol);
+  TopAbs_State aState = theBsc3d.State();
+  return (aState == TopAbs_IN || aState == TopAbs_ON );
+}
 
-  return true;
+/*!
+  \brief Creates a hole in a mesh by doubling the nodes of some particular elements
+  \param theElems - group of of elements (edges or faces) to be replicated
+  \param theNodesNot - group of nodes not to replicated
+  \param theShape - shape to detect affected elements (element which geometric center
+         located on or inside shape).
+         The replicated nodes should be associated to affected elements.
+  \return TRUE if operation has been completed successfully, FALSE otherwise
+*/
+
+bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
+                                            const TIDSortedElemSet& theNodesNot,
+                                            const TopoDS_Shape&     theShape )
+{
+  SMESHDS_Mesh* aMesh = GetMeshDS();
+  if (!aMesh)
+    return false;
+  if ( theShape.IsNull() )
+    return false;
+
+  const double aTol = Precision::Confusion();
+  BRepClass3d_SolidClassifier bsc3d(theShape);
+  bsc3d.PerformInfinitePoint(aTol);
+
+  // iterates on indicated elements and get elements by back references from their nodes
+  TIDSortedElemSet anAffected;
+  TIDSortedElemSet::iterator elemItr = theElems.begin();
+  for ( ;  elemItr != theElems.end(); ++elemItr )
+  {
+    SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+    if (!anElem)
+      continue;
+
+    SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+    while ( nodeItr->more() )
+    {
+      const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
+      if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+        continue;
+      SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
+      while ( backElemItr->more() )
+      {
+        SMDS_MeshElement* curElem = (SMDS_MeshElement*)backElemItr->next();
+        if ( curElem && theElems.find(curElem) == theElems.end() &&
+             isInside( curElem, bsc3d, aTol ) )
+          anAffected.insert( curElem );
+      }
+    }
+  }
+  return DoubleNodes( theElems, theNodesNot, anAffected );
 }