Salome HOME
Bug 0020034: [CEA 282] crash in SALOME_Session_Server after SMESH computation.
[modules/smesh.git] / src / SMESH / SMESH_Pattern.cxx
index 44396d2afbd43cc0d247785edf3431f7148ea1a8..292af478f4181ff6480e151f861608b6e53304a1 100644 (file)
 #include <Bnd_Box.hxx>
 #include <Bnd_Box2d.hxx>
 #include <ElSLib.hxx>
+#include <Extrema_ExtPC.hxx>
 #include <Extrema_GenExtPS.hxx>
 #include <Extrema_POnSurf.hxx>
 #include <Geom2d_Curve.hxx>
 #include <GeomAdaptor_Surface.hxx>
 #include <Geom_Curve.hxx>
 #include <Geom_Surface.hxx>
-#include <IntAna2d_AnaIntersection.hxx>
 #include <TopAbs_ShapeEnum.hxx>
 #include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
 #include <TopLoc_Location.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Face.hxx>
@@ -47,7 +49,6 @@
 #include <TopoDS_Shell.hxx>
 #include <TopoDS_Vertex.hxx>
 #include <TopoDS_Wire.hxx>
-#include <TopTools_ListIteratorOfListOfShape.hxx>
 #include <gp_Ax2.hxx>
 #include <gp_Lin2d.hxx>
 #include <gp_Pnt2d.hxx>
@@ -248,7 +249,7 @@ bool SMESH_Pattern::Load (const char* theFileContents)
     MESSAGE(" Too few points ");
     return setErrorCode( ERR_READ_TOO_FEW_POINTS );
   }
-    
+
   // read the rest points
   int iPoint;
   for ( iPoint = 1; iPoint < nbPoints; iPoint++ )
@@ -395,7 +396,7 @@ bool SMESH_Pattern::Save (ostream& theFile)
   }
 
   theFile << endl;
-  
+
   return setErrorCode( ERR_OK );
 }
 
@@ -518,7 +519,7 @@ bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
 
   TopoDS_Face face = TopoDS::Face( theFace.Oriented( TopAbs_FORWARD ));
 
-  // check that face is not closed
+  // check if face is closed
   bool isClosed = helper.HasSeam();
   TopoDS_Vertex bidon;
   list<TopoDS_Edge> eList;
@@ -630,11 +631,15 @@ bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
 
     // vertices
     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) {
+      int nbV = myShapeIDMap.Extent();
       myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
-      if ( BRep_Tool::IsClosed( *elIt, theFace ) )
-        myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));
-      SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt );
-      if ( eSubMesh )
+      bool added = ( nbV < myShapeIDMap.Extent() );
+      if ( !added ) { // vertex encountered twice
+        // a seam vertex have two corresponding key points
+        myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ).Reversed());
+        ++nbNodes;
+      }
+      if ( SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt ))
         nbNodes += eSubMesh->NbNodes() + 1;
     }
     // edges
@@ -652,9 +657,7 @@ bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
       TopoDS_Edge & edge = *elIt;
       list< TPoint* > & ePoints = getShapePoints( edge );
       double f, l;
-      Handle(Geom2d_Curve) C2d;
-      if ( !theProject )
-        C2d = BRep_Tool::CurveOnSurface( edge, face, f, l );
+      Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( edge, face, f, l );
       bool isForward = ( edge.Orientation() == TopAbs_FORWARD );
 
       TopoDS_Shape v1 = TopExp::FirstVertex( edge, true ); // always FORWARD
@@ -664,18 +667,18 @@ bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
       v2.Reverse();
 
       // on closed face we must have REVERSED some of seam vertices
