Salome HOME
Fix problem with highlighting polyhedrons
[modules/smesh.git] / src / SMESH / SMESH_MesherHelper.cxx
index e1f9709707c252af600fac0d909ea4bc6e5de50e..decd8803a16d4513fce62fa5c6b669123eae5aea 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -32,6 +32,7 @@
 #include "SMDS_IteratorOnIterators.hxx"
 #include "SMDS_VolumeTool.hxx"
 #include "SMESH_Block.hxx"
+#include "SMESH_MeshAlgos.hxx"
 #include "SMESH_ProxyMesh.hxx"
 #include "SMESH_subMesh.hxx"
 
@@ -165,14 +166,14 @@ bool SMESH_MesherHelper::IsQuadraticSubMesh(const TopoDS_Shape& aSh)
             }
             else {
               // fill TLinkNodeMap
-              switch ( e->NbNodes() ) {
-              case 3:
+              switch ( e->NbCornerNodes() ) {
+              case 2:
                 AddTLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(2)); break;
-              case 6:
+              case 3:
                 AddTLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(3));
                 AddTLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(4));
                 AddTLinkNode(e->GetNode(2),e->GetNode(0),e->GetNode(5)); break;
-              case 8:
+              case 4:
                 AddTLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(4));
                 AddTLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(5));
                 AddTLinkNode(e->GetNode(2),e->GetNode(3),e->GetNode(6));
@@ -388,15 +389,26 @@ void SMESH_MesherHelper::AddTLinks(const SMDS_MeshFace* f)
 {
   if ( !f->IsPoly() )
     switch ( f->NbNodes() ) {
+    case 7:
+      // myMapWithCentralNode.insert
+      //   ( make_pair( TBiQuad( f->GetNode(0),f->GetNode(1),f->GetNode(2) ),
+      //                f->GetNode(6)));
+      // break; -- add medium nodes as well
     case 6:
       AddTLinkNode(f->GetNode(0),f->GetNode(1),f->GetNode(3));
       AddTLinkNode(f->GetNode(1),f->GetNode(2),f->GetNode(4));
       AddTLinkNode(f->GetNode(2),f->GetNode(0),f->GetNode(5)); break;
+
+    case 9:
+      // myMapWithCentralNode.insert
+      //   ( make_pair( TBiQuad( f->GetNode(0),f->GetNode(1),f->GetNode(2),f->GetNode(3) ),
+      //                f->GetNode(8)));
+      // break; -- add medium nodes as well
     case 8:
       AddTLinkNode(f->GetNode(0),f->GetNode(1),f->GetNode(4));
       AddTLinkNode(f->GetNode(1),f->GetNode(2),f->GetNode(5));
       AddTLinkNode(f->GetNode(2),f->GetNode(3),f->GetNode(6));
-      AddTLinkNode(f->GetNode(3),f->GetNode(0),f->GetNode(7));
+      AddTLinkNode(f->GetNode(3),f->GetNode(0),f->GetNode(7)); break;
     default:;
     }
 }
@@ -431,6 +443,15 @@ void SMESH_MesherHelper::AddTLinks(const SMDS_MeshVolume* volume)
         else
           addedLinks.erase( it_isNew.first ); // each link encounters only twice
       }
+      if ( vTool.NbNodes() == 27 )
+      {
+        const SMDS_MeshNode* nFCenter = nodes[ vTool.GetCenterNodeIndex( iF )];
+        if ( nFCenter->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE )
+          myMapWithCentralNode.insert
+            ( make_pair( TBiQuad( nodes[ iNodes[0]], nodes[ iNodes[1]],
+                                  nodes[ iNodes[2]], nodes[ iNodes[3]] ),
+                         nFCenter ));
+      }
     }
   }
 }
