Salome HOME
23418: [OCC] Mesh: Minimization of memory usage of SMESH
[modules/smesh.git] / src / SMESH / SMESH_Pattern.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File      : SMESH_Pattern.hxx
24 // Created   : Mon Aug  2 10:30:00 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #include "SMESH_Pattern.hxx"
28
29 #include "SMDS_EdgePosition.hxx"
30 #include "SMDS_FacePosition.hxx"
31 #include "SMDS_MeshElement.hxx"
32 #include "SMDS_MeshFace.hxx"
33 #include "SMDS_MeshNode.hxx"
34 #include "SMDS_VolumeTool.hxx"
35 #include "SMESHDS_Group.hxx"
36 #include "SMESHDS_Mesh.hxx"
37 #include "SMESHDS_SubMesh.hxx"
38 #include "SMESH_Block.hxx"
39 #include "SMESH_Mesh.hxx"
40 #include "SMESH_MeshAlgos.hxx"
41 #include "SMESH_MesherHelper.hxx"
42 #include "SMESH_subMesh.hxx"
43
44 #include <BRepAdaptor_Curve.hxx>
45 #include <BRepTools.hxx>
46 #include <BRepTools_WireExplorer.hxx>
47 #include <BRep_Tool.hxx>
48 #include <Bnd_Box.hxx>
49 #include <Bnd_Box2d.hxx>
50 #include <ElSLib.hxx>
51 #include <Extrema_ExtPC.hxx>
52 #include <Extrema_GenExtPS.hxx>
53 #include <Extrema_POnSurf.hxx>
54 #include <Geom2d_Curve.hxx>
55 #include <GeomAdaptor_Surface.hxx>
56 #include <Geom_Curve.hxx>
57 #include <Geom_Surface.hxx>
58 #include <Precision.hxx>
59 #include <TopAbs_ShapeEnum.hxx>
60 #include <TopExp.hxx>
61 #include <TopExp_Explorer.hxx>
62 #include <TopLoc_Location.hxx>
63 #include <TopTools_ListIteratorOfListOfShape.hxx>
64 #include <TopoDS.hxx>
65 #include <TopoDS_Edge.hxx>
66 #include <TopoDS_Face.hxx>
67 #include <TopoDS_Iterator.hxx>
68 #include <TopoDS_Shell.hxx>
69 #include <TopoDS_Vertex.hxx>
70 #include <TopoDS_Wire.hxx>
71 #include <gp_Ax2.hxx>
72 #include <gp_Lin2d.hxx>
73 #include <gp_Pnt2d.hxx>
74 #include <gp_Trsf.hxx>
75 #include <gp_XY.hxx>
76 #include <gp_XYZ.hxx>
77
78 #include <Basics_Utils.hxx>
79 #include "utilities.h"
80
81 using namespace std;
82
83 typedef map< const SMDS_MeshElement*, int > TNodePointIDMap;
84
85 #define smdsNode( elem ) static_cast<const SMDS_MeshNode*>( elem )
86
87 namespace
88 {
89   
90 //=======================================================================
91 //function : getInt
92 //purpose  : 
93 //=======================================================================
94
95 inline int getInt( const char * theSring )
96 {
97   if ( *theSring < '0' || *theSring > '9' )
98     return -1;
99
100   char *ptr;
101   int val = strtol( theSring, &ptr, 10 );
102   if ( ptr == theSring ||
103       // there must not be neither '.' nor ',' nor 'E' ...
104       (*ptr != ' ' && *ptr != '\n' && *ptr != '\0' && *ptr != '\r'))
105     return -1;
106
107   return val;
108 }
109
110 //=======================================================================
111 //function : getDouble
112 //purpose  : 
113 //=======================================================================
114
115 inline double getDouble( const char * theSring )
116 {
117   char *ptr;
118   return strtod( theSring, &ptr );
119 }
120
121 //=======================================================================
122 //function : readLine
123 //purpose  : Put token starting positions in theFields until '\n' or '\0'
124 //           Return the number of the found tokens
125 //=======================================================================
126
127 int readLine (list <const char*> & theFields,
128               const char*        & theLineBeg,
129               const bool           theClearFields )
130 {
131   if ( theClearFields )
132     theFields.clear();
133
134   //  algo:
135   /*  loop                                                       */
136   /*    switch ( symbol ) {                                      */
137   /*    case white-space:                                        */
138   /*      look for a non-space symbol;                           */
139   /*    case string-end:                                         */
140   /*    case line-end:                                           */
141   /*      exit;                                                  */
142   /*    case comment beginning:                                  */
143   /*      skip all till a line-end;                              */
144   /*    case a number                                            */
145   /*      put its position in theFields, skip till a white-space;*/
146   /*    default:                                                 */
147   /*      abort;                                                 */
148   /*  till line-end                                              */
149
150   int nbRead = 0;
151   bool stopReading = false;
152   do {
153     bool goOn = true;
154     bool isNumber = false;
155     switch ( *theLineBeg )
156     {
157     case ' ':  // white space
158     case '\t': // tab
159     case 13:   // ^M
160       break;
161
162     case '\n': // a line ends
163       stopReading = ( nbRead > 0 );
164       break;
165
166     case '!':  // comment
167       do theLineBeg++;
168       while ( *theLineBeg != '\n' && *theLineBeg != '\0' );
169       goOn = false;
170       break;
171
172     case '\0': // file ends
173       return nbRead;
174
175     case '-': // real number
176     case '+':
177     case '.':
178       isNumber = true;
179     default: // data
180       isNumber = isNumber || ( *theLineBeg >= '0' && *theLineBeg <= '9' );
181       if ( isNumber ) {
182         theFields.push_back( theLineBeg );
183         nbRead++;
184         do theLineBeg++;
185         while (*theLineBeg != ' ' &&
186                *theLineBeg != '\n' &&
187                *theLineBeg != '\0');
188         goOn = false;
189       }
190       else
191         return 0; // incorrect file format
192     }
193
194     if ( goOn )
195       theLineBeg++;
196
197   } while ( !stopReading );
198
199   return nbRead;
200 }
201
202 //=======================================================================
203 //function : isRealSeam
204 //purpose  : return true if an EDGE encounters twice in a FACE
205 //=======================================================================
206
207 // bool isRealSeam( const TopoDS_Edge& e, const TopoDS_Face& f )
208 // {
209 //   if ( BRep_Tool::IsClosed( e, f ))
210 //   {
211 //     int nb = 0;
212 //     for (TopExp_Explorer exp( f, TopAbs_EDGE ); exp.More(); exp.Next())
213 //       if ( exp.Current().IsSame( e ))
214 //         if ( ++nb == 2 )
215 //           return true;
216 //   }
217 //   return false;
218 // }
219
220 //=======================================================================
221 //function : loadVE
222 //purpose  : load VERTEXes and EDGEs in a map. Return nb loaded VERTEXes
223 //=======================================================================
224
225 int loadVE( const list< TopoDS_Edge > &          eList,
226             TopTools_IndexedMapOfOrientedShape & map )
227 {
228   list< TopoDS_Edge >::const_iterator eIt = eList.begin();
229   // vertices
230   int nbV;
231   for ( eIt = eList.begin(); eIt != eList.end(); eIt++ )
232   {
233     nbV = map.Extent();
234     map.Add( TopExp::FirstVertex( *eIt, true ));
235     bool added = ( nbV < map.Extent() );
236     if ( !added ) { // vertex encountered twice
237       // a seam vertex have two corresponding key points
238       map.Add( TopExp::FirstVertex( *eIt, true ).Reversed());
239     }
240   }
241   nbV = map.Extent();
242
243   // edges
244   for ( eIt = eList.begin(); eIt != eList.end(); eIt++ )
245     map.Add( *eIt );
246
247   return nbV;
248 }
249
250 } // namespace
251
252 //=======================================================================
253 //function : SMESH_Pattern
254 //purpose  :
255 //=======================================================================
256
257 SMESH_Pattern::SMESH_Pattern (): myToKeepNodes(false)
258 {
259 }
260
261 //=======================================================================
262 //function : Load
263 //purpose  : Load a pattern from <theFile>
264 //=======================================================================
265
266 bool SMESH_Pattern::Load (const char* theFileContents)
267 {
268   Kernel_Utils::Localizer loc;
269   
270   // file structure:
271
272   // ! This is a comment
273   // NB_POINTS               ! 1 integer - the number of points in the pattern.
274   //   X1 Y1 [Z1]            ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
275   //   X2 Y2 [Z2]            ! the pattern dimension is defined by the number of coordinates
276   //   ...
277   // [ ID1 ID2 ... IDn ]     ! Indices of key-points for a 2D pattern (only).
278   // ! elements description goes after all
279   // ID1 ID2 ... IDn         ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
280   // ...
281
282   Clear();
283
284   const char* lineBeg = theFileContents;
285   list <const char*> fields;
286   const bool clearFields = true;
287
288   // NB_POINTS               ! 1 integer - the number of points in the pattern.
289
290   if ( readLine( fields, lineBeg, clearFields ) != 1 ) {
291     MESSAGE("Error reading NB_POINTS");
292     return setErrorCode( ERR_READ_NB_POINTS );
293   }
294   int nbPoints = getInt( fields.front() );
295
296   //   X1 Y1 [Z1]            ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
297
298   // read the first point coordinates to define pattern dimension
299   int dim = readLine( fields, lineBeg, clearFields );
300   if ( dim == 2 )
301     myIs2D = true;
302   else if ( dim == 3 )
303     myIs2D = false;
304   else {
305     MESSAGE("Error reading points: wrong nb of coordinates");
306     return setErrorCode( ERR_READ_POINT_COORDS );
307   }
308   if ( nbPoints <= dim ) {
309     MESSAGE(" Too few points ");
310     return setErrorCode( ERR_READ_TOO_FEW_POINTS );
311   }
312
313   // read the rest points
314   int iPoint;
315   for ( iPoint = 1; iPoint < nbPoints; iPoint++ )
316     if ( readLine( fields, lineBeg, !clearFields ) != dim ) {
317       MESSAGE("Error reading  points : wrong nb of coordinates ");
318       return setErrorCode( ERR_READ_POINT_COORDS );
319     }
320   // store point coordinates
321   myPoints.resize( nbPoints );
322   list <const char*>::iterator fIt = fields.begin();
323   for ( iPoint = 0; iPoint < nbPoints; iPoint++ )
324   {
325     TPoint & p = myPoints[ iPoint ];
326     for ( int iCoord = 1; iCoord <= dim; iCoord++, fIt++ )
327     {
328       double coord = getDouble( *fIt );
329       if ( !myIs2D && ( coord < 0.0 || coord > 1.0 )) {
330         MESSAGE("Error reading 3D points, value should be in [0,1]: " << coord);
331         Clear();
332         return setErrorCode( ERR_READ_3D_COORD );
333       }
334       p.myInitXYZ.SetCoord( iCoord, coord );
335       if ( myIs2D )
336         p.myInitUV.SetCoord( iCoord, coord );
337     }
338   }
339
340   // [ ID1 ID2 ... IDn ]     ! Indices of key-points for a 2D pattern (only).
341   if ( myIs2D )
342   {
343     if ( readLine( fields, lineBeg, clearFields ) == 0 ) {
344       MESSAGE("Error: missing key-points");
345       Clear();
346       return setErrorCode( ERR_READ_NO_KEYPOINT );
347     }
348     set<int> idSet;
349     for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
350     {
351       int pointIndex = getInt( *fIt );
352       if ( pointIndex >= nbPoints || pointIndex < 0 ) {
353         MESSAGE("Error: invalid point index " << pointIndex );
354         Clear();
355         return setErrorCode( ERR_READ_BAD_INDEX );
356       }
357       if ( idSet.insert( pointIndex ).second ) // unique?
358         myKeyPointIDs.push_back( pointIndex );
359     }
360   }
361
362   // ID1 ID2 ... IDn         ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
363
364   while ( readLine( fields, lineBeg, clearFields ))
365   {
366     myElemPointIDs.push_back( TElemDef() );
367     TElemDef& elemPoints = myElemPointIDs.back();
368     for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
369     {
370       int pointIndex = getInt( *fIt );
371       if ( pointIndex >= nbPoints || pointIndex < 0 ) {
372         MESSAGE("Error: invalid point index " << pointIndex );
373         Clear();
374         return setErrorCode( ERR_READ_BAD_INDEX );
375       }
376       elemPoints.push_back( pointIndex );
377     }
378     // check the nb of nodes in element
379     bool Ok = true;
380     switch ( elemPoints.size() ) {
381     case 3: if ( !myIs2D ) Ok = false; break;
382     case 4: break;
383     case 5:
384     case 6:
385     case 8: if ( myIs2D ) Ok = false; break;
386     default: Ok = false;
387     }
388     if ( !Ok ) {
389       MESSAGE("Error: wrong nb of nodes in element " << elemPoints.size() );
390       Clear();
391       return setErrorCode( ERR_READ_ELEM_POINTS );
392     }
393   }
394   if ( myElemPointIDs.empty() ) {
395     MESSAGE("Error: no elements");
396     Clear();
397     return setErrorCode( ERR_READ_NO_ELEMS );
398   }
399
400   findBoundaryPoints(); // sort key-points
401
402   return setErrorCode( ERR_OK );
403 }
404
405 //=======================================================================
406 //function : Save
407 //purpose  : Save the loaded pattern into the file <theFileName>
408 //=======================================================================
409
410 bool SMESH_Pattern::Save (ostream& theFile)
411 {
412   Kernel_Utils::Localizer loc;
413     
414   if ( !IsLoaded() ) {
415     MESSAGE(" Pattern not loaded ");
416     return setErrorCode( ERR_SAVE_NOT_LOADED );
417   }
418
419   theFile << "!!! SALOME Mesh Pattern file" << endl;
420   theFile << "!!!" << endl;
421   theFile << "!!! Nb of points:" << endl;
422   theFile << myPoints.size() << endl;
423
424   // point coordinates
425   const int width = 8;
426 //  theFile.width( 8 );
427 //  theFile.setf(ios::fixed);// use 123.45 floating notation
428 //  theFile.setf(ios::right);
429 //  theFile.flags( theFile.flags() & ~ios::showpoint); // do not show trailing zeros
430 //   theFile.setf(ios::showpoint); // do not show trailing zeros
431   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
432   for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
433     const gp_XYZ & xyz = (*pVecIt).myInitXYZ;
434     theFile << " " << setw( width ) << xyz.X() << " " << setw( width ) << xyz.Y();
435     if ( !myIs2D ) theFile  << " " << setw( width ) << xyz.Z();
436     theFile  << "  !- " << i << endl; // point id to ease reading by a human being
437   }
438   // key-points
439   if ( myIs2D ) {
440     theFile << "!!! Indices of " << myKeyPointIDs.size() << " key-points:" << endl;
441     list< int >::const_iterator kpIt = myKeyPointIDs.begin();
442     for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
443       theFile << " " << *kpIt;
444     if ( !myKeyPointIDs.empty() )
445       theFile << endl;
446   }
447   // elements
448   theFile << "!!! Indices of points of " << myElemPointIDs.size() << " elements:" << endl;
449   list<TElemDef >::const_iterator epIt = myElemPointIDs.begin();
450   for ( ; epIt != myElemPointIDs.end(); epIt++ )
451   {
452     const TElemDef & elemPoints = *epIt;
453     TElemDef::const_iterator iIt = elemPoints.begin();
454     for ( ; iIt != elemPoints.end(); iIt++ )
455       theFile << " " << *iIt;
456     theFile << endl;
457   }
458
459   theFile << endl;
460
461   return setErrorCode( ERR_OK );
462 }
463
464 //=======================================================================
465 //function : sortBySize
466 //purpose  : sort theListOfList by size
467 //=======================================================================
468
469 template<typename T> struct TSizeCmp {
470   bool operator ()( const list < T > & l1, const list < T > & l2 )
471     const { return l1.size() < l2.size(); }
472 };
473
474 template<typename T> void sortBySize( list< list < T > > & theListOfList )
475 {
476   if ( theListOfList.size() > 2 ) {
477     TSizeCmp< T > SizeCmp;
478     theListOfList.sort( SizeCmp );
479   }
480 }
481
482 //=======================================================================
483 //function : project
484 //purpose  : 
485 //=======================================================================
486
487 static gp_XY project (const SMDS_MeshNode* theNode,
488                       Extrema_GenExtPS &   theProjectorPS)
489 {
490   gp_Pnt P( theNode->X(), theNode->Y(), theNode->Z() );
491   theProjectorPS.Perform( P );
492   if ( !theProjectorPS.IsDone() ) {
493     MESSAGE( "SMESH_Pattern: point projection FAILED");
494     return gp_XY(0.,0.);
495   }
496   double u =0, v =0, minVal = DBL_MAX;
497   for ( int i = theProjectorPS.NbExt(); i > 0; i-- )
498     if ( theProjectorPS.SquareDistance( i ) < minVal ) {
499       minVal = theProjectorPS.SquareDistance( i );
500       theProjectorPS.Point( i ).Parameter( u, v );
501     }
502   return gp_XY( u, v );
503 }
504
505 //=======================================================================
506 //function : areNodesBound
507 //purpose  : true if all nodes of faces are bound to shapes
508 //=======================================================================
509
510 template <class TFaceIterator> bool areNodesBound( TFaceIterator & faceItr )
511 {
512   while ( faceItr->more() )
513   {
514     SMDS_ElemIteratorPtr nIt = faceItr->next()->nodesIterator();
515     while ( nIt->more() )
516     {
517       const SMDS_MeshNode* node = smdsNode( nIt->next() );
518       if (node->getshapeId() <1) {
519         return false;
520       }
521     }
522   }
523   return true;
524 }
525
526 //=======================================================================
527 //function : isMeshBoundToShape
528 //purpose  : return true if all 2d elements are bound to shape
529 //           if aFaceSubmesh != NULL, then check faces bound to it
530 //           else check all faces in aMeshDS
531 //=======================================================================
532
533 static bool isMeshBoundToShape(SMESHDS_Mesh *     aMeshDS,
534                                SMESHDS_SubMesh *  aFaceSubmesh,
535                                const bool         isMainShape)
536 {
537   if ( isMainShape && aFaceSubmesh ) {
538     // check that all faces are bound to aFaceSubmesh
539     if ( aMeshDS->NbFaces() != aFaceSubmesh->NbElements() )
540       return false;
541   }
542
543   // check face nodes binding
544   if ( aFaceSubmesh ) {
545     SMDS_ElemIteratorPtr fIt = aFaceSubmesh->GetElements();
546     return areNodesBound( fIt );
547   }
548   SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
549   return areNodesBound( fIt );
550 }
551
552 //=======================================================================
553 //function : Load
554 //purpose  : Create a pattern from the mesh built on <theFace>.
555 //           <theProject>==true makes override nodes positions
556 //           on <theFace> computed by mesher
557 //=======================================================================
558
559 bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
560                           const TopoDS_Face& theFace,
561                           bool               theProject,
562                           TopoDS_Vertex      the1stVertex,
563                           bool               theKeepNodes)
564 {
565   Clear();
566   myIs2D = true;
567   myToKeepNodes = theKeepNodes;
568
569   SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
570   SMESHDS_SubMesh * fSubMesh = aMeshDS->MeshElements( theFace );
571   const bool isQuadMesh = aMeshDS->GetMeshInfo().NbFaces( ORDER_QUADRATIC );
572   SMESH_MesherHelper helper( *theMesh );
573   helper.SetSubShape( theFace );
574
575   int nbNodes = ( !fSubMesh ? 0 : fSubMesh->NbNodes() );
576   int nbElems = ( !fSubMesh ? 0 : fSubMesh->NbElements() );
577   if ( nbElems == 0 && aMeshDS->NbFaces() == 0 )
578   {
579     MESSAGE( "No elements bound to the face");
580     return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
581   }
582
583   TopoDS_Face face = TopoDS::Face( theFace.Oriented( TopAbs_FORWARD ));
584
585   // check if face is closed
586   bool isClosed = helper.HasSeam();
587   list<TopoDS_Edge> eList;
588   list<TopoDS_Edge>::iterator elIt;
589   SMESH_Block::GetOrderedEdges( face, eList, myNbKeyPntInBoundary, the1stVertex );
590
591   // check that requested or needed projection is possible
592   bool isMainShape = theMesh->IsMainShape( face );
593   bool needProject = !isMeshBoundToShape( aMeshDS, fSubMesh, isMainShape );
594   bool canProject  = ( nbElems ? true : isMainShape );
595   if ( isClosed )
596     canProject = false; // so far
597
598   if ( ( theProject || needProject ) && !canProject )
599     return setErrorCode( ERR_LOADF_CANT_PROJECT );
600
601   Extrema_GenExtPS projector;
602   GeomAdaptor_Surface aSurface( BRep_Tool::Surface( face ));
603   projector.Initialize( aSurface, 20,20, 1e-5,1e-5 );
604
605   int iPoint = 0;
606   TNodePointIDMap nodePointIDMap;
607   TNodePointIDMap closeNodePointIDMap; // for nodes on seam edges
608
609   if ( needProject )
610   {
611     // ---------------------------------------------------------------
612     // The case where the submesh is projected to theFace
613     // ---------------------------------------------------------------
614
615     // get all faces
616     SMDS_ElemIteratorPtr fIt;
617     if ( nbElems > 0 )
618       fIt = fSubMesh->GetElements();
619     else
620       fIt = aMeshDS->elementsIterator( SMDSAbs_Face );
621
622     // put nodes of all faces into the nodePointIDMap and fill myElemPointIDs
623     while ( fIt->more() )
624     {
625       const SMDS_MeshElement* face = fIt->next();
626       myElemPointIDs.push_back( TElemDef() );
627       TElemDef& elemPoints = myElemPointIDs.back();
628       int nbNodes = face->NbCornerNodes();
629       for ( int i = 0;i < nbNodes; ++i )
630       {
631         const SMDS_MeshElement* node = face->GetNode( i );
632         TNodePointIDMap::iterator nIdIt = nodePointIDMap.insert( make_pair( node, -1 )).first;
633         if ( nIdIt->second == -1 )
634           nIdIt->second = iPoint++;
635         elemPoints.push_back( (*nIdIt).second );
636       }
637     }
638     myPoints.resize( iPoint );
639
640     // project all nodes of 2d elements to theFace
641     TNodePointIDMap::iterator nIdIt = nodePointIDMap.begin();
642     for ( ; nIdIt != nodePointIDMap.end(); nIdIt++ )
643     {
644       const SMDS_MeshNode* node = smdsNode( (*nIdIt).first );
645       TPoint * p = & myPoints[ (*nIdIt).second ];
646       p->myInitUV = project( node, projector );
647       p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
648     }
649     // find key-points: the points most close to UV of vertices
650     TopExp_Explorer vExp( face, TopAbs_VERTEX );
651     set<int> foundIndices;
652     for ( ; vExp.More(); vExp.Next() ) {
653       const TopoDS_Vertex v = TopoDS::Vertex( vExp.Current() );
654       gp_Pnt2d uv = BRep_Tool::Parameters( v, face );
655       double minDist = DBL_MAX;
656       int index = 0;
657       vector< TPoint >::const_iterator pVecIt = myPoints.begin();
658       for ( iPoint = 0; pVecIt != myPoints.end(); pVecIt++, iPoint++ ) {
659         double dist = uv.SquareDistance( (*pVecIt).myInitUV );
660         if ( dist < minDist ) {
661           minDist = dist;
662           index = iPoint;
663         }
664       }
665       if ( foundIndices.insert( index ).second ) // unique?
666         myKeyPointIDs.push_back( index );
667     }
668     myIsBoundaryPointsFound = false;
669
670   }
671   else
672   {
673     // ---------------------------------------------------------------------
674     // The case where a pattern is being made from the mesh built by mesher
675     // ---------------------------------------------------------------------
676
677     // Load shapes in the consequent order and count nb of points
678
679     loadVE( eList, myShapeIDMap );
680     myShapeIDMap.Add( face );
681
682     nbNodes += myShapeIDMap.Extent() - 1;
683
684     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
685       if ( SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt ))
686         nbNodes += eSubMesh->NbNodes() + 1;
687
688     myPoints.resize( nbNodes );
689
690     // care of INTERNAL VERTEXes
691     TopExp_Explorer vExp( face, TopAbs_VERTEX, TopAbs_EDGE );
692     for ( ; vExp.More(); vExp.Next() )
693     {
694       const SMDS_MeshNode* node =
695         SMESH_Algo::VertexNode( TopoDS::Vertex( vExp.Current()), aMeshDS );
696       if ( !node || node->NbInverseElements( SMDSAbs_Face ) == 0 )
697         continue;
698       myPoints.resize( ++nbNodes );
699       list< TPoint* > & fPoints = getShapePoints( face );
700       nodePointIDMap.insert( make_pair( node, iPoint ));
701       TPoint* p = &myPoints[ iPoint++ ];
702       fPoints.push_back( p );
703       gp_XY uv = helper.GetNodeUV( face, node );
704       p->myInitUV.SetCoord( uv.X(), uv.Y() );
705       p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
706     }
707
708     // Load U of points on edges
709
710     Bnd_Box2d edgesUVBox;
711
712     list<int>::iterator nbEinW = myNbKeyPntInBoundary.begin();
713     int iE = 0;
714     vector< TopoDS_Edge > eVec;
715     for ( elIt = eList.begin(); elIt != eList.end(); elIt++, iE++ )
716     {
717       if ( isClosed && ( iE == 0 || iE == *nbEinW ))
718       {
719         // new wire begins; put wire EDGEs in eVec
720         list<TopoDS_Edge>::iterator eEnd = elIt;
721         if ( iE == *nbEinW )
722           ++nbEinW;
723         std::advance( eEnd, *nbEinW );
724         eVec.assign( elIt, eEnd );
725         iE = 0;
726       }
727       TopoDS_Edge & edge = *elIt;
728       list< TPoint* > & ePoints = getShapePoints( edge );
729       double f, l;
730       Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( edge, face, f, l );
731       bool isForward = ( edge.Orientation() == TopAbs_FORWARD );
732
733       TopoDS_Shape v1 = TopExp::FirstVertex( edge, true ); // always FORWARD
734       TopoDS_Shape v2 = TopExp::LastVertex( edge, true ); // always REVERSED
735       // to make adjacent edges share key-point, we make v2 FORWARD too
736       // (as we have different points for same shape with different orientation)
737       v2.Reverse();
738
739       // on closed face we must have REVERSED some of seam vertices
740       if ( isClosed ) {
741         if ( helper.IsSeamShape( edge ) ) {
742           if ( helper.IsRealSeam( edge ) && !isForward ) {
743             // reverse on reversed SEAM edge
744             v1.Reverse();
745             v2.Reverse();
746           }
747         }
748         else { // on CLOSED edge (i.e. having one vertex with different orientations)
749           for ( int is2 = 0; is2 < 2; ++is2 ) {
750             TopoDS_Shape & v = is2 ? v2 : v1;
751             if ( helper.IsRealSeam( v ) ) {
752               // reverse or not depending on orientation of adjacent seam
753               int iSeam = helper.WrapIndex( iE + ( is2 ? +1 : -1 ), eVec.size() );
754               if ( eVec[ iSeam ].Orientation() == TopAbs_REVERSED )
755                 v.Reverse();
756             }
757           }
758         }
759       }
760
761       // the forward key-point
762       list< TPoint* > * vPoint = & getShapePoints( v1 );
763       if ( vPoint->empty() )
764       {
765         SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v1 );
766         if ( vSubMesh && vSubMesh->NbNodes() ) {
767           myKeyPointIDs.push_back( iPoint );
768           SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
769           const SMDS_MeshNode* node = nIt->next();
770           if ( v1.Orientation() == TopAbs_REVERSED )
771             closeNodePointIDMap.insert( make_pair( node, iPoint ));
772           else
773             nodePointIDMap.insert( make_pair( node, iPoint ));
774
775           TPoint* keyPoint = &myPoints[ iPoint++ ];
776           vPoint->push_back( keyPoint );
777           if ( theProject )
778             keyPoint->myInitUV = project( node, projector );
779           else
780             keyPoint->myInitUV = C2d->Value( isForward ? f : l ).XY();
781           keyPoint->myInitXYZ.SetCoord (keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0);
782           edgesUVBox.Add( gp_Pnt2d( keyPoint->myInitUV ));
783         }
784       }
785       if ( !vPoint->empty() )
786         ePoints.push_back( vPoint->front() );
787
788       // on-edge points
789       SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edge );
790       if ( eSubMesh && eSubMesh->NbNodes() )
791       {
792         // loop on nodes of an edge: sort them by param on edge
793         typedef map < double, const SMDS_MeshNode* > TParamNodeMap;
794         TParamNodeMap paramNodeMap;
795         int nbMeduimNodes = 0;
796         SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
797         while ( nIt->more() )
798         {
799           const SMDS_MeshNode* node = nIt->next();
800           if ( isQuadMesh && helper.IsMedium( node, SMDSAbs_Face )) {
801             ++nbMeduimNodes;
802             continue;
803           }
804           SMDS_EdgePositionPtr epos = node->GetPosition();
805           double u = epos->GetUParameter();
806           paramNodeMap.insert( make_pair( u, node ));
807         }
808         if ((int) paramNodeMap.size() != eSubMesh->NbNodes() - nbMeduimNodes ) {
809           // wrong U on edge, project
810           Extrema_ExtPC proj;
811           BRepAdaptor_Curve aCurve( edge );
812           proj.Initialize( aCurve, f, l );
813           paramNodeMap.clear();
814           nIt = eSubMesh->GetNodes();
815           for ( int iNode = 0; nIt->more(); ++iNode ) {
816             const SMDS_MeshNode* node = nIt->next();
817             if ( isQuadMesh && helper.IsMedium( node, SMDSAbs_Face ))
818               continue;
819             proj.Perform( gp_Pnt( node->X(), node->Y(), node->Z()));
820             double u = 0;
821             if ( proj.IsDone() ) {
822               for ( int i = 1, nb = proj.NbExt(); i <= nb; ++i )
823                 if ( proj.IsMin( i )) {
824                   u = proj.Point( i ).Parameter();
825                   break;
826                 }
827             } else {
828               u = isForward ? iNode : eSubMesh->NbNodes() - iNode;
829             }
830             paramNodeMap.insert( make_pair( u, node ));
831           }
832
833           //rnv : To fix the bug IPAL21999 Pattern Mapping - New - collapse of pattern mesh
834           if ((int) paramNodeMap.size() != eSubMesh->NbNodes() - nbMeduimNodes )
835             return setErrorCode(ERR_UNEXPECTED);
836         }
837
838         // put U in [0,1] so that the first key-point has U==0
839         bool isSeam = helper.IsRealSeam( edge );
840         double du = l - f;
841         TParamNodeMap::iterator         unIt  = paramNodeMap.begin();
842         TParamNodeMap::reverse_iterator unRIt = paramNodeMap.rbegin();
843         while ( unIt != paramNodeMap.end() )
844         {
845           TPoint* p = & myPoints[ iPoint ];
846           ePoints.push_back( p );
847           const SMDS_MeshNode* node = isForward ? (*unIt).second : (*unRIt).second;
848           if ( isSeam && !isForward )
849             closeNodePointIDMap.insert( make_pair( node, iPoint ));
850           else
851             nodePointIDMap.insert ( make_pair( node, iPoint ));
852
853           if ( theProject )
854             p->myInitUV = project( node, projector );
855           else {
856             double u = isForward ? (*unIt).first : (*unRIt).first;
857             p->myInitU = isForward ? (( u - f ) / du ) : ( 1.0 - ( u - f ) / du );
858             p->myInitUV = C2d->Value( u ).XY();
859           }
860           p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
861           edgesUVBox.Add( gp_Pnt2d( p->myInitUV ));
862           unIt++; unRIt++;
863           iPoint++;
864         }
865       }
866       // the reverse key-point
867       vPoint = & getShapePoints( v2 );
868       if ( vPoint->empty() )
869       {
870         SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v2 );
871         if ( vSubMesh && vSubMesh->NbNodes() ) {
872           myKeyPointIDs.push_back( iPoint );
873           SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
874           const SMDS_MeshNode* node = nIt->next();
875           if ( v2.Orientation() == TopAbs_REVERSED )
876             closeNodePointIDMap.insert( make_pair( node, iPoint ));
877           else
878             nodePointIDMap.insert( make_pair( node, iPoint ));
879
880           TPoint* keyPoint = &myPoints[ iPoint++ ];
881           vPoint->push_back( keyPoint );
882           if ( theProject )
883             keyPoint->myInitUV = project( node, projector );
884           else
885             keyPoint->myInitUV = C2d->Value( isForward ? l : f ).XY();
886           keyPoint->myInitXYZ.SetCoord( keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0 );
887           edgesUVBox.Add( gp_Pnt2d( keyPoint->myInitUV ));
888         }
889       }
890       if ( !vPoint->empty() )
891         ePoints.push_back( vPoint->front() );
892
893       // compute U of edge-points
894       if ( theProject )
895       {
896         double totalDist = 0;
897         list< TPoint* >::iterator pIt = ePoints.begin();
898         TPoint* prevP = *pIt;
899         prevP->myInitU = totalDist;
900         for ( pIt++; pIt != ePoints.end(); pIt++ ) {
901           TPoint* p = *pIt;
902           totalDist += ( p->myInitUV - prevP->myInitUV ).Modulus();
903           p->myInitU = totalDist;
904           prevP = p;
905         }
906         if ( totalDist > DBL_MIN)
907           for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
908             TPoint* p = *pIt;
909             p->myInitU /= totalDist;
910           }
911       }
912     } // loop on edges of a wire
913
914     // Load in-face points and elements
915
916     if ( fSubMesh && fSubMesh->NbElements() )
917     {
918       list< TPoint* > & fPoints = getShapePoints( face );
919       SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes();
920       while ( nIt->more() )
921       {
922         const SMDS_MeshNode* node = nIt->next();
923         if ( isQuadMesh && helper.IsMedium( node, SMDSAbs_Face ))
924           continue;
925         nodePointIDMap.insert( make_pair( node, iPoint ));
926         TPoint* p = &myPoints[ iPoint++ ];
927         fPoints.push_back( p );
928         if ( theProject || edgesUVBox.IsOut( p->myInitUV ) )
929           p->myInitUV = project( node, projector );
930         else {
931           SMDS_FacePositionPtr pos = node->GetPosition();
932           p->myInitUV.SetCoord( pos->GetUParameter(), pos->GetVParameter() );
933         }
934         p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
935       }
936       // load elements
937       TNodePointIDMap::iterator n_id, not_found = closeNodePointIDMap.end();
938       SMDS_ElemIteratorPtr elemIt = fSubMesh->GetElements();
939       while ( elemIt->more() )
940       {
941         const SMDS_MeshElement* elem = elemIt->next();
942         SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
943         myElemPointIDs.push_back( TElemDef() );
944         TElemDef& elemPoints = myElemPointIDs.back();
945         // find point indices corresponding to element nodes
946         while ( nIt->more() )
947         {
948           const SMDS_MeshNode* node = smdsNode( nIt->next() );
949           n_id = nodePointIDMap.find( node );
950           if ( n_id == nodePointIDMap.end() )
951             continue; // medium node
952           iPoint = n_id->second; // point index of interest
953           // for a node on a seam edge there are two points
954           if ( helper.IsRealSeam( node->getshapeId() ) &&
955                ( n_id = closeNodePointIDMap.find( node )) != not_found )
956           {
957             TPoint & p1 = myPoints[ iPoint ];
958             TPoint & p2 = myPoints[ n_id->second ];
959             // Select point closest to the rest nodes of element in UV space
960             SMDS_ElemIteratorPtr nIt2 = elem->nodesIterator();
961             const SMDS_MeshNode* notSeamNode = 0;
962             // find node not on a seam edge
963             while ( nIt2->more() && !notSeamNode ) {
964               const SMDS_MeshNode* n = smdsNode( nIt2->next() );
965               if ( !helper.IsSeamShape( n->getshapeId() ))
966                 notSeamNode = n;
967             }
968             gp_Pnt2d uv = helper.GetNodeUV( theFace, node, notSeamNode );
969             double dist1 = uv.SquareDistance( p1.myInitUV );
970             double dist2 = uv.SquareDistance( p2.myInitUV );
971             if ( dist2 < dist1 )
972               iPoint = n_id->second;
973           }
974           elemPoints.push_back( iPoint );
975         }
976       }
977     }
978     myPoints.resize( nodePointIDMap.size() + closeNodePointIDMap.size() );
979
980     myIsBoundaryPointsFound = true;
981   }
982
983   if ( myToKeepNodes )
984   {
985     myInNodes.resize( nodePointIDMap.size() + closeNodePointIDMap.size() );
986
987     TNodePointIDMap::iterator nIdIt = nodePointIDMap.begin();
988     for ( ; nIdIt != nodePointIDMap.end(); nIdIt++ )
989       myInNodes[ nIdIt->second ] = smdsNode( nIdIt->first );
990
991     nIdIt = closeNodePointIDMap.begin();
992     for ( ; nIdIt != closeNodePointIDMap.end(); nIdIt++ )
993       myInNodes[ nIdIt->second ] = smdsNode( nIdIt->first );
994   }
995
996   // Assure that U range is proportional to V range
997
998   Bnd_Box2d bndBox;
999   vector< TPoint >::iterator pVecIt = myPoints.begin();
1000   for ( ; pVecIt != myPoints.end(); pVecIt++ )
1001     bndBox.Add( gp_Pnt2d( (*pVecIt).myInitUV ));
1002   double minU, minV, maxU, maxV;
1003   bndBox.Get( minU, minV, maxU, maxV );
1004   double dU = maxU - minU, dV = maxV - minV;
1005   if ( dU <= DBL_MIN || dV <= DBL_MIN ) {
1006     Clear();
1007     bndBox.SetVoid();
1008     // define where is the problem, in the face or in the mesh
1009     TopExp_Explorer vExp( face, TopAbs_VERTEX );
1010     for ( ; vExp.More(); vExp.Next() ) {
1011       gp_Pnt2d uv = BRep_Tool::Parameters( TopoDS::Vertex( vExp.Current() ), face );
1012       bndBox.Add( uv );
1013     }
1014     bndBox.Get( minU, minV, maxU, maxV );
1015     dU = maxU - minU, dV = maxV - minV;
1016     if ( dU <= DBL_MIN || dV <= DBL_MIN )
1017       // face problem
1018       return setErrorCode( ERR_LOADF_NARROW_FACE );
1019     else
1020       // mesh is projected onto a line, e.g.
1021       return setErrorCode( ERR_LOADF_CANT_PROJECT );
1022   }
1023   double ratio = dU / dV, maxratio = 3, scale;
1024   int iCoord = 0;
1025   if ( ratio > maxratio ) {
1026     scale = ratio / maxratio;
1027     iCoord = 2;
1028   }
1029   else if ( ratio < 1./maxratio ) {
1030     scale = maxratio / ratio;
1031     iCoord = 1;
1032   }
1033   if ( iCoord ) {
1034     SCRUTE( scale );
1035     for ( pVecIt = myPoints.begin(); pVecIt != myPoints.end(); pVecIt++ ) {
1036       TPoint & p = *pVecIt;
1037       p.myInitUV.SetCoord( iCoord, p.myInitUV.Coord( iCoord ) * scale );
1038       p.myInitXYZ.SetCoord( p.myInitUV.X(), p.myInitUV.Y(), 0 );
1039     }
1040   }
1041   if ( myElemPointIDs.empty() ) {
1042     MESSAGE( "No elements bound to the face");
1043     return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
1044   }
1045
1046   return setErrorCode( ERR_OK );
1047 }
1048
1049 //=======================================================================
1050 //function : computeUVOnEdge
1051 //purpose  : compute coordinates of points on theEdge
1052 //=======================================================================
1053
1054 void SMESH_Pattern::computeUVOnEdge (const TopoDS_Edge&      theEdge,
1055                                      const list< TPoint* > & ePoints )
1056 {
1057   bool isForward = ( theEdge.Orientation() == TopAbs_FORWARD );
1058   double f, l;
1059   Handle(Geom2d_Curve) C2d =
1060     BRep_Tool::CurveOnSurface( theEdge, TopoDS::Face( myShape ), f, l );
1061
1062   ePoints.back()->myInitU = 1.0;
1063   //ePoints.front()->myInitU = 0.0; //myUV = C2d->Value( isForward ? f : l ).XY();
1064   list< TPoint* >::const_iterator pIt = ePoints.begin();
1065   for ( pIt++; pIt != ePoints.end(); pIt++ )
1066   {
1067     TPoint* point = *pIt;
1068     // U
1069     double du = ( isForward ? point->myInitU : 1 - point->myInitU );
1070     point->myU = ( f * ( 1 - du ) + l * du );
1071     // UV
1072     point->myUV = C2d->Value( point->myU ).XY();
1073   }
1074 }
1075
1076 //=======================================================================
1077 //function : intersectIsolines
1078 //purpose  : 
1079 //=======================================================================
1080
1081 static bool intersectIsolines(const gp_XY& uv11, const gp_XY& uv12, const double r1,
1082                               const gp_XY& uv21, const gp_XY& uv22, const double r2,
1083                               gp_XY& resUV,
1084                               bool& isDeformed)
1085 {
1086   gp_XY loc1 = uv11 * ( 1 - r1 ) + uv12 * r1;
1087   gp_XY loc2 = uv21 * ( 1 - r2 ) + uv22 * r2;
1088   resUV = 0.5 * ( loc1 + loc2 );
1089   //isDeformed = ( loc1 - loc2 ).SquareModulus() > 1e-8;
1090   // SKL 26.07.2007 for NPAL16567
1091   double d1 = (uv11-uv12).Modulus();
1092   double d2 = (uv21-uv22).Modulus();
1093   // double delta = d1*d2*1e-6; PAL17233
1094   double delta = min( d1, d2 ) / 10.;
1095   isDeformed = ( loc1 - loc2 ).SquareModulus() > delta * delta;
1096
1097 //   double len1 = ( uv11 - uv12 ).Modulus();
1098 //   double len2 = ( uv21 - uv22 ).Modulus();
1099 //   resUV = loc1 * len2 / ( len1 + len2 ) + loc2 * len1 / ( len1 + len2 );
1100 //  return true;
1101
1102
1103 //   gp_Lin2d line1( uv11, uv12 - uv11 );
1104 //   gp_Lin2d line2( uv21, uv22 - uv21 );
1105 //   double angle = Abs( line1.Angle( line2 ) );
1106
1107 //     IntAna2d_AnaIntersection inter;
1108 //     inter.Perform( line1.Normal( loc1 ), line2.Normal( loc2 ) );
1109 //     if ( inter.IsDone() && inter.NbPoints() == 1 )
1110 //     {
1111 //       gp_Pnt2d interUV = inter.Point(1).Value();
1112 //       resUV += interUV.XY();
1113 //   inter.Perform( line1, line2 );
1114 //   interUV = inter.Point(1).Value();
1115 //   resUV += interUV.XY();
1116
1117 //   resUV /= 2.;
1118 //     }
1119   // if ( isDeformed ) {
1120   //   MESSAGE("intersectIsolines(), d1 = " << d1 << ", d2 = " << d2 << ", delta = " << delta <<
1121   //           ", " << (loc1 - loc2).SquareModulus() << " > " << delta * delta);
1122   // }
1123   return true;
1124 }
1125
1126 //=======================================================================
1127 //function : compUVByIsoIntersection
1128 //purpose  : 
1129 //=======================================================================
1130
1131 bool SMESH_Pattern::compUVByIsoIntersection (const list< list< TPoint* > >& theBndPoints,
1132                                              const gp_XY&                   theInitUV,
1133                                              gp_XY&                         theUV,
1134                                              bool &                         theIsDeformed )
1135 {
1136   // compute UV by intersection of 2 iso lines
1137   //gp_Lin2d isoLine[2];
1138   gp_XY uv1[2], uv2[2];
1139   double ratio[2];
1140   const double zero = DBL_MIN;
1141   for ( int iIso = 0; iIso < 2; iIso++ )
1142   {
1143     // to build an iso line:
1144     // find 2 pairs of consequent edge-points such that the range of their
1145     // initial parameters encloses the in-face point initial parameter
1146     gp_XY UV[2], initUV[2];
1147     int nbUV = 0, iCoord = iIso + 1;
1148     double initParam = theInitUV.Coord( iCoord );
1149
1150     list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
1151     for ( ; bndIt != theBndPoints.end(); bndIt++ )
1152     {
1153       const list< TPoint* > & bndPoints = * bndIt;
1154       TPoint* prevP = bndPoints.back(); // this is the first point
1155       list< TPoint* >::const_iterator pIt = bndPoints.begin();
1156       bool coincPrev = false;
1157       // loop on the edge-points
1158       for ( ; pIt != bndPoints.end(); pIt++ )
1159       {
1160         double paramDiff     = initParam - (*pIt)->myInitUV.Coord( iCoord );
1161         double prevParamDiff = initParam - prevP->myInitUV.Coord( iCoord );
1162         double sumOfDiff = Abs(prevParamDiff) + Abs(paramDiff);
1163         if (!coincPrev && // ignore if initParam coincides with prev point param
1164             sumOfDiff > zero && // ignore if both points coincide with initParam
1165             prevParamDiff * paramDiff <= zero )
1166         {
1167           // find UV in parametric space of theFace
1168           double r = Abs(prevParamDiff) / sumOfDiff;
1169           gp_XY uvInit = (*pIt)->myInitUV * r + prevP->myInitUV * ( 1 - r );
1170           int i = nbUV++;
1171           if ( i >= 2 ) {
1172             // throw away uv most distant from <theInitUV>
1173             gp_XY vec0 = initUV[0] - theInitUV;
1174             gp_XY vec1 = initUV[1] - theInitUV;
1175             gp_XY vec  = uvInit    - theInitUV;
1176             bool isBetween = ( vec0 * vec1 < 0 ); // is theInitUV between initUV[0] and initUV[1]
1177             double dist0 = vec0.SquareModulus();
1178             double dist1 = vec1.SquareModulus();
1179             double dist  = vec .SquareModulus();
1180             if ( !isBetween || dist < dist0 || dist < dist1 ) {
1181               i = ( dist0 < dist1 ? 1 : 0 );
1182               if ( isBetween && vec.Dot( i ? vec1 : vec0 ) < 0 )
1183                 i = 3; // theInitUV must remain between
1184             }
1185           }
1186           if ( i < 2 ) {
1187             initUV[ i ] = uvInit;
1188             UV[ i ]     = (*pIt)->myUV * r + prevP->myUV * ( 1 - r );
1189           }
1190           coincPrev = ( Abs(paramDiff) <= zero );
1191         }
1192         else
1193           coincPrev = false;
1194         prevP = *pIt;
1195       }
1196     }
1197     if ( nbUV < 2 || (UV[0]-UV[1]).SquareModulus() <= DBL_MIN*DBL_MIN ) {
1198       MESSAGE(" consequent edge-points not found, nb UV found: " << nbUV <<
1199               ", for point: " << theInitUV.X() <<" " << theInitUV.Y() );
1200       return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1201     }
1202     // an iso line should be normal to UV[0] - UV[1] direction
1203     // and be located at the same relative distance as from initial ends
1204     //gp_Lin2d iso( UV[0], UV[0] - UV[1] );
1205     double r =
1206       (initUV[0]-theInitUV).Modulus() / (initUV[0]-initUV[1]).Modulus();
1207     //gp_Pnt2d isoLoc = UV[0] * ( 1 - r ) + UV[1] * r;
1208     //isoLine[ iIso ] = iso.Normal( isoLoc );
1209     uv1[ iIso ] = UV[0];
1210     uv2[ iIso ] = UV[1];
1211     ratio[ iIso ] = r;
1212   }
1213   if ( !intersectIsolines( uv1[0], uv2[0], ratio[0],
1214                           uv1[1], uv2[1], ratio[1], theUV, theIsDeformed )) {
1215     MESSAGE(" Can't intersect isolines for a point "<<theInitUV.X()<<", "<<theInitUV.Y());
1216     return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1217   }
1218
1219   return true;
1220 }
1221
1222
1223 // ==========================================================
1224 // structure representing a node of a grid of iso-poly-lines
1225 // ==========================================================
1226
1227 struct TIsoNode {
1228   bool   myIsMovable;
1229   gp_XY  myInitUV;
1230   gp_XY  myUV;
1231   double myRatio[2];
1232   gp_Dir2d  myDir[2]; // boundary tangent dir for boundary nodes, iso dir for internal ones
1233   TIsoNode* myNext[4]; // order: (iDir=0,isForward=0), (1,0), (0,1), (1,1)
1234   TIsoNode* myBndNodes[4];     // order: (iDir=0,i=0), (1,0), (0,1), (1,1)
1235   TIsoNode(double initU, double initV):
1236     myIsMovable(true), myInitUV( initU, initV ), myUV( 1e100, 1e100 )
1237   { myNext[0] = myNext[1] = myNext[2] = myNext[3] = 0; }
1238   bool IsUVComputed() const
1239   { return myUV.X() != 1e100; }
1240   bool IsMovable() const
1241   { return myIsMovable && myNext[0] && myNext[1] && myNext[2] && myNext[3]; }
1242   void SetNotMovable()
1243   { myIsMovable = false; }
1244   void SetBoundaryNode(TIsoNode* node, int iDir, int i)
1245   { myBndNodes[ iDir + i * 2 ] = node; }
1246   TIsoNode* GetBoundaryNode(int iDir, int i)
1247   { return myBndNodes[ iDir + i * 2 ]; }
1248   void SetNext(TIsoNode* node, int iDir, int isForward)
1249   { myNext[ iDir + isForward  * 2 ] = node; }
1250   TIsoNode* GetNext(int iDir, int isForward)
1251   { return myNext[ iDir + isForward * 2 ]; }
1252 };
1253
1254 //=======================================================================
1255 //function : getNextNode
1256 //purpose  : 
1257 //=======================================================================
1258
1259 static inline TIsoNode* getNextNode(const TIsoNode* node, int dir )
1260 {
1261   TIsoNode* n = node->myNext[ dir ];
1262   if ( n && !n->IsUVComputed()/* && node->IsMovable()*/ ) {
1263     n = 0;//node->myBndNodes[ dir ];
1264 //     MESSAGE("getNextNode: use bnd for node "<<
1265 //             node->myInitUV.X()<<" "<<node->myInitUV.Y());
1266   }
1267   return n;
1268 }
1269 //=======================================================================
1270 //function : checkQuads
1271 //purpose  : check if newUV destortes quadrangles around node,
1272 //           and if ( crit == FIX_OLD ) fix newUV in this case
1273 //=======================================================================
1274
1275 enum { CHECK_NEW_IN, CHECK_NEW_OK, FIX_OLD };
1276
1277 static bool checkQuads (const TIsoNode* node,
1278                         gp_XY&          newUV,
1279                         const bool      reversed,
1280                         const int       crit = FIX_OLD,
1281                         double          fixSize = 0.)
1282 {
1283   gp_XY oldUV = node->myUV, oldUVFixed[4], oldUVImpr[4];
1284   int nbOldFix = 0, nbOldImpr = 0;
1285   double newBadRate = 0, oldBadRate = 0;
1286   bool newIsOk = true, newIsIn = true, oldIsIn = true, oldIsOk = true;
1287   int i, dir1 = 0, dir2 = 3;
1288   for ( ; dir1 < 4; dir1++, dir2++ )  // loop on 4 quadrangles around <node>
1289   {
1290     if ( dir2 > 3 ) dir2 = 0;
1291     TIsoNode* n[3];
1292     // walking counterclockwise around a quad,
1293     // nodes are in the order: node, n[0], n[1], n[2]
1294     n[0] = getNextNode( node, dir1 );
1295     n[2] = getNextNode( node, dir2 );
1296     if ( !n[0] || !n[2] ) continue;
1297     n[1] = getNextNode( n[0], dir2 );
1298     if ( !n[1] ) n[1] = getNextNode( n[2], dir1 );
1299     bool isTriangle = ( !n[1] );
1300     if ( reversed ) {
1301       TIsoNode* tmp = n[0]; n[0] = n[2]; n[2] = tmp;
1302     }
1303 //     if ( fixSize != 0 ) {
1304 // cout<<"NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1305 // cout<<"\t0: "<<n[0]->myInitUV.X()<<" "<<n[0]->myInitUV.Y()<<" UV: "<<n[0]->myUV.X()<<" "<<n[0]->myUV.Y()<<endl;
1306 // cout<<"\t1: "<<n[1]->myInitUV.X()<<" "<<n[1]->myInitUV.Y()<<" UV: "<<n[1]->myUV.X()<<" "<<n[1]->myUV.Y()<<endl;
1307 // cout<<"\t2: "<<n[2]->myInitUV.X()<<" "<<n[2]->myInitUV.Y()<<" UV: "<<n[2]->myUV.X()<<" "<<n[2]->myUV.Y()<<endl;
1308 // }
1309     // check if a quadrangle is degenerated
1310     if ( !isTriangle &&
1311         ((( n[0]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN ) ||
1312          (( n[2]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN )))
1313       isTriangle = true;
1314     if ( isTriangle &&
1315         ( n[0]->myUV - n[2]->myUV ).SquareModulus() <= DBL_MIN )
1316       continue;
1317
1318     // find min size of the diagonal node-n[1]
1319     double minDiag = fixSize;
1320     if ( minDiag == 0. ) {
1321       double maxLen2 = ( node->myUV - n[0]->myUV ).SquareModulus();
1322       if ( !isTriangle ) {
1323         maxLen2 = Max( maxLen2, ( n[0]->myUV - n[1]->myUV ).SquareModulus() );
1324         maxLen2 = Max( maxLen2, ( n[1]->myUV - n[2]->myUV ).SquareModulus() );
1325       }
1326       maxLen2 = Max( maxLen2, ( n[2]->myUV - node->myUV ).SquareModulus() );
1327       minDiag = sqrt( maxLen2 ) * M_PI / 60.; // ~ maxLen * Sin( 3 deg )
1328     }
1329
1330     // check if newUV is behind 3 dirs: n[0]-n[1], n[1]-n[2] and n[0]-n[2]
1331     // ( behind means "to the right of")
1332     // it is OK if
1333     // 1. newUV is not behind 01 and 12 dirs
1334     // 2. or newUV is not behind 02 dir and n[2] is convex
1335     bool newIn[3] = { true, true, true }, newOk[3] = { true, true, true };
1336     bool wasIn[3] = { true, true, true }, wasOk[3] = { true, true, true };
1337     gp_Vec2d moveVec[3], outVec[3];
1338     for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1339     {
1340       bool isDiag = ( i == 2 );
1341       if ( isDiag && newOk[0] && newOk[1] && !isTriangle )
1342         break;
1343       gp_Vec2d sideDir;
1344       if ( isDiag )
1345         sideDir = gp_Vec2d( n[0]->myUV, n[2]->myUV );
1346       else
1347         sideDir = gp_Vec2d( n[i]->myUV, n[i+1]->myUV );
1348
1349       gp_Vec2d outDir( sideDir.Y(), -sideDir.X() ); // to the right
1350       outDir.Normalize();
1351       gp_Vec2d newDir( n[i]->myUV, newUV );
1352       gp_Vec2d oldDir( n[i]->myUV, oldUV );
1353       outVec[i] = outDir;
1354       if ( newIsOk ) newOk[i] = ( outDir * newDir < -minDiag );
1355       if ( newIsIn ) newIn[i] = ( outDir * newDir < 0 );
1356       if ( crit == FIX_OLD ) {
1357         wasIn[i] = ( outDir * oldDir < 0 );
1358         wasOk[i] = ( outDir * oldDir < -minDiag );
1359         if ( !newOk[i] )
1360           newBadRate += outDir * newDir;
1361         if ( !wasOk[i] )
1362           oldBadRate += outDir * oldDir;
1363         // push node inside
1364         if ( !wasOk[i] ) {
1365           double oldDist = - outDir * oldDir;//, l2 = outDir * newDir;
1366           //               double r = ( l1 - minDiag ) / ( l1 + l2 );
1367           //               moveVec[i] = r * gp_Vec2d( node->myUV, newUV );
1368           moveVec[i] = ( oldDist - minDiag ) * outDir;
1369         }
1370       }
1371     }
1372
1373     // check if n[2] is convex
1374     bool convex = true;
1375     if ( !isTriangle )
1376       convex = ( outVec[0] * gp_Vec2d( n[1]->myUV, n[2]->myUV ) < 0 );
1377
1378     bool isNewOk = ( newOk[0] && newOk[1] ) || ( newOk[2] && convex );
1379     bool isNewIn = ( newIn[0] && newIn[1] ) || ( newIn[2] && convex );
1380     newIsOk = ( newIsOk && isNewOk );
1381     newIsIn = ( newIsIn && isNewIn );
1382
1383     if ( crit != FIX_OLD ) {
1384       if ( crit == CHECK_NEW_OK && !newIsOk ) break;
1385       if ( crit == CHECK_NEW_IN && !newIsIn ) break;
1386       continue;
1387     }
1388
1389     bool isOldIn = ( wasIn[0] && wasIn[1] ) || ( wasIn[2] && convex );
1390     bool isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1391     oldIsIn = ( oldIsIn && isOldIn );
1392     oldIsOk = ( oldIsOk && isOldIn );
1393
1394
1395     if ( !isOldIn ) { // node is outside a quadrangle
1396       // move newUV inside a quadrangle
1397 //MESSAGE("Quad "<< dir1 << "  WAS IN " << wasIn[0]<<" "<<wasIn[1]<<" "<<wasIn[2]);
1398       // node and newUV are outside: push newUV inside
1399       gp_XY uv;
1400       if ( convex || isTriangle ) {
1401         uv = 0.5 * ( n[0]->myUV + n[2]->myUV ) - minDiag * outVec[2].XY();
1402       }
1403       else {
1404         gp_Vec2d out = outVec[0].Normalized() + outVec[1].Normalized();
1405         double outSize = out.Magnitude();
1406         if ( outSize > DBL_MIN )
1407           out /= outSize;
1408         else
1409           out.SetCoord( -outVec[1].Y(), outVec[1].X() );
1410         uv = n[1]->myUV - minDiag * out.XY();
1411       }
1412       oldUVFixed[ nbOldFix++ ] = uv;
1413       //node->myUV = newUV;
1414     }
1415     else if ( !isOldOk )  {
1416       // try to fix old UV: move node inside as less as possible
1417 //MESSAGE("Quad "<< dir1 << "  old is BAD, try to fix old, minDiag: "<< minDiag);
1418       gp_XY uv1, uv2 = node->myUV;
1419       for ( i = isTriangle ? 2 : 0; i < 3; i++ ) // mark not computed vectors
1420         if ( wasOk[i] )
1421           moveVec[ i ].SetCoord( 1, 2e100); // not use this vector
1422       while ( !isOldOk ) {
1423         // find the least moveVec
1424         int i, iMin = 4;
1425         double minMove2 = 1e100;
1426         for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1427         {
1428           if ( moveVec[i].Coord(1) < 1e100 ) {
1429             double move2 = moveVec[i].SquareMagnitude();
1430             if ( move2 < minMove2 ) {
1431               minMove2 = move2;
1432               iMin = i;
1433             }
1434           }
1435         }
1436         if ( iMin == 4 ) {
1437           break;
1438         }
1439         // move node to newUV
1440         uv1 = node->myUV + moveVec[ iMin ].XY();
1441         uv2 += moveVec[ iMin ].XY();
1442         moveVec[ iMin ].SetCoord( 1, 2e100); // not use this vector more
1443         // check if uv1 is ok
1444         for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1445           wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv1 ) < -minDiag );
1446         isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1447         if ( isOldOk )
1448           oldUVImpr[ nbOldImpr++ ] = uv1;
1449         else {
1450           // check if uv2 is ok
1451           for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1452             wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv2 ) < -minDiag );
1453           isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1454           if ( isOldOk )
1455             oldUVImpr[ nbOldImpr++ ] = uv2;
1456         }
1457       }
1458     }
1459
1460   } // loop on 4 quadrangles around <node>
1461
1462   if ( crit == CHECK_NEW_OK  )
1463     return newIsOk;
1464   if ( crit == CHECK_NEW_IN  )
1465     return newIsIn;
1466
1467   if ( newIsOk )
1468     return true;
1469
1470   if ( oldIsOk )
1471     newUV = oldUV;
1472   else {
1473     if ( oldIsIn && nbOldImpr ) {
1474 //       MESSAGE(" Try to improve UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1475 //               " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1476       gp_XY uv = oldUVImpr[ 0 ];
1477       for ( int i = 1; i < nbOldImpr; i++ )
1478         uv += oldUVImpr[ i ];
1479       uv /= nbOldImpr;
1480       if ( checkQuads( node, uv, reversed, CHECK_NEW_OK )) {
1481         newUV = uv;
1482         return false;
1483       }
1484       else {
1485         //MESSAGE(" Can't improve UV, uv: "<<uv.X()<<" "<<uv.Y());
1486       }
1487     }
1488     if ( !oldIsIn && nbOldFix ) {
1489 //       MESSAGE(" Try to fix UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1490 //               " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1491       gp_XY uv = oldUVFixed[ 0 ];
1492       for ( int i = 1; i < nbOldFix; i++ )
1493         uv += oldUVFixed[ i ];
1494       uv /= nbOldFix;
1495       if ( checkQuads( node, uv, reversed, CHECK_NEW_IN )) {
1496         newUV = uv;
1497         return false;
1498       }
1499       else {
1500         //MESSAGE(" Can't fix UV, uv: "<<uv.X()<<" "<<uv.Y());
1501       }
1502     }
1503     if ( newIsIn && oldIsIn )
1504       newUV = ( newBadRate < oldBadRate ) ? newUV : oldUV;
1505     else if ( !newIsIn )
1506       newUV = oldUV;
1507   }
1508
1509   return false;
1510 }
1511
1512 //=======================================================================
1513 //function : compUVByElasticIsolines
1514 //purpose  : compute UV as nodes of iso-poly-lines consisting of
1515 //           segments keeping relative size as in the pattern
1516 //=======================================================================
1517 //#define DEB_COMPUVBYELASTICISOLINES
1518 bool SMESH_Pattern::
1519   compUVByElasticIsolines(const list< list< TPoint* > >& theBndPoints,
1520                           const list< TPoint* >&         thePntToCompute)
1521 {
1522   return false; // PAL17233
1523 //cout << "============================== KEY POINTS =============================="<<endl;
1524 //   list< int >::iterator kpIt = myKeyPointIDs.begin();
1525 //   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ ) {
1526 //     TPoint& p = myPoints[ *kpIt ];
1527 //     cout << "INIT: " << p.myInitUV.X() << " " << p.myInitUV.Y() <<
1528 //       " UV: " << p.myUV.X() << " " << p.myUV.Y() << endl;
1529 //  }
1530 //cout << "=============================="<<endl;
1531
1532   // Define parameters of iso-grid nodes in U and V dir
1533
1534   set< double > paramSet[ 2 ];
1535   list< list< TPoint* > >::const_iterator pListIt;
1536   list< TPoint* >::const_iterator pIt;
1537   for ( pListIt = theBndPoints.begin(); pListIt != theBndPoints.end(); pListIt++ ) {
1538     const list< TPoint* > & pList = * pListIt;
1539     for ( pIt = pList.begin(); pIt != pList.end(); pIt++ ) {
1540       paramSet[0].insert( (*pIt)->myInitUV.X() );
1541       paramSet[1].insert( (*pIt)->myInitUV.Y() );
1542     }
1543   }
1544   for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1545     paramSet[0].insert( (*pIt)->myInitUV.X() );
1546     paramSet[1].insert( (*pIt)->myInitUV.Y() );
1547   }
1548   // unite close parameters and split too long segments
1549   int iDir;
1550   double tol[ 2 ];
1551   for ( iDir = 0; iDir < 2; iDir++ )
1552   {
1553     set< double > & params = paramSet[ iDir ];
1554     double range = ( *params.rbegin() - *params.begin() );
1555     double toler = range / 1e6;
1556     tol[ iDir ] = toler;
1557 //    double maxSegment = range / params.size() / 2.;
1558 //
1559 //     set< double >::iterator parIt = params.begin();
1560 //     double prevPar = *parIt;
1561 //     for ( parIt++; parIt != params.end(); parIt++ )
1562 //     {
1563 //       double segLen = (*parIt) - prevPar;
1564 //       if ( segLen < toler )
1565 //         ;//params.erase( prevPar ); // unite
1566 //       else if ( segLen > maxSegment )
1567 //         params.insert( prevPar + 0.5 * segLen ); // split
1568 //       prevPar = (*parIt);
1569 //     }
1570   }
1571
1572   // Make nodes of a grid of iso-poly-lines
1573
1574   list < TIsoNode > nodes;
1575   typedef list < TIsoNode *> TIsoLine;
1576   map < double, TIsoLine > isoMap[ 2 ];
1577
1578   set< double > & params0 = paramSet[ 0 ];
1579   set< double >::iterator par0It = params0.begin();
1580   for ( ; par0It != params0.end(); par0It++ )
1581   {
1582     TIsoLine & isoLine0 = isoMap[0][ *par0It ]; // vertical isoline with const U
1583     set< double > & params1 = paramSet[ 1 ];
1584     set< double >::iterator par1It = params1.begin();
1585     for ( ; par1It != params1.end(); par1It++ )
1586     {
1587       nodes.push_back( TIsoNode( *par0It, *par1It ) );
1588       isoLine0.push_back( & nodes.back() );
1589       isoMap[1][ *par1It ].push_back( & nodes.back() );
1590     }
1591   }
1592
1593   // Compute intersections of boundaries with iso-lines:
1594   // only boundary nodes will have computed UV so far
1595
1596   Bnd_Box2d uvBnd;
1597   list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
1598   list< TIsoNode* > bndNodes; // nodes corresponding to outer theBndPoints
1599   for ( ; bndIt != theBndPoints.end(); bndIt++ )
1600   {
1601     const list< TPoint* > & bndPoints = * bndIt;
1602     TPoint* prevP = bndPoints.back(); // this is the first point
1603     list< TPoint* >::const_iterator pIt = bndPoints.begin();
1604     // loop on the edge-points
1605     for ( ; pIt != bndPoints.end(); pIt++ )
1606     {
1607       TPoint* point = *pIt;
1608       for ( iDir = 0; iDir < 2; iDir++ )
1609       {
1610         const int iCoord = iDir + 1;
1611         const int iOtherCoord = 2 - iDir;
1612         double par1 = prevP->myInitUV.Coord( iCoord );
1613         double par2 = point->myInitUV.Coord( iCoord );
1614         double parDif = par2 - par1;
1615         if ( Abs( parDif ) <= DBL_MIN )
1616           continue;
1617         // find iso-lines intersecting a bounadry
1618         double toler = tol[ 1 - iDir ];
1619         double minPar = Min ( par1, par2 );
1620         double maxPar = Max ( par1, par2 );
1621         map < double, TIsoLine >& isos = isoMap[ iDir ];
1622         map < double, TIsoLine >::iterator isoIt = isos.begin();
1623         for ( ; isoIt != isos.end(); isoIt++ )
1624         {
1625           double isoParam = (*isoIt).first;
1626           if ( isoParam < minPar || isoParam > maxPar )
1627             continue;
1628           double r = ( isoParam - par1 ) / parDif;
1629           gp_XY uv = ( 1 - r ) * prevP->myUV + r * point->myUV;
1630           gp_XY initUV = ( 1 - r ) * prevP->myInitUV + r * point->myInitUV;
1631           double otherPar = initUV.Coord( iOtherCoord ); // along isoline
1632           // find existing node with otherPar or insert a new one
1633           TIsoLine & isoLine = (*isoIt).second;
1634           double nodePar;
1635           TIsoLine::iterator nIt = isoLine.begin();
1636           for ( ; nIt != isoLine.end(); nIt++ ) {
1637             nodePar = (*nIt)->myInitUV.Coord( iOtherCoord );
1638             if ( nodePar >= otherPar )
1639               break;
1640           }
1641           TIsoNode * node;
1642           if ( Abs( nodePar - otherPar ) <= toler )
1643             node = ( nIt == isoLine.end() ) ? isoLine.back() : (*nIt);
1644           else {
1645             nodes.push_back( TIsoNode( initUV.X(), initUV.Y() ) );
1646             node = & nodes.back();
1647             isoLine.insert( nIt, node );
1648           }
1649           node->SetNotMovable();
1650           node->myUV = uv;
1651           uvBnd.Add( gp_Pnt2d( uv ));
1652 //  cout << "bnd: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1653           // tangent dir
1654           gp_XY tgt( point->myUV - prevP->myUV );
1655           if ( ::IsEqual( r, 1. ))
1656             node->myDir[ 0 ] = tgt;
1657           else if ( ::IsEqual( r, 0. ))
1658             node->myDir[ 1 ] = tgt;
1659           else
1660             node->myDir[ 1 ] = node->myDir[ 0 ] = tgt;
1661           // keep boundary nodes corresponding to boundary points
1662           if ( bndIt == theBndPoints.begin() && ::IsEqual( r, 1. ))
1663             if ( bndNodes.empty() || bndNodes.back() != node )
1664               bndNodes.push_back( node );
1665         } // loop on isolines
1666       } // loop on 2 directions
1667       prevP = point;
1668     } // loop on boundary points
1669   } // loop on boundaries
1670
1671   // Define orientation
1672
1673   // find the point with the least X
1674   double leastX = DBL_MAX;
1675   TIsoNode * leftNode;
1676   list < TIsoNode >::iterator nodeIt = nodes.begin();
1677   for ( ; nodeIt != nodes.end(); nodeIt++  ) {
1678     TIsoNode & node = *nodeIt;
1679     if ( node.IsUVComputed() && node.myUV.X() < leastX ) {
1680       leastX = node.myUV.X();
1681       leftNode = &node;
1682     }
1683 // if ( node.IsUVComputed() ) {
1684 // cout << "bndNode INIT: " << node.myInitUV.X()<<" "<<node.myInitUV.Y()<<" UV: "<<
1685 //   node.myUV.X()<<" "<<node.myUV.Y()<<endl<<
1686 //    " dir0: "<<node.myDir[0].X()<<" "<<node.myDir[0].Y() <<
1687 //      " dir1: "<<node.myDir[1].X()<<" "<<node.myDir[1].Y() << endl;
1688 // }
1689   }
1690   bool reversed = ( leftNode->myDir[0].Y() + leftNode->myDir[1].Y() > 0 );
1691   //SCRUTE( reversed );
1692
1693   // Prepare internal nodes:
1694   // 1. connect nodes
1695   // 2. compute ratios
1696   // 3. find boundary nodes for each node
1697   // 4. remove nodes out of the boundary
1698   for ( iDir = 0; iDir < 2; iDir++ )
1699   {
1700     const int iCoord = 2 - iDir; // coord changing along an isoline
1701     map < double, TIsoLine >& isos = isoMap[ iDir ];
1702     map < double, TIsoLine >::iterator isoIt = isos.begin();
1703     for ( ; isoIt != isos.end(); isoIt++ )
1704     {
1705       TIsoLine & isoLine = (*isoIt).second;
1706       bool firstCompNodeFound = false;
1707       TIsoLine::iterator lastCompNodePos, nPrevIt, nIt, nNextIt, nIt2;
1708       nPrevIt = nIt = nNextIt = isoLine.begin();
1709       nIt++;
1710       nNextIt++; nNextIt++;
1711       while ( nIt != isoLine.end() )
1712       {
1713         // 1. connect prev - cur
1714         TIsoNode* node = *nIt, * prevNode = *nPrevIt;
1715         if ( !firstCompNodeFound && prevNode->IsUVComputed() ) {
1716           firstCompNodeFound = true;
1717           lastCompNodePos = nPrevIt;
1718         }
1719         if ( firstCompNodeFound ) {
1720           node->SetNext( prevNode, iDir, 0 );
1721           prevNode->SetNext( node, iDir, 1 );
1722         }
1723         // 2. compute ratio
1724         if ( nNextIt != isoLine.end() ) {
1725           double par1 = prevNode->myInitUV.Coord( iCoord );
1726           double par2 = node->myInitUV.Coord( iCoord );
1727           double par3 = (*nNextIt)->myInitUV.Coord( iCoord );
1728           node->myRatio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1729         }
1730         // 3. find boundary nodes
1731         if ( node->IsUVComputed() )
1732           lastCompNodePos = nIt;
1733         else if ( firstCompNodeFound && nNextIt != isoLine.end() ) {
1734           TIsoNode* bndNode1 = *lastCompNodePos, *bndNode2 = 0;
1735           for ( nIt2 = nNextIt; nIt2 != isoLine.end(); nIt2++ )
1736             if ( (*nIt2)->IsUVComputed() )
1737               break;
1738           if ( nIt2 != isoLine.end() ) {
1739             bndNode2 = *nIt2;
1740             node->SetBoundaryNode( bndNode1, iDir, 0 );
1741             node->SetBoundaryNode( bndNode2, iDir, 1 );
1742 // cout << "--------------------------------------------------"<<endl;
1743 //  cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<<endl<<
1744 //   " dir0: "<<bndNode1->myDir[0].X()<<" "<<bndNode1->myDir[0].Y() <<
1745 //     " dir1: "<<bndNode1->myDir[1].X()<<" "<<bndNode1->myDir[1].Y() << endl;
1746 //  cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl<<
1747 //   " dir0: "<<bndNode2->myDir[0].X()<<" "<<bndNode2->myDir[0].Y() <<
1748 //     " dir1: "<<bndNode2->myDir[1].X()<<" "<<bndNode2->myDir[1].Y() << endl;
1749           }
1750           else {
1751             /// WHAT IN THIS CASE ????????????? MAY BE THIS, I AM NOT SURE :(
1752             node->SetBoundaryNode( 0, iDir, 0 );
1753             node->SetBoundaryNode( 0, iDir, 1 );
1754           }
1755         }
1756         nIt++; nPrevIt++;
1757         if ( nNextIt != isoLine.end() ) nNextIt++;
1758         // 4. remove nodes out of the boundary
1759         if ( !firstCompNodeFound )
1760           isoLine.pop_front();
1761       } // loop on isoLine nodes
1762
1763       // remove nodes after the boundary
1764 //       for ( nIt = ++lastCompNodePos; nIt != isoLine.end(); nIt++ )
1765 //         (*nIt)->SetNotMovable();
1766       isoLine.erase( ++lastCompNodePos, isoLine.end() );
1767     } // loop on isolines
1768   } // loop on 2 directions
1769
1770   // Compute local isoline direction for internal nodes
1771
1772   /*
1773   map < double, TIsoLine >& isos = isoMap[ 0 ]; // vertical isolines with const U
1774   map < double, TIsoLine >::iterator isoIt = isos.begin();
1775   for ( ; isoIt != isos.end(); isoIt++ )
1776   {
1777     TIsoLine & isoLine = (*isoIt).second;
1778     TIsoLine::iterator nIt = isoLine.begin();
1779     for ( ; nIt != isoLine.end(); nIt++ )
1780     {
1781       TIsoNode* node = *nIt;
1782       if ( node->IsUVComputed() || !node->IsMovable() )
1783         continue;
1784       gp_Vec2d aTgt[2], aNorm[2];
1785       double ratio[2];
1786       bool OK = true;
1787       for ( iDir = 0; iDir < 2; iDir++ )
1788       {
1789         TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1790         TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1791         if ( !bndNode1 || !bndNode2 ) {
1792           OK = false;
1793           break;
1794         }
1795         const int iCoord = 2 - iDir; // coord changing along an isoline
1796         double par1 = bndNode1->myInitUV.Coord( iCoord );
1797         double par2 = node->myInitUV.Coord( iCoord );
1798         double par3 = bndNode2->myInitUV.Coord( iCoord );
1799         ratio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1800
1801         gp_Vec2d tgt1( bndNode1->myDir[0].XY() + bndNode1->myDir[1].XY() );
1802         gp_Vec2d tgt2( bndNode2->myDir[0].XY() + bndNode2->myDir[1].XY() );
1803         if ( bool( iDir ) == reversed ) tgt2.Reverse(); // along perpend. isoline
1804         else                            tgt1.Reverse();
1805 //cout<<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" | "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1806
1807         if ( ratio[ iDir ] < 0.5 )
1808           aNorm[ iDir ] = gp_Vec2d( -tgt1.Y(), tgt1.X() ); // rotate tgt to the left
1809         else
1810           aNorm[ iDir ] = gp_Vec2d( -tgt2.Y(), tgt2.X() );
1811         if ( iDir == 1 )
1812           aNorm[ iDir ].Reverse();  // along iDir isoline
1813
1814         double angle = tgt1.Angle( tgt2 ); //  [-PI, PI]
1815         // maybe angle is more than |PI|
1816         if ( Abs( angle ) > PI / 2. ) {
1817           // check direction of the last but one perpendicular isoline
1818           TIsoNode* prevNode = bndNode2->GetNext( iDir, 0 );
1819           bndNode1 = prevNode->GetBoundaryNode( 1 - iDir, 0 );
1820           bndNode2 = prevNode->GetBoundaryNode( 1 - iDir, 1 );
1821           gp_Vec2d isoDir( bndNode1->myUV, bndNode2->myUV );
1822           if ( isoDir * tgt2 < 0 )
1823             isoDir.Reverse();
1824           double angle2 = tgt1.Angle( isoDir );
1825           //cout << " isoDir: "<< isoDir.X() <<" "<<isoDir.Y() << " ANGLE: "<< angle << " "<<angle2<<endl;
1826           if (angle2 * angle < 0 && // check the sign of an angle close to PI
1827               Abs ( Abs ( angle ) - PI ) <= PI / 180. ) {
1828             //MESSAGE("REVERSE ANGLE");
1829             angle = -angle;
1830           }
1831           if ( Abs( angle2 ) > Abs( angle ) ||
1832               ( angle2 * angle < 0 && Abs( angle2 ) > Abs( angle - angle2 ))) {
1833             //MESSAGE("Add PI");
1834             // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1835             // cout <<"ISO: " << isoParam << " " << (*iso2It).first << endl;
1836             // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<< endl;
1837             // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl;
1838             // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<"  "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1839             angle += ( angle < 0 ) ? 2. * PI : -2. * PI;
1840           }
1841         }
1842         aTgt[ iDir ] = tgt1.Rotated( angle * ratio[ iDir ] ).XY();
1843       } // loop on 2 dir
1844
1845       if ( OK ) {
1846         for ( iDir = 0; iDir < 2; iDir++ )
1847         {
1848           aTgt[iDir].Normalize();
1849           aNorm[1-iDir].Normalize();
1850           double r = Abs ( ratio[iDir] - 0.5 ) * 2.0; // [0,1] - distance from the middle
1851           r *= r;
1852
1853           node->myDir[iDir] = //aTgt[iDir];
1854             aNorm[1-iDir] * r + aTgt[iDir] * ( 1. - r );
1855         }
1856 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1857 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" - "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1858 //  cout << " isoDir: "<< node->myDir[0].X() <<" "<<node->myDir[0].Y()<<"  |  "
1859 //    << node->myDir[1].X() <<" "<<node->myDir[1].Y()<<endl;
1860       }
1861     } // loop on iso nodes
1862   } // loop on isolines
1863 */
1864   // Find nodes to start computing UV from
1865
1866   list< TIsoNode* > startNodes;
1867   list< TIsoNode* >::iterator nIt = bndNodes.end();
1868   TIsoNode* node = *(--nIt);
1869   TIsoNode* prevNode = *(--nIt);
1870   for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1871   {
1872     TIsoNode* nextNode = *nIt;
1873     gp_Vec2d initTgt1( prevNode->myInitUV, node->myInitUV );
1874     gp_Vec2d initTgt2( node->myInitUV, nextNode->myInitUV );
1875     double initAngle = initTgt1.Angle( initTgt2 );
1876     double angle = node->myDir[0].Angle( node->myDir[1] );
1877     if ( reversed ) angle = -angle;
1878     if ( initAngle > angle && initAngle - angle > M_PI / 2.1 ) {
1879       // find a close internal node
1880       TIsoNode* nClose = 0;
1881       list< TIsoNode* > testNodes;
1882       testNodes.push_back( node );
1883       list< TIsoNode* >::iterator it = testNodes.begin();
1884       for ( ; !nClose && it != testNodes.end(); it++ )
1885       {
1886         for (int i = 0; i < 4; i++ )
1887         {
1888           nClose = (*it)->myNext[ i ];
1889           if ( nClose ) {
1890             if ( !nClose->IsUVComputed() )
1891               break;
1892             else {
1893               testNodes.push_back( nClose );
1894               nClose = 0;
1895             }
1896           }
1897         }
1898       }
1899       startNodes.push_back( nClose );
1900 // cout << "START: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<
1901 //   node->myUV.X()<<" "<<node->myUV.Y()<<endl<<
1902 //   "initAngle: " << initAngle << " angle: " << angle << endl;
1903 // cout <<" init tgt: " << initTgt1.X()<<" "<<initTgt1.Y()<<" | "<< initTgt2.X()<<" "<<initTgt2.Y()<<endl;
1904 // cout << " tgt: "<< node->myDir[ 0 ].X() <<" "<<node->myDir[ 0 ].Y()<<" | "<<
1905 //    node->myDir[ 1 ].X() <<" "<<node->myDir[ 1 ].Y()<<endl;
1906 // cout << "CLOSE: "<<nClose->myInitUV.X()<<" "<<nClose->myInitUV.Y()<<endl;
1907     }
1908     prevNode = node;
1909     node = nextNode;
1910   }
1911
1912   // Compute starting UV of internal nodes
1913
1914   list < TIsoNode* > internNodes;
1915   bool needIteration = true;
1916   if ( startNodes.empty() ) {
1917     //MESSAGE( " Starting UV by compUVByIsoIntersection()");
1918     needIteration = false;
1919     map < double, TIsoLine >& isos = isoMap[ 0 ];
1920     map < double, TIsoLine >::iterator isoIt = isos.begin();
1921     for ( ; isoIt != isos.end(); isoIt++ )
1922     {
1923       TIsoLine & isoLine = (*isoIt).second;
1924       TIsoLine::iterator nIt = isoLine.begin();
1925       for ( ; !needIteration && nIt != isoLine.end(); nIt++ )
1926       {
1927         TIsoNode* node = *nIt;
1928         if ( !node->IsUVComputed() && node->IsMovable() ) {
1929           internNodes.push_back( node );
1930           //bool isDeformed;
1931           if ( !compUVByIsoIntersection(theBndPoints, node->myInitUV,
1932                                         node->myUV, needIteration ))
1933             node->myUV = node->myInitUV;
1934         }
1935       }
1936     }
1937     if ( needIteration )
1938       for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1939       {
1940         TIsoNode* node = *nIt, *nClose = 0;
1941         list< TIsoNode* > testNodes;
1942         testNodes.push_back( node );
1943         list< TIsoNode* >::iterator it = testNodes.begin();
1944         for ( ; !nClose && it != testNodes.end(); it++ )
1945         {
1946           for (int i = 0; i < 4; i++ )
1947           {
1948             nClose = (*it)->myNext[ i ];
1949             if ( nClose ) {
1950               if ( !nClose->IsUVComputed() && nClose->IsMovable() )
1951                 break;
1952               else {
1953                 testNodes.push_back( nClose );
1954                 nClose = 0;
1955               }
1956             }
1957           }
1958         }
1959         startNodes.push_back( nClose );
1960       }
1961   }
1962
1963   double aMin[2], aMax[2], step[2];
1964   uvBnd.Get( aMin[0], aMin[1], aMax[0], aMax[1] );
1965   double minUvSize = Min ( aMax[0]-aMin[0], aMax[1]-aMin[1] );
1966   step[0] = minUvSize / paramSet[ 0 ].size() / 10;
1967   step[1] = minUvSize / paramSet[ 1 ].size() / 10;
1968 //cout << "STEPS: " << step[0] << " " << step[1]<< endl;
1969
1970   for ( nIt = startNodes.begin(); nIt != startNodes.end(); nIt++ )
1971   {
1972     TIsoNode *node = *nIt;
1973     if ( node->IsUVComputed() || !node->IsMovable() )
1974       continue;
1975     gp_XY newUV( 0, 0 ), sumDir( 0, 0 );
1976     int nbComp = 0, nbPrev = 0;
1977     for ( iDir = 0; iDir < 2; iDir++ )
1978     {
1979       TIsoNode* prevNode1 = 0, *prevNode2 = 0;
1980       TIsoNode* n = node->GetNext( iDir, 0 );
1981       if ( n->IsUVComputed() )
1982         prevNode1 = n;
1983       else
1984         startNodes.push_back( n );
1985       n = node->GetNext( iDir, 1 );
1986       if ( n->IsUVComputed() )
1987         prevNode2 = n;
1988       else
1989         startNodes.push_back( n );
1990       if ( !prevNode1 ) {
1991         prevNode1 = prevNode2;
1992         prevNode2 = 0;
1993       }
1994       if ( prevNode1 ) nbPrev++;
1995       if ( prevNode2 ) nbPrev++;
1996       if ( prevNode1 ) {
1997         gp_XY dir;
1998           double prevPar = prevNode1->myInitUV.Coord( 2 - iDir );
1999           double par = node->myInitUV.Coord( 2 - iDir );
2000           bool isEnd = ( prevPar > par );
2001 //          dir = node->myDir[ 1 - iDir ].XY() * ( isEnd ? -1. : 1. );
2002         //cout << "__________"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
2003           TIsoNode* bndNode = node->GetBoundaryNode( iDir, isEnd );
2004           if ( !bndNode ) {
2005             MESSAGE("Why we are here?");
2006             continue;
2007           }
2008           gp_XY tgt( bndNode->myDir[0].XY() + bndNode->myDir[1].XY() );
2009           dir.SetCoord( 1, tgt.Y() * ( reversed ? 1 : -1 ));
2010           dir.SetCoord( 2, tgt.X() * ( reversed ? -1 : 1 ));
2011         //cout << "bndNode UV: " << bndNode->myUV.X()<<" "<<bndNode->myUV.Y()<< endl;
2012           //  cout << " tgt: "<< bndNode->myDir[ 0 ].X() <<" "<<bndNode->myDir[ 0 ].Y()<<" | "<<
2013           //     bndNode->myDir[ 1 ].X() <<" "<<bndNode->myDir[ 1 ].Y()<<endl;
2014           //cout << "prevNode UV: " << prevNode1->myUV.X()<<" "<<prevNode1->myUV.Y()<<
2015             //" par: " << prevPar << endl;
2016           //           cout <<" tgt: " << tgt.X()<<" "<<tgt.Y()<<endl;
2017         //cout << " DIR: "<< dir.X() <<" "<<dir.Y()<<endl;
2018         if ( prevNode2 ) {
2019           //cout << "____2next______"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
2020           gp_XY & uv1 = prevNode1->myUV;
2021           gp_XY & uv2 = prevNode2->myUV;
2022 //           dir = ( uv2 - uv1 );
2023 //           double len = dir.Modulus();
2024 //           if ( len > DBL_MIN )
2025 //             dir /= len * 0.5;
2026           double r = node->myRatio[ iDir ];
2027           newUV += uv1 * ( 1 - r ) + uv2 * r;
2028         }
2029         else {
2030           newUV += prevNode1->myUV + dir * step[ iDir ];
2031         }
2032         sumDir += dir;
2033         nbComp++;
2034       }
2035     }
2036     if ( !nbComp ) continue;
2037     newUV /= nbComp;
2038     node->myUV = newUV;
2039     //cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
2040
2041     // check if a quadrangle is not distorted
2042     if ( nbPrev > 1 ) {
2043       //int crit = ( nbPrev == 4 ) ? FIX_OLD : CHECK_NEW_IN;
2044       if ( !checkQuads( node, newUV, reversed, FIX_OLD, step[0] + step[1] )) {
2045       //cout <<" newUV: " << node->myUV.X() << " "<<node->myUV.Y() << " nbPrev: "<<nbPrev<< endl;
2046       //  cout << "_FIX_INIT_ fixedUV: " << newUV.X() << " "<<newUV.Y() << endl;
2047         node->myUV = newUV;
2048       }
2049     }
2050     internNodes.push_back( node );
2051   }
2052
2053   // Move nodes
2054
2055   static int maxNbIter = 100;
2056 #ifdef DEB_COMPUVBYELASTICISOLINES
2057 //   maxNbIter++;
2058   bool useNbMoveNode = 0;
2059   static int maxNbNodeMove = 100;
2060   maxNbNodeMove++;
2061   int nbNodeMove = 0;
2062   if ( !useNbMoveNode )
2063     maxNbIter = ( maxNbIter < 0 ) ? 100 : -1;
2064 #endif
2065   double maxMove;
2066   int nbIter = 0;
2067   do {
2068     if ( !needIteration) break;
2069 #ifdef DEB_COMPUVBYELASTICISOLINES
2070     if ( nbIter >= maxNbIter ) break;
2071 #endif
2072     maxMove = 0.0;
2073     list < TIsoNode* >::iterator nIt = internNodes.begin();
2074     for ( ; nIt != internNodes.end(); nIt++  ) {
2075 #ifdef DEB_COMPUVBYELASTICISOLINES
2076       if (useNbMoveNode )
2077         cout << nbNodeMove <<" =================================================="<<endl;
2078 #endif
2079       TIsoNode * node = *nIt;
2080       // make lines
2081       //gp_Lin2d line[2];
2082       gp_XY loc[2];
2083       for ( iDir = 0; iDir < 2; iDir++ )
2084       {
2085         gp_XY & uv1 = node->GetNext( iDir, 0 )->myUV;
2086         gp_XY & uv2 = node->GetNext( iDir, 1 )->myUV;
2087         double r = node->myRatio[ iDir ];
2088         loc[ iDir ] = uv1 * ( 1 - r ) + uv2 * r;
2089 //         line[ iDir ].SetLocation( loc[ iDir ] );
2090 //         line[ iDir ].SetDirection( node->myDir[ iDir ] );
2091       }
2092       // define ratio
2093       bool ok = true; // <- stupid fix TO AVOID PB OF NODES WITH NULL BND NODES
2094 //      double locR[2] = { 0, 0 };
2095       for ( iDir = 0; iDir < 2; iDir++ )
2096       {
2097         const int iCoord = 2 - iDir; // coord changing along an isoline
2098         TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
2099         TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
2100         if ( !bndNode1 || !bndNode2 ) {
2101           ok = false; break;
2102         }
2103         double par1 = bndNode1->myInitUV.Coord( iCoord );
2104         double par2 = node->myInitUV.Coord( iCoord );
2105         double par3 = bndNode2->myInitUV.Coord( iCoord );
2106         double r = ( par2 - par1 ) / ( par3 - par1 );
2107         r = Abs ( r - 0.5 ) * 2.0;  // [0,1] - distance from the middle
2108 //        locR[ iDir ] = ( 1 - r * r ) * 0.25;
2109       }
2110       //locR[0] = locR[1] = 0.25;
2111       // intersect the 2 lines and move a node
2112       //IntAna2d_AnaIntersection inter( line[0], line[1] );
2113       if ( ok /*inter.IsDone() && inter.NbPoints() ==*/ )
2114       {
2115 //         double intR = 1 - locR[0] - locR[1];
2116 //         gp_XY newUV = inter.Point(1).Value().XY();
2117 //         if ( !checkQuads( node, newUV, reversed, CHECK_NEW_IN ))
2118 //           newUV = ( locR[0] * loc[0] + locR[1] * loc[1] ) / ( 1 - intR );
2119 //         else
2120 //           newUV = intR * newUV + locR[0] * loc[0] + locR[1] * loc[1];
2121         gp_XY newUV = 0.5 * ( loc[0] +  loc[1] );
2122         // avoid parallel isolines intersection
2123         checkQuads( node, newUV, reversed );
2124
2125         maxMove = Max( maxMove, ( newUV - node->myUV ).SquareModulus());
2126         node->myUV = newUV;
2127       } // intersection found
2128 #ifdef DEB_COMPUVBYELASTICISOLINES
2129       if (useNbMoveNode && ++nbNodeMove >= maxNbNodeMove ) break;
2130 #endif
2131     } // loop on internal nodes
2132 #ifdef DEB_COMPUVBYELASTICISOLINES
2133     if (useNbMoveNode && nbNodeMove >= maxNbNodeMove ) break;
2134 #endif
2135   } while ( maxMove > 1e-8 && nbIter++ < maxNbIter );
2136
2137   //MESSAGE( "compUVByElasticIsolines(): Nb iterations " << nbIter << " dist: " << sqrt( maxMove ));
2138
2139   if ( nbIter >= maxNbIter && sqrt(maxMove) > minUvSize * 0.05 ) {
2140     MESSAGE( "compUVByElasticIsolines() failed: "<<sqrt(maxMove)<<">"<<minUvSize * 0.05);
2141 #ifndef DEB_COMPUVBYELASTICISOLINES
2142     return false;
2143 #endif
2144   }
2145
2146   // Set computed UV to points
2147
2148   for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
2149     TPoint* point = *pIt;
2150     //gp_XY oldUV = point->myUV;
2151     double minDist = DBL_MAX;
2152     list < TIsoNode >::iterator nIt = nodes.begin();
2153     for ( ; nIt != nodes.end(); nIt++ ) {
2154       double dist = ( (*nIt).myInitUV - point->myInitUV ).SquareModulus();
2155       if ( dist < minDist ) {
2156         minDist = dist;
2157         point->myUV = (*nIt).myUV;
2158       }
2159     }
2160   }
2161
2162   return true;
2163 }
2164
2165
2166 //=======================================================================
2167 //function : setFirstEdge
2168 //purpose  : choose the best first edge of theWire; return the summary distance
2169 //           between point UV computed by isolines intersection and
2170 //           eventual UV got from edge p-curves
2171 //=======================================================================
2172
2173 //#define DBG_SETFIRSTEDGE
2174 double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstEdgeID)
2175 {
2176   int iE, nbEdges = theWire.size();
2177   if ( nbEdges == 1 )
2178     return 0;
2179
2180   // Transform UVs computed by iso to fit bnd box of a wire
2181
2182   // max nb of points on an edge
2183   int maxNbPnt = 0;
2184   int eID = theFirstEdgeID;
2185   for ( iE = 0; iE < nbEdges; iE++ )
2186     maxNbPnt = Max ( maxNbPnt, getShapePoints( eID++ ).size() );
2187
2188   // compute bnd boxes
2189   TopoDS_Face face = TopoDS::Face( myShape );
2190   Bnd_Box2d bndBox, eBndBox;
2191   eID = theFirstEdgeID;
2192   list< TopoDS_Edge >::iterator eIt;
2193   list< TPoint* >::iterator pIt;
2194   for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
2195   {
2196     // UV by isos stored in TPoint.myXYZ
2197     list< TPoint* > & ePoints = getShapePoints( eID++ );
2198     for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
2199       TPoint* p = (*pIt);
2200       bndBox.Add( gp_Pnt2d( p->myXYZ.X(), p->myXYZ.Y() ));
2201     }
2202     // UV by an edge p-curve
2203     double f, l;
2204     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( *eIt, face, f, l );
2205     double dU = ( l - f ) / ( maxNbPnt - 1 );
2206     for ( int i = 0; i < maxNbPnt; i++ )
2207       eBndBox.Add( C2d->Value( f + i * dU ));
2208   }
2209
2210   // transform UVs by isos
2211   double minPar[2], maxPar[2], eMinPar[2], eMaxPar[2];
2212   bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2213   eBndBox.Get( eMinPar[0], eMinPar[1], eMaxPar[0], eMaxPar[1] );
2214 #ifdef DBG_SETFIRSTEDGE
2215   MESSAGE ( "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
2216          << eMinPar[1] << " - " << eMaxPar[1] );
2217 #endif
2218   for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2219   {
2220     double dMin = eMinPar[i] - minPar[i];
2221     double dMax = eMaxPar[i] - maxPar[i];
2222     double dPar = maxPar[i] - minPar[i];
2223     eID = theFirstEdgeID;
2224     for ( iE = 0; iE < nbEdges; iE++ ) // loop on edges of a boundary
2225     {
2226       list< TPoint* > & ePoints = getShapePoints( eID++ );
2227       for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) // loop on edge points
2228       {
2229         double par = (*pIt)->myXYZ.Coord( iC );
2230         double r = ( par - minPar[i] ) / dPar;
2231         par += ( 1 - r ) * dMin + r * dMax;
2232         (*pIt)->myXYZ.SetCoord( iC, par );
2233       }
2234     }
2235   }
2236
2237   TopoDS_Edge eBest;
2238   double minDist = DBL_MAX;
2239   for ( iE = 0 ; iE < nbEdges; iE++ )
2240   {
2241 #ifdef DBG_SETFIRSTEDGE
2242     MESSAGE ( " VARIANT " << iE );
2243 #endif
2244     // evaluate the distance between UV computed by the 2 methods:
2245     // by isos intersection ( myXYZ ) and by edge p-curves ( myUV )
2246     double dist = 0;
2247     int eID = theFirstEdgeID;
2248     for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
2249     {
2250       list< TPoint* > & ePoints = getShapePoints( eID++ );
2251       computeUVOnEdge( *eIt, ePoints );
2252       for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
2253         TPoint* p = (*pIt);
2254         dist += ( p->myUV - gp_XY( p->myXYZ.X(), p->myXYZ.Y() )).SquareModulus();
2255 #ifdef DBG_SETFIRSTEDGE
2256         MESSAGE ( " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
2257                   p->myUV.X() << ", " << p->myUV.Y() << ") " );
2258 #endif
2259       }
2260     }
2261 #ifdef DBG_SETFIRSTEDGE
2262     MESSAGE ( "dist -- " << dist );
2263 #endif
2264     if ( dist < minDist ) {
2265       minDist = dist;
2266       eBest = theWire.front();
2267     }
2268     // check variant with another first edge
2269     theWire.splice( theWire.begin(), theWire, --theWire.end(), theWire.end() );
2270   }
2271   // put the best first edge to the theWire front
2272   if ( eBest != theWire.front() ) {
2273     eIt = find ( theWire.begin(), theWire.end(), eBest );
2274     theWire.splice( theWire.begin(), theWire, eIt, theWire.end() );
2275   }
2276
2277   return minDist;
2278 }
2279
2280 //=======================================================================
2281 //function : sortSameSizeWires
2282 //purpose  : sort wires in theWireList from theFromWire until theToWire,
2283 //           the wires are set in the order to correspond to the order
2284 //           of boundaries; after sorting, edges in the wires are put
2285 //           in a good order, point UVs on edges are computed and points
2286 //           are appended to theEdgesPointsList
2287 //=======================================================================
2288
2289 bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList &                theWireList,
2290                                        const TListOfEdgesList::iterator& theFromWire,
2291                                        const TListOfEdgesList::iterator& theToWire,
2292                                        const int                         theFirstEdgeID,
2293                                        list< list< TPoint* > >&          theEdgesPointsList )
2294 {
2295   TopoDS_Face F = TopoDS::Face( myShape );
2296   int iW, nbWires = 0;
2297   TListOfEdgesList::iterator wlIt = theFromWire;
2298   while ( wlIt++ != theToWire )
2299     nbWires++;
2300
2301   // Recompute key-point UVs by isolines intersection,
2302   // compute CG of key-points for each wire and bnd boxes of GCs
2303
2304   bool aBool;
2305   gp_XY orig( gp::Origin2d().XY() );
2306   vector< gp_XY > vGcVec( nbWires, orig ), gcVec( nbWires, orig );
2307   Bnd_Box2d bndBox, vBndBox;
2308   int eID = theFirstEdgeID;
2309   list< TopoDS_Edge >::iterator eIt;
2310   for ( iW = 0, wlIt = theFromWire; wlIt != theToWire; wlIt++, iW++ )
2311   {
2312     list< TopoDS_Edge > & wire = *wlIt;
2313     for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2314     {
2315       list< TPoint* > & ePoints = getShapePoints( eID++ );
2316       TPoint* p = ePoints.front();
2317       if ( !compUVByIsoIntersection( theEdgesPointsList, p->myInitUV, p->myUV, aBool )) {
2318         MESSAGE("can't sortSameSizeWires()");
2319         return false;
2320       }
2321       gcVec[iW] += p->myUV;
2322       bndBox.Add( gp_Pnt2d( p->myUV ));
2323       TopoDS_Vertex V = TopExp::FirstVertex( *eIt, true );
2324       gp_Pnt2d vXY = BRep_Tool::Parameters( V, F );
2325       vGcVec[iW] += vXY.XY();
2326       vBndBox.Add( vXY );
2327       // keep the computed UV to compare against by setFirstEdge()
2328       p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2329     }
2330     gcVec[iW] /= nbWires;
2331     vGcVec[iW] /= nbWires;
2332 // cout << " Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2333 //   " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2334   }
2335
2336   // Transform GCs computed by isos to fit in bnd box of GCs by vertices
2337
2338   double minPar[2], maxPar[2], vMinPar[2], vMaxPar[2];
2339   bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2340   vBndBox.Get( vMinPar[0], vMinPar[1], vMaxPar[0], vMaxPar[1] );
2341   for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2342   {
2343     double dMin = vMinPar[i] - minPar[i];
2344     double dMax = vMaxPar[i] - maxPar[i];
2345     double dPar = maxPar[i] - minPar[i];
2346     if ( Abs( dPar ) <= DBL_MIN )
2347       continue;
2348     for ( iW = 0; iW < nbWires; iW++ ) { // loop on GCs of wires
2349       double par = gcVec[iW].Coord( iC );
2350       double r = ( par - minPar[i] ) / dPar;
2351       par += ( 1 - r ) * dMin + r * dMax;
2352       gcVec[iW].SetCoord( iC, par );
2353     }
2354   }
2355
2356   // Define boundary - wire correspondence by GC closeness
2357
2358   TListOfEdgesList tmpWList;
2359   tmpWList.splice( tmpWList.end(), theWireList, theFromWire, theToWire );
2360   typedef map< int, TListOfEdgesList::iterator > TIntWirePosMap;
2361   TIntWirePosMap bndIndWirePosMap;
2362   vector< bool > bndFound( nbWires, false );
2363   for ( iW = 0, wlIt = tmpWList.begin(); iW < nbWires; iW++, wlIt++ )
2364   {
2365 // cout << " TRSF Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2366 //   " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2367     double minDist = DBL_MAX;
2368     gp_XY & wGc = vGcVec[ iW ];
2369     int bIndex = 0;
2370     for ( int iB = 0; iB < nbWires; iB++ ) {
2371       if ( bndFound[ iB ] ) continue;
2372       double dist = ( wGc - gcVec[ iB ] ).SquareModulus();
2373       if ( dist < minDist ) {
2374         minDist = dist;
2375         bIndex = iB;
2376       }
2377     }
2378     bndFound[ bIndex ] = true;
2379     bndIndWirePosMap.insert( TIntWirePosMap::value_type( bIndex, wlIt ));
2380   }
2381
2382   // Treat each wire
2383
2384   TIntWirePosMap::iterator bIndWPosIt = bndIndWirePosMap.begin();
2385   eID = theFirstEdgeID;
2386   for ( ; bIndWPosIt != bndIndWirePosMap.end(); bIndWPosIt++ )
2387   {
2388     TListOfEdgesList::iterator wirePos = (*bIndWPosIt).second;
2389     list < TopoDS_Edge > & wire = ( *wirePos );
2390
2391     // choose the best first edge of a wire
2392     setFirstEdge( wire, eID );
2393
2394     // compute eventual UV and fill theEdgesPointsList
2395     theEdgesPointsList.push_back( list< TPoint* >() );
2396     list< TPoint* > & edgesPoints = theEdgesPointsList.back();
2397     for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2398     {
2399       list< TPoint* > & ePoints = getShapePoints( eID++ );
2400       computeUVOnEdge( *eIt, ePoints );
2401       edgesPoints.insert( edgesPoints.end(), ePoints.begin(), (--ePoints.end()));
2402     }
2403     // put wire back to theWireList
2404     wlIt = wirePos++;
2405     theWireList.splice( theToWire, tmpWList, wlIt, wirePos );
2406   }
2407
2408   return true;
2409 }
2410
2411 //=======================================================================
2412 //function : Apply
2413 //purpose  : Compute  nodes coordinates applying
2414 //           the loaded pattern to <theFace>. The first key-point
2415 //           will be mapped into <theVertexOnKeyPoint1>
2416 //=======================================================================
2417
2418 bool SMESH_Pattern::Apply (const TopoDS_Face&   theFace,
2419                            const TopoDS_Vertex& theVertexOnKeyPoint1,
2420                            const bool           theReverse)
2421 {
2422   TopoDS_Face face  = theReverse ? TopoDS::Face( theFace.Reversed() ) : theFace;
2423   if ( !setShapeToMesh( face ))
2424     return false;
2425
2426   // find points on edges, it fills myNbKeyPntInBoundary
2427   if ( !findBoundaryPoints() )
2428     return false;
2429
2430   // Define the edges order so that the first edge starts at
2431   // theVertexOnKeyPoint1
2432
2433   list< TopoDS_Edge > eList;
2434   list< int >         nbVertexInWires;
2435   int nbWires = SMESH_Block::GetOrderedEdges( face, eList, nbVertexInWires, theVertexOnKeyPoint1);
2436   if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true )))
2437   {
2438     MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire ");
2439     return setErrorCode( ERR_APPLF_BAD_VERTEX );
2440   }
2441   // check nb wires and edges
2442   list< int > l1 = myNbKeyPntInBoundary, l2 = nbVertexInWires;
2443   l1.sort(); l2.sort();
2444   if ( l1 != l2 )
2445   {
2446     MESSAGE( "Wrong nb vertices in wires" );
2447     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2448   }
2449
2450   // here shapes get IDs, for the outer wire IDs are OK
2451   int nbVertices = loadVE( eList, myShapeIDMap );
2452   myShapeIDMap.Add( face );
2453
2454   if ((int) myShapeIDToPointsMap.size() != myShapeIDMap.Extent() ) {
2455     MESSAGE( myShapeIDToPointsMap.size() <<" != " << myShapeIDMap.Extent());
2456     return setErrorCode( ERR_APPLF_INTERNAL_EEROR );
2457   }
2458
2459   // points on edges to be used for UV computation of in-face points
2460   list< list< TPoint* > > edgesPointsList;
2461   edgesPointsList.push_back( list< TPoint* >() );
2462   list< TPoint* > * edgesPoints = & edgesPointsList.back();
2463   list< TPoint* >::iterator pIt, pEnd;
2464
2465   // compute UV of points on the outer wire
2466   int iE, nbEdgesInOuterWire = nbVertexInWires.front();
2467   list< TopoDS_Edge >::iterator elIt;
2468   for (iE = 0, elIt = eList.begin();
2469        iE < nbEdgesInOuterWire && elIt != eList.end();
2470        iE++, elIt++ )
2471   {
2472     list< TPoint* > & ePoints = getShapePoints( *elIt );
2473     // compute UV
2474     computeUVOnEdge( *elIt, ePoints );
2475     // collect on-edge points (excluding the last one)
2476     edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2477   }
2478
2479   // If there are several wires, define the order of edges of inner wires:
2480   // compute UV of inner edge-points using 2 methods: the one for in-face points
2481   // and the one for on-edge points and then choose the best edge order
2482   // by the best correspondence of the 2 results
2483   if ( nbWires > 1 )
2484   {
2485     // compute UV of inner edge-points using the method for in-face points
2486     // and divide eList into a list of separate wires
2487     bool aBool;
2488     list< list< TopoDS_Edge > > wireList;
2489     list<TopoDS_Edge>::iterator eIt = elIt;
2490     list<int>::iterator nbEIt = nbVertexInWires.begin();
2491     for ( nbEIt++; nbEIt != nbVertexInWires.end(); nbEIt++ )
2492     {
2493       int nbEdges = *nbEIt;
2494       wireList.push_back( list< TopoDS_Edge >() );
2495       list< TopoDS_Edge > & wire = wireList.back();
2496       for ( iE = 0 ; iE < nbEdges; eIt++, iE++ )
2497       {
2498         list< TPoint* > & ePoints = getShapePoints( *eIt );
2499         pIt = ePoints.begin();
2500         for (  pIt++; pIt != ePoints.end(); pIt++ ) {
2501           TPoint* p = (*pIt);
2502           if ( !compUVByIsoIntersection( edgesPointsList, p->myInitUV, p->myUV, aBool )) {
2503             MESSAGE("can't Apply(face)");
2504             return false;
2505           }
2506           // keep the computed UV to compare against by setFirstEdge()
2507           p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2508         }
2509         wire.push_back( *eIt );
2510       }
2511     }
2512     // remove inner edges from eList
2513     eList.erase( elIt, eList.end() );
2514
2515     // sort wireList by nb edges in a wire
2516     sortBySize< TopoDS_Edge > ( wireList );
2517
2518     // an ID of the first edge of a boundary
2519     int id1 = nbVertices + nbEdgesInOuterWire + 1;
2520 //     if ( nbSeamShapes > 0 )
2521 //       id1 += 2; // 2 vertices more
2522
2523     // find points - edge correspondence for wires of unique size,
2524     // edge order within a wire should be defined only
2525
2526     list< list< TopoDS_Edge > >::iterator wlIt = wireList.begin();
2527     while ( wlIt != wireList.end() )
2528     {
2529       list< TopoDS_Edge >& wire = (*wlIt);
2530       size_t nbEdges = wire.size();
2531       wlIt++;
2532       if ( wlIt != wireList.end() && (*wlIt).size() != nbEdges ) // a unique size wire
2533       {
2534         // choose the best first edge of a wire
2535         setFirstEdge( wire, id1 );
2536
2537         // compute eventual UV and collect on-edge points
2538         edgesPointsList.push_back( list< TPoint* >() );
2539         edgesPoints = & edgesPointsList.back();
2540         int eID = id1;
2541         for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2542         {
2543           list< TPoint* > & ePoints = getShapePoints( eID++ );
2544           computeUVOnEdge( *eIt, ePoints );
2545           edgesPoints->insert( edgesPoints->end(), ePoints.begin(), (--ePoints.end()));
2546         }
2547       }
2548       id1 += nbEdges;
2549     }
2550
2551     // find boundary - wire correspondence for several wires of same size
2552
2553     id1 = nbVertices + nbEdgesInOuterWire + 1;
2554     wlIt = wireList.begin();
2555     while ( wlIt != wireList.end() )
2556     {
2557       size_t nbSameSize = 0, nbEdges = (*wlIt).size();
2558       list< list< TopoDS_Edge > >::iterator wlIt2 = wlIt;
2559       wlIt2++;
2560       while ( wlIt2 != wireList.end() && (*wlIt2).size() == nbEdges ) { // a same size wire
2561         nbSameSize++;
2562         wlIt2++;
2563       }
2564       if ( nbSameSize > 0 )
2565         if (!sortSameSizeWires(wireList, wlIt, wlIt2, id1, edgesPointsList))
2566           return false;
2567       wlIt = wlIt2;
2568       id1 += nbEdges * ( nbSameSize + 1 );
2569     }
2570
2571     // add well-ordered edges to eList
2572
2573     for ( wlIt = wireList.begin(); wlIt != wireList.end(); wlIt++ )
2574     {
2575       list< TopoDS_Edge >& wire = (*wlIt);
2576       eList.splice( eList.end(), wire, wire.begin(), wire.end() );
2577     }
2578
2579     // re-fill myShapeIDMap - all shapes get good IDs
2580
2581     myShapeIDMap.Clear();
2582     nbVertices = loadVE( eList, myShapeIDMap );
2583     myShapeIDMap.Add( face );
2584
2585   } // there are inner wires
2586
2587   // Set XYZ of on-vertex points
2588
2589   // for ( int iV = 1; iV <= nbVertices; ++iV )
2590   // {
2591   //   const TopoDS_Vertex&    V = TopoDS::Vertex( myShapeIDMap( iV ));
2592   //   list< TPoint* > & vPoints = getShapePoints( iV );
2593   //   if ( !vPoints.empty() )
2594   //   {
2595   //     //vPoints.front()->myUV  = BRep_Tool::Parameters( V, theFace ).XY();
2596   //     vPoints.front()->myXYZ = BRep_Tool::Pnt( V );
2597   //   }
2598   // }
2599
2600   // Compute XYZ of on-edge points
2601
2602   TopLoc_Location loc;
2603   for ( iE = nbVertices + 1, elIt = eList.begin(); elIt != eList.end(); elIt++ )
2604   {
2605     BRepAdaptor_Curve C3d( *elIt );
2606     list< TPoint* > & ePoints = getShapePoints( iE++ );
2607     for ( pIt = ++ePoints.begin(), pEnd = ePoints.end(); pIt != pEnd; pIt++ )
2608     {
2609       TPoint* point = *pIt;
2610       point->myXYZ = C3d.Value( point->myU );
2611     }
2612   }
2613
2614   // Compute UV and XYZ of in-face points
2615
2616   // try to use a simple algo
2617   list< TPoint* > & fPoints = getShapePoints( face );
2618   bool isDeformed = false;
2619   for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2620     if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2621                                   (*pIt)->myUV, isDeformed )) {
2622       MESSAGE("can't Apply(face)");
2623       return false;
2624     }
2625   // try to use a complex algo if it is a difficult case
2626   if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2627   {
2628     for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2629       if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2630                                     (*pIt)->myUV, isDeformed )) {
2631         MESSAGE("can't Apply(face)");
2632         return false;
2633       }
2634   }
2635
2636   Handle(Geom_Surface) aSurface = BRep_Tool::Surface( face, loc );
2637   const gp_Trsf & aTrsf = loc.Transformation();
2638   for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2639   {
2640     TPoint * point = *pIt;
2641     point->myXYZ = aSurface->Value( point->myUV.X(), point->myUV.Y() );
2642     if ( !loc.IsIdentity() )
2643       aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2644   }
2645
2646   myIsComputed = true;
2647
2648   return setErrorCode( ERR_OK );
2649 }
2650
2651 //=======================================================================
2652 //function : Apply
2653 //purpose  : Compute nodes coordinates applying
2654 //           the loaded pattern to <theFace>. The first key-point
2655 //           will be mapped into <theNodeIndexOnKeyPoint1>-th node
2656 //=======================================================================
2657
2658 bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace,
2659                            const int            theNodeIndexOnKeyPoint1,
2660                            const bool           theReverse)
2661 {
2662 //  MESSAGE(" ::Apply(MeshFace) " );
2663
2664   if ( !IsLoaded() ) {
2665     MESSAGE( "Pattern not loaded" );
2666     return setErrorCode( ERR_APPL_NOT_LOADED );
2667   }
2668
2669   // check nb of nodes
2670   const int nbFaceNodes = theFace->NbCornerNodes();
2671   if ( nbFaceNodes != myNbKeyPntInBoundary.front() ) {
2672     MESSAGE( myKeyPointIDs.size() << " != " << nbFaceNodes );
2673     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2674   }
2675
2676   // find points on edges, it fills myNbKeyPntInBoundary
2677   if ( !findBoundaryPoints() )
2678     return false;
2679
2680   // check that there are no holes in a pattern
2681   if (myNbKeyPntInBoundary.size() > 1 ) {
2682     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2683   }
2684
2685   // Define the nodes order
2686
2687   list< const SMDS_MeshNode* > nodes;
2688   list< const SMDS_MeshNode* >::iterator n = nodes.end();
2689   SMDS_NodeIteratorPtr noIt = theFace->nodeIterator();
2690   int iSub = 0;
2691   while ( noIt->more() && iSub < nbFaceNodes ) {
2692     const SMDS_MeshNode* node = noIt->next();
2693     nodes.push_back( node );
2694     if ( iSub++ == theNodeIndexOnKeyPoint1 )
2695       n = --nodes.end();
2696   }
2697   if ( n != nodes.end() ) {
2698     if ( theReverse ) {
2699       if ( n != --nodes.end() )
2700         nodes.splice( nodes.begin(), nodes, ++n, nodes.end() );
2701       nodes.reverse();
2702     }
2703     else if ( n != nodes.begin() )
2704       nodes.splice( nodes.end(), nodes, nodes.begin(), n );
2705   }
2706   list< gp_XYZ > xyzList;
2707   myOrderedNodes.resize( nbFaceNodes );
2708   for ( iSub = 0, n = nodes.begin(); n != nodes.end(); ++n ) {
2709     xyzList.push_back( SMESH_TNodeXYZ( *n ));
2710     myOrderedNodes[ iSub++] = *n;
2711   }
2712
2713   // Define a face plane
2714
2715   list< gp_XYZ >::iterator xyzIt = xyzList.begin();
2716   gp_Pnt P ( *xyzIt++ );
2717   gp_Vec Vx( P, *xyzIt++ ), N;
2718   do {
2719     N = Vx ^ gp_Vec( P, *xyzIt++ );
2720   } while ( N.SquareMagnitude() <= DBL_MIN && xyzIt != xyzList.end() );
2721   if ( N.SquareMagnitude() <= DBL_MIN )
2722     return setErrorCode( ERR_APPLF_BAD_FACE_GEOM );
2723   gp_Ax2 pos( P, N, Vx );
2724
2725   // Compute UV of key-points on a plane
2726   for ( xyzIt = xyzList.begin(), iSub = 1; xyzIt != xyzList.end(); xyzIt++, iSub++ )
2727   {
2728     gp_Vec vec ( pos.Location(), *xyzIt );
2729     TPoint* p = getShapePoints( iSub ).front();
2730     p->myUV.SetX( vec * pos.XDirection() );
2731     p->myUV.SetY( vec * pos.YDirection() );
2732     p->myXYZ = *xyzIt;
2733   }
2734
2735   // points on edges to be used for UV computation of in-face points
2736   list< list< TPoint* > > edgesPointsList;
2737   edgesPointsList.push_back( list< TPoint* >() );
2738   list< TPoint* > * edgesPoints = & edgesPointsList.back();
2739   list< TPoint* >::iterator pIt;
2740
2741   // compute UV and XYZ of points on edges
2742
2743   for ( xyzIt = xyzList.begin(); xyzIt != xyzList.end(); iSub++ )
2744   {
2745     gp_XYZ& xyz1 = *xyzIt++;
2746     gp_XYZ& xyz2 = ( xyzIt != xyzList.end() ) ? *xyzIt : xyzList.front();
2747
2748     list< TPoint* > & ePoints = getShapePoints( iSub );
2749     ePoints.back()->myInitU = 1.0;
2750     list< TPoint* >::const_iterator pIt = ++ePoints.begin();
2751     while ( *pIt != ePoints.back() )
2752     {
2753       TPoint* p = *pIt++;
2754       p->myXYZ = xyz1 * ( 1 - p->myInitU ) + xyz2 * p->myInitU;
2755       gp_Vec vec ( pos.Location(), p->myXYZ );
2756       p->myUV.SetX( vec * pos.XDirection() );
2757       p->myUV.SetY( vec * pos.YDirection() );
2758     }
2759     // collect on-edge points (excluding the last one)
2760     edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2761   }
2762
2763   // Compute UV and XYZ of in-face points
2764
2765   // try to use a simple algo to compute UV
2766   list< TPoint* > & fPoints = getShapePoints( iSub );
2767   bool isDeformed = false;
2768   for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2769     if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2770                                   (*pIt)->myUV, isDeformed )) {
2771       MESSAGE("can't Apply(face)");
2772       return false;
2773     }
2774   // try to use a complex algo if it is a difficult case
2775   if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2776   {
2777     for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2778       if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2779                                     (*pIt)->myUV, isDeformed )) {
2780         MESSAGE("can't Apply(face)");
2781         return false;
2782       }
2783   }
2784
2785   for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2786   {
2787     (*pIt)->myXYZ = ElSLib::PlaneValue( (*pIt)->myUV.X(), (*pIt)->myUV.Y(), pos );
2788   }
2789
2790   myIsComputed = true;
2791
2792   return setErrorCode( ERR_OK );
2793 }
2794
2795 //=======================================================================
2796 //function : Apply
2797 //purpose  : Compute nodes coordinates applying
2798 //           the loaded pattern to <theFace>. The first key-point
2799 //           will be mapped into <theNodeIndexOnKeyPoint1>-th node
2800 //=======================================================================
2801
2802 bool SMESH_Pattern::Apply (SMESH_Mesh*          theMesh,
2803                            const SMDS_MeshFace* theFace,
2804                            const TopoDS_Shape&  theSurface,
2805                            const int            theNodeIndexOnKeyPoint1,
2806                            const bool           theReverse)
2807 {
2808 //  MESSAGE(" ::Apply(MeshFace) " );
2809   if ( theSurface.IsNull() || theSurface.ShapeType() != TopAbs_FACE ) {
2810     return Apply( theFace, theNodeIndexOnKeyPoint1, theReverse);
2811   }
2812   const TopoDS_Face& face = TopoDS::Face( theSurface );
2813   TopLoc_Location loc;
2814   Handle(Geom_Surface) surface = BRep_Tool::Surface( face, loc );
2815   const gp_Trsf & aTrsf = loc.Transformation();
2816
2817   if ( !IsLoaded() ) {
2818     MESSAGE( "Pattern not loaded" );
2819     return setErrorCode( ERR_APPL_NOT_LOADED );
2820   }
2821
2822   // check nb of nodes
2823   if (theFace->NbNodes() != myNbKeyPntInBoundary.front() ) {
2824     MESSAGE( myKeyPointIDs.size() << " != " << theFace->NbNodes() );
2825     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2826   }
2827
2828   // find points on edges, it fills myNbKeyPntInBoundary
2829   if ( !findBoundaryPoints() )
2830     return false;
2831
2832   // check that there are no holes in a pattern
2833   if (myNbKeyPntInBoundary.size() > 1 ) {
2834     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2835   }
2836
2837   // Define the nodes order
2838
2839   list< const SMDS_MeshNode* > nodes;
2840   list< const SMDS_MeshNode* >::iterator n = nodes.end();
2841   SMDS_ElemIteratorPtr noIt = theFace->nodesIterator();
2842   int iSub = 0;
2843   while ( noIt->more() ) {
2844     const SMDS_MeshNode* node = smdsNode( noIt->next() );
2845     nodes.push_back( node );
2846     if ( iSub++ == theNodeIndexOnKeyPoint1 )
2847       n = --nodes.end();
2848   }
2849   if ( n != nodes.end() ) {
2850     if ( theReverse ) {
2851       if ( n != --nodes.end() )
2852         nodes.splice( nodes.begin(), nodes, ++n, nodes.end() );
2853       nodes.reverse();
2854     }
2855     else if ( n != nodes.begin() )
2856       nodes.splice( nodes.end(), nodes, nodes.begin(), n );
2857   }
2858
2859   // find a node not on a seam edge, if necessary
2860   SMESH_MesherHelper helper( *theMesh );
2861   helper.SetSubShape( theSurface );
2862   const SMDS_MeshNode* inFaceNode = 0;
2863   if ( helper.GetNodeUVneedInFaceNode() )
2864   {
2865     SMESH_MeshEditor editor( theMesh );
2866     for ( n = nodes.begin(); ( !inFaceNode && n != nodes.end()); ++n ) {
2867       int shapeID = editor.FindShape( *n );
2868       if ( !shapeID )
2869         return Apply( theFace, theNodeIndexOnKeyPoint1, theReverse);
2870       if ( !helper.IsSeamShape( shapeID ))
2871         inFaceNode = *n;
2872     }
2873   }
2874
2875   // Set UV of key-points (i.e. of nodes of theFace )
2876   vector< gp_XY > keyUV( theFace->NbNodes() );
2877   myOrderedNodes.resize( theFace->NbNodes() );
2878   for ( iSub = 1, n = nodes.begin(); n != nodes.end(); ++n, ++iSub )
2879   {
2880     TPoint* p = getShapePoints( iSub ).front();
2881     p->myUV  = helper.GetNodeUV( face, *n, inFaceNode );
2882     p->myXYZ = gp_XYZ( (*n)->X(), (*n)->Y(), (*n)->Z() );
2883
2884     keyUV[ iSub-1 ] = p->myUV;
2885     myOrderedNodes[ iSub-1 ] = *n;
2886   }
2887
2888   // points on edges to be used for UV computation of in-face points
2889   list< list< TPoint* > > edgesPointsList;
2890   edgesPointsList.push_back( list< TPoint* >() );
2891   list< TPoint* > * edgesPoints = & edgesPointsList.back();
2892   list< TPoint* >::iterator pIt;
2893
2894   // compute UV and XYZ of points on edges
2895
2896   for ( size_t i = 0; i < myOrderedNodes.size(); ++i, ++iSub )
2897   {
2898     gp_XY& uv1 = keyUV[ i ];
2899     gp_XY& uv2 = ( i+1 < keyUV.size() ) ? keyUV[ i+1 ] : keyUV[ 0 ];
2900
2901     list< TPoint* > & ePoints = getShapePoints( iSub );
2902     ePoints.back()->myInitU = 1.0;
2903     list< TPoint* >::const_iterator pIt = ++ePoints.begin();
2904     while ( *pIt != ePoints.back() )
2905     {
2906       TPoint* p = *pIt++;
2907       p->myUV = uv1 * ( 1 - p->myInitU ) + uv2 * p->myInitU;
2908       p->myXYZ = surface->Value( p->myUV.X(), p->myUV.Y() );
2909       if ( !loc.IsIdentity() )
2910         aTrsf.Transforms( p->myXYZ.ChangeCoord() );
2911     }
2912     // collect on-edge points (excluding the last one)
2913     edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2914   }
2915
2916   // Compute UV and XYZ of in-face points
2917
2918   // try to use a simple algo to compute UV
2919   list< TPoint* > & fPoints = getShapePoints( iSub );
2920   bool isDeformed = false;
2921   for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2922     if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2923                                   (*pIt)->myUV, isDeformed )) {
2924       MESSAGE("can't Apply(face)");
2925       return false;
2926     }
2927   // try to use a complex algo if it is a difficult case
2928   if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2929   {
2930     for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2931       if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2932                                     (*pIt)->myUV, isDeformed )) {
2933         MESSAGE("can't Apply(face)");
2934         return false;
2935       }
2936   }
2937
2938   for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2939   {
2940     TPoint * point = *pIt;
2941     point->myXYZ = surface->Value( point->myUV.X(), point->myUV.Y() );
2942     if ( !loc.IsIdentity() )
2943       aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2944   }
2945
2946   myIsComputed = true;
2947
2948   return setErrorCode( ERR_OK );
2949 }
2950
2951 //=======================================================================
2952 //function : undefinedXYZ
2953 //purpose  : 
2954 //=======================================================================
2955
2956 static const gp_XYZ& undefinedXYZ()
2957 {
2958   static gp_XYZ xyz( 1.e100, 0., 0. );
2959   return xyz;
2960 }
2961
2962 //=======================================================================
2963 //function : isDefined
2964 //purpose  : 
2965 //=======================================================================
2966
2967 inline static bool isDefined(const gp_XYZ& theXYZ)
2968 {
2969   return theXYZ.X() < 1.e100;
2970 }
2971
2972 //=======================================================================
2973 //function : Apply
2974 //purpose  : Compute nodes coordinates applying
2975 //           the loaded pattern to <theFaces>. The first key-point
2976 //           will be mapped into <theNodeIndexOnKeyPoint1>-th node
2977 //=======================================================================
2978
2979 bool SMESH_Pattern::Apply (SMESH_Mesh*                     theMesh,
2980                            std::set<const SMDS_MeshFace*>& theFaces,
2981                            const int                       theNodeIndexOnKeyPoint1,
2982                            const bool                      theReverse)
2983 {
2984   MESSAGE(" ::Apply(set<MeshFace>) " );
2985
2986   if ( !IsLoaded() ) {
2987     MESSAGE( "Pattern not loaded" );
2988     return setErrorCode( ERR_APPL_NOT_LOADED );
2989   }
2990
2991   // find points on edges, it fills myNbKeyPntInBoundary
2992   if ( !findBoundaryPoints() )
2993     return false;
2994
2995   // check that there are no holes in a pattern
2996   if (myNbKeyPntInBoundary.size() > 1 ) {
2997     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2998   }
2999
3000   myShape.Nullify();
3001   myXYZ.clear();
3002   myElemXYZIDs.clear();
3003   myXYZIdToNodeMap.clear();
3004   myElements.clear();
3005   myIdsOnBoundary.clear();
3006   myReverseConnectivity.clear();
3007
3008   myXYZ.resize( myPoints.size() * theFaces.size(), undefinedXYZ() );
3009   myElements.reserve( theFaces.size() );
3010
3011   int ind1 = 0; // lowest point index for a face
3012
3013   // meshed geometry
3014   TopoDS_Shape shape;
3015 //   int          shapeID = 0;
3016 //   SMESH_MeshEditor editor( theMesh );
3017
3018   // apply to each face in theFaces set
3019   set<const SMDS_MeshFace*>::iterator face = theFaces.begin();
3020   for ( ; face != theFaces.end(); ++face )
3021   {
3022 //     int curShapeId = editor.FindShape( *face );
3023 //     if ( curShapeId != shapeID ) {
3024 //       if ( curShapeId )
3025 //         shape = theMesh->GetMeshDS()->IndexToShape( curShapeId );
3026 //       else
3027 //         shape.Nullify();
3028 //       shapeID = curShapeId;
3029 //     }
3030     bool ok;
3031     if ( shape.IsNull() )
3032       ok = Apply( *face, theNodeIndexOnKeyPoint1, theReverse );
3033     else
3034       ok = Apply( theMesh, *face, shape, theNodeIndexOnKeyPoint1, theReverse );
3035     if ( !ok ) {
3036       MESSAGE( "Failed on " << *face );
3037       continue;
3038     }
3039     myElements.push_back( *face );
3040
3041     // store computed points belonging to elements
3042     list< TElemDef >::iterator ll = myElemPointIDs.begin();
3043     for ( ; ll != myElemPointIDs.end(); ++ll )
3044     {
3045       myElemXYZIDs.push_back(TElemDef());
3046       TElemDef& xyzIds = myElemXYZIDs.back();
3047       TElemDef& pIds = *ll;
3048       for ( TElemDef::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
3049         int pIndex = *id + ind1;
3050         xyzIds.push_back( pIndex );
3051         myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
3052         myReverseConnectivity[ pIndex ].push_back( & xyzIds );
3053       }
3054     }
3055     // put points on links to myIdsOnBoundary,
3056     // they will be used to sew new elements on adjacent refined elements
3057     int nbNodes = (*face)->NbCornerNodes(), eID = nbNodes + 1;
3058     for ( int i = 0; i < nbNodes; i++ )
3059     {
3060       list< TPoint* > & linkPoints = getShapePoints( eID++ );
3061       const SMDS_MeshNode* n1 = myOrderedNodes[ i ];
3062       const SMDS_MeshNode* n2 = myOrderedNodes[( i+1 ) % nbNodes ];
3063       // make a link and a node set
3064       TNodeSet linkSet, node1Set;
3065       linkSet.insert( n1 );
3066       linkSet.insert( n2 );
3067       node1Set.insert( n1 );
3068       list< TPoint* >::iterator p = linkPoints.begin();
3069       {
3070         // map the first link point to n1
3071         int nId = ( *p - &myPoints[0] ) + ind1;
3072         myXYZIdToNodeMap[ nId ] = n1;
3073         list< list< int > >& groups = myIdsOnBoundary[ node1Set ];
3074         groups.push_back(list< int > ());
3075         groups.back().push_back( nId );
3076       }
3077       // add the linkSet to the map
3078       list< list< int > >& groups = myIdsOnBoundary[ linkSet ];
3079       groups.push_back(list< int > ());
3080       list< int >& indList = groups.back();
3081       // add points to the map excluding the end points
3082       for ( p++; *p != linkPoints.back(); p++ )
3083         indList.push_back( ( *p - &myPoints[0] ) + ind1 );
3084     }
3085     ind1 += myPoints.size();
3086   }
3087
3088   return !myElemXYZIDs.empty();
3089 }
3090
3091 //=======================================================================
3092 //function : Apply
3093 //purpose  : Compute nodes coordinates applying
3094 //           the loaded pattern to <theVolumes>. The (0,0,0) key-point
3095 //           will be mapped into <theNode000Index>-th node. The
3096 //           (0,0,1) key-point will be mapped into <theNode000Index>-th
3097 //           node.
3098 //=======================================================================
3099
3100 bool SMESH_Pattern::Apply (std::set<const SMDS_MeshVolume*> & theVolumes,
3101                            const int                          theNode000Index,
3102                            const int                          theNode001Index)
3103 {
3104   if ( !IsLoaded() ) {
3105     MESSAGE( "Pattern not loaded" );
3106     return setErrorCode( ERR_APPL_NOT_LOADED );
3107   }
3108
3109    // bind ID to points
3110   if ( !findBoundaryPoints() )
3111     return false;
3112
3113   // check that there are no holes in a pattern
3114   if (myNbKeyPntInBoundary.size() > 1 ) {
3115     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
3116   }
3117
3118   myShape.Nullify();
3119   myXYZ.clear();
3120   myElemXYZIDs.clear();
3121   myXYZIdToNodeMap.clear();
3122   myElements.clear();
3123   myIdsOnBoundary.clear();
3124   myReverseConnectivity.clear();
3125
3126   myXYZ.resize( myPoints.size() * theVolumes.size(), undefinedXYZ() );
3127   myElements.reserve( theVolumes.size() );
3128
3129   // to find point index
3130   map< TPoint*, int > pointIndex;
3131   for ( size_t i = 0; i < myPoints.size(); i++ )
3132     pointIndex.insert( make_pair( & myPoints[ i ], i ));
3133
3134   int ind1 = 0; // lowest point index for an element
3135
3136   // apply to each element in theVolumes set
3137   set<const SMDS_MeshVolume*>::iterator vol = theVolumes.begin();
3138   for ( ; vol != theVolumes.end(); ++vol )
3139   {
3140     if ( !Apply( *vol, theNode000Index, theNode001Index )) {
3141       MESSAGE( "Failed on " << *vol );
3142       continue;
3143     }
3144     myElements.push_back( *vol );
3145
3146     // store computed points belonging to elements
3147     list< TElemDef >::iterator ll = myElemPointIDs.begin();
3148     for ( ; ll != myElemPointIDs.end(); ++ll )
3149     {
3150       myElemXYZIDs.push_back(TElemDef());
3151       TElemDef& xyzIds = myElemXYZIDs.back();
3152       TElemDef& pIds = *ll;
3153       for ( TElemDef::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
3154         int pIndex = *id + ind1;
3155         xyzIds.push_back( pIndex );
3156         myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
3157         myReverseConnectivity[ pIndex ].push_back( & xyzIds );
3158       }
3159     }
3160     // put points on edges and faces to myIdsOnBoundary,
3161     // they will be used to sew new elements on adjacent refined elements
3162     for ( int Id = SMESH_Block::ID_V000; Id <= SMESH_Block::ID_F1yz; Id++ )
3163     {
3164       // make a set of sub-points
3165       TNodeSet subNodes;
3166       vector< int > subIDs;
3167       if ( SMESH_Block::IsVertexID( Id )) {
3168         subNodes.insert( myOrderedNodes[ Id - 1 ]);
3169       }
3170       else if ( SMESH_Block::IsEdgeID( Id )) {
3171         SMESH_Block::GetEdgeVertexIDs( Id, subIDs );
3172         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
3173         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
3174       }
3175       else {
3176         SMESH_Block::GetFaceEdgesIDs( Id, subIDs );
3177         int e1 = subIDs[ 0 ], e2 = subIDs[ 1 ];
3178         SMESH_Block::GetEdgeVertexIDs( e1, subIDs );
3179         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
3180         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
3181         SMESH_Block::GetEdgeVertexIDs( e2, subIDs );
3182         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
3183         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
3184       }
3185       // add points
3186       list< TPoint* > & points = getShapePoints( Id );
3187       list< TPoint* >::iterator p = points.begin();
3188       list< list< int > >& groups = myIdsOnBoundary[ subNodes ];
3189       groups.push_back(list< int > ());
3190       list< int >& indList = groups.back();
3191       for ( ; p != points.end(); p++ )
3192         indList.push_back( pointIndex[ *p ] + ind1 );
3193       if ( subNodes.size() == 1 ) // vertex case
3194         myXYZIdToNodeMap[ indList.back() ] = myOrderedNodes[ Id - 1 ];
3195     }
3196     ind1 += myPoints.size();
3197   }
3198
3199   return !myElemXYZIDs.empty();
3200 }
3201
3202 //=======================================================================
3203 //function : Load
3204 //purpose  : Create a pattern from the mesh built on <theBlock>
3205 //=======================================================================
3206
3207 bool SMESH_Pattern::Load (SMESH_Mesh*         theMesh,
3208                           const TopoDS_Shell& theBlock,
3209                           bool                theKeepNodes)
3210 {
3211   Clear();
3212   myIs2D = false;
3213   myToKeepNodes = theKeepNodes;
3214   SMESHDS_SubMesh * aSubMesh;
3215
3216   const bool isQuadMesh = theMesh->NbVolumes( ORDER_QUADRATIC );
3217
3218   // load shapes in myShapeIDMap
3219   SMESH_Block block;
3220   TopoDS_Vertex v1, v2;
3221   if ( !block.LoadBlockShapes( theBlock, v1, v2, myShapeIDMap ))
3222     return setErrorCode( ERR_LOADV_BAD_SHAPE );
3223
3224   // count nodes
3225   int nbNodes = 0, shapeID;
3226   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
3227   {
3228     const TopoDS_Shape& S = myShapeIDMap( shapeID );
3229     aSubMesh = getSubmeshWithElements( theMesh, S );
3230     if ( aSubMesh )
3231       nbNodes += aSubMesh->NbNodes();
3232   }
3233   myPoints.resize( nbNodes );
3234
3235   // load U of points on edges
3236   TNodePointIDMap nodePointIDMap;
3237   int iPoint = 0;
3238   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
3239   {
3240     const TopoDS_Shape& S = myShapeIDMap( shapeID );
3241     list< TPoint* > & shapePoints = getShapePoints( shapeID );
3242     aSubMesh = getSubmeshWithElements( theMesh, S );
3243     if ( ! aSubMesh ) continue;
3244     SMDS_NodeIteratorPtr nIt = aSubMesh->GetNodes();
3245     if ( !nIt->more() ) continue;
3246
3247     // store a node and a point
3248     while ( nIt->more() ) {
3249       const SMDS_MeshNode* node = smdsNode( nIt->next() );
3250       if ( isQuadMesh && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Volume ))
3251         continue;
3252       nodePointIDMap.insert( make_pair( node, iPoint ));
3253       if ( block.IsVertexID( shapeID ))
3254         myKeyPointIDs.push_back( iPoint );
3255       TPoint* p = & myPoints[ iPoint++ ];
3256       shapePoints.push_back( p );
3257       p->myXYZ.SetCoord( node->X(), node->Y(), node->Z() );
3258       p->myInitXYZ.SetCoord( 0,0,0 );
3259     }
3260     list< TPoint* >::iterator pIt = shapePoints.begin();
3261
3262     // compute init XYZ
3263     switch ( S.ShapeType() )
3264     {
3265     case TopAbs_VERTEX:
3266     case TopAbs_EDGE: {
3267
3268       for ( ; pIt != shapePoints.end(); pIt++ ) {
3269         double * coef = block.GetShapeCoef( shapeID );
3270         for ( int iCoord = 1; iCoord <= 3; iCoord++ )
3271           if ( coef[ iCoord - 1] > 0 )
3272             (*pIt)->myInitXYZ.SetCoord( iCoord, 1. );
3273       }
3274       if ( S.ShapeType() == TopAbs_VERTEX )
3275         break;
3276
3277       const TopoDS_Edge& edge = TopoDS::Edge( S );
3278       double f,l;
3279       BRep_Tool::Range( edge, f, l );
3280       int iCoord     = SMESH_Block::GetCoordIndOnEdge( shapeID );
3281       bool isForward = SMESH_Block::IsForwardEdge( edge, myShapeIDMap );
3282       pIt = shapePoints.begin();
3283       nIt = aSubMesh->GetNodes();
3284       for ( ; nIt->more(); pIt++ )
3285       {
3286         const SMDS_MeshNode* node = nIt->next();
3287         if ( isQuadMesh && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Edge ))
3288           continue;
3289         SMDS_EdgePositionPtr epos = node->GetPosition();
3290         double u = ( epos->GetUParameter() - f ) / ( l - f );
3291         (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u );
3292       }
3293       break;
3294     }
3295     default:
3296       for ( ; pIt != shapePoints.end(); pIt++ )
3297       {
3298         if ( !block.ComputeParameters( (*pIt)->myXYZ, (*pIt)->myInitXYZ, shapeID )) {
3299           MESSAGE( "!block.ComputeParameters()" );
3300           return setErrorCode( ERR_LOADV_COMPUTE_PARAMS );
3301         }
3302       }
3303     }
3304   } // loop on block sub-shapes
3305
3306   // load elements
3307
3308   aSubMesh = getSubmeshWithElements( theMesh, theBlock );
3309   if ( aSubMesh )
3310   {
3311     SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements();
3312     while ( elemIt->more() ) {
3313       const SMDS_MeshElement* elem = elemIt->next();
3314       myElemPointIDs.push_back( TElemDef() );
3315       TElemDef& elemPoints = myElemPointIDs.back();
3316       int nbNodes = elem->NbCornerNodes();
3317       for ( int i = 0;i < nbNodes; ++i )
3318         elemPoints.push_back( nodePointIDMap[ elem->GetNode( i )]);
3319     }
3320   }
3321
3322   myIsBoundaryPointsFound = true;
3323
3324   if ( myToKeepNodes )
3325   {
3326     myInNodes.resize( nodePointIDMap.size() );
3327     TNodePointIDMap::iterator nIdIt = nodePointIDMap.begin();
3328     for ( ; nIdIt != nodePointIDMap.end(); nIdIt++ )
3329       myInNodes[ nIdIt->second ] = smdsNode( nIdIt->first );
3330   }
3331
3332   return setErrorCode( ERR_OK );
3333 }
3334
3335 //=======================================================================
3336 //function : getSubmeshWithElements
3337 //purpose  : return submesh containing elements bound to theBlock in theMesh
3338 //=======================================================================
3339
3340 SMESHDS_SubMesh * SMESH_Pattern::getSubmeshWithElements(SMESH_Mesh*         theMesh,
3341                                                         const TopoDS_Shape& theShape)
3342 {
3343   SMESHDS_SubMesh * aSubMesh = theMesh->GetMeshDS()->MeshElements( theShape );
3344   if ( aSubMesh && ( aSubMesh->GetElements()->more() || aSubMesh->GetNodes()->more() ))
3345     return aSubMesh;
3346
3347   if ( theShape.ShapeType() == TopAbs_SHELL )
3348   {
3349     // look for submesh of VOLUME
3350     TopTools_ListIteratorOfListOfShape it( theMesh->GetAncestors( theShape ));
3351     for (; it.More(); it.Next()) {
3352       aSubMesh = theMesh->GetMeshDS()->MeshElements( it.Value() );
3353       if ( aSubMesh && ( aSubMesh->GetElements()->more() || aSubMesh->GetNodes()->more() ))
3354         return aSubMesh;
3355     }
3356   }
3357   return 0;
3358 }
3359
3360
3361 //=======================================================================
3362 //function : Apply
3363 //purpose  : Compute nodes coordinates applying
3364 //           the loaded pattern to <theBlock>. The (0,0,0) key-point
3365 //           will be mapped into <theVertex000>. The (0,0,1)
3366 //           fifth key-point will be mapped into <theVertex001>.
3367 //=======================================================================
3368
3369 bool SMESH_Pattern::Apply (const TopoDS_Shell&  theBlock,
3370                            const TopoDS_Vertex& theVertex000,
3371                            const TopoDS_Vertex& theVertex001)
3372 {
3373   if (!findBoundaryPoints()     || // bind ID to points
3374       !setShapeToMesh( theBlock )) // check theBlock is a suitable shape
3375     return false;
3376
3377   SMESH_Block block;  // bind ID to shape
3378   if (!block.LoadBlockShapes( theBlock, theVertex000, theVertex001, myShapeIDMap ))
3379     return setErrorCode( ERR_APPLV_BAD_SHAPE );
3380
3381   // compute XYZ of points on shapes
3382
3383   for ( int shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
3384   {
3385     list< TPoint* > & shapePoints = getShapePoints( shapeID );
3386     list< TPoint* >::iterator pIt = shapePoints.begin();
3387     const TopoDS_Shape& S = myShapeIDMap( shapeID );
3388     switch ( S.ShapeType() )
3389     {
3390     case TopAbs_VERTEX: {
3391
3392       for ( ; pIt != shapePoints.end(); pIt++ )
3393         block.VertexPoint( shapeID, (*pIt)->myXYZ.ChangeCoord() );
3394       break;
3395     }
3396     case TopAbs_EDGE: {
3397
3398       for ( ; pIt != shapePoints.end(); pIt++ )
3399         block.EdgePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3400       break;
3401     }
3402     case TopAbs_FACE: {
3403
3404       for ( ; pIt != shapePoints.end(); pIt++ )
3405         block.FacePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3406       break;
3407     }
3408     default:
3409       for ( ; pIt != shapePoints.end(); pIt++ )
3410         block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3411     }
3412   } // loop on block sub-shapes
3413
3414   myIsComputed = true;
3415
3416   return setErrorCode( ERR_OK );
3417 }
3418
3419 //=======================================================================
3420 //function : Apply
3421 //purpose  : Compute nodes coordinates applying
3422 //           the loaded pattern to <theVolume>. The (0,0,0) key-point
3423 //           will be mapped into <theNode000Index>-th node. The
3424 //           (0,0,1) key-point will be mapped into <theNode000Index>-th
3425 //           node.
3426 //=======================================================================
3427
3428 bool SMESH_Pattern::Apply (const SMDS_MeshVolume* theVolume,
3429                            const int              theNode000Index,
3430                            const int              theNode001Index)
3431 {
3432   if (!findBoundaryPoints()) // bind ID to points
3433     return false;
3434
3435   SMESH_Block block;  // bind ID to shape
3436   if (!block.LoadMeshBlock( theVolume, theNode000Index, theNode001Index, myOrderedNodes ))
3437     return setErrorCode( ERR_APPLV_BAD_SHAPE );
3438   // compute XYZ of points on shapes
3439
3440   for ( int ID = SMESH_Block::ID_V000; ID <= SMESH_Block::ID_Shell; ID++ )
3441   {
3442     list< TPoint* > & shapePoints = getShapePoints( ID );
3443     list< TPoint* >::iterator pIt = shapePoints.begin();
3444
3445     if ( block.IsVertexID( ID ))
3446       for ( ; pIt != shapePoints.end(); pIt++ ) {
3447         block.VertexPoint( ID, (*pIt)->myXYZ.ChangeCoord() );
3448       }
3449     else if ( block.IsEdgeID( ID ))
3450       for ( ; pIt != shapePoints.end(); pIt++ ) {
3451         block.EdgePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3452       }
3453     else if ( block.IsFaceID( ID ))
3454       for ( ; pIt != shapePoints.end(); pIt++ ) {
3455         block.FacePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3456       }
3457     else
3458       for ( ; pIt != shapePoints.end(); pIt++ )
3459         block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3460   } // loop on block sub-shapes
3461
3462   myIsComputed = true;
3463
3464   return setErrorCode( ERR_OK );
3465 }
3466
3467 //=======================================================================
3468 //function : mergePoints
3469 //purpose  : Merge XYZ on edges and/or faces.
3470 //=======================================================================
3471
3472 void SMESH_Pattern::mergePoints (const bool uniteGroups)
3473 {
3474   map< TNodeSet, list< list< int > > >::iterator idListIt = myIdsOnBoundary.begin();
3475   for ( ; idListIt != myIdsOnBoundary.end(); idListIt++ )
3476   {
3477     list<list< int > >& groups = idListIt->second;
3478     if ( groups.size() < 2 )
3479       continue;
3480
3481     // find tolerance
3482     const TNodeSet& nodes = idListIt->first;
3483     double tol2 = 1.e-10;
3484     if ( nodes.size() > 1 ) {
3485       Bnd_Box box;
3486       TNodeSet::const_iterator n = nodes.begin();
3487       for ( ; n != nodes.end(); ++n )
3488         box.Add( gp_Pnt( SMESH_TNodeXYZ( *n )));
3489       double x, y, z, X, Y, Z;
3490       box.Get( x, y, z, X, Y, Z );
3491       gp_Pnt p( x, y, z ), P( X, Y, Z );
3492       tol2 = 1.e-4 * p.SquareDistance( P );
3493     }
3494
3495     // to unite groups on link
3496     bool unite = ( uniteGroups && nodes.size() == 2 );
3497     map< double, int > distIndMap;
3498     const SMDS_MeshNode* node = *nodes.begin();
3499     gp_Pnt P = SMESH_TNodeXYZ( node );
3500
3501     // compare points, replace indices
3502
3503     list< int >::iterator ind1, ind2;
3504     list< list< int > >::iterator grpIt1, grpIt2;
3505     for ( grpIt1 = groups.begin(); grpIt1 != groups.end(); grpIt1++ )
3506     {
3507       list< int >& indices1 = *grpIt1;
3508       grpIt2 = grpIt1;
3509       for ( grpIt2++; grpIt2 != groups.end(); grpIt2++ )
3510       {
3511         list< int >& indices2 = *grpIt2;
3512         for ( ind1 = indices1.begin(); ind1 != indices1.end(); ind1++ )
3513         {
3514           gp_XYZ& p1 = myXYZ[ *ind1 ];
3515           ind2 = indices2.begin();
3516           while ( ind2 != indices2.end() )
3517           {
3518             gp_XYZ& p2 = myXYZ[ *ind2 ];
3519             //MESSAGE("COMP: " << *ind1 << " " << *ind2 << " X: " << p2.X() << " tol2: " << tol2);
3520             if ( ( p1 - p2 ).SquareModulus() <= tol2 )
3521             {
3522               ASSERT( myReverseConnectivity.find( *ind2 ) != myReverseConnectivity.end() );
3523               list< TElemDef* > & elemXYZIDsList = myReverseConnectivity[ *ind2 ];
3524               list< TElemDef* >::iterator elemXYZIDs = elemXYZIDsList.begin();
3525               for ( ; elemXYZIDs != elemXYZIDsList.end(); elemXYZIDs++ )
3526               {
3527                 //MESSAGE( " Replace " << *ind2 << " with " << *ind1 );
3528                 myXYZ[ *ind2 ] = undefinedXYZ();
3529                 replace( (*elemXYZIDs)->begin(), (*elemXYZIDs)->end(), *ind2, *ind1 );
3530               }
3531               ind2 = indices2.erase( ind2 );
3532             }
3533             else
3534               ind2++;
3535           }
3536         }
3537       }
3538       if ( unite ) { // sort indices using distIndMap
3539         for ( ind1 = indices1.begin(); ind1 != indices1.end(); ind1++ )
3540         {
3541           ASSERT( isDefined( myXYZ[ *ind1 ] ));
3542           double dist = P.SquareDistance( myXYZ[ *ind1 ]);
3543           distIndMap.insert( make_pair( dist, *ind1 ));
3544         }
3545       }
3546     }
3547     if ( unite ) { // put all sorted indices into the first group
3548       list< int >& g = groups.front();
3549       g.clear();
3550       map< double, int >::iterator dist_ind = distIndMap.begin();
3551       for ( ; dist_ind != distIndMap.end(); dist_ind++ )
3552         g.push_back( dist_ind->second );
3553     }
3554   } // loop on myIdsOnBoundary
3555 }
3556
3557 //=======================================================================
3558 //function : makePolyElements
3559 //purpose  : prepare intermediate data to create Polygons and Polyhedrons
3560 //=======================================================================
3561
3562 void SMESH_Pattern::
3563   makePolyElements(const vector< const SMDS_MeshNode* >& theNodes,
3564                    const bool                            toCreatePolygons,
3565                    const bool                            toCreatePolyedrs)
3566 {
3567   myPolyElemXYZIDs.clear();
3568   myPolyElems.clear();
3569   myPolyElems.reserve( myIdsOnBoundary.size() );
3570
3571   // make a set of refined elements
3572   TIDSortedElemSet elemSet, avoidSet( myElements.begin(), myElements.end() );
3573
3574   map< TNodeSet, list< list< int > > >::iterator indListIt, nn_IdList;
3575
3576   if ( toCreatePolygons )
3577   {
3578     int lastFreeId = myXYZ.size();
3579
3580     // loop on links of refined elements
3581     indListIt = myIdsOnBoundary.begin();
3582     for ( ; indListIt != myIdsOnBoundary.end(); indListIt++ )
3583     {
3584       const TNodeSet & linkNodes = indListIt->first;
3585       if ( linkNodes.size() != 2 )
3586         continue; // skip face
3587       const SMDS_MeshNode* n1 = * linkNodes.begin();
3588       const SMDS_MeshNode* n2 = * linkNodes.rbegin();
3589
3590       list<list< int > >& idGroups = indListIt->second; // ids of nodes to build
3591       if ( idGroups.empty() || idGroups.front().empty() )
3592         continue;
3593
3594       // find not refined face having n1-n2 link
3595
3596       while (true)
3597       {
3598         const SMDS_MeshElement* face =
3599           SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
3600         if ( face )
3601         {
3602           avoidSet.insert ( face );
3603           myPolyElems.push_back( face );
3604
3605           // some links of <face> are split;
3606           // make list of xyz for <face>
3607           myPolyElemXYZIDs.push_back(TElemDef());
3608           TElemDef & faceNodeIds = myPolyElemXYZIDs.back();
3609           // loop on links of a <face>
3610           SMDS_ElemIteratorPtr nIt = face->nodesIterator();
3611           int i = 0, nbNodes = face->NbNodes();
3612           vector<const SMDS_MeshNode*> nodes( nbNodes + 1 );
3613           while ( nIt->more() )
3614             nodes[ i++ ] = smdsNode( nIt->next() );
3615           nodes[ i ] = nodes[ 0 ];
3616           for ( i = 0; i < nbNodes; ++i )
3617           {
3618             // look for point mapped on a link
3619             TNodeSet faceLinkNodes;
3620             faceLinkNodes.insert( nodes[ i ] );
3621             faceLinkNodes.insert( nodes[ i + 1 ] );
3622             if ( faceLinkNodes == linkNodes )
3623               nn_IdList = indListIt;
3624             else
3625               nn_IdList = myIdsOnBoundary.find( faceLinkNodes );
3626             // add face point ids
3627             faceNodeIds.push_back( ++lastFreeId );
3628             myXYZIdToNodeMap.insert( make_pair( lastFreeId, nodes[ i ]));
3629             if ( nn_IdList != myIdsOnBoundary.end() )
3630             {
3631               // there are points mapped on a link
3632               list< int >& mappedIds = nn_IdList->second.front();
3633               if ( isReversed( nodes[ i ], mappedIds ))
3634                 faceNodeIds.insert (faceNodeIds.end(),mappedIds.rbegin(), mappedIds.rend() );
3635               else
3636                 faceNodeIds.insert (faceNodeIds.end(),mappedIds.begin(), mappedIds.end() );
3637             }
3638           } // loop on links of a <face>
3639         } // if ( face )
3640         else
3641           break;
3642       } // while (true)
3643
3644       if ( myIs2D && idGroups.size() > 1 ) {
3645
3646         // sew new elements on 2 refined elements sharing n1-n2 link
3647
3648         list< int >& idsOnLink = idGroups.front();
3649         // temporarily add ids of link nodes to idsOnLink
3650         bool rev = isReversed( n1, idsOnLink );
3651         for ( int i = 0; i < 2; ++i )
3652         {
3653           TNodeSet nodeSet;
3654           nodeSet.insert( i ? n2 : n1 );
3655           ASSERT( myIdsOnBoundary.find( nodeSet ) != myIdsOnBoundary.end() );
3656           list<list< int > >& groups = myIdsOnBoundary[ nodeSet ];
3657           int nodeId = groups.front().front();
3658           bool append = i;
3659           if ( rev ) append = !append;
3660           if ( append )
3661             idsOnLink.push_back( nodeId );
3662           else
3663             idsOnLink.push_front( nodeId );
3664         }
3665         list< int >::iterator id = idsOnLink.begin();
3666         for ( ; id != idsOnLink.end(); ++id ) // loop on XYZ ids on a link
3667         {
3668           list< TElemDef* >& elemDefs = myReverseConnectivity[ *id ]; // elems sharing id
3669           list< TElemDef* >::iterator pElemDef = elemDefs.begin();
3670           for ( ; pElemDef != elemDefs.end(); pElemDef++ ) // loop on elements sharing id
3671           {
3672             TElemDef* pIdList = *pElemDef; // ptr on list of ids making element up
3673             // look for <id> in element definition
3674             TElemDef::iterator idDef = find( pIdList->begin(), pIdList->end(), *id );
3675             ASSERT ( idDef != pIdList->end() );
3676             // look for 2 neighbour ids of <id> in element definition
3677             for ( int prev = 0; prev < 2; ++prev ) {
3678               TElemDef::iterator idDef2 = idDef;
3679               if ( prev )
3680                 idDef2 = ( idDef2 == pIdList->begin() ) ? --pIdList->end() : --idDef2;
3681               else
3682                 idDef2 = ( ++idDef2 == pIdList->end() ) ? pIdList->begin() : idDef2;
3683               // look for idDef2 on a link starting from id
3684               list< int >::iterator id2 = find( id, idsOnLink.end(), *idDef2 );
3685               if ( id2 != idsOnLink.end() && id != --id2 ) { // found not next to id
3686                 // insert ids located on link between <id> and <id2>
3687                 // into the element definition between idDef and idDef2
3688                 if ( prev )
3689                   for ( ; id2 != id; --id2 )
3690                     pIdList->insert( idDef, *id2 );
3691                 else {
3692                   list< int >::iterator id1 = id;
3693                   for ( ++id1, ++id2; id1 != id2; ++id1 )
3694                     pIdList->insert( idDef2, *id1 );
3695                 }
3696               }
3697             }
3698           }
3699         }
3700         // remove ids of link nodes
3701         idsOnLink.pop_front();
3702         idsOnLink.pop_back();
3703       }
3704     } // loop on myIdsOnBoundary
3705   } // if ( toCreatePolygons )
3706
3707   if ( toCreatePolyedrs )
3708   {
3709     // check volumes adjacent to the refined elements
3710     SMDS_VolumeTool volTool;
3711     vector<const SMDS_MeshElement*>::iterator refinedElem = myElements.begin();
3712     for ( ; refinedElem != myElements.end(); ++refinedElem )
3713     {
3714       // loop on nodes of refinedElem
3715       SMDS_ElemIteratorPtr nIt = (*refinedElem)->nodesIterator();
3716       while ( nIt->more() ) {
3717         const SMDS_MeshNode* node = smdsNode( nIt->next() );
3718         // loop on inverse elements of node
3719         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3720         while ( eIt->more() )
3721         {
3722           const SMDS_MeshElement* elem = eIt->next();
3723           if ( !volTool.Set( elem ) || !avoidSet.insert( elem ).second )
3724             continue; // skip faces or refined elements
3725           // add polyhedron definition
3726           myPolyhedronQuantities.push_back(vector<int> ());
3727           myPolyElemXYZIDs.push_back(TElemDef());
3728           vector<int>& quantity = myPolyhedronQuantities.back();
3729           TElemDef &   elemDef  = myPolyElemXYZIDs.back();
3730           // get definitions of new elements on volume faces
3731           bool makePoly = false;
3732           for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
3733           {
3734             if ( getFacesDefinition(volTool.GetFaceNodes( iF ),
3735                                     volTool.NbFaceNodes( iF ),
3736                                     theNodes, elemDef, quantity))
3737               makePoly = true;
3738           }
3739           if ( makePoly )
3740             myPolyElems.push_back( elem );
3741           else {
3742             myPolyhedronQuantities.pop_back();
3743             myPolyElemXYZIDs.pop_back();
3744           }
3745         }
3746       }
3747     }
3748   }
3749 }
3750
3751 //=======================================================================
3752 //function : getFacesDefinition
3753 //purpose  : return faces definition for a volume face defined by theBndNodes
3754 //=======================================================================
3755
3756 bool SMESH_Pattern::
3757   getFacesDefinition(const SMDS_MeshNode**                 theBndNodes,
3758                      const int                             theNbBndNodes,
3759                      const vector< const SMDS_MeshNode* >& theNodes,
3760                      list< int >&                          theFaceDefs,
3761                      vector<int>&                          theQuantity)
3762 {
3763   bool makePoly = false;
3764
3765   set< const SMDS_MeshNode* > bndNodeSet( theBndNodes, theBndNodes + theNbBndNodes);
3766
3767   map< TNodeSet, list< list< int > > >::iterator nn_IdList;
3768
3769   // make a set of all nodes on a face
3770   set< int > ids;
3771   if ( !myIs2D ) { // for 2D, merge only edges
3772     nn_IdList = myIdsOnBoundary.find( bndNodeSet );
3773     if ( nn_IdList != myIdsOnBoundary.end() ) {
3774       list< int > & faceIds = nn_IdList->second.front();
3775       if ( !faceIds.empty() ) {
3776         makePoly = true;
3777         ids.insert( faceIds.begin(), faceIds.end() );
3778       }
3779     }
3780   }
3781
3782   // add ids on links and bnd nodes
3783   int lastFreeId = Max( myXYZIdToNodeMap.rbegin()->first, theNodes.size() );
3784   TElemDef faceDef; // definition for the case if there is no new adjacent volumes
3785   for ( int iN = 0; iN < theNbBndNodes; ++iN )
3786   {
3787     // add id of iN-th bnd node
3788     TNodeSet nSet;
3789     nSet.insert( theBndNodes[ iN ] );
3790     nn_IdList = myIdsOnBoundary.find( nSet );
3791     int bndId = ++lastFreeId;
3792     if ( nn_IdList != myIdsOnBoundary.end() ) {
3793       bndId = nn_IdList->second.front().front();
3794       ids.insert( bndId );
3795     }
3796     else {
3797       myXYZIdToNodeMap.insert( make_pair( bndId, theBndNodes[ iN ] ));
3798     }
3799     faceDef.push_back( bndId );
3800     // add ids on a link
3801     TNodeSet linkNodes;
3802     linkNodes.insert( theBndNodes[ iN ]);
3803     linkNodes.insert( theBndNodes[ (iN + 1) % theNbBndNodes] );
3804     nn_IdList = myIdsOnBoundary.find( linkNodes );
3805     if ( nn_IdList != myIdsOnBoundary.end() ) {
3806       list< int > & linkIds = nn_IdList->second.front();
3807       if ( !linkIds.empty() )
3808       {
3809         makePoly = true;
3810         ids.insert( linkIds.begin(), linkIds.end() );
3811         if ( isReversed( theBndNodes[ iN ], linkIds ))
3812           faceDef.insert( faceDef.end(), linkIds.begin(), linkIds.end() );
3813         else
3814           faceDef.insert( faceDef.end(), linkIds.rbegin(), linkIds.rend() );
3815       }
3816     }
3817   }
3818
3819   // find faces definition of new volumes
3820
3821   bool defsAdded = false;
3822   if ( !myIs2D ) { // for 2D, merge only edges
3823     SMDS_VolumeTool vol;
3824     set< TElemDef* > checkedVolDefs;
3825     set< int >::iterator id = ids.begin();
3826     for ( ; id != ids.end(); ++id )
3827     {
3828       // definitions of volumes sharing id
3829       list< TElemDef* >& defList = myReverseConnectivity[ *id ];
3830       ASSERT( !defList.empty() );
3831       // loop on volume definitions
3832       list< TElemDef* >::iterator pIdList = defList.begin();
3833       for ( ; pIdList != defList.end(); ++pIdList)
3834       {
3835         if ( !checkedVolDefs.insert( *pIdList ).second )
3836           continue; // skip already checked volume definition
3837         vector< int > idVec( (*pIdList)->begin(), (*pIdList)->end() );
3838         // loop on face defs of a volume
3839         SMDS_VolumeTool::VolumeType volType = vol.GetType( idVec.size() );
3840         if ( volType == SMDS_VolumeTool::UNKNOWN )
3841           continue;
3842         int nbFaces = vol.NbFaces( volType );
3843         for ( int iF = 0; iF < nbFaces; ++iF )
3844         {
3845           const int* nodeInds = vol.GetFaceNodesIndices( volType, iF, true );
3846           int iN, nbN = vol.NbFaceNodes( volType, iF );
3847           // check if all nodes of a faces are in <ids>
3848           bool all = true;
3849           for ( iN = 0; iN < nbN && all; ++iN ) {
3850             int nodeId = idVec[ nodeInds[ iN ]];
3851             all = ( ids.find( nodeId ) != ids.end() );
3852           }
3853           if ( all ) {
3854             // store a face definition
3855             for ( iN = 0; iN < nbN; ++iN ) {
3856               theFaceDefs.push_back( idVec[ nodeInds[ iN ]]);
3857             }
3858             theQuantity.push_back( nbN );
3859             defsAdded = true;
3860           }
3861         }
3862       }
3863     }
3864   }
3865   if ( !defsAdded ) {
3866     theQuantity.push_back( faceDef.size() );
3867     theFaceDefs.splice( theFaceDefs.end(), faceDef );
3868   }
3869
3870   return makePoly;
3871 }
3872
3873 //=======================================================================
3874 //function : clearSubMesh
3875 //purpose  : 
3876 //=======================================================================
3877
3878 static bool clearSubMesh( SMESH_Mesh*         theMesh,
3879                           const TopoDS_Shape& theShape)
3880 {
3881   bool removed = false;
3882   if ( SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( theShape ))
3883   {
3884     removed = !aSubMesh->IsEmpty();
3885     if ( removed )
3886       aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
3887   }
3888   else {
3889     SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
3890     if ( SMESHDS_SubMesh* aSubMeshDS = aMeshDS->MeshElements( theShape ))
3891     {
3892       SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
3893       removed = eIt->more();
3894       while ( eIt->more() )
3895         aMeshDS->RemoveElement( eIt->next() );
3896       SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
3897       removed = removed || nIt->more();
3898       while ( nIt->more() )
3899         aMeshDS->RemoveNode( smdsNode( nIt->next() ));
3900     }
3901   }
3902   return removed;
3903 }
3904
3905 //=======================================================================
3906 //function : clearMesh
3907 //purpose  : clear mesh elements existing on myShape in theMesh
3908 //=======================================================================
3909
3910 void SMESH_Pattern::clearMesh(SMESH_Mesh* theMesh) const
3911 {
3912
3913   if ( !myShape.IsNull() )
3914   {
3915     if ( !clearSubMesh( theMesh, myShape ) && !myIs2D ) { // myShape is SHELL but volumes may be bound to SOLID
3916       TopTools_ListIteratorOfListOfShape it( theMesh->GetAncestors( myShape ));
3917       for (; it.More() && it.Value().ShapeType() == TopAbs_SOLID; it.Next())
3918       {
3919         clearSubMesh( theMesh, it.Value() );
3920       }
3921     }
3922   }
3923 }
3924
3925 //=======================================================================
3926 //function : findExistingNodes
3927 //purpose  : fills nodes vector with nodes existing on a given shape (IMP 22368)
3928 //           Returns true if all nodes for all points on S are found
3929 //=======================================================================
3930
3931 bool SMESH_Pattern::findExistingNodes( SMESH_Mesh*                      mesh,
3932                                        const TopoDS_Shape&              S,
3933                                        const std::list< TPoint* > &     points,
3934                                        vector< const SMDS_MeshNode* > & nodesVector)
3935 {
3936   if ( S.IsNull() || points.empty() )
3937     return false;
3938
3939   SMESHDS_Mesh* aMeshDS = mesh->GetMeshDS();
3940
3941   switch ( S.ShapeType() )
3942   {
3943   case TopAbs_VERTEX:
3944   {
3945     int pIndex = points.back() - &myPoints[0];
3946     if ( !nodesVector[ pIndex ] )
3947       nodesVector[ pIndex ] = SMESH_Algo::VertexNode( TopoDS::Vertex( S ), aMeshDS );
3948     return nodesVector[ pIndex ];
3949   }
3950   case TopAbs_EDGE:
3951   {
3952     const TopoDS_Edge& edge = TopoDS::Edge( S );
3953     map< double, const SMDS_MeshNode* > paramsOfNodes;
3954     if ( !SMESH_Algo::GetSortedNodesOnEdge( aMeshDS, edge,
3955                                             /*ignoreMediumNodes=*/false,
3956                                             paramsOfNodes )
3957          || paramsOfNodes.size() < 3 )
3958       break;
3959     // points on VERTEXes are included with wrong myU
3960     list< TPoint* >::const_reverse_iterator pItR = ++points.rbegin();
3961     list< TPoint* >::const_iterator         pItF = ++points.begin();
3962     const bool isForward = ( (*pItF)->myU < (*pItR)->myU );
3963     map< double, const SMDS_MeshNode* >::iterator u2n    = ++paramsOfNodes.begin();
3964     map< double, const SMDS_MeshNode* >::iterator u2nEnd = --paramsOfNodes.end();
3965     TPoint* p;
3966     if ( paramsOfNodes.size() == points.size() )
3967     {
3968       for ( ; u2n != u2nEnd; ++u2n )
3969       {
3970         p = ( isForward ? *pItF : *pItR );
3971         int pIndex = p - &myPoints[0];
3972         if ( !nodesVector [ pIndex ] )
3973           nodesVector [ pIndex ] = u2n->second;
3974         ++pItF;
3975         ++pItR;
3976       }
3977       return true;
3978     }
3979     else
3980     {
3981       const double tolFact = 0.05;
3982       while ( u2n != u2nEnd && pItF != points.end() )
3983       {
3984         const double         u = u2n->first;
3985         const SMDS_MeshNode* n = u2n->second;
3986         const double       tol = ( (++u2n)->first - u ) * tolFact;
3987         do
3988         {
3989           p = ( isForward ? *pItF : *pItR );
3990           if ( Abs( u - p->myU ) < tol )
3991           {
3992             int pIndex = p - &myPoints[0];
3993             if ( !nodesVector [ pIndex ] )
3994               nodesVector [ pIndex ] = n;
3995             ++pItF;
3996             ++pItR;
3997             break;
3998           }
3999         }
4000         while ( p->myU < u && ( ++pItF, ++pItR != points.rend() ));
4001       }
4002     }
4003     break;
4004   } // case TopAbs_EDGE:
4005
4006   default:;
4007   } // switch ( S.ShapeType() )
4008
4009   return false;
4010 }
4011
4012 //=======================================================================
4013 //function : MakeMesh
4014 //purpose  : Create nodes and elements in <theMesh> using nodes
4015 //           coordinates computed by either of Apply...() methods
4016 //=======================================================================
4017
4018 bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh,
4019                              const bool  toCreatePolygons,
4020                              const bool  toCreatePolyedrs)
4021 {
4022   if ( !myIsComputed )
4023     return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
4024
4025   mergePoints( toCreatePolygons );
4026
4027   SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
4028
4029   // clear elements and nodes existing on myShape
4030   clearMesh(theMesh);
4031
4032   bool onMeshElements = ( !myElements.empty() );
4033
4034   // Create missing nodes
4035
4036   vector< const SMDS_MeshNode* > nodesVector; // i-th point/xyz -> node
4037   if ( onMeshElements )
4038   {
4039     nodesVector.resize( Max( myXYZ.size(), myXYZIdToNodeMap.rbegin()->first ), 0 );
4040     map< int, const SMDS_MeshNode*>::iterator i_node = myXYZIdToNodeMap.begin();
4041     for ( ; i_node != myXYZIdToNodeMap.end(); i_node++ ) {
4042       nodesVector[ i_node->first ] = i_node->second;
4043     }
4044     for ( size_t i = 0; i < myXYZ.size(); ++i ) {
4045       if ( !nodesVector[ i ] && isDefined( myXYZ[ i ] ) )
4046         nodesVector[ i ] = aMeshDS->AddNode (myXYZ[ i ].X(),
4047                                              myXYZ[ i ].Y(),
4048                                              myXYZ[ i ].Z());
4049     }
4050     if ( theMesh->HasShapeToMesh() )
4051     {
4052       // set nodes on EDGEs (IMP 22368)
4053       SMESH_MesherHelper helper( *theMesh );
4054       helper.ToFixNodeParameters( true );
4055       map< TNodeSet, list< list< int > > >::iterator idListIt = myIdsOnBoundary.begin();
4056       for ( ; idListIt != myIdsOnBoundary.end(); idListIt++ )
4057       {
4058         list<list< int > >& groups = idListIt->second;
4059         const TNodeSet&      nodes = idListIt->first;
4060         if ( nodes.size() != 2 )
4061           continue; // not a link
4062         const SMDS_MeshNode* n1 = *nodes.begin();
4063         const SMDS_MeshNode* n2 = *nodes.rbegin();
4064         TopoDS_Shape S1 = helper.GetSubShapeByNode( n1, aMeshDS );
4065         TopoDS_Shape S2 = helper.GetSubShapeByNode( n2, aMeshDS );
4066         if ( S1.IsNull() || S1.ShapeType() < TopAbs_EDGE ||
4067              S2.IsNull() || S2.ShapeType() < TopAbs_EDGE )
4068           continue;
4069         TopoDS_Shape S;
4070         if ( S1.ShapeType() == TopAbs_EDGE )
4071         {
4072           if ( S1 == S2 || helper.IsSubShape( S2, S1 ))
4073             S = S1;
4074         }
4075         else if ( S2.ShapeType() == TopAbs_EDGE )
4076         {
4077           if ( helper.IsSubShape( S1, S2 ))
4078             S = S2;
4079         }
4080         else
4081         {
4082           S = helper.GetCommonAncestor( S1, S2, *theMesh, TopAbs_EDGE );
4083         } 
4084         if ( S.IsNull() )
4085           continue;
4086         const TopoDS_Edge & E = TopoDS::Edge( S );
4087         helper.SetSubShape( E );
4088         list<list< int > >::iterator g = groups.begin();
4089         for ( ; g != groups.end(); ++g )
4090         {
4091           list< int >& ids = *g;
4092           list< int >::iterator id = ids.begin();
4093           for ( ; id != ids.end(); ++id )
4094             if ( nodesVector[ *id ] && nodesVector[ *id ]->getshapeId() < 1 )
4095             {
4096               double u = 1e100;
4097               aMeshDS->SetNodeOnEdge( nodesVector[ *id ], E, u );
4098               helper.CheckNodeU( E, nodesVector[ *id ], u, 1e-7, true );
4099             }
4100         }
4101       }
4102     }
4103   }  // if ( onMeshElements )
4104
4105   else
4106   {
4107     nodesVector.resize( myPoints.size(), 0 );
4108
4109     // loop on sub-shapes of myShape: create nodes
4110     map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
4111     for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
4112     {
4113       list< TPoint* > & points = idPointIt->second;
4114       TopoDS_Shape S;
4115       if ( !myShapeIDMap.IsEmpty() )
4116         S = myShapeIDMap( idPointIt->first );
4117
4118       // find existing nodes on EDGEs and VERTEXes
4119       if ( findExistingNodes( theMesh, S, points, nodesVector ))
4120         continue;
4121
4122       list< TPoint* >::iterator pIt = points.begin();
4123       for ( ; pIt != points.end(); pIt++ )
4124       {
4125         TPoint* point = *pIt;
4126         int pIndex = point - &myPoints[0];
4127         if ( nodesVector [ pIndex ] )
4128           continue;
4129         SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
4130                                                 point->myXYZ.Y(),
4131                                                 point->myXYZ.Z());
4132         nodesVector [ pIndex ] = node;
4133
4134         if ( !S.IsNull() ) {
4135
4136           switch ( S.ShapeType() ) {
4137           case TopAbs_VERTEX: {
4138             aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S )); break;
4139           }
4140           case TopAbs_EDGE: {
4141             aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ), point->myU ); break;
4142           }
4143           case TopAbs_FACE: {
4144             aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ),
4145                                     point->myUV.X(), point->myUV.Y() ); break;
4146           }
4147           default:
4148             aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
4149           }
4150         }
4151       }
4152     }
4153   }
4154
4155   // create elements
4156
4157   if ( onMeshElements )
4158   {
4159     // prepare data to create poly elements
4160     makePolyElements( nodesVector, toCreatePolygons, toCreatePolyedrs );
4161
4162     // refine elements
4163     createElements( theMesh, nodesVector, myElemXYZIDs, myElements );
4164     // sew old and new elements
4165     createElements( theMesh, nodesVector, myPolyElemXYZIDs, myPolyElems );
4166   }
4167   else
4168   {
4169     createElements( theMesh, nodesVector, myElemPointIDs, myElements );
4170   }
4171
4172   aMeshDS->Modified();
4173   aMeshDS->CompactMesh();
4174
4175   if ( myToKeepNodes )
4176     myOutNodes.swap( nodesVector );
4177
4178 //   const map<int,SMESHDS_SubMesh*>& sm = aMeshDS->SubMeshes();
4179 //   map<int,SMESHDS_SubMesh*>::const_iterator i_sm = sm.begin();
4180 //   for ( ; i_sm != sm.end(); i_sm++ )
4181 //   {
4182 //     cout << " SM " << i_sm->first << " ";
4183 //     TopAbs::Print( aMeshDS->IndexToShape( i_sm->first ).ShapeType(), cout)<< " ";
4184 //     //SMDS_ElemIteratorPtr GetElements();
4185 //     SMDS_NodeIteratorPtr nit = i_sm->second->GetNodes();
4186 //     while ( nit->more() )
4187 //       cout << nit->next()->GetID() << " ";
4188 //     cout << endl;
4189 //   }
4190   return setErrorCode( ERR_OK );
4191 }
4192
4193 //=======================================================================
4194 //function : createElements
4195 //purpose  : add elements to the mesh
4196 //=======================================================================
4197
4198 void SMESH_Pattern::createElements(SMESH_Mesh*                            theMesh,
4199                                    const vector<const SMDS_MeshNode* >&   theNodesVector,
4200                                    const list< TElemDef > &               theElemNodeIDs,
4201                                    const vector<const SMDS_MeshElement*>& theElements)
4202 {
4203   SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
4204   SMESH_MeshEditor editor( theMesh );
4205
4206   bool onMeshElements = !theElements.empty();
4207
4208   // shapes and groups theElements are on
4209   vector< int > shapeIDs;
4210   vector< list< SMESHDS_Group* > > groups;
4211   set< const SMDS_MeshNode* > shellNodes;
4212   if ( onMeshElements )
4213   {
4214     shapeIDs.resize( theElements.size() );
4215     groups.resize( theElements.size() );
4216     const set<SMESHDS_GroupBase*>& allGroups = aMeshDS->GetGroups();
4217     set<SMESHDS_GroupBase*>::const_iterator grIt;
4218     for ( size_t i = 0; i < theElements.size(); i++ )
4219     {
4220       shapeIDs[ i ] = editor.FindShape( theElements[ i ] );
4221       for ( grIt = allGroups.begin(); grIt != allGroups.end(); grIt++ ) {
4222         SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
4223         if ( group && group->SMDSGroup().Contains( theElements[ i ] ))
4224           groups[ i ].push_back( group );
4225       }
4226     }
4227     // get all nodes bound to shells because their SpacePosition is not set
4228     // by SMESHDS_Mesh::SetNodeInVolume()
4229     TopoDS_Shape aMainShape = aMeshDS->ShapeToMesh();
4230     if ( !aMainShape.IsNull() ) {
4231       TopExp_Explorer shellExp( aMainShape, TopAbs_SHELL );
4232       for ( ; shellExp.More(); shellExp.Next() )
4233       {
4234         SMESHDS_SubMesh * sm = aMeshDS->MeshElements( shellExp.Current() );
4235         if ( sm ) {
4236           SMDS_NodeIteratorPtr nIt = sm->GetNodes();
4237           while ( nIt->more() )
4238             shellNodes.insert( nIt->next() );
4239         }
4240       }
4241     }
4242   }
4243    // nb new elements per a refined element
4244   int nbNewElemsPerOld = 1;
4245   if ( onMeshElements )
4246     nbNewElemsPerOld = theElemNodeIDs.size() / theElements.size();
4247
4248   bool is2d = myIs2D;
4249
4250   list< TElemDef >::const_iterator enIt = theElemNodeIDs.begin();
4251   list< vector<int> >::iterator quantity = myPolyhedronQuantities.begin();
4252   for ( int iElem = 0; enIt != theElemNodeIDs.end(); enIt++, iElem++ )
4253   {
4254     const TElemDef & elemNodeInd = *enIt;
4255     // retrieve nodes
4256     vector< const SMDS_MeshNode* > nodes( elemNodeInd.size() );
4257     TElemDef::const_iterator id = elemNodeInd.begin();
4258     int nbNodes;
4259     for ( nbNodes = 0; id != elemNodeInd.end(); id++ ) {
4260       if ( *id < (int) theNodesVector.size() )
4261         nodes[ nbNodes++ ] = theNodesVector[ *id ];
4262       else
4263         nodes[ nbNodes++ ] = myXYZIdToNodeMap[ *id ];
4264     }
4265     // dim of refined elem
4266     int elemIndex = iElem / nbNewElemsPerOld; // refined element index
4267     if ( onMeshElements ) {
4268       is2d = ( theElements[ elemIndex ]->GetType() == SMDSAbs_Face );
4269     }
4270     // add an element
4271     const SMDS_MeshElement* elem = 0;
4272     if ( is2d ) {
4273       switch ( nbNodes ) {
4274       case 3:
4275         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
4276       case 4:
4277         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
4278       case 6:
4279         if ( !onMeshElements ) {// create a quadratic face
4280           elem = aMeshDS->AddFace (nodes[0], nodes[1], nodes[2], nodes[3],
4281                                    nodes[4], nodes[5] ); break;
4282         } // else do not break but create a polygon
4283       case 8:
4284         if ( !onMeshElements ) {// create a quadratic face
4285           elem = aMeshDS->AddFace (nodes[0], nodes[1], nodes[2], nodes[3],
4286                                    nodes[4], nodes[5], nodes[6], nodes[7] ); break;
4287         } // else do not break but create a polygon
4288       default:
4289         elem = aMeshDS->AddPolygonalFace( nodes );
4290       }
4291     }
4292     else {
4293       switch ( nbNodes ) {
4294       case 4:
4295         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
4296       case 5:
4297         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
4298                                    nodes[4] ); break;
4299       case 6:
4300         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
4301                                    nodes[4], nodes[5] ); break;
4302       case 8:
4303         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
4304                                    nodes[4], nodes[5], nodes[6], nodes[7] ); break;
4305       default:
4306         elem = aMeshDS->AddPolyhedralVolume( nodes, *quantity++ );
4307       }
4308     }
4309     // set element on a shape
4310     if ( elem && onMeshElements ) // applied to mesh elements
4311     {
4312       int shapeID = shapeIDs[ elemIndex ];
4313       if ( shapeID > 0 ) {
4314         aMeshDS->SetMeshElementOnShape( elem, shapeID );
4315         // set nodes on a shape
4316         TopoDS_Shape S = aMeshDS->IndexToShape( shapeID );
4317         if ( S.ShapeType() == TopAbs_SOLID ) {
4318           TopoDS_Iterator shellIt( S );
4319           if ( shellIt.More() )
4320             shapeID = aMeshDS->ShapeToIndex( shellIt.Value() );
4321         }
4322         SMDS_ElemIteratorPtr noIt = elem->nodesIterator();
4323         while ( noIt->more() ) {
4324           SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>(smdsNode( noIt->next() ));
4325           if ( node->getshapeId() < 1 &&
4326                shellNodes.find( node ) == shellNodes.end() )
4327           {
4328             if ( S.ShapeType() == TopAbs_FACE )
4329               aMeshDS->SetNodeOnFace( node, shapeID,
4330                                       Precision::Infinite(),// <- it's a sign that UV is not set
4331                                       Precision::Infinite());
4332             else {
4333               aMeshDS->SetNodeInVolume( node, shapeID );
4334               shellNodes.insert( node );
4335             }
4336           }
4337         }
4338       }
4339       // add elem in groups
4340       list< SMESHDS_Group* >::iterator g = groups[ elemIndex ].begin();
4341       for ( ; g != groups[ elemIndex ].end(); ++g )
4342         (*g)->SMDSGroup().Add( elem );
4343     }
4344     if ( elem && !myShape.IsNull() ) // applied to shape
4345       aMeshDS->SetMeshElementOnShape( elem, myShape );
4346   }
4347
4348   // make that SMESH_subMesh::_computeState == COMPUTE_OK
4349   // so that operations with hypotheses will erase the mesh being built
4350
4351   SMESH_subMesh * subMesh;
4352   if ( !myShape.IsNull() ) {
4353     subMesh = theMesh->GetSubMesh( myShape );
4354     if ( subMesh )
4355       subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
4356   }
4357   if ( onMeshElements ) {
4358     list< int > elemIDs;
4359     for ( size_t i = 0; i < theElements.size(); i++ )
4360     {
4361       subMesh = theMesh->GetSubMeshContaining( shapeIDs[ i ] );
4362       if ( subMesh )
4363         subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
4364
4365       elemIDs.push_back( theElements[ i ]->GetID() );
4366     }
4367     // remove refined elements
4368     editor.Remove( elemIDs, false );
4369   }
4370 }
4371
4372 //=======================================================================
4373 //function : isReversed
4374 //purpose  : check xyz ids order in theIdsList taking into account
4375 //           theFirstNode on a link
4376 //=======================================================================
4377
4378 bool SMESH_Pattern::isReversed(const SMDS_MeshNode* theFirstNode,
4379                                const list< int >&   theIdsList) const
4380 {
4381   if ( theIdsList.size() < 2 )
4382     return false;
4383
4384   gp_Pnt Pf ( theFirstNode->X(), theFirstNode->Y(), theFirstNode->Z() );
4385   gp_Pnt P[2];
4386   list<int>::const_iterator id = theIdsList.begin();
4387   for ( int i = 0; i < 2; ++i, ++id ) {
4388     if ( *id < (int) myXYZ.size() )
4389       P[ i ] = myXYZ[ *id ];
4390     else {
4391       map< int, const SMDS_MeshNode*>::const_iterator i_n;
4392       i_n = myXYZIdToNodeMap.find( *id );
4393       ASSERT( i_n != myXYZIdToNodeMap.end() );
4394       const SMDS_MeshNode* n = i_n->second;
4395       P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
4396     }
4397   }
4398   return Pf.SquareDistance( P[ 1 ] ) < Pf.SquareDistance( P[ 0 ] );
4399 }
4400
4401
4402 //=======================================================================
4403 //function : arrangeBoundaries
4404 //purpose  : if there are several wires, arrange boundaryPoints so that
4405 //           the outer wire goes first and fix inner wires orientation
4406 //           update myKeyPointIDs to correspond to the order of key-points
4407 //           in boundaries; sort internal boundaries by the nb of key-points
4408 //=======================================================================
4409
4410 void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
4411 {
4412   typedef list< list< TPoint* > >::iterator TListOfListIt;
4413   TListOfListIt bndIt;
4414   list< TPoint* >::iterator pIt;
4415
4416   int nbBoundaries = boundaryList.size();
4417   if ( nbBoundaries > 1 )
4418   {
4419     // sort boundaries by nb of key-points
4420     if ( nbBoundaries > 2 )
4421     {
4422       // move boundaries in tmp list
4423       list< list< TPoint* > > tmpList;
4424       tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
4425       // make a map nb-key-points to boundary-position-in-tmpList,
4426       // boundary-positions get ordered in it
4427       typedef map< int, TListOfListIt > TNbKpBndPosMap;
4428       TNbKpBndPosMap nbKpBndPosMap;
4429       bndIt = tmpList.begin();
4430       list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
4431       for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
4432         int nb = *nbKpIt * nbBoundaries;
4433         while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
4434           nb++;
4435         nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
4436       }
4437       // move boundaries back to boundaryList
4438       TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
4439       for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
4440         TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
4441         TListOfListIt bndPos1 = bndPos2++;
4442         boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
4443       }
4444     }
4445
4446     // Look for the outer boundary: the one with the point with the least X
4447     double leastX = DBL_MAX;
4448     TListOfListIt outerBndPos;
4449     for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
4450     {
4451       list< TPoint* >& boundary = (*bndIt);
4452       for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
4453       {
4454         TPoint* point = *pIt;
4455         if ( point->myInitXYZ.X() < leastX ) {
4456           leastX = point->myInitXYZ.X();
4457           outerBndPos = bndIt;
4458         }
4459       }
4460     }
4461
4462     if ( outerBndPos != boundaryList.begin() )
4463       boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos );
4464
4465   } // if nbBoundaries > 1
4466
4467   // Check boundaries orientation and re-fill myKeyPointIDs
4468
4469   set< TPoint* > keyPointSet;
4470   list< int >::iterator kpIt = myKeyPointIDs.begin();
4471   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
4472     keyPointSet.insert( & myPoints[ *kpIt ]);
4473   myKeyPointIDs.clear();
4474
4475   // update myNbKeyPntInBoundary also
4476   list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
4477
4478   for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
4479   {
4480     // find the point with the least X
4481     double leastX = DBL_MAX;
4482     list< TPoint* >::iterator xpIt;
4483     list< TPoint* >& boundary = (*bndIt);
4484     for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
4485     {
4486       TPoint* point = *pIt;
4487       if ( point->myInitXYZ.X() < leastX ) {
4488         leastX = point->myInitXYZ.X();
4489         xpIt = pIt;
4490       }
4491     }
4492     // find points next to the point with the least X
4493     TPoint* p = *xpIt, *pPrev, *pNext;
4494     if ( p == boundary.front() )
4495       pPrev = *(++boundary.rbegin());
4496     else {
4497       xpIt--;
4498       pPrev = *xpIt;
4499       xpIt++;
4500     }
4501     if ( p == boundary.back() )
4502       pNext = *(++boundary.begin());
4503     else {
4504       xpIt++;
4505       pNext = *xpIt;
4506     }
4507     // vectors of boundary direction near <p>
4508     gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
4509     double sqMag1 = v1.SquareMagnitude(), sqMag2 = v2.SquareMagnitude();
4510     if ( sqMag1 > DBL_MIN && sqMag2 > DBL_MIN ) {
4511       double yPrev = v1.Y() / sqrt( sqMag1 );
4512       double yNext = v2.Y() / sqrt( sqMag2 );
4513       double sumY = yPrev + yNext;
4514       bool reverse;
4515       if ( bndIt == boundaryList.begin() ) // outer boundary
4516         reverse = sumY > 0;
4517       else
4518         reverse = sumY < 0;
4519       if ( reverse )
4520         boundary.reverse();
4521     }
4522
4523     // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
4524     (*nbKpIt) = 0; // count nb of key-points again
4525     pIt = boundary.begin();
4526     for ( ; pIt != boundary.end(); pIt++)
4527     {
4528       TPoint* point = *pIt;
4529       if ( keyPointSet.find( point ) == keyPointSet.end() )
4530         continue;
4531       // find an index of a keypoint
4532       int index = 0;
4533       vector< TPoint >::const_iterator pVecIt = myPoints.begin();
4534       for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
4535         if ( &(*pVecIt) == point )
4536           break;
4537       myKeyPointIDs.push_back( index );
4538       (*nbKpIt)++;
4539     }
4540     myKeyPointIDs.pop_back(); // remove the first key-point from the back
4541     (*nbKpIt)--;
4542
4543   } // loop on a list of boundaries
4544
4545   ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
4546 }
4547
4548 //=======================================================================
4549 //function : findBoundaryPoints
4550 //purpose  : if loaded from file, find points to map on edges and faces and
4551 //           compute their parameters
4552 //=======================================================================
4553
4554 bool SMESH_Pattern::findBoundaryPoints()
4555 {
4556   if ( myIsBoundaryPointsFound ) return true;
4557
4558   myNbKeyPntInBoundary.clear();
4559
4560   if ( myIs2D )
4561   {
4562     set< TPoint* > pointsInElems;
4563
4564     // Find free links of elements:
4565     // put links of all elements in a set and remove links encountered twice
4566
4567     typedef pair< TPoint*, TPoint*> TLink;
4568     set< TLink > linkSet;
4569     list<TElemDef >::iterator epIt = myElemPointIDs.begin();
4570     for ( ; epIt != myElemPointIDs.end(); epIt++ )
4571     {
4572       TElemDef & elemPoints = *epIt;
4573       TElemDef::iterator pIt = elemPoints.begin();
4574       int prevP = elemPoints.back();
4575       for ( ; pIt != elemPoints.end(); pIt++ ) {
4576         TPoint* p1 = & myPoints[ prevP ];
4577         TPoint* p2 = & myPoints[ *pIt ];
4578         TLink link(( p1 < p2 ? p1 : p2 ), ( p1 < p2 ? p2 : p1 ));
4579         ASSERT( link.first != link.second );
4580         pair<set< TLink >::iterator,bool> itUniq = linkSet.insert( link );
4581         if ( !itUniq.second )
4582           linkSet.erase( itUniq.first );
4583         prevP = *pIt;
4584
4585         pointsInElems.insert( p1 );
4586       }
4587     }
4588     // Now linkSet contains only free links,
4589     // find the points order that they have in boundaries
4590
4591     // 1. make a map of key-points
4592     set< TPoint* > keyPointSet;
4593     list< int >::iterator kpIt = myKeyPointIDs.begin();
4594     for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
4595       keyPointSet.insert( & myPoints[ *kpIt ]);
4596
4597     // 2. chain up boundary points
4598     list< list< TPoint* > > boundaryList;
4599     boundaryList.push_back( list< TPoint* >() );
4600     list< TPoint* > * boundary = & boundaryList.back();
4601
4602     TPoint *point1, *point2, *keypoint1;
4603     kpIt = myKeyPointIDs.begin();
4604     point1 = keypoint1 = & myPoints[ *kpIt++ ];
4605     // loop on free links: look for the next point
4606     int iKeyPoint = 0;
4607     set< TLink >::iterator lIt = linkSet.begin();
4608     while ( lIt != linkSet.end() )
4609     {
4610       if ( (*lIt).first == point1 )
4611         point2 = (*lIt).second;
4612       else if ( (*lIt).second == point1 )
4613         point2 = (*lIt).first;
4614       else {
4615         lIt++;
4616         continue;
4617       }
4618       linkSet.erase( lIt );
4619       lIt = linkSet.begin();
4620
4621       if ( keyPointSet.find( point2 ) == keyPointSet.end() ) // not a key-point
4622       {
4623         boundary->push_back( point2 );
4624       }
4625       else // a key-point found
4626       {
4627         keyPointSet.erase( point2 ); // keyPointSet contains not found key-points only
4628         iKeyPoint++;
4629         if ( point2 != keypoint1 ) // its not the boundary end
4630         {
4631           boundary->push_back( point2 );
4632         }
4633         else  // the boundary end reached
4634         {
4635           boundary->push_front( keypoint1 );
4636           boundary->push_back( keypoint1 );
4637           myNbKeyPntInBoundary.push_back( iKeyPoint );
4638           if ( keyPointSet.empty() )
4639             break; // all boundaries containing key-points are found
4640
4641           // prepare to search for the next boundary
4642           boundaryList.push_back( list< TPoint* >() );
4643           boundary = & boundaryList.back();
4644           point2 = keypoint1 = (*keyPointSet.begin());
4645         }
4646       }
4647       point1 = point2;
4648     } // loop on the free links set
4649
4650     if ( boundary->empty() ) {
4651       MESSAGE(" a separate key-point");
4652       return setErrorCode( ERR_READ_BAD_KEY_POINT );
4653     }
4654
4655     // if there are several wires, arrange boundaryPoints so that
4656     // the outer wire goes first and fix inner wires orientation;
4657     // sort myKeyPointIDs to correspond to the order of key-points
4658     // in boundaries
4659     arrangeBoundaries( boundaryList );
4660
4661     // Find correspondence shape ID - points,
4662     // compute points parameter on edge
4663
4664     keyPointSet.clear();
4665     for ( kpIt = myKeyPointIDs.begin(); kpIt != myKeyPointIDs.end(); kpIt++ )
4666       keyPointSet.insert( & myPoints[ *kpIt ]);
4667
4668     set< TPoint* > edgePointSet; // to find in-face points
4669     int vertexID = 1; // the first index in TopTools_IndexedMapOfShape
4670     int edgeID = myKeyPointIDs.size() + 1;
4671
4672     list< list< TPoint* > >::iterator bndIt = boundaryList.begin();
4673     for ( ; bndIt != boundaryList.end(); bndIt++ )
4674     {
4675       boundary = & (*bndIt);
4676       double edgeLength = 0;
4677       list< TPoint* >::iterator pIt = boundary->begin();
4678       getShapePoints( edgeID ).push_back( *pIt );
4679       getShapePoints( vertexID++ ).push_back( *pIt );
4680       for ( pIt++; pIt != boundary->end(); pIt++)
4681       {
4682         list< TPoint* > & edgePoints = getShapePoints( edgeID );
4683         TPoint* prevP = edgePoints.empty() ? 0 : edgePoints.back();
4684         TPoint* point = *pIt;
4685         edgePointSet.insert( point );
4686         if ( keyPointSet.find( point ) == keyPointSet.end() ) // inside-edge point
4687         {
4688           edgePoints.push_back( point );
4689           edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
4690           point->myInitU = edgeLength;
4691         }
4692         else // a key-point
4693         {
4694           // treat points on the edge which ends up: compute U [0,1]
4695           edgePoints.push_back( point );
4696           if ( edgePoints.size() > 2 ) {
4697             edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
4698             list< TPoint* >::iterator epIt = edgePoints.begin();
4699             for ( ; epIt != edgePoints.end(); epIt++ )
4700               (*epIt)->myInitU /= edgeLength;
4701           }
4702           // begin the next edge treatment
4703           edgeLength = 0;
4704           edgeID++;
4705           if ( point != boundary->front() ) { // not the first key-point again
4706             getShapePoints( edgeID ).push_back( point );
4707             getShapePoints( vertexID++ ).push_back( point );
4708           }
4709         }
4710       }
4711     }
4712
4713     // find in-face points
4714     list< TPoint* > & facePoints = getShapePoints( edgeID );
4715     vector< TPoint >::iterator pVecIt = myPoints.begin();
4716     for ( ; pVecIt != myPoints.end(); pVecIt++ ) {
4717       TPoint* point = &(*pVecIt);
4718       if ( edgePointSet.find( point ) == edgePointSet.end() &&
4719           pointsInElems.find( point ) != pointsInElems.end())
4720         facePoints.push_back( point );
4721     }
4722
4723   } // 2D case
4724
4725   else // 3D case
4726   {
4727     // bind points to shapes according to point parameters
4728     vector< TPoint >::iterator pVecIt = myPoints.begin();
4729     for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
4730       TPoint* point = &(*pVecIt);
4731       int shapeID = SMESH_Block::GetShapeIDByParams( point->myInitXYZ );
4732       getShapePoints( shapeID ).push_back( point );
4733       // detect key-points
4734       if ( SMESH_Block::IsVertexID( shapeID ))
4735         myKeyPointIDs.push_back( i );
4736     }
4737   }
4738
4739   myIsBoundaryPointsFound = true;
4740   return myIsBoundaryPointsFound;
4741 }
4742
4743 //=======================================================================
4744 //function : Clear
4745 //purpose  : clear fields
4746 //=======================================================================
4747
4748 void SMESH_Pattern::Clear()
4749 {
4750   myIsComputed = myIsBoundaryPointsFound = false;
4751
4752   myPoints.clear();
4753   myKeyPointIDs.clear();
4754   myElemPointIDs.clear();
4755   myShapeIDToPointsMap.clear();
4756   myShapeIDMap.Clear();
4757   myShape.Nullify();
4758   myNbKeyPntInBoundary.clear();
4759
4760   myXYZ.clear();
4761   myElemXYZIDs.clear();
4762   myXYZIdToNodeMap.clear();
4763   myElements.clear();
4764   myOrderedNodes.clear();
4765   myPolyElems.clear();
4766   myPolyElemXYZIDs.clear();
4767   myPolyhedronQuantities.clear();
4768   myIdsOnBoundary.clear();
4769   myReverseConnectivity.clear();
4770 }
4771
4772 //================================================================================
4773 /*!
4774  * \brief set ErrorCode and return true if it is Ok
4775  */
4776 //================================================================================
4777
4778 bool SMESH_Pattern::setErrorCode( const ErrorCode theErrorCode )
4779 {
4780   myErrorCode = theErrorCode;
4781   return myErrorCode == ERR_OK;
4782 }
4783
4784 //=======================================================================
4785 //function : setShapeToMesh
4786 //purpose  : set a shape to be meshed. Return True if meshing is possible
4787 //=======================================================================
4788
4789 bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape)
4790 {
4791   if ( !IsLoaded() ) {
4792     MESSAGE( "Pattern not loaded" );
4793     return setErrorCode( ERR_APPL_NOT_LOADED );
4794   }
4795
4796   TopAbs_ShapeEnum aType = theShape.ShapeType();
4797   bool dimOk = ( myIs2D ? aType == TopAbs_FACE : aType == TopAbs_SHELL );
4798   if ( !dimOk ) {
4799     MESSAGE( "Pattern dimension mismatch" );
4800     return setErrorCode( ERR_APPL_BAD_DIMENTION );
4801   }
4802
4803   // check if a face is closed
4804   int nbNodeOnSeamEdge = 0;
4805   if ( myIs2D ) {
4806     TopTools_MapOfShape seamVertices;
4807     TopoDS_Face face = TopoDS::Face( theShape );
4808     TopExp_Explorer eExp( theShape, TopAbs_EDGE );
4809     for ( ; eExp.More() /*&& nbNodeOnSeamEdge == 0*/; eExp.Next() ) {
4810       const TopoDS_Edge& ee = TopoDS::Edge(eExp.Current());
4811       if ( BRep_Tool::IsClosed(ee, face) ) {
4812         // seam edge and vertices encounter twice in theFace
4813         if ( !seamVertices.Add( TopExp::FirstVertex( ee ))) nbNodeOnSeamEdge++;
4814         if ( !seamVertices.Add( TopExp::LastVertex( ee ))) nbNodeOnSeamEdge++;
4815       }
4816     }
4817   }
4818
4819   // check nb of vertices
4820   TopTools_IndexedMapOfShape vMap;
4821   TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
4822   if ( vMap.Extent() + nbNodeOnSeamEdge != (int)myKeyPointIDs.size() ) {
4823     MESSAGE( myKeyPointIDs.size() + nbNodeOnSeamEdge << " != " << vMap.Extent() );
4824     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
4825   }
4826
4827   myElements.clear(); // not refine elements
4828   myElemXYZIDs.clear();
4829
4830   myShapeIDMap.Clear();
4831   myShape = theShape;
4832   return true;
4833 }
4834
4835 //=======================================================================
4836 //function : GetMappedPoints
4837 //purpose  : Return nodes coordinates computed by Apply() method
4838 //=======================================================================
4839
4840 bool SMESH_Pattern::GetMappedPoints ( list< const gp_XYZ * > & thePoints ) const
4841 {
4842   thePoints.clear();
4843   if ( !myIsComputed )
4844     return false;
4845
4846   if ( myElements.empty() ) { // applied to shape
4847     vector< TPoint >::const_iterator pVecIt = myPoints.begin();
4848     for ( ; pVecIt != myPoints.end(); pVecIt++ )
4849       thePoints.push_back( & (*pVecIt).myXYZ.XYZ() );
4850   }
4851   else { // applied to mesh elements
4852     const gp_XYZ * definedXYZ = & myPoints[ myKeyPointIDs.front() ].myXYZ.XYZ();
4853     vector<gp_XYZ>::const_iterator xyz = myXYZ.begin();
4854     for ( ; xyz != myXYZ.end(); ++xyz )
4855       if ( !isDefined( *xyz ))
4856         thePoints.push_back( definedXYZ );
4857       else
4858         thePoints.push_back( & (*xyz) );
4859   }
4860   return !thePoints.empty();
4861 }
4862
4863
4864 //=======================================================================
4865 //function : GetPoints
4866 //purpose  : Return nodes coordinates of the pattern
4867 //=======================================================================
4868
4869 bool SMESH_Pattern::GetPoints ( list< const gp_XYZ * > & thePoints ) const
4870 {
4871   thePoints.clear();
4872
4873   if ( !IsLoaded() )
4874     return false;
4875
4876   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
4877   for ( ; pVecIt != myPoints.end(); pVecIt++ )
4878     thePoints.push_back( & (*pVecIt).myInitXYZ );
4879
4880   return ( thePoints.size() > 0 );
4881 }
4882
4883 //=======================================================================
4884 //function : getShapePoints
4885 //purpose  : return list of points located on theShape
4886 //=======================================================================
4887
4888 list< SMESH_Pattern::TPoint* > &
4889   SMESH_Pattern::getShapePoints(const TopoDS_Shape& theShape)
4890 {
4891   int aShapeID;
4892   if ( !myShapeIDMap.Contains( theShape ))
4893     aShapeID = myShapeIDMap.Add( theShape );
4894   else
4895     aShapeID = myShapeIDMap.FindIndex( theShape );
4896
4897   return myShapeIDToPointsMap[ aShapeID ];
4898 }
4899
4900 //=======================================================================
4901 //function : getShapePoints
4902 //purpose  : return list of points located on the shape
4903 //=======================================================================
4904
4905 list< SMESH_Pattern::TPoint* > & SMESH_Pattern::getShapePoints(const int theShapeID)
4906 {
4907   return myShapeIDToPointsMap[ theShapeID ];
4908 }
4909
4910 //=======================================================================
4911 //function : DumpPoints
4912 //purpose  : Debug
4913 //=======================================================================
4914
4915 void SMESH_Pattern::DumpPoints() const
4916 {
4917 #ifdef _DEBUG_
4918   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
4919   for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ )
4920     MESSAGE_ADD ( std::endl << i << ": " << *pVecIt );
4921 #endif
4922 }
4923
4924 //=======================================================================
4925 //function : TPoint()
4926 //purpose  : 
4927 //=======================================================================
4928
4929 SMESH_Pattern::TPoint::TPoint()
4930 {
4931 #ifdef _DEBUG_
4932   myInitXYZ.SetCoord(0,0,0);
4933   myInitUV.SetCoord(0.,0.);
4934   myInitU = 0;
4935   myXYZ.SetCoord(0,0,0);
4936   myUV.SetCoord(0.,0.);
4937   myU = 0;
4938 #endif
4939 }
4940
4941 //=======================================================================
4942 //function : operator <<
4943 //purpose  : 
4944 //=======================================================================
4945
4946 ostream & operator <<(ostream & OS, const SMESH_Pattern::TPoint& p)
4947 {
4948   gp_XYZ xyz = p.myInitXYZ;
4949   OS << "\tinit( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
4950   gp_XY xy = p.myInitUV;
4951   OS << " uv( " <<  xy.X() << " " << xy.Y() << " )";
4952   double u = p.myInitU;
4953   OS << " u( " <<  u << " )) " << &p << endl;
4954   xyz = p.myXYZ.XYZ();
4955   OS << "\t    ( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
4956   xy = p.myUV;
4957   OS << " uv( " <<  xy.X() << " " << xy.Y() << " )";
4958   u = p.myU;
4959   OS << " u( " <<  u << " ))" << endl;
4960
4961   return OS;
4962 }