Salome HOME
PAL16202,16203 (Propagation 1D on edges group)
[modules/smesh.git] / src / StdMeshers / StdMeshers_Quadrangle_2D.cxx
index 913f5a129400fcad984ebc8d673f5e71bcde7728..12c132959fe4f4924901a0960a991e9be86d8306 100644 (file)
@@ -17,7 +17,7 @@
 //  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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 //
 //
 //  Module : SMESH
 //  $Header$
 
-using namespace std;
 #include "StdMeshers_Quadrangle_2D.hxx"
+
+#include "StdMeshers_FaceSide.hxx"
+
 #include "SMESH_Gen.hxx"
 #include "SMESH_Mesh.hxx"
 #include "SMESH_subMesh.hxx"
+#include "SMESH_MesherHelper.hxx"
+#include "SMESH_Block.hxx"
+#include "SMESH_Comment.hxx"
 
 #include "SMDS_MeshElement.hxx"
 #include "SMDS_MeshNode.hxx"
 #include "SMDS_EdgePosition.hxx"
 #include "SMDS_FacePosition.hxx"
 
-#include <BRep_Tool.hxx>
 #include <BRepTools.hxx>
 #include <BRepTools_WireExplorer.hxx>
-
+#include <BRep_Tool.hxx>
 #include <Geom_Surface.hxx>
-#include <Geom_Curve.hxx>
-#include <Geom2d_Curve.hxx>
-#include <GeomAdaptor_Curve.hxx>
-#include <GCPnts_UniformAbscissa.hxx>
-
+#include <NCollection_DefineArray2.hxx>
 #include <Precision.hxx>
-#include <gp_Pnt2d.hxx>
-#include <TColStd_ListIteratorOfListOfInteger.hxx>
+#include <TColStd_SequenceOfReal.hxx>
+#include <TColgp_SequenceOfXY.hxx>
+#include <TopExp.hxx>
+#include <TopoDS.hxx>
 
 #include "utilities.h"
 #include "Utils_ExceptHandlers.hxx"
 