@@ -513,6 +534,7 @@ gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face&   F,
                                     bool*                check) const
 {
   gp_Pnt2d uv( Precision::Infinite(), Precision::Infinite() );
+
   const SMDS_PositionPtr Pos = n->GetPosition();
   bool uvOK = false;
   if(Pos->GetTypeOfPosition()==SMDS_TOP_FACE)
@@ -797,7 +819,8 @@ double SMESH_MesherHelper::GetNodeU(const TopoDS_Edge&   E,
                                     const SMDS_MeshNode* inEdgeNode,
                                     bool*                check)
 {
-  double param = 0;
+  double param = Precision::Infinite();
+
   const SMDS_PositionPtr pos = n->GetPosition();
   if ( pos->GetTypeOfPosition()==SMDS_TOP_EDGE )
   {
@@ -1043,7 +1066,7 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1,
   // Find an existing central node
 
   TBiQuad keyOfMap(n1,n2,n3,n4);
-  std::map<TBiQuad, SMDS_MeshNode* >::iterator itMapCentralNode;
+  std::map<TBiQuad, const SMDS_MeshNode* >::iterator itMapCentralNode;
   itMapCentralNode = myMapWithCentralNode.find( keyOfMap );
   if ( itMapCentralNode != myMapWithCentralNode.end() ) 
   {
@@ -1053,7 +1076,7 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1,
   // Get type of shape for the new central node
 
   TopAbs_ShapeEnum shapeType = TopAbs_SHAPE;
-  int              shapeID = -1;
+  int              solidID = -1;
   int              faceID = -1;
   TopoDS_Shape     shape;
   TopTools_ListIteratorOfListOfShape it;
@@ -1063,7 +1086,7 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1,
   
   SMESHDS_Mesh* meshDS = GetMeshDS();
   
-  // check if a face lie on a FACE, i.e. its all corner nodes lie either on the FACE or
+  // check if a face lies on a FACE, i.e. its all corner nodes lie either on the FACE or
   // on sub-shapes of the FACE
   if ( GetMesh()->HasShapeToMesh() )
   {
@@ -1074,7 +1097,7 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1,
       if ( shape.IsNull() ) break;
       if ( shape.ShapeType() == TopAbs_SOLID )
       {
-        shapeID   = nodes[i]->getshapeId();
+        solidID   = nodes[i]->getshapeId();
         shapeType = TopAbs_SOLID;
         break;
       }
@@ -1096,7 +1119,7 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1,
       }
     }
   }
-  if ( shapeID < 1 && !faceId2nbNodes.empty() ) // SOLID not found
+  if ( solidID < 1 && !faceId2nbNodes.empty() ) // SOLID not found
   {
     // find ID of the FACE the four corner nodes belong to
     itMapWithIdFace = faceId2nbNodes.begin();
@@ -1121,49 +1144,184 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1,
 
   gp_XY  uvAvg;
   gp_Pnt P;
-  if ( !F.IsNull() )
+  if ( !F.IsNull() && !force3d )
   {
-    if ( !force3d )
-    {
-      uvAvg = calcTFI (0.5, 0.5,
-                       GetNodeUV(F,n1,n3),  GetNodeUV(F,n2,n4),
-                       GetNodeUV(F,n3,n1),  GetNodeUV(F,n4,n2), 
-                       GetNodeUV(F,n12,n3), GetNodeUV(F,n23,n4),
-                       GetNodeUV(F,n34,n2), GetNodeUV(F,n41,n2));
-      TopLoc_Location loc;
-      Handle( Geom_Surface ) S = BRep_Tool::Surface( F, loc );
-      P = S->Value( uvAvg.X(), uvAvg.Y() ).Transformed( loc );
-      centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
-      if ( mySetElemOnShape )
-        meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() );
-      myMapWithCentralNode.insert( std::make_pair( keyOfMap, centralNode ) );
-      return centralNode;
-    }
+    uvAvg = calcTFI (0.5, 0.5,
+                     GetNodeUV(F,n1,n3),  GetNodeUV(F,n2,n4),
+                     GetNodeUV(F,n3,n1),  GetNodeUV(F,n4,n2), 
+                     GetNodeUV(F,n12,n3), GetNodeUV(F,n23,n4),
+                     GetNodeUV(F,n34,n2), GetNodeUV(F,n41,n2));
+    TopLoc_Location loc;
+    Handle( Geom_Surface ) S = BRep_Tool::Surface( F, loc );
+    P = S->Value( uvAvg.X(), uvAvg.Y() ).Transformed( loc );
+    centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
+    // if ( mySetElemOnShape ) node is not elem!
+    meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() );
   }
-
-  P = ( SMESH_TNodeXYZ( n1 ) +
-        SMESH_TNodeXYZ( n2 ) +
-        SMESH_TNodeXYZ( n3 ) +
-        SMESH_TNodeXYZ( n4 ) ) / 4;
-  centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
-
-  if ( mySetElemOnShape )
+  else // ( force3d || F.IsNull() )
   {
-    if ( !F.IsNull() )
+    P = ( SMESH_TNodeXYZ( n1 ) +
+          SMESH_TNodeXYZ( n2 ) +
+          SMESH_TNodeXYZ( n3 ) +
+          SMESH_TNodeXYZ( n4 ) ) / 4;
+    centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
+
+    if ( !F.IsNull() ) // force3d
     {
       uvAvg = (GetNodeUV(F,n1,n3) +
                GetNodeUV(F,n2,n4) +
                GetNodeUV(F,n3,n1) +
                GetNodeUV(F,n4,n2)) / 4;
-      CheckNodeUV( F, centralNode, uvAvg, 2*BRep_Tool::Tolerance( F ), /*force=*/true);
+      //CheckNodeUV( F, centralNode, uvAvg, 2*BRep_Tool::Tolerance( F ), /*force=*/true);
       meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() );
     }
-    else if ( shapeID > 0 )
-      meshDS->SetNodeInVolume( centralNode, shapeID );
-    else if ( myShapeID > 0 )
+    else if ( solidID > 0 )
+    {
+      meshDS->SetNodeInVolume( centralNode, solidID );
+    }
+    else if ( myShapeID > 0 && mySetElemOnShape )
+    {
       meshDS->SetMeshElementOnShape( centralNode, myShapeID );
+    }
+  }
+  myMapWithCentralNode.insert( std::make_pair( keyOfMap, centralNode ) );
+  return centralNode;
+}
+
+//=======================================================================
+//function : GetCentralNode
+//purpose  : Return existing or create a new central node for a
+//           quadratic triangle given its 6 nodes.
+//@param   : force3d - true means node creation in between the given nodes,
+//             else node position is found on a geometrical face if any.
+//=======================================================================
+
+const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1,
+                                                        const SMDS_MeshNode* n2,
+                                                        const SMDS_MeshNode* n3,
+                                                        const SMDS_MeshNode* n12,
+                                                        const SMDS_MeshNode* n23,
+                                                        const SMDS_MeshNode* n31,
+                                                        bool                 force3d)
+{
+  SMDS_MeshNode *centralNode = 0; // central node to return
+
+  // Find an existing central node
+
+  TBiQuad keyOfMap(n1,n2,n3);
+  std::map<TBiQuad, const SMDS_MeshNode* >::iterator itMapCentralNode;
+  itMapCentralNode = myMapWithCentralNode.find( keyOfMap );
+  if ( itMapCentralNode != myMapWithCentralNode.end() ) 
+  {
+    return (*itMapCentralNode).second;
   }
 
+  // Get type of shape for the new central node
+
+  TopAbs_ShapeEnum shapeType = TopAbs_SHAPE;
+  int              solidID = -1;
+  int              faceID = -1;
+  TopoDS_Shape     shape;
+  TopTools_ListIteratorOfListOfShape it;
+
+  std::map< int, int > faceId2nbNodes;
+  std::map< int, int > ::iterator itMapWithIdFace;
+  
+  SMESHDS_Mesh* meshDS = GetMeshDS();
+  
+  // check if a face lies on a FACE, i.e. its all corner nodes lie either on the FACE or
+  // on sub-shapes of the FACE
+  if ( GetMesh()->HasShapeToMesh() )
+  {
+    const SMDS_MeshNode* nodes[] = { n1, n2, n3 };
+    for(int i = 0; i < 3; i++)
+    {
+      shape = GetSubShapeByNode( nodes[i], meshDS );
+      if ( shape.IsNull() ) break;
+      if ( shape.ShapeType() == TopAbs_SOLID )
+      {
+        solidID   = nodes[i]->getshapeId();
+        shapeType = TopAbs_SOLID;
+        break;
+      }
+      if ( shape.ShapeType() == TopAbs_FACE )
+      {
+        faceID          = nodes[i]->getshapeId();
+        itMapWithIdFace = faceId2nbNodes.insert( std::make_pair( faceID, 0 ) ).first;
+        itMapWithIdFace->second++;
+      }
+      else
+      {
+        PShapeIteratorPtr it = GetAncestors(shape, *GetMesh(), TopAbs_FACE );
+        while ( const TopoDS_Shape* face = it->next() )
+        {
+          faceID = meshDS->ShapeToIndex( *face );
+          itMapWithIdFace = faceId2nbNodes.insert( std::make_pair( faceID, 0 ) ).first;
+          itMapWithIdFace->second++;
+        }
+      }
+    }
+  }
+  if ( solidID < 1 && !faceId2nbNodes.empty() ) // SOLID not found
+  {
+    // find ID of the FACE the four corner nodes belong to
+    itMapWithIdFace = faceId2nbNodes.begin();
+    for ( ; itMapWithIdFace != faceId2nbNodes.end(); ++itMapWithIdFace)
+    {
+      if ( itMapWithIdFace->second == 3 ) 
+      {
+        shapeType = TopAbs_FACE;
+        faceID = (*itMapWithIdFace).first;
+        break;
+      }
+    }
+  }
+
+  TopoDS_Face F;
+  if ( shapeType == TopAbs_FACE )
+  {
+    F = TopoDS::Face( meshDS->IndexToShape( faceID ));
+  }
+
+  // Create a node
+
+  gp_XY  uvAvg;
+  gp_Pnt P;
+  if ( !F.IsNull() && !force3d )
+  {
+    uvAvg = ( GetNodeUV(F,n12,n3) +
+              GetNodeUV(F,n23,n1) +
+              GetNodeUV(F,n31,n2) ) / 3.;
+    TopLoc_Location loc;
+    Handle( Geom_Surface ) S = BRep_Tool::Surface( F, loc );
+    P = S->Value( uvAvg.X(), uvAvg.Y() ).Transformed( loc );
+    centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
+    // if ( mySetElemOnShape ) node is not elem!
+    meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() );
+  }
+  else // ( force3d || F.IsNull() )
+  {
+    P = ( SMESH_TNodeXYZ( n12 ) +
+          SMESH_TNodeXYZ( n23 ) +
+          SMESH_TNodeXYZ( n31 ) ) / 3;
+    centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
+
+    if ( !F.IsNull() ) // force3d
+    {
+      uvAvg = ( GetNodeUV(F,n12,n3) +
+                GetNodeUV(F,n23,n1) +
+                GetNodeUV(F,n31,n2) ) / 3.;
+      meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() );
+    }
+    else if ( solidID > 0 )
+    {
+      meshDS->SetNodeInVolume( centralNode, solidID );
+    }
+    else if ( myShapeID > 0 && mySetElemOnShape )
+    {
+      meshDS->SetMeshElementOnShape( centralNode, myShapeID );
+    }
+  }
   myMapWithCentralNode.insert( std::make_pair( keyOfMap, centralNode ) );
   return centralNode;
 }