-      bool isSeam = helper.IsSeamShape( edge );
       if ( isClosed ) {
-        if ( isSeam ) { // reverse on reversed SEAM edge
-          if ( !isForward ) {
+        if ( helper.IsSeamShape( edge ) ) {
+          if ( helper.IsRealSeam( edge ) && !isForward ) {
+            // reverse on reversed SEAM edge
             v1.Reverse();
             v2.Reverse();
           }
         }
-        else { // on CLOSED edge
+        else { // on CLOSED edge (i.e. having one vertex with different orienations)
           for ( int is2 = 0; is2 < 2; ++is2 ) {
             TopoDS_Shape & v = is2 ? v2 : v1;
-            if ( helper.IsSeamShape( v ) ) {
+            if ( helper.IsRealSeam( v ) ) {
               // reverse or not depending on orientation of adjacent seam
               TopoDS_Edge seam;
               list<TopoDS_Edge>::iterator eIt2 = elIt;
@@ -730,9 +733,33 @@ bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
           const SMDS_EdgePosition* epos =
             static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
           double u = epos->GetUParameter();
-          paramNodeMap.insert( TParamNodeMap::value_type( u, node ));
+          paramNodeMap.insert( make_pair( u, node ));
+        }
+        if ( paramNodeMap.size() != eSubMesh->NbNodes() ) {
+          // wrong U on edge, project
+          Extrema_ExtPC proj;
+          BRepAdaptor_Curve aCurve( edge );
+          proj.Initialize( aCurve, f, l );
+          paramNodeMap.clear();
+          nIt = eSubMesh->GetNodes();
+          for ( int iNode = 0; nIt->more(); ++iNode ) {
+            const SMDS_MeshNode* node = smdsNode( nIt->next() );
+            proj.Perform( gp_Pnt( node->X(), node->Y(), node->Z()));
+            double u = 0;
+            if ( proj.IsDone() ) {
+              for ( int i = 1, nb = proj.NbExt(); i <= nb; ++i )
+                if ( proj.IsMin( i )) {
+                  u = proj.Point( i ).Parameter();
+                  break;
+                }
+            } else {
+              u = isForward ? iNode : eSubMesh->NbNodes() - iNode;
+            }
+            paramNodeMap.insert( make_pair( u, node ));
+          }
         }
         // put U in [0,1] so that the first key-point has U==0
+        bool isSeam = helper.IsRealSeam( edge );
         double du = l - f;
         TParamNodeMap::iterator         unIt  = paramNodeMap.begin();
         TParamNodeMap::reverse_iterator unRIt = paramNodeMap.rbegin();
@@ -827,6 +854,7 @@ bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
         p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
       }
       // load elements
+      TNodePointIDMap::iterator n_id, not_found = closeNodePointIDMap.end();
       SMDS_ElemIteratorPtr elemIt = fSubMesh->GetElements();
       while ( elemIt->more() )
       {
@@ -840,10 +868,8 @@ bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
           const SMDS_MeshNode* node = smdsNode( nIt->next() );
           iPoint = nodePointIDMap[ node ]; // point index of interest
           // for a node on a seam edge there are two points
-          TNodePointIDMap::iterator n_id = closeNodePointIDMap.end();
-          if ( helper.IsSeamShape( node->GetPosition()->GetShapeId() ))
-            n_id = closeNodePointIDMap.find( node );
-          if ( n_id != closeNodePointIDMap.end() )
+          if ( helper.IsRealSeam( node->GetPosition()->GetShapeId() ) &&
+               ( n_id = closeNodePointIDMap.find( node )) != not_found )
           {
             TPoint & p1 = myPoints[ iPoint ];
             TPoint & p2 = myPoints[ n_id->second ];
@@ -962,13 +988,20 @@ static bool intersectIsolines(const gp_XY& uv11, const gp_XY& uv12, const double
   gp_XY loc1 = uv11 * ( 1 - r1 ) + uv12 * r1;
   gp_XY loc2 = uv21 * ( 1 - r2 ) + uv22 * r2;
   resUV = 0.5 * ( loc1 + loc2 );
-  isDeformed = ( loc1 - loc2 ).SquareModulus() > 1e-8;
+  //isDeformed = ( loc1 - loc2 ).SquareModulus() > 1e-8;
+  // SKL 26.07.2007 for NPAL16567
+  double d1 = (uv11-uv12).Modulus();
+  double d2 = (uv21-uv22).Modulus();
+  // double delta = d1*d2*1e-6; PAL17233
+  double delta = min( d1, d2 ) / 10.;
+  isDeformed = ( loc1 - loc2 ).SquareModulus() > delta * delta;
+
 //   double len1 = ( uv11 - uv12 ).Modulus();
 //   double len2 = ( uv21 - uv22 ).Modulus();
 //   resUV = loc1 * len2 / ( len1 + len2 ) + loc2 * len1 / ( len1 + len2 );
 //  return true;
 
-  
+
 //   gp_Lin2d line1( uv11, uv12 - uv11 );
 //   gp_Lin2d line2( uv21, uv22 - uv21 );
 //   double angle = Abs( line1.Angle( line2 ) );
@@ -982,9 +1015,13 @@ static bool intersectIsolines(const gp_XY& uv11, const gp_XY& uv12, const double
 //   inter.Perform( line1, line2 );
 //   interUV = inter.Point(1).Value();
 //   resUV += interUV.XY();
-  
+
 //   resUV /= 2.;
 //     }
+  if ( isDeformed ) {
+    MESSAGE("intersectIsolines(), d1 = " << d1 << ", d2 = " << d2 << ", delta = " << delta <<
+            ", " << (loc1 - loc2).SquareModulus() << " > " << delta * delta);
+  }
   return true;
 }
 
@@ -1018,7 +1055,7 @@ bool SMESH_Pattern::compUVByIsoIntersection (const list< list< TPoint* > >& theB
       const list< TPoint* > & bndPoints = * bndIt;
       TPoint* prevP = bndPoints.back(); // this is the first point
       list< TPoint* >::const_iterator pIt = bndPoints.begin();
-      bool coincPrev = false; 
+      bool coincPrev = false;
       // loop on the edge-points
       for ( ; pIt != bndPoints.end(); pIt++ )
       {
@@ -1283,7 +1320,7 @@ static bool checkQuads (const TIsoNode* node,
       gp_XY uv1, uv2 = node->myUV;
       for ( i = isTriangle ? 2 : 0; i < 3; i++ ) // mark not computed vectors
         if ( wasOk[i] )
-          moveVec[ i ].SetCoord( 1, 2e100); // not use this vector 
+          moveVec[ i ].SetCoord( 1, 2e100); // not use this vector
       while ( !isOldOk ) {
         // find the least moveVec
         int i, iMin = 4;
@@ -1384,7 +1421,7 @@ bool SMESH_Pattern::
   compUVByElasticIsolines(const list< list< TPoint* > >& theBndPoints,
                           const list< TPoint* >&         thePntToCompute)
 {
-  //return false;
+  return false; // PAL17233
 //cout << "============================== KEY POINTS =============================="<<endl;
 //   list< int >::iterator kpIt = myKeyPointIDs.begin();
 //   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ ) {
@@ -1714,7 +1751,7 @@ bool SMESH_Pattern::
           aNorm[1-iDir].Normalize();
           double r = Abs ( ratio[iDir] - 0.5 ) * 2.0; // [0,1] - distance from the middle
           r *= r;
-          
+
           node->myDir[iDir] = //aTgt[iDir];
             aNorm[1-iDir] * r + aTgt[iDir] * ( 1. - r );
         }
@@ -1915,7 +1952,7 @@ bool SMESH_Pattern::
     }
     internNodes.push_back( node );
   }
-  
+
   // Move nodes
 
   static int maxNbIter = 100;
@@ -1927,7 +1964,7 @@ bool SMESH_Pattern::
   int nbNodeMove = 0;
   if ( !useNbMoveNode )
     maxNbIter = ( maxNbIter < 0 ) ? 100 : -1;
-#endif    
+#endif
   double maxMove;
   int nbIter = 0;
   do {
@@ -2024,8 +2061,7 @@ bool SMESH_Pattern::
       }
     }
   }
-      
-    
+
   return true;
 }
 
@@ -2051,7 +2087,7 @@ double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstE
   int eID = theFirstEdgeID;
   for ( iE = 0; iE < nbEdges; iE++ )
     maxNbPnt = Max ( maxNbPnt, getShapePoints( eID++ ).size() );
-  
+
   // compute bnd boxes
   TopoDS_Face face = TopoDS::Face( myShape );
   Bnd_Box2d bndBox, eBndBox;
@@ -2079,8 +2115,8 @@ double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstE
   bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
   eBndBox.Get( eMinPar[0], eMinPar[1], eMaxPar[0], eMaxPar[1] );
 #ifdef DBG_SETFIRSTEDGE
-  cout << "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
-    << eMinPar[1] << " - " << eMaxPar[1] << endl;
+  MESSAGE ( "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
+         << eMinPar[1] << " - " << eMaxPar[1] );
 #endif
   for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
   {
@@ -2106,7 +2142,7 @@ double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstE
   for ( iE = 0 ; iE < nbEdges; iE++ )
   {
 #ifdef DBG_SETFIRSTEDGE
-    cout << " VARIANT " << iE << endl;
+    MESSAGE ( " VARIANT " << iE );
 #endif
     // evaluate the distance between UV computed by the 2 methods:
     // by isos intersection ( myXYZ ) and by edge p-curves ( myUV )
@@ -2120,13 +2156,13 @@ double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstE
         TPoint* p = (*pIt);
         dist += ( p->myUV - gp_XY( p->myXYZ.X(), p->myXYZ.Y() )).SquareModulus();
 #ifdef DBG_SETFIRSTEDGE
-        cout << " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
-          p->myUV.X() << ", " << p->myUV.Y() << ") " << endl;
+        MESSAGE ( " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
+                  p->myUV.X() << ", " << p->myUV.Y() << ") " );
 #endif
       }
     }
 #ifdef DBG_SETFIRSTEDGE
-    cout << "dist -- " << dist << endl;
+    MESSAGE ( "dist -- " << dist );
 #endif
     if ( dist < minDist ) {
       minDist = dist;
@@ -2246,7 +2282,7 @@ bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList &                theWire
     bndIndWirePosMap.insert( TIntWirePosMap::value_type( bIndex, wlIt ));
   }
 
-  // Treat each wire  
+  // Treat each wire
 
   TIntWirePosMap::iterator bIndWPosIt = bndIndWirePosMap.begin();
   eID = theFirstEdgeID;
@@ -2257,7 +2293,7 @@ bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList &                theWire
 
     // choose the best first edge of a wire
     setFirstEdge( wire, eID );
-    
+
     // compute eventual UV and fill theEdgesPointsList
     theEdgesPointsList.push_back( list< TPoint* >() );
     list< TPoint* > & edgesPoints = theEdgesPointsList.back();
@@ -2319,8 +2355,24 @@ bool SMESH_Pattern::Apply (const TopoDS_Face&   theFace,
   list<TopoDS_Edge>::iterator elIt = eList.begin();
   for ( ; elIt != eList.end(); elIt++ ) {
     myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
-    if ( BRep_Tool::IsClosed( *elIt, theFace ) )
-      myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));
+    bool isClosed1 = BRep_Tool::IsClosed( *elIt, theFace );
+    // BEGIN: jfa for bug 0019943
+    if (isClosed1) {
+      isClosed1 = false;
+      for (TopExp_Explorer expw (theFace, TopAbs_WIRE); expw.More() && !isClosed1; expw.Next()) {
+        const TopoDS_Wire& wire = TopoDS::Wire(expw.Current());
+        int nbe = 0;
+        for (BRepTools_WireExplorer we (wire, theFace); we.More() && !isClosed1; we.Next()) {
+          if (we.Current().IsSame(*elIt)) {
+            nbe++;
+            if (nbe == 2) isClosed1 = true;
+          }
+        }
+      }
+    }
+    // END: jfa for bug 0019943
+    if (isClosed1)
+      myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));// vertex orienation is REVERSED
   }
   int nbVertices = myShapeIDMap.Extent();
 
@@ -2329,7 +2381,7 @@ bool SMESH_Pattern::Apply (const TopoDS_Face&   theFace,
 
   myShapeIDMap.Add( face );
 
-  if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent()/* + nbSeamShapes*/ ) {
+  if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent() ) {
     MESSAGE( myShapeIDToPointsMap.size() <<" != " << myShapeIDMap.Extent());
     return setErrorCode( ERR_APPLF_INTERNAL_EEROR );
   }
@@ -2426,7 +2478,7 @@ bool SMESH_Pattern::Apply (const TopoDS_Face&   theFace,
     }
 
     // find boundary - wire correspondence for several wires of same size
-    
+
     id1 = nbVertices + nbEdgesInOuterWire + 1;
     wlIt = wireList.begin();
     while ( wlIt != wireList.end() )
@@ -2446,7 +2498,7 @@ bool SMESH_Pattern::Apply (const TopoDS_Face&   theFace,
     }
 
     // add well-ordered edges to eList
-    
+
     for ( wlIt = wireList.begin(); wlIt != wireList.end(); wlIt++ )
     {
       list< TopoDS_Edge >& wire = (*wlIt);
@@ -2461,7 +2513,7 @@ bool SMESH_Pattern::Apply (const TopoDS_Face&   theFace,
     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
       myShapeIDMap.Add( *elIt );
     myShapeIDMap.Add( face );
-    
+
   } // there are inner wires
 
   // Compute XYZ of on-edge points
@@ -2611,7 +2663,7 @@ bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace,
   {
     gp_XYZ& xyz1 = *xyzIt++;
     gp_XYZ& xyz2 = ( xyzIt != xyzList.end() ) ? *xyzIt : xyzList.front();
-    
+
     list< TPoint* > & ePoints = getShapePoints( iSub );
     ePoints.back()->myInitU = 1.0;
     list< TPoint* >::const_iterator pIt = ++ePoints.begin();
@@ -2659,6 +2711,162 @@ bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace,
   return setErrorCode( ERR_OK );
 }
 
+//=======================================================================
+//function : Apply
+//purpose  : Compute nodes coordinates applying
+//           the loaded pattern to <theFace>. The first key-point
+//           will be mapped into <theNodeIndexOnKeyPoint1>-th node
+//=======================================================================
+
+bool SMESH_Pattern::Apply (SMESH_Mesh*          theMesh,
+                           const SMDS_MeshFace* theFace,
+                           const TopoDS_Shape&  theSurface,
+                           const int            theNodeIndexOnKeyPoint1,
+                           const bool           theReverse)
+{
+//  MESSAGE(" ::Apply(MeshFace) " );
+  if ( theSurface.IsNull() || theSurface.ShapeType() != TopAbs_FACE ) {
+    return Apply( theFace, theNodeIndexOnKeyPoint1, theReverse);
+  }
+  const TopoDS_Face& face = TopoDS::Face( theSurface );
+  TopLoc_Location loc;
+  Handle(Geom_Surface) surface = BRep_Tool::Surface( face, loc );
+  const gp_Trsf & aTrsf = loc.Transformation();
+
+  if ( !IsLoaded() ) {
+    MESSAGE( "Pattern not loaded" );
+    return setErrorCode( ERR_APPL_NOT_LOADED );
+  }
+
+  // check nb of nodes
+  if (theFace->NbNodes() != myNbKeyPntInBoundary.front() ) {
+    MESSAGE( myKeyPointIDs.size() << " != " << theFace->NbNodes() );
+    return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
+  }
+
+  // find points on edges, it fills myNbKeyPntInBoundary
+  if ( !findBoundaryPoints() )
+    return false;
+
+  // check that there are no holes in a pattern
+  if (myNbKeyPntInBoundary.size() > 1 ) {
+    return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
+  }
+
+  // Define the nodes order
+
+  list< const SMDS_MeshNode* > nodes;
+  list< const SMDS_MeshNode* >::iterator n = nodes.end();
+  SMDS_ElemIteratorPtr noIt = theFace->nodesIterator();
+  int iSub = 0;
+  while ( noIt->more() ) {
+    const SMDS_MeshNode* node = smdsNode( noIt->next() );
+    nodes.push_back( node );
+    if ( iSub++ == theNodeIndexOnKeyPoint1 )
+      n = --nodes.end();
+  }
+  if ( n != nodes.end() ) {
+    if ( theReverse ) {
+      if ( n != --nodes.end() )
+        nodes.splice( nodes.begin(), nodes, ++n, nodes.end() );
+      nodes.reverse();
+    }
+    else if ( n != nodes.begin() )
+      nodes.splice( nodes.end(), nodes, nodes.begin(), n );
+  }
+
+  // find a node not on a seam edge, if necessary
+  SMESH_MesherHelper helper( *theMesh );
+  helper.SetSubShape( theSurface );
+  const SMDS_MeshNode* inFaceNode = 0;
+  if ( helper.GetNodeUVneedInFaceNode() )
+  {
+    SMESH_MeshEditor editor( theMesh );
+    for ( n = nodes.begin(); ( !inFaceNode && n != nodes.end()); ++n ) {
+      int shapeID = editor.FindShape( *n );
+      if ( !shapeID )
+        return Apply( theFace, theNodeIndexOnKeyPoint1, theReverse);
+      if ( !helper.IsSeamShape( shapeID ))
+        inFaceNode = *n;
+    }
+  }
+
+  // Set UV of key-points (i.e. of nodes of theFace )
+  vector< gp_XY > keyUV( theFace->NbNodes() );
+  myOrderedNodes.resize( theFace->NbNodes() );
+  for ( iSub = 1, n = nodes.begin(); n != nodes.end(); ++n, ++iSub )
+  {
+    TPoint* p = getShapePoints( iSub ).front();
+    p->myUV  = helper.GetNodeUV( face, *n, inFaceNode );
+    p->myXYZ = gp_XYZ( (*n)->X(), (*n)->Y(), (*n)->Z() );
+
+    keyUV[ iSub-1 ] = p->myUV;
+    myOrderedNodes[ iSub-1 ] = *n;
+  }
+
+  // points on edges to be used for UV computation of in-face points
+  list< list< TPoint* > > edgesPointsList;
+  edgesPointsList.push_back( list< TPoint* >() );
+  list< TPoint* > * edgesPoints = & edgesPointsList.back();
+  list< TPoint* >::iterator pIt;
+
+  // compute UV and XYZ of points on edges
+
+  for ( int i = 0; i < myOrderedNodes.size(); ++i, ++iSub )
+  {
+    gp_XY& uv1 = keyUV[ i ];
+    gp_XY& uv2 = ( i+1 < keyUV.size() ) ? keyUV[ i+1 ] : keyUV[ 0 ];
+
+    list< TPoint* > & ePoints = getShapePoints( iSub );
+    ePoints.back()->myInitU = 1.0;
+    list< TPoint* >::const_iterator pIt = ++ePoints.begin();
+    while ( *pIt != ePoints.back() )
+    {
+      TPoint* p = *pIt++;
+      p->myUV = uv1 * ( 1 - p->myInitU ) + uv2 * p->myInitU;
+      p->myXYZ = surface->Value( p->myUV.X(), p->myUV.Y() );
+      if ( !loc.IsIdentity() )
+        aTrsf.Transforms( p->myXYZ.ChangeCoord() );
+    }
+    // collect on-edge points (excluding the last one)
+    edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
+  }
+
+  // Compute UV and XYZ of in-face points
+
+  // try to use a simple algo to compute UV
+  list< TPoint* > & fPoints = getShapePoints( iSub );
+  bool isDeformed = false;
+  for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
+    if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
+                                  (*pIt)->myUV, isDeformed )) {
+      MESSAGE("cant Apply(face)");
+      return false;
+    }
+  // try to use a complex algo if it is a difficult case
+  if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
+  {
+    for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
+      if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
+                                    (*pIt)->myUV, isDeformed )) {
+        MESSAGE("cant Apply(face)");
+        return false;
+      }
+  }
+
+  for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
+  {
+    TPoint * point = *pIt;
+    point->myXYZ = surface->Value( point->myUV.X(), point->myUV.Y() );
+    if ( !loc.IsIdentity() )
+      aTrsf.Transforms( point->myXYZ.ChangeCoord() );
+  }
+
+  myIsComputed = true;
+
+  return setErrorCode( ERR_OK );
+}
+
 //=======================================================================
 //function : undefinedXYZ
 //purpose  : 
@@ -2687,7 +2895,8 @@ inline static bool isDefined(const gp_XYZ& theXYZ)
 //           will be mapped into <theNodeIndexOnKeyPoint1>-th node
 //=======================================================================
 
-bool SMESH_Pattern::Apply (std::set<const SMDS_MeshFace*>& theFaces,
+bool SMESH_Pattern::Apply (SMESH_Mesh*                     theMesh,
+                           std::set<const SMDS_MeshFace*>& theFaces,
                            const int                       theNodeIndexOnKeyPoint1,
                            const bool                      theReverse)
 {
@@ -2725,11 +2934,29 @@ bool SMESH_Pattern::Apply (std::set<const SMDS_MeshFace*>& theFaces,
 
   int ind1 = 0; // lowest point index for a face
 
+  // meshed geometry
+  TopoDS_Shape shape;
+//   int          shapeID = 0;
+//   SMESH_MeshEditor editor( theMesh );
+
   // apply to each face in theFaces set
   set<const SMDS_MeshFace*>::iterator face = theFaces.begin();
   for ( ; face != theFaces.end(); ++face )
   {
-    if ( !Apply( *face, theNodeIndexOnKeyPoint1, theReverse )) {
+//     int curShapeId = editor.FindShape( *face );
+//     if ( curShapeId != shapeID ) {
+//       if ( curShapeId )
+//         shape = theMesh->GetMeshDS()->IndexToShape( curShapeId );
+//       else
+//         shape.Nullify();
+//       shapeID = curShapeId;
+//     }
+    bool ok;
+    if ( shape.IsNull() )
+      ok = Apply( *face, theNodeIndexOnKeyPoint1, theReverse );
+    else
+      ok = Apply( theMesh, *face, shape, theNodeIndexOnKeyPoint1, theReverse );
+    if ( !ok ) {
       MESSAGE( "Failed on " << *face );
       continue;
     }
@@ -3491,7 +3718,7 @@ bool SMESH_Pattern::
       bndId = nn_IdList->second.front().front();
       ids.insert( bndId );
     }
-    else 
+    else
       myXYZIdToNodeMap.insert( make_pair( bndId, theBndNodes[ iN ] ));
     faceDef.push_back( bndId );
     // add ids on a link
@@ -3577,11 +3804,9 @@ static bool clearSubMesh( SMESH_Mesh*         theMesh,
   bool removed = false;
   if ( SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( theShape ))
   {
-    if ( aSubMesh->GetSubMeshDS() ) {
-      removed =
-        aSubMesh->GetSubMeshDS()->NbElements() || aSubMesh->GetSubMeshDS()->NbNodes();
+    removed = !aSubMesh->IsEmpty();
+    if ( removed )
       aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
-    }
   }
   else {
     SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
@@ -3759,7 +3984,7 @@ void SMESH_Pattern::createElements(SMESH_Mesh*                            theMes
                                    const vector<const SMDS_MeshElement*>& theElements)
 {
   SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
-  SMESH_MeshEditor editor( theMesh ); 
+  SMESH_MeshEditor editor( theMesh );
 
   bool onMeshElements = !theElements.empty();
 
@@ -3905,7 +4130,7 @@ void SMESH_Pattern::createElements(SMESH_Mesh*                            theMes
 
   SMESH_subMesh * subMesh;
   if ( !myShape.IsNull() ) {
-    subMesh = theMesh->GetSubMeshContaining( myShape );
+    subMesh = theMesh->GetSubMesh( myShape );
     if ( subMesh )
       subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
   }
@@ -3975,7 +4200,7 @@ void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
     if ( nbBoundaries > 2 )
     {
       // move boundaries in tmp list
-      list< list< TPoint* > > tmpList; 
+      list< list< TPoint* > > tmpList;
       tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
       // make a map nb-key-points to boundary-position-in-tmpList,
       // boundary-positions get ordered in it
@@ -4018,7 +4243,7 @@ void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
       boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos );
 
   } // if nbBoundaries > 1
-                 
+
   // Check boundaries orientation and re-fill myKeyPointIDs
 
   set< TPoint* > keyPointSet;
@@ -4289,7 +4514,7 @@ bool SMESH_Pattern::findBoundaryPoints()
       getShapePoints( shapeID ).push_back( point );
       // detect key-points
       if ( SMESH_Block::IsVertexID( shapeID ))
-        myKeyPointIDs.push_back( i );        
+        myKeyPointIDs.push_back( i );
     }
   }
 
@@ -4337,13 +4562,19 @@ bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape)
   // check if a face is closed
   int nbNodeOnSeamEdge = 0;
   if ( myIs2D ) {
+    TopTools_MapOfShape seamVertices;
     TopoDS_Face face = TopoDS::Face( theShape );
     TopExp_Explorer eExp( theShape, TopAbs_EDGE );
-    for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() )
-      if ( BRep_Tool::IsClosed( TopoDS::Edge( eExp.Current() ), face ))
-        nbNodeOnSeamEdge = 2;
+    for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() ) {
+      const TopoDS_Edge& ee = TopoDS::Edge(eExp.Current());
+      if ( BRep_Tool::IsClosed(ee, face) ) {
+        // seam edge and vertices encounter twice in theFace
+        if ( !seamVertices.Add( TopExp::FirstVertex( ee ))) nbNodeOnSeamEdge++;
+        if ( !seamVertices.Add( TopExp::LastVertex( ee ))) nbNodeOnSeamEdge++;
+      }
+    }
   }
-    
+
   // check nb of vertices
   TopTools_IndexedMapOfShape vMap;
   TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
@@ -4445,7 +4676,7 @@ void SMESH_Pattern::DumpPoints() const
 #ifdef _DEBUG_
   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
   for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ )
-    cout << i << ": " << *pVecIt;
+    MESSAGE_ADD ( std::endl << i << ": " << *pVecIt );
 #endif
 }
 
@@ -4485,6 +4716,6 @@ ostream & operator <<(ostream & OS, const SMESH_Pattern::TPoint& p)
   OS << " uv( " <<  xy.X() << " " << xy.Y() << " )";
   u = p.myU;
   OS << " u( " <<  u << " ))" << endl;
-  
+
   return OS;
 }