+#ifndef StdMeshers_Array2OfNode_HeaderFile
+#define StdMeshers_Array2OfNode_HeaderFile
+typedef const SMDS_MeshNode* SMDS_MeshNodePtr;
+DEFINE_BASECOLLECTION (StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
+DEFINE_ARRAY2(StdMeshers_Array2OfNode,
+              StdMeshers_BaseCollectionNodePtr, SMDS_MeshNodePtr)
+#endif
+
+using namespace std;
+
+typedef gp_XY gp_UV;
+typedef SMESH_Comment TComm;
 
 //=============================================================================
 /*!
@@ -67,8 +81,9 @@ StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D (int hypId, int studyId, SMES
 {
   MESSAGE("StdMeshers_Quadrangle_2D::StdMeshers_Quadrangle_2D");
   _name = "Quadrangle_2D";
-  //  _shapeType = TopAbs_FACE;
   _shapeType = (1 << TopAbs_FACE);
+  _compatibleHypothesis.push_back("QuadranglePreference");
+  myTool = 0;
 }
 
 //=============================================================================
@@ -89,16 +104,16 @@ StdMeshers_Quadrangle_2D::~StdMeshers_Quadrangle_2D()
 //=============================================================================
 
 bool StdMeshers_Quadrangle_2D::CheckHypothesis
-                         (SMESH_Mesh& aMesh,
-                          const TopoDS_Shape& aShape,
+                         (SMESH_Mesh&                          aMesh,
+                          const TopoDS_Shape&                  aShape,
                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
 {
-  //MESSAGE("StdMeshers_Quadrangle_2D::CheckHypothesis");
-
   bool isOk = true;
   aStatus = SMESH_Hypothesis::HYP_OK;
 
-  // nothing to check
+  // there is only one compatible Hypothesis so far
+  const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape, false);
+  myQuadranglePreference = hyps.size() > 0;
 
   return isOk;
 }
@@ -110,28 +125,51 @@ bool StdMeshers_Quadrangle_2D::CheckHypothesis
 //=============================================================================
 
 bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
-                                        const TopoDS_Shape& aShape) throw (SALOME_Exception)
+                                        const TopoDS_Shape& aShape)// throw (SALOME_Exception)
 {
-  Unexpect aCatch(SalomeException);
-  //MESSAGE("StdMeshers_Quadrangle_2D::Compute");
+  // PAL14921. Enable catching std::bad_alloc and Standard_OutOfMemory outside
+  //Unexpect aCatchSalomeException);
+
   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
   aMesh.GetSubMesh(aShape);
 
-  FaceQuadStruct *quad = CheckAnd2Dcompute(aMesh, aShape);
+  SMESH_MesherHelper helper(aMesh);
+  myTool = &helper;
+
+  _quadraticMesh = myTool->IsQuadraticSubMesh(aShape);
+
+  FaceQuadStruct *quad = CheckNbEdges( aMesh, aShape );
+  std::auto_ptr<FaceQuadStruct> quadDeleter( quad ); // to delete quad at exit from Compute()
   if (!quad)
     return false;
 
+  if(myQuadranglePreference) {
+    int n1 = quad->side[0]->NbPoints();
+    int n2 = quad->side[1]->NbPoints();
+    int n3 = quad->side[2]->NbPoints();
+    int n4 = quad->side[3]->NbPoints();
+    int nfull = n1+n2+n3+n4;
+    int ntmp = nfull/2;
+    ntmp = ntmp*2;
+    if( nfull==ntmp && ( (n1!=n3) || (n2!=n4) ) ) {
+      // special path for using only quandrangle faces
+      bool ok = ComputeQuadPref(aMesh, aShape, quad);
+      return ok;
+    }
+  }
+
+  // set normalized grid on unit square in parametric domain
+  
+  if (!SetNormalizedGrid(aMesh, aShape, quad))
+    return false;
+
   // --- compute 3D values on points, store points & quadrangles
 
-  int nbdown  = quad->nbPts[0];
-  int nbup    = quad->nbPts[2];
-//  bool isDownOut = (nbdown > nbup);
-//  bool isUpOut   = (nbdown < nbup);
+  int nbdown  = quad->side[0]->NbPoints();
+  int nbup    = quad->side[2]->NbPoints();
 
-  int nbright = quad->nbPts[1];
-  int nbleft  = quad->nbPts[3];
-//  bool isRightOut = (nbright > nbleft);
-//  bool isLeftOut  = (nbright < nbleft);
+  int nbright = quad->side[1]->NbPoints();
+  int nbleft  = quad->side[3]->NbPoints();
 
   int nbhoriz  = Min(nbdown, nbup);
   int nbvertic = Min(nbright, nbleft);
@@ -140,7 +178,7 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
   Handle(Geom_Surface) S = BRep_Tool::Surface(F);
 
   // internal mesh nodes
-  int i, j;
+  int i, j, geomFaceID = meshDS->ShapeToIndex( F );
   for (i = 1; i < nbhoriz - 1; i++) {
     for (j = 1; j < nbvertic - 1; j++) {
       int ij = j * nbhoriz + i;
@@ -148,15 +186,11 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
       double v = quad->uv_grid[ij].v;
       gp_Pnt P = S->Value(u, v);
       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
-      meshDS->SetNodeOnFace(node, F);
+      meshDS->SetNodeOnFace(node, geomFaceID, u, v);
       quad->uv_grid[ij].node = node;
-      SMDS_FacePosition* fpos =
-        dynamic_cast<SMDS_FacePosition*>(node->GetPosition().get());
-      fpos->SetUParameter(u);
-      fpos->SetVParameter(v);
     }
   }
-
+  
   // mesh faces
 
   //             [2]
@@ -170,18 +204,17 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
   //     0 > > > > > > > > nbhoriz
   //              i
   //             [0]
-
+  
   i = 0;
   int ilow = 0;
   int iup = nbhoriz - 1;
   if (quad->isEdgeOut[3]) { ilow++; } else { if (quad->isEdgeOut[1]) iup--; }
-
+  
   int jlow = 0;
   int jup = nbvertic - 1;
   if (quad->isEdgeOut[0]) { jlow++; } else { if (quad->isEdgeOut[2]) jup--; }
-
+  
   // regular quadrangles
-  //   bool isQuadForward = ( faceIsForward == quad->isEdgeForward[0]);
   for (i = ilow; i < iup; i++) {
     for (j = jlow; j < jup; j++) {
       const SMDS_MeshNode *a, *b, *c, *d;
@@ -189,22 +222,23 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
       b = quad->uv_grid[j * nbhoriz + i + 1].node;
       c = quad->uv_grid[(j + 1) * nbhoriz + i + 1].node;
       d = quad->uv_grid[(j + 1) * nbhoriz + i].node;
-      //  if (isQuadForward) faceId = meshDS->AddFace(a,b,c,d);
-      //  else faceId = meshDS->AddFace(a,d,c,b);
-      SMDS_MeshFace * face = meshDS->AddFace(a, b, c, d);
-      meshDS->SetMeshElementOnShape(face, F);
+      SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
+      meshDS->SetMeshElementOnShape(face, geomFaceID);
     }
   }
 
-  UVPtStruct *uv_e0 = quad->uv_edges[0];
-  UVPtStruct *uv_e1 = quad->uv_edges[1];
-  UVPtStruct *uv_e2 = quad->uv_edges[2];
-  UVPtStruct *uv_e3 = quad->uv_edges[3];
+  const vector<UVPtStruct>& uv_e0 = quad->side[0]->GetUVPtStruct(true,0 );
+  const vector<UVPtStruct>& uv_e1 = quad->side[1]->GetUVPtStruct(false,1);
+  const vector<UVPtStruct>& uv_e2 = quad->side[2]->GetUVPtStruct(true,1 );
+  const vector<UVPtStruct>& uv_e3 = quad->side[3]->GetUVPtStruct(false,0);
+
+  if ( uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty() )
+    return error( COMPERR_BAD_INPUT_MESH );
 
   double eps = Precision::Confusion();
 
   // Boundary quadrangles
-
+  
   if (quad->isEdgeOut[0]) {
     // Down edge is out
     // 
@@ -216,14 +250,14 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
     // .  .  .  .  .  .  .  .  . __ down edge nodes
     // 
     // >->->->->->->->->->->->-> -- direction of processing
-
+      
     int g = 0; // number of last processed node in the regular grid
-
+    
     // number of last node of the down edge to be processed
     int stop = nbdown - 1;
     // if right edge is out, we will stop at a node, previous to the last one
     if (quad->isEdgeOut[1]) stop--;
-
+    
     // for each node of the down edge find nearest node
     // in the first row of the regular grid and link them
     for (i = 0; i < stop; i++) {
@@ -231,18 +265,19 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
       a = uv_e0[i].node;
       b = uv_e0[i + 1].node;
       gp_Pnt pb (b->X(), b->Y(), b->Z());
-
+      
       // find node c in the regular grid, which will be linked with node b
       int near = g;
       if (i == stop - 1) {
         // right bound reached, link with the rightmost node
         near = iup;
         c = quad->uv_grid[nbhoriz + iup].node;
-      } else {
+      }
+      else {
         // find in the grid node c, nearest to the b
         double mind = RealLast();
         for (int k = g; k <= iup; k++) {
-
+          
           const SMDS_MeshNode *nk;
           if (k < ilow) // this can be, if left edge is out
             nk = uv_e3[1].node; // get node from the left edge
@@ -262,15 +297,18 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
       }
 
       if (near == g) { // make triangle
-        SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
-        meshDS->SetMeshElementOnShape(face, F);
-      } else { // make quadrangle
+        //SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
+        SMDS_MeshFace* face = myTool->AddFace(a, b, c);
+        meshDS->SetMeshElementOnShape(face, geomFaceID);
+      }
+      else { // make quadrangle
         if (near - 1 < ilow)
           d = uv_e3[1].node;
         else
           d = quad->uv_grid[nbhoriz + near - 1].node;
-        SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
-        meshDS->SetMeshElementOnShape(face, F);
+        //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
+        SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
+        meshDS->SetMeshElementOnShape(face, geomFaceID);
 
         // if node d is not at position g - make additional triangles
         if (near - 1 > g) {
@@ -280,8 +318,9 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
               d = uv_e3[1].node;
             else
               d = quad->uv_grid[nbhoriz + k - 1].node;
-            SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
-            meshDS->SetMeshElementOnShape(face, F);
+            //SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
+            SMDS_MeshFace* face = myTool->AddFace(a, c, d);
+            meshDS->SetMeshElementOnShape(face, geomFaceID);
           }
         }
         g = near;
@@ -342,15 +381,18 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
         }
 
         if (near == g) { // make triangle
-          SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
-          meshDS->SetMeshElementOnShape(face, F);
-        } else { // make quadrangle
+          //SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
+          SMDS_MeshFace* face = myTool->AddFace(a, b, c);
+          meshDS->SetMeshElementOnShape(face, geomFaceID);
+        }
+        else { // make quadrangle
           if (near + 1 > iup)
             d = uv_e1[nbright - 2].node;
           else
             d = quad->uv_grid[nbhoriz*(nbvertic - 2) + near + 1].node;
-          SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
-          meshDS->SetMeshElementOnShape(face, F);
+          //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
+          SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
+          meshDS->SetMeshElementOnShape(face, geomFaceID);
 
           if (near + 1 < g) { // if d not is at g - make additional triangles
             for (int k = near + 1; k < g; k++) {
@@ -359,8 +401,9 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
                 d = uv_e1[nbright - 2].node;
               else
                 d = quad->uv_grid[nbhoriz*(nbvertic - 2) + k + 1].node;
-              SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
-              meshDS->SetMeshElementOnShape(face, F);
+              //SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
+              SMDS_MeshFace* face = myTool->AddFace(a, c, d);
+              meshDS->SetMeshElementOnShape(face, geomFaceID);
             }
           }
           g = near;
@@ -407,15 +450,18 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
       }
 
       if (near == g) { // make triangle
-        SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
-        meshDS->SetMeshElementOnShape(face, F);
-      } else { // make quadrangle
+        //SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
+        SMDS_MeshFace* face = myTool->AddFace(a, b, c);
+        meshDS->SetMeshElementOnShape(face, geomFaceID);
+      }
+      else { // make quadrangle
         if (near - 1 < jlow)
           d = uv_e0[nbdown - 2].node;
         else
           d = quad->uv_grid[nbhoriz*near - 2].node;
-        SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
-        meshDS->SetMeshElementOnShape(face, F);
+        //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
+        SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
+        meshDS->SetMeshElementOnShape(face, geomFaceID);
 
         if (near - 1 > g) { // if d not is at g - make additional triangles
           for (int k = near - 1; k > g; k--) {
@@ -424,8 +470,9 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
               d = uv_e0[nbdown - 2].node;
             else
               d = quad->uv_grid[nbhoriz*k - 2].node;
-            SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
-            meshDS->SetMeshElementOnShape(face, F);
+            //SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
+            SMDS_MeshFace* face = myTool->AddFace(a, c, d);
+            meshDS->SetMeshElementOnShape(face, geomFaceID);
           }
         }
         g = near;
@@ -469,15 +516,18 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
         }
 
         if (near == g) { // make triangle
-          SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
-          meshDS->SetMeshElementOnShape(face, F);
-        } else { // make quadrangle
+          //SMDS_MeshFace* face = meshDS->AddFace(a, b, c);
+          SMDS_MeshFace* face = myTool->AddFace(a, b, c);
+          meshDS->SetMeshElementOnShape(face, geomFaceID);
+        }
+        else { // make quadrangle
           if (near + 1 > jup)
             d = uv_e2[1].node;
           else
             d = quad->uv_grid[nbhoriz*(near + 1) + 1].node;
-          SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
-          meshDS->SetMeshElementOnShape(face, F);
+          //SMDS_MeshFace* face = meshDS->AddFace(a, b, c, d);
+          SMDS_MeshFace* face = myTool->AddFace(a, b, c, d);
+          meshDS->SetMeshElementOnShape(face, geomFaceID);
 
           if (near + 1 < g) { // if d not is at g - make additional triangles
             for (int k = near + 1; k < g; k++) {
@@ -486,8 +536,9 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
                 d = uv_e2[1].node;
               else
                 d = quad->uv_grid[nbhoriz*(k + 1) + 1].node;
-              SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
-              meshDS->SetMeshElementOnShape(face, F);
+              //SMDS_MeshFace* face = meshDS->AddFace(a, c, d);
+              SMDS_MeshFace* face = myTool->AddFace(a, c, d);
+              meshDS->SetMeshElementOnShape(face, geomFaceID);
             }
           }
           g = near;
@@ -496,7 +547,6 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
     }
   }
 
-  QuadDelete(quad);
   bool isOk = true;
   return isOk;
 }
@@ -507,53 +557,102 @@ bool StdMeshers_Quadrangle_2D::Compute (SMESH_Mesh& aMesh,
  */
 //=============================================================================
 
-FaceQuadStruct *StdMeshers_Quadrangle_2D::CheckAnd2Dcompute
-  (SMESH_Mesh & aMesh, const TopoDS_Shape & aShape) throw(SALOME_Exception)
+FaceQuadStruct* StdMeshers_Quadrangle_2D::CheckNbEdges(SMESH_Mesh &         aMesh,
+                                                       const TopoDS_Shape & aShape)
+  //throw(SALOME_Exception)
 {
-  Unexpect aCatch(SalomeException);
-
-  //SMESH_subMesh *theSubMesh = aMesh.GetSubMesh(aShape);
-
   const TopoDS_Face & F = TopoDS::Face(aShape);
+  const bool ignoreMediumNodes = _quadraticMesh;
 
   // verify 1 wire only, with 4 edges
-
-  if (NumberOfWires(F) != 1)
-  {
-    INFOS("only 1 wire by face (quadrangles)");
+  TopoDS_Vertex V;
+  list< TopoDS_Edge > edges;
+  list< int > nbEdgesInWire;
+  int nbWire = SMESH_Block::GetOrderedEdges (F, V, edges, nbEdgesInWire);
+  if (nbWire != 1) {
+    error(COMPERR_BAD_SHAPE, TComm("Wrong number of wires: ") << nbWire);
     return 0;
   }
-  const TopoDS_Wire& W = BRepTools::OuterWire(F);
-  BRepTools_WireExplorer wexp (W, F);
-
-  FaceQuadStruct *quad = new FaceQuadStruct;
-  for (int i = 0; i < 4; i++)
-    quad->uv_edges[i] = 0;
+  FaceQuadStruct* quad = new FaceQuadStruct;
   quad->uv_grid = 0;
-
-  int nbEdges = 0;
-  for (wexp.Init(W, F); wexp.More(); wexp.Next())
-  {
-    const TopoDS_Edge& E = wexp.Current();
-    int nb = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
-    if (nbEdges < 4)
-    {
-      quad->edge[nbEdges] = E;
-      quad->nbPts[nbEdges] = nb + 2; // internal points + 2 extrema
+  quad->side.reserve(nbEdgesInWire.front());
+
+  int nbSides = 0;
+  list< TopoDS_Edge >::iterator edgeIt = edges.begin();
+  if ( nbEdgesInWire.front() == 4 ) { // exactly 4 edges
+    for ( ; edgeIt != edges.end(); ++edgeIt, nbSides++ )
+      quad->side.push_back( new StdMeshers_FaceSide(F, *edgeIt, &aMesh,
+                                                    nbSides<TOP_SIDE, ignoreMediumNodes));
+  }
+  else if ( nbEdgesInWire.front() > 4 ) { // more than 4 edges - try to unite some
+    list< TopoDS_Edge > sideEdges;
+    while ( !edges.empty()) {
+      sideEdges.clear();
+      sideEdges.splice( sideEdges.end(), edges, edges.begin()); // edges.front() -> sideEdges.end()
+      bool sameSide = true;
+      while ( !edges.empty() && sameSide ) {
+        sameSide = SMESH_Algo::IsContinuous( sideEdges.back(), edges.front() );
+        if ( sameSide )
+          sideEdges.splice( sideEdges.end(), edges, edges.begin());
+      }
+      if ( nbSides == 0 ) { // go backward from the first edge
+        sameSide = true;
+        while ( !edges.empty() && sameSide ) {
+          sameSide = SMESH_Algo::IsContinuous( sideEdges.front(), edges.back() );
+          if ( sameSide )
+            sideEdges.splice( sideEdges.begin(), edges, --edges.end());
+        }
+      }
+      quad->side.push_back( new StdMeshers_FaceSide(F, sideEdges, &aMesh,
+                                                    nbSides<TOP_SIDE, ignoreMediumNodes));
+      ++nbSides;
     }
-    nbEdges++;
   }
-
-  if (nbEdges != 4)
-  {
-    INFOS("face must have 4 edges /quadrangles");
-    QuadDelete(quad);
-    return 0;
+  if (nbSides != 4) {
+#ifdef _DEBUG_
+    cout << endl << "StdMeshers_Quadrangle_2D. Edge IDs of " << nbSides << " sides:";
+    for ( int i = 0; i < nbSides; ++i ) {
+      cout << " ( ";
+      for ( int e = 0; e < quad->side[i]->NbEdges(); ++e )
+        cout << myTool->GetMeshDS()->ShapeToIndex( quad->side[i]->Edge( e )) << " ";
+      cout << ")";
+    }
+    cout << endl;
+#endif
+    if ( !nbSides )
+      nbSides = nbEdgesInWire.front();
+    error(COMPERR_BAD_SHAPE, TComm("Face must have 4 sides but not ") << nbSides);
+    delete quad;
+    quad = 0;
   }
 
-  // set normalized grid on unit square in parametric domain
+  return quad;
+}
+
+//=============================================================================
+/*!
+ *  CheckAnd2Dcompute
+ */
+//=============================================================================
+
+FaceQuadStruct *StdMeshers_Quadrangle_2D::CheckAnd2Dcompute
+                           (SMESH_Mesh &         aMesh,
+                            const TopoDS_Shape & aShape,
+                            const bool           CreateQuadratic) //throw(SALOME_Exception)
+{
+  _quadraticMesh = CreateQuadratic;
+
+  FaceQuadStruct *quad = CheckNbEdges(aMesh, aShape);
 
-  SetNormalizedGrid(aMesh, F, quad);
+  if(!quad) return 0;
+
+  // set normalized grid on unit square in parametric domain
+  bool stat = SetNormalizedGrid(aMesh, aShape, quad);
+  if(!stat) {
+    if(!quad)
+      delete quad;
+    quad = 0;
+  }
 
   return quad;
 }
@@ -564,20 +663,23 @@ FaceQuadStruct *StdMeshers_Quadrangle_2D::CheckAnd2Dcompute
  */
 //=============================================================================
 
-void StdMeshers_Quadrangle_2D::QuadDelete (FaceQuadStruct * quad)
+faceQuadStruct::~faceQuadStruct()
 {
-  //MESSAGE("StdMeshers_Quadrangle_2D::QuadDelete");
-  if (quad)
+  for (int i = 0; i < side.size(); i++) {
+    if (side[i])     delete side[i];
+  }
+  if (uv_grid)       delete [] uv_grid;
+}
+
+namespace {
+  inline const vector<UVPtStruct>& GetUVPtStructIn(FaceQuadStruct* quad, int i, int nbSeg)
   {
-    for (int i = 0; i < 4; i++)
-    {
-      if (quad->uv_edges[i])
-        delete [] quad->uv_edges[i];
-      quad->edge[i].Nullify();
-    }
-    if (quad->uv_grid)
-      delete [] quad->uv_grid;
-    delete quad;
+    bool   isXConst   = ( i == BOTTOM_SIDE || i == TOP_SIDE );
+    double constValue = ( i == BOTTOM_SIDE || i == LEFT_SIDE ) ? 0 : 1;
+    return
+      quad->isEdgeOut[i] ?
+      quad->side[i]->SimulateUVPtStruct(nbSeg,isXConst,constValue) :
+      quad->side[i]->GetUVPtStruct(isXConst,constValue);
   }
 }
 
@@ -587,18 +689,17 @@ void StdMeshers_Quadrangle_2D::QuadDelete (FaceQuadStruct * quad)
  */
 //=============================================================================
 
-void StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh,
+bool StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh,
                                                   const TopoDS_Shape& aShape,
-                                                  FaceQuadStruct* quad) throw (SALOME_Exception)
+                                                  FaceQuadStruct* & quad) //throw (SALOME_Exception)
 {
-  Unexpect aCatch(SalomeException);
   // Algorithme décrit dans "Génération automatique de maillages"
   // P.L. GEORGE, MASSON, Â§ 6.4.1 p. 84-85
   // traitement dans le domaine paramétrique 2d u,v
   // transport - projection sur le carré unité
 
 //  MESSAGE("StdMeshers_Quadrangle_2D::SetNormalizedGrid");
-  const TopoDS_Face& F = TopoDS::Face(aShape);
+//  const TopoDS_Face& F = TopoDS::Face(aShape);
 
   // 1 --- find orientation of the 4 edges, by test on extrema
 
@@ -614,88 +715,26 @@ void StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh,
   //             =down
   //
 
-  Handle(Geom2d_Curve) c2d[4];
-  gp_Pnt2d pf[4];
-  gp_Pnt2d pl[4];
-  for (int i = 0; i < 4; i++)
-  {
-    c2d[i] = BRep_Tool::CurveOnSurface(quad->edge[i], F,
-                                       quad->first[i], quad->last[i]);
-    pf[i] = c2d[i]->Value(quad->first[i]);
-    pl[i] = c2d[i]->Value(quad->last[i]);
-    quad->isEdgeForward[i] = false;
-  }
-
-  double l0f1 = pl[0].SquareDistance(pf[1]);
-  double l0l1 = pl[0].SquareDistance(pl[1]);
-  double f0f1 = pf[0].SquareDistance(pf[1]);
-  double f0l1 = pf[0].SquareDistance(pl[1]);
-  if ( Min( l0f1, l0l1 ) < Min ( f0f1, f0l1 ))
-  {
-    quad->isEdgeForward[0] = true;
-  } else {
-    double tmp = quad->first[0];
-    quad->first[0] = quad->last[0];
-    quad->last[0] = tmp;
-    pf[0] = c2d[0]->Value(quad->first[0]);
-    pl[0] = c2d[0]->Value(quad->last[0]);
-  }
-  for (int i = 1; i < 4; i++)
-  {
-    l0l1 = pl[i - 1].SquareDistance(pl[i]);
-    l0f1 = pl[i - 1].SquareDistance(pf[i]);
-    quad->isEdgeForward[i] = ( l0f1 < l0l1 );
-    if (!quad->isEdgeForward[i])
-    {
-      double tmp = quad->first[i];
-      quad->first[i] = quad->last[i];
-      quad->last[i] = tmp;
-      pf[i] = c2d[i]->Value(quad->first[i]);
-      pl[i] = c2d[i]->Value(quad->last[i]);
-    }
-  }
-
-  // 2 --- load 2d edge points (u,v) with orientation and value on unit square
-
-  bool loadOk = true;
-  for (int i = 0; i < 2; i++)
-  {
-    quad->uv_edges[i] = LoadEdgePoints(aMesh, F, quad->edge[i],
-                                       quad->first[i], quad->last[i]);
-    if (!quad->uv_edges[i]) loadOk = false;
-  }
-
-  for (int i = 2; i < 4; i++)
-  {
-    quad->uv_edges[i] = LoadEdgePoints(aMesh, F, quad->edge[i],
-                                       quad->last[i], quad->first[i]);
-    if (!quad->uv_edges[i]) loadOk = false;
-  }
-
-  if (!loadOk)
-  {
-    INFOS("StdMeshers_Quadrangle_2D::SetNormalizedGrid - LoadEdgePoints failed");
-    QuadDelete( quad );
-    quad = 0;
-    return;
-  }
   // 3 --- 2D normalized values on unit square [0..1][0..1]
 
-  int nbhoriz  = Min(quad->nbPts[0], quad->nbPts[2]);
-  int nbvertic = Min(quad->nbPts[1], quad->nbPts[3]);
+  int nbhoriz  = Min(quad->side[0]->NbPoints(), quad->side[2]->NbPoints());
+  int nbvertic = Min(quad->side[1]->NbPoints(), quad->side[3]->NbPoints());
+
+  quad->isEdgeOut[0] = (quad->side[0]->NbPoints() > quad->side[2]->NbPoints());
+  quad->isEdgeOut[1] = (quad->side[1]->NbPoints() > quad->side[3]->NbPoints());
+  quad->isEdgeOut[2] = (quad->side[2]->NbPoints() > quad->side[0]->NbPoints());
+  quad->isEdgeOut[3] = (quad->side[3]->NbPoints() > quad->side[1]->NbPoints());
 
-  quad->isEdgeOut[0] = (quad->nbPts[0] > quad->nbPts[2]);
-  quad->isEdgeOut[1] = (quad->nbPts[1] > quad->nbPts[3]);
-  quad->isEdgeOut[2] = (quad->nbPts[2] > quad->nbPts[0]);
-  quad->isEdgeOut[3] = (quad->nbPts[3] > quad->nbPts[1]);
+  UVPtStruct *uv_grid = quad->uv_grid = new UVPtStruct[nbvertic * nbhoriz];
 
-  quad->uv_grid = new UVPtStruct[nbvertic * nbhoriz];
+  const vector<UVPtStruct>& uv_e0 = GetUVPtStructIn( quad, 0, nbhoriz - 1 );
+  const vector<UVPtStruct>& uv_e1 = GetUVPtStructIn( quad, 1, nbvertic - 1 );
+  const vector<UVPtStruct>& uv_e2 = GetUVPtStructIn( quad, 2, nbhoriz - 1 );
+  const vector<UVPtStruct>& uv_e3 = GetUVPtStructIn( quad, 3, nbvertic - 1 );
 
-  UVPtStruct *uv_grid = quad->uv_grid;
-  UVPtStruct *uv_e0 = quad->uv_edges[0];
-  UVPtStruct *uv_e1 = quad->uv_edges[1];
-  UVPtStruct *uv_e2 = quad->uv_edges[2];
-  UVPtStruct *uv_e3 = quad->uv_edges[3];
+  if ( uv_e0.empty() || uv_e1.empty() || uv_e2.empty() || uv_e3.empty() )
+    //return error( "Can't find nodes on sides");
+    return error( COMPERR_BAD_INPUT_MESH );
 
   // nodes Id on "in" edges
   if (! quad->isEdgeOut[0]) {
@@ -727,21 +766,6 @@ void StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh,
     }
   }
 
-  // falsificate "out" edges
-  if (quad->isEdgeOut[0]) // down
-    uv_e0 = MakeEdgePoints
-      (aMesh, F, quad->edge[0], quad->first[0], quad->last[0], nbhoriz - 1);
-  else if (quad->isEdgeOut[2]) // up
-    uv_e2 = MakeEdgePoints
-      (aMesh, F, quad->edge[2], quad->last[2], quad->first[2], nbhoriz - 1);
-
-  if (quad->isEdgeOut[1]) // right
-    uv_e1 = MakeEdgePoints
-      (aMesh, F, quad->edge[1], quad->first[1], quad->last[1], nbvertic - 1);
-  else if (quad->isEdgeOut[3]) // left
-    uv_e3 = MakeEdgePoints
-      (aMesh, F, quad->edge[3], quad->last[3], quad->first[3], nbvertic - 1);
-
   // normalized 2d values on grid
   for (int i = 0; i < nbhoriz; i++)
   {
@@ -765,10 +789,10 @@ void StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh,
   }
 
   // 4 --- projection on 2d domain (u,v)
-  gp_Pnt2d a0 = pf[0];
-  gp_Pnt2d a1 = pf[1];
-  gp_Pnt2d a2 = pf[2];
-  gp_Pnt2d a3 = pf[3];
+  gp_UV a0( uv_e0.front().u, uv_e0.front().v );
+  gp_UV a1( uv_e0.back().u,  uv_e0.back().v );
+  gp_UV a2( uv_e2.back().u,  uv_e2.back().v );
+  gp_UV a3( uv_e2.front().u, uv_e2.front().v );
 
   for (int i = 0; i < nbhoriz; i++)
   {
@@ -777,290 +801,428 @@ void StdMeshers_Quadrangle_2D::SetNormalizedGrid (SMESH_Mesh & aMesh,
       int ij = j * nbhoriz + i;
       double x = uv_grid[ij].x;
       double y = uv_grid[ij].y;
-      double param_0 = uv_e0[0].param + x * (uv_e0[nbhoriz - 1].param - uv_e0[0].param); // sud
-      double param_2 = uv_e2[0].param + x * (uv_e2[nbhoriz - 1].param - uv_e2[0].param); // nord
-      double param_1 = uv_e1[0].param + y * (uv_e1[nbvertic - 1].param - uv_e1[0].param); // est
-      double param_3 = uv_e3[0].param + y * (uv_e3[nbvertic - 1].param - uv_e3[0].param); // ouest
+      double param_0 = uv_e0[0].normParam + x * (uv_e0.back().normParam - uv_e0[0].normParam); // sud
+      double param_2 = uv_e2[0].normParam + x * (uv_e2.back().normParam - uv_e2[0].normParam); // nord
+      double param_1 = uv_e1[0].normParam + y * (uv_e1.back().normParam - uv_e1[0].normParam); // est
+      double param_3 = uv_e3[0].normParam + y * (uv_e3.back().normParam - uv_e3[0].normParam); // ouest
 
       //MESSAGE("params "<<param_0<<" "<<param_1<<" "<<param_2<<" "<<param_3);
-      gp_Pnt2d p0 = c2d[0]->Value(param_0);
-      gp_Pnt2d p1 = c2d[1]->Value(param_1);
-      gp_Pnt2d p2 = c2d[2]->Value(param_2);
-      gp_Pnt2d p3 = c2d[3]->Value(param_3);
-
-      double u = (1 - y) * p0.X() + x * p1.X() + y * p2.X() + (1 - x) * p3.X();
-      double v = (1 - y) * p0.Y() + x * p1.Y() + y * p2.Y() + (1 - x) * p3.Y();
+      gp_UV p0 = quad->side[0]->Value2d(param_0).XY();
+      gp_UV p1 = quad->side[1]->Value2d(param_1).XY();
+      gp_UV p2 = quad->side[2]->Value2d(param_2).XY();
+      gp_UV p3 = quad->side[3]->Value2d(param_3).XY();
 
-      u -= (1 - x) * (1 - y) * a0.X() + x * (1 - y) * a1.X() +
-        x * y * a2.X() + (1 - x) * y * a3.X();
-      v -= (1 - x) * (1 - y) * a0.Y() + x * (1 - y) * a1.Y() +
-        x * y * a2.Y() + (1 - x) * y * a3.Y();
+      gp_UV uv = (1 - y) * p0 + x * p1 + y * p2 + (1 - x) * p3;
+      uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3;
 
-      uv_grid[ij].u = u;
-      uv_grid[ij].v = v;
+      uv_grid[ij].u = uv.X();
+      uv_grid[ij].v = uv.Y();
     }
   }
+  return true;
 }
 
-//=============================================================================
-/*!
- *  LoadEdgePoints
- */
-//=============================================================================
-UVPtStruct* StdMeshers_Quadrangle_2D::LoadEdgePoints (SMESH_Mesh & aMesh,
-                                                      const TopoDS_Face& F,
-                                                      const TopoDS_Edge& E,
-                                                      double first, double last)
-//                        bool isForward)
-{
-  //MESSAGE("StdMeshers_Quadrangle_2D::LoadEdgePoints");
+//=======================================================================
+//function : ShiftQuad
+//purpose  : auxilary function for ComputeQuadPref
+//=======================================================================
 
-  //SMDS_Mesh* meshDS = aMesh.GetMeshDS();
+static void ShiftQuad(FaceQuadStruct* quad, const int num, bool)
+{
+  StdMeshers_FaceSide* side[4] = { quad->side[0], quad->side[1], quad->side[2], quad->side[3] };
+  for (int i = BOTTOM_SIDE; i < NB_SIDES; ++i ) {
+    int id = ( i + num ) % NB_SIDES;
+    bool wasForward = ( i < TOP_SIDE );
+    bool newForward = ( id < TOP_SIDE );
+    if ( wasForward != newForward )
+      side[ i ]->Reverse();
+    quad->side[ id ] = side[ i ];
+  }
+}
 
-  // --- IDNodes of first and last Vertex
+//=======================================================================
+//function : CalcUV
+//purpose  : auxilary function for ComputeQuadPref
+//=======================================================================
 
-  TopoDS_Vertex VFirst, VLast;
-  TopExp::Vertices(E, VFirst, VLast); // corresponds to f and l
+static gp_UV CalcUV(double x0, double x1, double y0, double y1,
+                    FaceQuadStruct* quad,
+                    const gp_UV& a0, const gp_UV& a1,
+                    const gp_UV& a2, const gp_UV& a3)
+{
+  const vector<UVPtStruct>& uv_eb = quad->side[0]->GetUVPtStruct(true,0 );
+  const vector<UVPtStruct>& uv_er = quad->side[1]->GetUVPtStruct(false,1);
+  const vector<UVPtStruct>& uv_et = quad->side[2]->GetUVPtStruct(true,1 );
+  const vector<UVPtStruct>& uv_el = quad->side[3]->GetUVPtStruct(false,0);
 
-  ASSERT(!VFirst.IsNull());
-  SMDS_NodeIteratorPtr lid = aMesh.GetSubMesh(VFirst)->GetSubMeshDS()->GetNodes();
-  if (!lid->more())
-  {
-    MESSAGE ( "NO NODE BUILT ON VERTEX" );
-    return 0;
-  }
-  const SMDS_MeshNode* idFirst = lid->next();
+  double x = (x0 + y0 * (x1 - x0)) / (1 - (y1 - y0) * (x1 - x0));
+  double y = y0 + x * (y1 - y0);
 
-  ASSERT(!VLast.IsNull());
-  lid = aMesh.GetSubMesh(VLast)->GetSubMeshDS()->GetNodes();
-  if (!lid->more())
-  {
-    MESSAGE ( "NO NODE BUILT ON VERTEX" );
-    return 0;
-  }
-  const SMDS_MeshNode* idLast = lid->next();
+  double param_b = uv_eb[0].normParam + x * (uv_eb.back().normParam - uv_eb[0].normParam);
+  double param_t = uv_et[0].normParam + x * (uv_et.back().normParam - uv_et[0].normParam);
+  double param_r = uv_er[0].normParam + y * (uv_er.back().normParam - uv_er[0].normParam);
+  double param_l = uv_el[0].normParam + y * (uv_el.back().normParam - uv_el[0].normParam);
 
-  // --- edge internal IDNodes (relies on good order storage, not checked)
+  gp_UV p0 = quad->side[BOTTOM_SIDE]->Value2d(param_b).XY();
+  gp_UV p1 = quad->side[RIGHT_SIDE ]->Value2d(param_r).XY();
+  gp_UV p2 = quad->side[TOP_SIDE   ]->Value2d(param_t).XY();
+  gp_UV p3 = quad->side[LEFT_SIDE  ]->Value2d(param_l).XY();
 
-  map<double, const SMDS_MeshNode *> params;
-  SMDS_NodeIteratorPtr ite = aMesh.GetSubMesh(E)->GetSubMeshDS()->GetNodes();
+  gp_UV uv = p0 * (1 - y) + p1 * x + p2 * y + p3 * (1 - x);
 
-  while(ite->more())
-  {
-    const SMDS_MeshNode* node = ite->next();
-    const SMDS_EdgePosition* epos =
-      static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
-    double param = epos->GetUParameter();
-    params[param] = node;
-  }
+  uv -= (1 - x) * (1 - y) * a0 + x * (1 - y) * a1 + x * y * a2 + (1 - x) * y * a3;
 
-  int nbPoints = aMesh.GetSubMesh(E)->GetSubMeshDS()->NbNodes();
-  if (nbPoints != params.size())
-  {
-    MESSAGE( "BAD NODE ON EDGE POSITIONS" );
-    return 0;
-  }
-  UVPtStruct* uvslf = new UVPtStruct[nbPoints + 2];
+  return uv;
+}
 
-  double f, l;
-  Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
+//=======================================================================
+/*!
+ * Create only quandrangle faces
+ */
+//=======================================================================
 
-  bool isForward = (((l - f) * (last - first)) > 0);
-  double paramin = 0;
-  double paramax = 0;
-  if (isForward)
-  {
-    paramin = f;
-    paramax = l;
-    gp_Pnt2d p = C2d->Value(f);        // first point = Vertex Forward
-    uvslf[0].x = p.X();
-    uvslf[0].y = p.Y();
-    uvslf[0].param = f;
-    uvslf[0].node = idFirst;
-    //MESSAGE("__ f "<<f<<" "<<uvslf[0].x <<" "<<uvslf[0].y);
-    map < double, const SMDS_MeshNode* >::iterator itp = params.begin();
-    for (int i = 1; i <= nbPoints; i++)        // nbPoints internal
-    {
-      double param = (*itp).first;
-      gp_Pnt2d p = C2d->Value(param);
-      uvslf[i].x = p.X();
-      uvslf[i].y = p.Y();
-      uvslf[i].param = param;
-      uvslf[i].node = (*itp).second;
-      //MESSAGE("__ "<<i<<" "<<param<<" "<<uvslf[i].x <<" "<<uvslf[i].y);
-      itp++;
+bool StdMeshers_Quadrangle_2D::ComputeQuadPref (SMESH_Mesh &        aMesh,
+                                                const TopoDS_Shape& aShape,
+                                                FaceQuadStruct*     quad)
+{
+  SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
+  const TopoDS_Face& F = TopoDS::Face(aShape);
+  Handle(Geom_Surface) S = BRep_Tool::Surface(F);
+//  const TopoDS_Wire& W = BRepTools::OuterWire(F);
+  bool WisF = true;
+//   if(W.Orientation()==TopAbs_FORWARD) 
+//     WisF = true;
+  //if(WisF) cout<<"W is FORWARD"<<endl;
+  //else cout<<"W is REVERSED"<<endl;
+//   bool FisF = (F.Orientation()==TopAbs_FORWARD);
+//   if(!FisF) WisF = !WisF;
+//  WisF = FisF;
+  int i,j,geomFaceID = meshDS->ShapeToIndex( F );
+
+  int nb = quad->side[0]->NbPoints();
+  int nr = quad->side[1]->NbPoints();
+  int nt = quad->side[2]->NbPoints();
+  int nl = quad->side[3]->NbPoints();
+  int dh = abs(nb-nt);
+  int dv = abs(nr-nl);
+
+  if( dh>=dv ) {
+    if( nt>nb ) {
+      // it is a base case => not shift quad but me be replacement is need
+      ShiftQuad(quad,0,WisF);
     }
-    p = C2d->Value(l);         // last point = Vertex Reversed
-    uvslf[nbPoints + 1].x = p.X();
-    uvslf[nbPoints + 1].y = p.Y();
-    uvslf[nbPoints + 1].param = l;
-    uvslf[nbPoints + 1].node = idLast;
-    //MESSAGE("__ l "<<l<<" "<<uvslf[nbPoints+1].x <<" "<<uvslf[nbPoints+1].y);
-  } else
-  {
-    paramin = l;
-    paramax = f;
-    gp_Pnt2d p = C2d->Value(l);        // first point = Vertex Reversed
-    uvslf[0].x = p.X();
-    uvslf[0].y = p.Y();
-    uvslf[0].param = l;
-    uvslf[0].node = idLast;
-    //MESSAGE("__ l "<<l<<" "<<uvslf[0].x <<" "<<uvslf[0].y);
-    map < double, const SMDS_MeshNode* >::reverse_iterator itp = params.rbegin();
-
-    for (int j = nbPoints; j >= 1; j--)        // nbPoints internal
-    {
-      double param = (*itp).first;
-      int i = nbPoints + 1 - j;
-      gp_Pnt2d p = C2d->Value(param);
-      uvslf[i].x = p.X();
-      uvslf[i].y = p.Y();
-      uvslf[i].param = param;
-      uvslf[i].node = (*itp).second;
-      //MESSAGE("__ "<<i<<" "<<param<<" "<<uvslf[i].x <<" "<<uvslf[i].y);
-      itp++;
+    else {
+      // we have to shift quad on 2
+      ShiftQuad(quad,2,WisF);
+    }
+  }
+  else {
+    if( nr>nl ) {
+      // we have to shift quad on 1
+      ShiftQuad(quad,1,WisF);
+    }
+    else {
+      // we have to shift quad on 3
+      ShiftQuad(quad,3,WisF);
     }
-    p = C2d->Value(f);         // last point = Vertex Forward
-    uvslf[nbPoints + 1].x = p.X();
-    uvslf[nbPoints + 1].y = p.Y();
-    uvslf[nbPoints + 1].param = f;
-    uvslf[nbPoints + 1].node = idFirst;
-    //MESSAGE("__ f "<<f<<" "<<uvslf[nbPoints+1].x <<" "<<uvslf[nbPoints+1].y);
   }
 
-  ASSERT(paramin != paramax);
-  for (int i = 0; i < nbPoints + 2; i++)
-  {
-    uvslf[i].normParam = (uvslf[i].param - paramin) / (paramax - paramin);
+  nb = quad->side[0]->NbPoints();
+  nr = quad->side[1]->NbPoints();
+  nt = quad->side[2]->NbPoints();
+  nl = quad->side[3]->NbPoints();
+  dh = abs(nb-nt);
+  dv = abs(nr-nl);
+  int nbh  = Max(nb,nt);
+  int nbv = Max(nr,nl);
+  int addh = 0;
+  int addv = 0;
+
+  // orientation of face and 3 main domain for future faces
+  //       0   top    1
+  //      1------------1
+  //       |   |  |   |
+  //       |   |  |   |
+  //       | L |  | R |
+  //  left |   |  |   | rigth
+  //       |  /    \  |
+  //       | /  C   \ |
+  //       |/        \|
+  //      0------------0
+  //       0  bottom  1
+
+  if(dh>dv) {
+    addv = (dh-dv)/2;
+    nbv = nbv + addv;
+  }
+  else { // dv>=dh
+    addh = (dv-dh)/2;
+    nbh = nbh + addh;
   }
 
-  return uvslf;
-}
+  const vector<UVPtStruct>& uv_eb = quad->side[0]->GetUVPtStruct(true,0 );
+  const vector<UVPtStruct>& uv_er = quad->side[1]->GetUVPtStruct(false,1);
+  const vector<UVPtStruct>& uv_et = quad->side[2]->GetUVPtStruct(true,1 );
+  const vector<UVPtStruct>& uv_el = quad->side[3]->GetUVPtStruct(false,0);
+
+  // arrays for normalized params
+  //cout<<"Dump B:"<<endl;
+  TColStd_SequenceOfReal npb, npr, npt, npl;
+  for(i=0; i<nb; i++) {
+    npb.Append(uv_eb[i].normParam);
+    //cout<<"i="<<i<<" par="<<uv_eb[i].normParam<<" npar="<<uv_eb[i].normParam;
+    //const SMDS_MeshNode* N = uv_eb[i].node;
+    //cout<<" node("<<N->X()<<","<<N->Y()<<","<<N->Z()<<")"<<endl;
+  }
+  for(i=0; i<nr; i++) {
+    npr.Append(uv_er[i].normParam);
+  }
+  for(i=0; i<nt; i++) {
+    npt.Append(uv_et[i].normParam);
+  }
+  for(i=0; i<nl; i++) {
+    npl.Append(uv_el[i].normParam);
+  }
 
-//=============================================================================
-/*!
- *  MakeEdgePoints
- */
-//=============================================================================
-UVPtStruct* StdMeshers_Quadrangle_2D::MakeEdgePoints (SMESH_Mesh & aMesh,
-                                                      const TopoDS_Face& F,
-                                                      const TopoDS_Edge& E,
-                                                      double first, double last,
-                                                      int nb_segm)
-{
-//  MESSAGE("StdMeshers_Quadrangle_2D::MakeEdgePoints");
-
-  UVPtStruct* uvslf = new UVPtStruct[nb_segm + 1];
-  list<double> params;
-
-  // --- edge internal points
-  double fi, li;
-  Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, fi, li);
-  if (!Curve.IsNull()) {
-    try {
-      GeomAdaptor_Curve C3d (Curve);
-      double length = EdgeLength(E);
-      double eltSize = length / nb_segm;
-      GCPnts_UniformAbscissa Discret (C3d, eltSize, fi, li);
-      if (!Discret.IsDone()) return false;
-      int NbPoints = Discret.NbPoints();
-      for (int i = 1; i <= NbPoints; i++) {
-        double param = Discret.Parameter(i);
-        params.push_back(param);
+  // add some params to right and left after the first param
+  // insert to right
+  int dr = nbv - nr;
+  double dpr = (npr.Value(2) - npr.Value(1))/(dr+1);
+  for(i=1; i<=dr; i++) {
+    npr.InsertAfter(1,npr.Value(2)-dpr);
+  }
+  // insert to left
+  int dl = nbv - nl;
+  dpr = (npl.Value(2) - npl.Value(1))/(dl+1);
+  for(i=1; i<=dl; i++) {
+    npl.InsertAfter(1,npl.Value(2)-dpr);
+  }
+  //cout<<"npb:";
+  //for(i=1; i<=npb.Length(); i++) {
+  //  cout<<" "<<npb.Value(i);
+  //}
+  //cout<<endl;
+  
+  gp_XY a0( uv_eb.front().u, uv_eb.front().v );
+  gp_XY a1( uv_eb.back().u,  uv_eb.back().v );
+  gp_XY a2( uv_et.back().u,  uv_et.back().v );
+  gp_XY a3( uv_et.front().u, uv_et.front().v );
+  //cout<<" a0("<<a0.X()<<","<<a0.Y()<<")"<<" a1("<<a1.X()<<","<<a1.Y()<<")"
+  //    <<" a2("<<a2.X()<<","<<a2.Y()<<")"<<" a3("<<a3.X()<<","<<a3.Y()<<")"<<endl;
+
+  int nnn = Min(nr,nl);
+  // auxilary sequence of XY for creation nodes
+  // in the bottom part of central domain
+  // it's length must be == nbv-nnn-1
+  TColgp_SequenceOfXY UVL;
+  TColgp_SequenceOfXY UVR;
+
+  // step1: create faces for left domain
+  StdMeshers_Array2OfNode NodesL(1,dl+1,1,nl);
+  // add left nodes
+  for(j=1; j<=nl; j++)
+    NodesL.SetValue(1,j,uv_el[j-1].node);
+  if(dl>0) {
+    // add top nodes
+    for(i=1; i<=dl; i++) 
+      NodesL.SetValue(i+1,nl,uv_et[i].node);
+    // create and add needed nodes
+    TColgp_SequenceOfXY UVtmp;
+    for(i=1; i<=dl; i++) {
+      double x0 = npt.Value(i+1);
+      double x1 = x0;
+      // diagonal node
+      double y0 = npl.Value(i+1);
+      double y1 = npr.Value(i+1);
+      gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
+      gp_Pnt P = S->Value(UV.X(),UV.Y());
+      SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z());
+      meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
+      NodesL.SetValue(i+1,1,N);
+      if(UVL.Length()<nbv-nnn-1) UVL.Append(UV);
+      // internal nodes
+      for(j=2; j<nl; j++) {
+        double y0 = npl.Value(dl+j);
+        double y1 = npr.Value(dl+j);
+        gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
+        gp_Pnt P = S->Value(UV.X(),UV.Y());
+        SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
+        meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
+        NodesL.SetValue(i+1,j,N);
+        if( i==dl ) UVtmp.Append(UV);
       }
     }
-    catch (Standard_Failure) {
-      return 0;
+    for(i=1; i<=UVtmp.Length() && UVL.Length()<nbv-nnn-1; i++) {
+      UVL.Append(UVtmp.Value(i));
+    }
+    //cout<<"Dump NodesL:"<<endl;
+    //for(i=1; i<=dl+1; i++) {
+    //  cout<<"i="<<i;
+    //  for(j=1; j<=nl; j++) {
+    //    cout<<" ("<<NodesL.Value(i,j)->X()<<","<<NodesL.Value(i,j)->Y()<<","<<NodesL.Value(i,j)->Z()<<")";
+    //  }
+    //  cout<<endl;
+    //}
+    // create faces
+    for(i=1; i<=dl; i++) {
+      for(j=1; j<nl; j++) {
+        if(WisF) {
+          SMDS_MeshFace* F =
+            myTool->AddFace(NodesL.Value(i,j), NodesL.Value(i+1,j),
+                            NodesL.Value(i+1,j+1), NodesL.Value(i,j+1));
+          meshDS->SetMeshElementOnShape(F, geomFaceID);
+        }
+        else {
+          SMDS_MeshFace* F =
+            myTool->AddFace(NodesL.Value(i,j), NodesL.Value(i,j+1),
+                            NodesL.Value(i+1,j+1), NodesL.Value(i+1,j));
+          meshDS->SetMeshElementOnShape(F, geomFaceID);
+        }
+      }
     }
   }
-  else
-  {
-    // Edge is a degenerated Edge
-    BRep_Tool::Range(E, fi, li);
-    double du = (li - fi) / nb_segm;
-    for (int i = 1; i <= nb_segm + 1; i++)
-    {
-      double param = fi + (i - 1) * du;
-      params.push_back(param);
+  else {
+    // fill UVL using c2d
+    for(i=1; i<npl.Length() && UVL.Length()<nbv-nnn-1; i++) {
+      UVL.Append( gp_UV ( uv_el[i].u, uv_el[i].v ));
     }
   }
 
-  double f, l;
-  Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
-  ASSERT(f != l);
-
-  bool isForward = (((l - f) * (last - first)) > 0);
-  if (isForward) {
-    list<double>::iterator itU = params.begin();
-    for (int i = 0; i <= nb_segm; i++) // nbPoints internal
-    {
-      double param = *itU;
-      gp_Pnt2d p = C2d->Value(param);
-      uvslf[i].x = p.X();
-      uvslf[i].y = p.Y();
-      uvslf[i].param = param;
-      uvslf[i].normParam = (param - f) / (l - f);
-      itU++;
+  // step2: create faces for right domain
+  StdMeshers_Array2OfNode NodesR(1,dr+1,1,nr);
+  // add right nodes
+  for(j=1; j<=nr; j++) 
+    NodesR.SetValue(1,j,uv_er[nr-j].node);
+  if(dr>0) {
+    // add top nodes
+    for(i=1; i<=dr; i++) 
+      NodesR.SetValue(i+1,1,uv_et[nt-1-i].node);
+    // create and add needed nodes
+    TColgp_SequenceOfXY UVtmp;
+    for(i=1; i<=dr; i++) {
+      double x0 = npt.Value(nt-i);
+      double x1 = x0;
+      // diagonal node
+      double y0 = npl.Value(i+1);
+      double y1 = npr.Value(i+1);
+      gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
+      gp_Pnt P = S->Value(UV.X(),UV.Y());
+      SMDS_MeshNode * N = meshDS->AddNode(P.X(), P.Y(), P.Z());
+      meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
+      NodesR.SetValue(i+1,nr,N);
+      if(UVR.Length()<nbv-nnn-1) UVR.Append(UV);
+      // internal nodes
+      for(j=2; j<nr; j++) {
+        double y0 = npl.Value(nbv-j+1);
+        double y1 = npr.Value(nbv-j+1);
+        gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
+        gp_Pnt P = S->Value(UV.X(),UV.Y());
+        SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
+        meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
+        NodesR.SetValue(i+1,j,N);
+        if( i==dr ) UVtmp.Prepend(UV);
+      }
     }
-  } else {
-    list<double>::reverse_iterator itU = params.rbegin();
-    for (int j = nb_segm; j >= 0; j--) // nbPoints internal
-    {
-      double param = *itU;
-      int i = nb_segm - j;
-      gp_Pnt2d p = C2d->Value(param);
-      uvslf[i].x = p.X();
-      uvslf[i].y = p.Y();
-      uvslf[i].param = param;
-      uvslf[i].normParam = (param - l) / (f - l);
-      itU++;
+    for(i=1; i<=UVtmp.Length() && UVR.Length()<nbv-nnn-1; i++) {
+      UVR.Append(UVtmp.Value(i));
+    }
+    // create faces
+    for(i=1; i<=dr; i++) {
+      for(j=1; j<nr; j++) {
+        if(WisF) {
+          SMDS_MeshFace* F =
+            myTool->AddFace(NodesR.Value(i,j), NodesR.Value(i+1,j),
+                            NodesR.Value(i+1,j+1), NodesR.Value(i,j+1));
+          meshDS->SetMeshElementOnShape(F, geomFaceID);
+        }
+        else {
+          SMDS_MeshFace* F =
+            myTool->AddFace(NodesR.Value(i,j), NodesR.Value(i,j+1),
+                            NodesR.Value(i+1,j+1), NodesR.Value(i+1,j));
+          meshDS->SetMeshElementOnShape(F, geomFaceID);
+        }
+      }
+    }
+  }
+  else {
+    // fill UVR using c2d
+    for(i=1; i<npr.Length() && UVR.Length()<nbv-nnn-1; i++) {
+      UVR.Append( gp_UV( uv_er[i].u, uv_er[i].v ));
     }
   }
 
-  return uvslf;
-}
-
-
-//=============================================================================
-/*!
- *  
- */
-//=============================================================================
-
-ostream & StdMeshers_Quadrangle_2D::SaveTo(ostream & save)
-{
-  return save;
-}
-
-//=============================================================================
-/*!
- *  
- */
-//=============================================================================
-
-istream & StdMeshers_Quadrangle_2D::LoadFrom(istream & load)
-{
-  return load;
-}
-
-//=============================================================================
-/*!
- *  
- */
-//=============================================================================
+  // step3: create faces for central domain
+  StdMeshers_Array2OfNode NodesC(1,nb,1,nbv);
+  // add first string using NodesL
+  for(i=1; i<=dl+1; i++)
+    NodesC.SetValue(1,i,NodesL(i,1));
+  for(i=2; i<=nl; i++)
+    NodesC.SetValue(1,dl+i,NodesL(dl+1,i));
+  // add last string using NodesR
+  for(i=1; i<=dr+1; i++)
+    NodesC.SetValue(nb,i,NodesR(i,nr));
+  for(i=1; i<nr; i++)
+    NodesC.SetValue(nb,dr+i+1,NodesR(dr+1,nr-i));
+  // add top nodes (last columns)
+  for(i=dl+2; i<nbh-dr; i++) 
+    NodesC.SetValue(i-dl,nbv,uv_et[i-1].node);
+  // add bottom nodes (first columns)
+  for(i=2; i<nb; i++)
+    NodesC.SetValue(i,1,uv_eb[i-1].node);
+
+  // create and add needed nodes
+  // add linear layers
+  for(i=2; i<nb; i++) {
+    double x0 = npt.Value(dl+i);
+    double x1 = x0;
+    for(j=1; j<nnn; j++) {
+      double y0 = npl.Value(nbv-nnn+j);
+      double y1 = npr.Value(nbv-nnn+j);
+      gp_UV UV = CalcUV(x0, x1, y0, y1, quad, a0, a1, a2, a3);
+      gp_Pnt P = S->Value(UV.X(),UV.Y());
+      SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
+      meshDS->SetNodeOnFace(N, geomFaceID, UV.X(), UV.Y());
+      NodesC.SetValue(i,nbv-nnn+j,N);
+    }
+  }
+  // add diagonal layers
+  //cout<<"UVL.Length()="<<UVL.Length()<<" UVR.Length()="<<UVR.Length()<<endl;
+  //cout<<"Dump UVL:"<<endl;
+  //for(i=1; i<=UVL.Length(); i++) {
+  //  cout<<" ("<<UVL.Value(i).X()<<","<<UVL.Value(i).Y()<<")";
+  //}
+  //cout<<endl;
+  for(i=1; i<nbv-nnn; i++) {
+    double du = UVR.Value(i).X() - UVL.Value(i).X();
+    double dv = UVR.Value(i).Y() - UVL.Value(i).Y();
+    for(j=2; j<nb; j++) {
+      double u = UVL.Value(i).X() + du*npb.Value(j);
+      double v = UVL.Value(i).Y() + dv*npb.Value(j);
+      gp_Pnt P = S->Value(u,v);
+      SMDS_MeshNode* N = meshDS->AddNode(P.X(), P.Y(), P.Z());
+      meshDS->SetNodeOnFace(N, geomFaceID, u, v);
+      NodesC.SetValue(j,i+1,N);
+    }
+  }
+  // create faces
+  for(i=1; i<nb; i++) {
+    for(j=1; j<nbv; j++) {
+      if(WisF) {
+        SMDS_MeshFace* F =
+          myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i+1,j),
+                          NodesC.Value(i+1,j+1), NodesC.Value(i,j+1));
+        meshDS->SetMeshElementOnShape(F, geomFaceID);
+      }
+      else {
+        SMDS_MeshFace* F =
+          myTool->AddFace(NodesC.Value(i,j), NodesC.Value(i,j+1),
+                          NodesC.Value(i+1,j+1), NodesC.Value(i+1,j));
+        meshDS->SetMeshElementOnShape(F, geomFaceID);
+      }
+    }
+  }
 
-ostream & operator <<(ostream & save, StdMeshers_Quadrangle_2D & hyp)
-{
-  return hyp.SaveTo( save );
+  bool isOk = true;
+  return isOk;
 }
 
-//=============================================================================
-/*!
- *  
- */
-//=============================================================================
-
-istream & operator >>(istream & load, StdMeshers_Quadrangle_2D & hyp)
-{
-  return hyp.LoadFrom( load );
-}