@@ -1201,6 +1359,9 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1,
   bool uvOK[2] = { false, false };
 
   pair<int, TopAbs_ShapeEnum> pos = GetMediumPos( n1, n2, mySetElemOnShape );
+  // calling GetMediumPos() with useCurSubShape=mySetElemOnShape is OK only for the
+  // case where the lower dim mesh is already constructed, else, nodes on EDGEs are
+  // assigned to FACE, for example.
 
   // get positions of the given nodes on shapes
   if ( pos.second == TopAbs_FACE )
@@ -1247,8 +1408,8 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1,
         gp_XY UV = GetMiddleUV( S, uv[0], uv[1] );
         gp_Pnt P = S->Value( UV.X(), UV.Y() ).Transformed(loc);
         n12 = meshDS->AddNode(P.X(), P.Y(), P.Z());
-        if ( mySetElemOnShape )
-          meshDS->SetNodeOnFace(n12, faceID, UV.X(), UV.Y());
+        // if ( mySetElemOnShape ) node is not elem!
+        meshDS->SetNodeOnFace(n12, faceID, UV.X(), UV.Y());
         myTLinkNodeMap.insert(make_pair(link,n12));
         return n12;
       }
@@ -1272,8 +1433,8 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1,
 
         gp_Pnt P = C->Value( U );
         n12 = meshDS->AddNode(P.X(), P.Y(), P.Z());
-        if ( mySetElemOnShape )
-          meshDS->SetNodeOnEdge(n12, edgeID, U);
+        //if ( mySetElemOnShape ) node is not elem!
+        meshDS->SetNodeOnEdge(n12, edgeID, U);
         myTLinkNodeMap.insert(make_pair(link,n12));
         return n12;
       }
@@ -1286,21 +1447,21 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1,
   double z = ( n1->Z() + n2->Z() )/2.;
   n12 = meshDS->AddNode(x,y,z);
 
-  if ( mySetElemOnShape )
+  //if ( mySetElemOnShape ) node is not elem!
   {
     if ( !F.IsNull() )
     {
       gp_XY UV = ( uv[0] + uv[1] ) / 2.;
-      CheckNodeUV( F, n12, UV, 2*BRep_Tool::Tolerance( F ), /*force=*/true);
+      CheckNodeUV( F, n12, UV, 2 * BRep_Tool::Tolerance( F ), /*force=*/true);
       meshDS->SetNodeOnFace(n12, faceID, UV.X(), UV.Y() );
     }
     else if ( !E.IsNull() )
     {
       double U = ( u[0] + u[1] ) / 2.;
-      CheckNodeU( E, n12, U, 2*BRep_Tool::Tolerance( E ), /*force=*/true);
+      CheckNodeU( E, n12, U, 2 * BRep_Tool::Tolerance( E ), /*force=*/true);
       meshDS->SetNodeOnEdge(n12, edgeID, U);
     }
-    else if ( myShapeID > 0 )
+    else if ( myShapeID > 0 && mySetElemOnShape )
     {
       meshDS->SetMeshElementOnShape(n12, myShapeID);
     }
@@ -1375,9 +1536,13 @@ const SMDS_MeshNode* SMESH_MesherHelper::getMediumNodeOnComposedWire(const SMDS_
     GetMeshDS()->MoveNode( n12, p.X(), p.Y(), p.Z() );
   }
 
-  if ( mySetElemOnShape )
-    GetMeshDS()->SetNodeOnEdge(n12, edges[iOkEdge], u);
-
+  //if ( mySetElemOnShape ) node is not elem!
+  {
+    int edgeID = GetMeshDS()->ShapeToIndex( edges[iOkEdge] );
+    if ( edgeID != n12->getshapeId() )
+      GetMeshDS()->UnSetNodeOnShape( n12 );
+    GetMeshDS()->SetNodeOnEdge(n12, edgeID, u);
+  }
   myTLinkNodeMap.insert( make_pair( SMESH_TLink(n1,n2), n12 ));
 
   return n12;
@@ -1397,7 +1562,7 @@ SMDS_MeshNode* SMESH_MesherHelper::AddNode(double x, double y, double z, int ID,
     node = meshDS->AddNodeWithID( x, y, z, ID );
   else
     node = meshDS->AddNode( x, y, z );
-  if ( mySetElemOnShape && myShapeID > 0 ) {
+  if ( mySetElemOnShape && myShapeID > 0 ) { // node is not elem ?
     switch ( myShape.ShapeType() ) {
     case TopAbs_SOLID:  meshDS->SetNodeInVolume( node, myShapeID);       break;
     case TopAbs_SHELL:  meshDS->SetNodeInVolume( node, myShapeID);       break;
@@ -1470,11 +1635,21 @@ SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1,
     const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
     const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
     const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d);
-
-    if(id)
-      elem = meshDS->AddFaceWithID(n1, n2, n3, n12, n23, n31, id);
+    if(myCreateBiQuadratic)
+    {
+     const SMDS_MeshNode* nCenter = GetCentralNode(n1, n2, n3, n12, n23, n31, force3d);
+     if(id)
+       elem = meshDS->AddFaceWithID(n1, n2, n3, n12, n23, n31, nCenter, id);
+     else
+       elem = meshDS->AddFace(n1, n2, n3, n12, n23, n31, nCenter);
+    }
     else
-      elem = meshDS->AddFace(n1, n2, n3, n12, n23, n31);
+    {
+      if(id)
+        elem = meshDS->AddFaceWithID(n1, n2, n3, n12, n23, n31, id);
+      else
+        elem = meshDS->AddFace(n1, n2, n3, n12, n23, n31);
+    }
   }
   if ( mySetElemOnShape && myShapeID > 0 )
     meshDS->SetMeshElementOnShape( elem, myShapeID );
@@ -2015,7 +2190,6 @@ bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap &            theParam2
   if ( theParam2ColumnMap.empty() )
   {
     // get data of edges for normalization of params
-
     vector< double > length;
     double fullLen = 0;
     list<TopoDS_Edge>::const_iterator edge;
@@ -2039,8 +2213,8 @@ bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap &            theParam2
       map< double, const SMDS_MeshNode*>::iterator u_n = sortedBaseNN.begin();
       if ( theProxyMesh ) // from sortedBaseNN remove nodes not shared by faces of faceSubMesh
       {
-        const SMDS_MeshNode* n1 = sortedBaseNN.begin()->second;
-        const SMDS_MeshNode* n2 = sortedBaseNN.rbegin()->second;
+        const SMDS_MeshNode* n1 = (++sortedBaseNN.begin())->second;
+        const SMDS_MeshNode* n2 = (++sortedBaseNN.rbegin())->second;
         bool allNodesAreProxy = ( n1 != theProxyMesh->GetProxyNode( n1 ) &&
                                   n2 != theProxyMesh->GetProxyNode( n2 ));
         if ( allNodesAreProxy )
@@ -2052,7 +2226,7 @@ bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap &            theParam2
           while ( ++u_n != sortedBaseNN.end() && !isNodeInSubMesh( u_n->second, faceSubMesh ));
           sortedBaseNN.erase( sortedBaseNN.begin(), u_n );
         }
-        else if ( u_n = --sortedBaseNN.end(), !isNodeInSubMesh( u_n->second, faceSubMesh ))
+        if ( u_n = --sortedBaseNN.end(), !isNodeInSubMesh( u_n->second, faceSubMesh ))
         {
           while ( u_n != sortedBaseNN.begin() && !isNodeInSubMesh( (--u_n)->second, faceSubMesh ));
           sortedBaseNN.erase( ++u_n, sortedBaseNN.end() );
@@ -2100,7 +2274,7 @@ bool SMESH_MesherHelper::LoadNodeColumns(TParam2ColumnMap &            theParam2
     const SMDS_MeshNode *n2 = nCol2[ prevNbRows-1 ];
     // find face sharing node n1 and n2 and belonging to faceSubMesh
     while ( const SMDS_MeshElement* face =
-            SMESH_MeshEditor::FindFaceInSet( n1, n2, emptySet, avoidSet, &i1, &i2))
+            SMESH_MeshAlgos::FindFaceInSet( n1, n2, emptySet, avoidSet, &i1, &i2))
     {
       if ( faceSubMesh->Contains( face ))
       {
@@ -2169,7 +2343,7 @@ bool SMESH_MesherHelper::IsStructured( SMESH_subMesh* faceSM )
   list< int > nbEdgesInWires;
   int nbWires = SMESH_Block::GetOrderedEdges( TopoDS::Face( faceSM->GetSubShape() ),
                                               edges, nbEdgesInWires );
-  if ( nbWires != 1 || nbEdgesInWires.front() != 4 )
+  if ( nbWires != 1 /*|| nbEdgesInWires.front() != 4*/ ) // allow composite sides
     return false;
 
   // algo: find corners of a structure and then analyze nb of faces and
@@ -3693,7 +3867,7 @@ namespace { // Structures used by FixQuadraticElements()
             if ( nOnFace && nOnEdge.size() == 2 )
             {
               theHelper.AddTLinks( static_cast< const SMDS_MeshFace* > ( f ));
-              if ( !SMESH_Algo::FaceNormal( f, faceNorm, /*normalized=*/false ))
+              if ( !SMESH_MeshAlgos::FaceNormal( f, faceNorm, /*normalized=*/false ))
                 continue;
               gp_XYZ edgeDir  = SMESH_TNodeXYZ( nOnEdge[0] ) - SMESH_TNodeXYZ( nOnEdge[1] );
               gp_XYZ edgeNorm = faceNorm ^ edgeDir;
@@ -3783,7 +3957,7 @@ namespace { // Structures used by FixQuadraticElements()
 
       // a seacher to check if a volume is close to a concave face
       std::auto_ptr< SMESH_ElementSearcher > faceSearcher
-        ( SMESH_MeshEditor( theHelper.GetMesh() ).GetElementSearcher( faceIter ));
+        ( SMESH_MeshAlgos::GetElementSearcher( *theHelper.GetMeshDS(), faceIter ));
 
       // classifier
       //BRepClass3d_SolidClassifier solidClassifier( shape );
@@ -3857,7 +4031,7 @@ namespace { // Structures used by FixQuadraticElements()
             // to nInSolid than the link middle
             bool isDistorted = false;
             SMDS_FaceOfNodes onFaceTria( nOnFace[0], nOnFace[1], nOnFace[2] );
-            if ( !SMESH_Algo::FaceNormal( &onFaceTria, faceNorm, /*normalized=*/false ))
+            if ( !SMESH_MeshAlgos::FaceNormal( &onFaceTria, faceNorm, /*normalized=*/false ))
               continue;
             theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* > ( vol ));
             vector< pair< SMESH_TLink, const SMDS_MeshNode* > > links;
@@ -4294,9 +4468,10 @@ void SMESH_MesherHelper::FixQuadraticElements(SMESH_ComputeErrorPtr& compError,
   // 4. Move nodes
   // -------------
 
-  TIDSortedElemSet biQuadQuas, triQuadHexa;
+  TIDSortedElemSet biQuadQuas, biQuadTris, triQuadHexa;
   const SMDS_MeshElement *biQuadQua, *triQuadHex;
   const bool toFixCentralNodes = ( myMesh->NbBiQuadQuadrangles() +
+                                   myMesh->NbBiQuadTriangles() +
                                    myMesh->NbTriQuadraticHexas() );
 
   for ( pLink = links.begin(); pLink != links.end(); ++pLink ) {
@@ -4313,23 +4488,22 @@ void SMESH_MesherHelper::FixQuadraticElements(SMESH_ComputeErrorPtr& compError,
         while ( eIt->more() )
         {
           const SMDS_MeshElement* e = eIt->next();
-          SMDSAbs_EntityType   type = e->GetEntityType();
-          if ( type == SMDSEntity_BiQuad_Quadrangle )
-            biQuadQuas.insert( e );
-          else if ( type == SMDSEntity_TriQuad_Hexa )
-            triQuadHexa.insert( e );
+          switch( e->GetEntityType() ) {
+          case SMDSEntity_BiQuad_Quadrangle: biQuadQuas.insert( e ); break;
+          case SMDSEntity_BiQuad_Triangle:   biQuadTris.insert( e ); break;
+          case SMDSEntity_TriQuad_Hexa:      triQuadHexa.insert( e ); break;
+          default:;
+          }
         }
       }
     }
   }
-
   // Fix positions of central nodes of bi-tri-quadratic elements
 
   // treat bi-quad quadrangles
   {
     vector< const SMDS_MeshNode* > nodes( 9 );
     gp_XY uv[ 9 ];
-    //TIDSortedNodeSet checkedNodes;
     TIDSortedElemSet::iterator quadIt = biQuadQuas.begin();
     for ( ; quadIt != biQuadQuas.end(); ++quadIt )
     {
@@ -4352,13 +4526,46 @@ void SMESH_MesherHelper::FixQuadraticElements(SMESH_ComputeErrorPtr& compError,
         if ( i > 3 && nodes[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
           CheckNodeUV( F, nodes[i], uv[ i ], 2*tol, /*force=*/true );
       }
-      // move central node
+      // move the central node
       gp_XY uvCent = calcTFI (0.5, 0.5, uv[0],uv[1],uv[2],uv[3],uv[4],uv[5],uv[6],uv[7] );
       gp_Pnt p = surf->Value( uvCent.X(), uvCent.Y() ).Transformed( loc );
       GetMeshDS()->MoveNode( nodes[8], p.X(), p.Y(), p.Z());
     }
   }
 
+  // treat bi-quad triangles
+  {
+    const SMDS_MeshNode* nodes[3]; // medium nodes
+    gp_XY uv[ 3 ]; // UV of medium nodes
+    TIDSortedElemSet::iterator triIt = biQuadTris.begin();
+    for ( ; triIt != biQuadTris.end(); ++triIt )
+    {
+      const SMDS_MeshElement* tria = *triIt;
+      // nodes
+      for ( int i = 3; i < 6; ++i )
+        nodes[ i-3 ] = tria->GetNode( i );
+      // FACE
+      const TopoDS_Shape& S = GetMeshDS()->IndexToShape( tria->getshapeId() );
+      if ( S.IsNull() || S.ShapeType() != TopAbs_FACE ) continue;
+      const TopoDS_Face& F = TopoDS::Face( S );
+      Handle( Geom_Surface ) surf = BRep_Tool::Surface( F, loc );
+      const double tol = BRep_Tool::Tolerance( F );
+      // UV
+      for ( int i = 0; i < 3; ++i )
+      {
+        uv[ i ] = GetNodeUV( F, nodes[i], nodes[(i+1)%3], &checkUV );
+        // as this method is used after mesh generation, UV of nodes is not
+        // updated according to bending links, so we update 
+        if ( nodes[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
+          CheckNodeUV( F, nodes[i], uv[ i ], 2*tol, /*force=*/true );
+      }
+      // move the central node
+      gp_XY uvCent = ( uv[0] + uv[1] + uv[2] ) / 3.;
+      gp_Pnt p = surf->Value( uvCent.X(), uvCent.Y() ).Transformed( loc );
+      GetMeshDS()->MoveNode( tria->GetNode(6), p.X(), p.Y(), p.Z() );
+    }
+  }
+
   // treat tri-quadratic hexahedra
   {
     SMDS_VolumeTool volExp;