Salome HOME
Merge with OCC_development_01
[modules/smesh.git] / src / SMESH / SMESH_Pattern.cxx
1 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
3 // 
4 //  This library is free software; you can redistribute it and/or 
5 //  modify it under the terms of the GNU Lesser General Public 
6 //  License as published by the Free Software Foundation; either 
7 //  version 2.1 of the License. 
8 // 
9 //  This library is distributed in the hope that it will be useful, 
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 //  Lesser General Public License for more details. 
13 // 
14 //  You should have received a copy of the GNU Lesser General Public 
15 //  License along with this library; if not, write to the Free Software 
16 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
17 // 
18 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
19
20 // File      : SMESH_Pattern.hxx
21 // Created   : Mon Aug  2 10:30:00 2004
22 // Author    : Edward AGAPOV (eap)
23
24 #include "SMESH_Pattern.hxx"
25
26 #include <BRepTools.hxx>
27 #include <BRepTools_WireExplorer.hxx>
28 #include <BRep_Tool.hxx>
29 #include <Bnd_Box.hxx>
30 #include <Bnd_Box2d.hxx>
31 #include <ElSLib.hxx>
32 #include <Extrema_GenExtPS.hxx>
33 #include <Extrema_POnSurf.hxx>
34 #include <Geom2d_Curve.hxx>
35 #include <GeomAdaptor_Surface.hxx>
36 #include <Geom_Curve.hxx>
37 #include <Geom_Surface.hxx>
38 #include <IntAna2d_AnaIntersection.hxx>
39 #include <TopAbs_ShapeEnum.hxx>
40 #include <TopExp.hxx>
41 #include <TopLoc_Location.hxx>
42 #include <TopoDS.hxx>
43 #include <TopoDS_Edge.hxx>
44 #include <TopoDS_Face.hxx>
45 #include <TopoDS_Iterator.hxx>
46 #include <TopoDS_Shell.hxx>
47 #include <TopoDS_Vertex.hxx>
48 #include <TopoDS_Wire.hxx>
49 #include <gp_Ax2.hxx>
50 #include <gp_Lin2d.hxx>
51 #include <gp_Pnt2d.hxx>
52 #include <gp_Trsf.hxx>
53 #include <gp_XY.hxx>
54 #include <gp_XYZ.hxx>
55
56 #include "SMDS_EdgePosition.hxx"
57 #include "SMDS_FacePosition.hxx"
58 #include "SMDS_MeshElement.hxx"
59 #include "SMDS_MeshFace.hxx"
60 #include "SMDS_MeshNode.hxx"
61 #include "SMESHDS_Group.hxx"
62 #include "SMESHDS_Mesh.hxx"
63 #include "SMESHDS_SubMesh.hxx"
64 #include "SMESH_Block.hxx"
65 #include "SMESH_Mesh.hxx"
66 #include "SMESH_MeshEditor.hxx"
67 #include "SMESH_subMesh.hxx"
68
69 #include "utilities.h"
70
71 using namespace std;
72
73 typedef map< const SMDS_MeshElement*, int > TNodePointIDMap;
74
75 //=======================================================================
76 //function : SMESH_Pattern
77 //purpose  : 
78 //=======================================================================
79
80 SMESH_Pattern::SMESH_Pattern ()
81 {
82 }
83 //=======================================================================
84 //function : getInt
85 //purpose  : 
86 //=======================================================================
87
88 static inline int getInt( const char * theSring )
89 {
90   if ( *theSring < '0' || *theSring > '9' )
91     return -1;
92
93   char *ptr;
94   int val = strtol( theSring, &ptr, 10 );
95   if ( ptr == theSring ||
96       // there must not be neither '.' nor ',' nor 'E' ...
97       (*ptr != ' ' && *ptr != '\n' && *ptr != '\0'))
98     return -1;
99
100   return val;
101 }
102
103 //=======================================================================
104 //function : getDouble
105 //purpose  : 
106 //=======================================================================
107
108 static inline double getDouble( const char * theSring )
109 {
110   char *ptr;
111   return strtod( theSring, &ptr );
112 }
113
114 //=======================================================================
115 //function : readLine
116 //purpose  : Put token starting positions in theFields until '\n' or '\0'
117 //           Return the number of the found tokens
118 //=======================================================================
119
120 static int readLine (list <const char*> & theFields,
121                      const char*        & theLineBeg,
122                      const bool           theClearFields )
123 {
124   if ( theClearFields )
125     theFields.clear();
126
127   //  algo:
128   /*  loop                                                       */
129   /*    switch ( symbol ) {                                      */
130   /*    case white-space:                                        */
131   /*      look for a non-space symbol;                           */
132   /*    case string-end:                                         */
133   /*    case line-end:                                           */
134   /*      exit;                                                  */
135   /*    case comment beginning:                                  */
136   /*      skip all till a line-end;                              */
137   /*    case a number                                            */
138   /*      put its position in theFields, skip till a white-space;*/
139   /*    default:                                                 */
140   /*      abort;                                                 */
141   /*  till line-end                                              */
142
143   int nbRead = 0;
144   bool stopReading = false;
145   do {
146     bool goOn = true;
147     bool isNumber = false;
148     switch ( *theLineBeg )
149     {
150     case ' ':  // white space
151     case '\t': // tab
152     case 13:   // ^M
153       break;
154
155     case '\n': // a line ends
156       stopReading = ( nbRead > 0 );
157       break;
158
159     case '!':  // comment
160       do theLineBeg++;
161       while ( *theLineBeg != '\n' && *theLineBeg != '\0' );
162       goOn = false;
163       break;
164
165     case '\0': // file ends
166       return nbRead;
167
168     case '-': // real number
169     case '+':
170     case '.':
171       isNumber = true;
172     default: // data
173       isNumber = isNumber || ( *theLineBeg >= '0' && *theLineBeg <= '9' );
174       if ( isNumber ) {
175         theFields.push_back( theLineBeg );
176         nbRead++;
177         do theLineBeg++;
178         while (*theLineBeg != ' ' &&
179                *theLineBeg != '\n' &&
180                *theLineBeg != '\0');
181         goOn = false;
182       }
183       else
184         return 0; // incorrect file format
185     }
186
187     if ( goOn )
188       theLineBeg++;
189
190   } while ( !stopReading );
191
192   return nbRead;
193 }
194
195 //=======================================================================
196 //function : Load
197 //purpose  : Load a pattern from <theFile>
198 //=======================================================================
199
200 bool SMESH_Pattern::Load (const char* theFileContents)
201 {
202   MESSAGE("Load( file ) ");
203
204   // file structure:
205
206   // ! This is a comment
207   // NB_POINTS               ! 1 integer - the number of points in the pattern.
208   //   X1 Y1 [Z1]            ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
209   //   X2 Y2 [Z2]            ! the pattern dimention is defined by the number of coordinates
210   //   ...
211   // [ ID1 ID2 ... IDn ]     ! Indices of key-points for a 2D pattern (only).
212   // ! elements description goes after all
213   // ID1 ID2 ... IDn         ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
214   // ...
215
216   Clear();
217
218   const char* lineBeg = theFileContents;
219   list <const char*> fields;
220   const bool clearFields = true;
221
222   // NB_POINTS               ! 1 integer - the number of points in the pattern.
223
224   if ( readLine( fields, lineBeg, clearFields ) != 1 ) {
225     MESSAGE("Error reading NB_POINTS");
226     return setErrorCode( ERR_READ_NB_POINTS );
227   }
228   int nbPoints = getInt( fields.front() );
229
230   //   X1 Y1 [Z1]            ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
231
232   // read the first point coordinates to define pattern dimention
233   int dim = readLine( fields, lineBeg, clearFields );
234   if ( dim == 2 )
235     myIs2D = true;
236   else if ( dim == 3 )
237     myIs2D = false;
238   else {
239     MESSAGE("Error reading points: wrong nb of coordinates");
240     return setErrorCode( ERR_READ_POINT_COORDS );
241   }
242   if ( nbPoints <= dim ) {
243     MESSAGE(" Too few points ");
244     return setErrorCode( ERR_READ_TOO_FEW_POINTS );
245   }
246     
247   // read the rest points
248   int iPoint;
249   for ( iPoint = 1; iPoint < nbPoints; iPoint++ )
250     if ( readLine( fields, lineBeg, !clearFields ) != dim ) {
251       MESSAGE("Error reading  points : wrong nb of coordinates ");
252       return setErrorCode( ERR_READ_POINT_COORDS );
253     }
254   // store point coordinates
255   myPoints.resize( nbPoints );
256   list <const char*>::iterator fIt = fields.begin();
257   for ( iPoint = 0; iPoint < nbPoints; iPoint++ )
258   {
259     TPoint & p = myPoints[ iPoint ];
260     for ( int iCoord = 1; iCoord <= dim; iCoord++, fIt++ )
261     {
262       double coord = getDouble( *fIt );
263       if ( !myIs2D && ( coord < 0.0 || coord > 1.0 )) {
264         MESSAGE("Error reading 3D points, value should be in [0,1]: " << coord);
265         Clear();
266         return setErrorCode( ERR_READ_3D_COORD );
267       }
268       p.myInitXYZ.SetCoord( iCoord, coord );
269       if ( myIs2D )
270         p.myInitUV.SetCoord( iCoord, coord );
271     }
272   }
273
274   // [ ID1 ID2 ... IDn ]     ! Indices of key-points for a 2D pattern (only).
275   if ( myIs2D )
276   {
277     if ( readLine( fields, lineBeg, clearFields ) == 0 ) {
278       MESSAGE("Error: missing key-points");
279       Clear();
280       return setErrorCode( ERR_READ_NO_KEYPOINT );
281     }
282     set<int> idSet;
283     for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
284     {
285       int pointIndex = getInt( *fIt );
286       if ( pointIndex >= nbPoints || pointIndex < 0 ) {
287         MESSAGE("Error: invalid point index " << pointIndex );
288         Clear();
289         return setErrorCode( ERR_READ_BAD_INDEX );
290       }
291       if ( idSet.insert( pointIndex ).second ) // unique?
292         myKeyPointIDs.push_back( pointIndex );
293     }
294   }
295
296   // ID1 ID2 ... IDn         ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
297
298   while ( readLine( fields, lineBeg, clearFields ))
299   {
300     myElemPointIDs.push_back( list< int >() );
301     list< int >& elemPoints = myElemPointIDs.back();
302     for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
303     {
304       int pointIndex = getInt( *fIt );
305       if ( pointIndex >= nbPoints || pointIndex < 0 ) {
306         MESSAGE("Error: invalid point index " << pointIndex );
307         Clear();
308         return setErrorCode( ERR_READ_BAD_INDEX );
309       }
310       elemPoints.push_back( pointIndex );
311     }
312     // check the nb of nodes in element
313     bool Ok = true;
314     switch ( elemPoints.size() ) {
315     case 3: if ( !myIs2D ) Ok = false; break;
316     case 4: break;
317     case 5:
318     case 6:
319     case 8: if ( myIs2D ) Ok = false; break;
320     default: Ok = false;
321     }
322     if ( !Ok ) {
323       MESSAGE("Error: wrong nb of nodes in element " << elemPoints.size() );
324       Clear();
325       return setErrorCode( ERR_READ_ELEM_POINTS );
326     }
327   }
328   if ( myElemPointIDs.empty() ) {
329     MESSAGE("Error: no elements");
330     Clear();
331     return setErrorCode( ERR_READ_NO_ELEMS );
332   }
333
334   findBoundaryPoints(); // sort key-points
335
336   return setErrorCode( ERR_OK );
337 }
338
339 //=======================================================================
340 //function : Save
341 //purpose  : Save the loaded pattern into the file <theFileName>
342 //=======================================================================
343
344 bool SMESH_Pattern::Save (ostream& theFile)
345 {
346   MESSAGE(" ::Save(file) " );
347   if ( !IsLoaded() ) {
348     MESSAGE(" Pattern not loaded ");
349     return setErrorCode( ERR_SAVE_NOT_LOADED );
350   }
351
352   theFile << "!!! SALOME Mesh Pattern file" << endl;
353   theFile << "!!!" << endl;
354   theFile << "!!! Nb of points:" << endl;
355   theFile << myPoints.size() << endl;
356
357   // point coordinates
358   const int width = 8;
359 //  theFile.width( 8 );
360 //  theFile.setf(ios::fixed);// use 123.45 floating notation
361 //  theFile.setf(ios::right);
362 //  theFile.flags( theFile.flags() & ~ios::showpoint); // do not show trailing zeros
363 //   theFile.setf(ios::showpoint); // do not show trailing zeros
364   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
365   for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
366     const gp_XYZ & xyz = (*pVecIt).myInitXYZ;
367     theFile << " " << setw( width ) << xyz.X() << " " << setw( width ) << xyz.Y();
368     if ( !myIs2D ) theFile  << " " << setw( width ) << xyz.Z();
369     theFile  << "  !- " << i << endl; // point id to ease reading by a human being
370   }
371   // key-points
372   if ( myIs2D ) {
373     theFile << "!!! Indices of " << myKeyPointIDs.size() << " key-points:" << endl;
374     list< int >::const_iterator kpIt = myKeyPointIDs.begin();
375     for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
376       theFile << " " << *kpIt;
377     if ( !myKeyPointIDs.empty() )
378       theFile << endl;
379   }
380   // elements
381   theFile << "!!! Indices of points of " << myElemPointIDs.size() << " elements:" << endl;
382   list<list< int > >::const_iterator epIt = myElemPointIDs.begin();
383   for ( ; epIt != myElemPointIDs.end(); epIt++ )
384   {
385     const list< int > & elemPoints = *epIt;
386     list< int >::const_iterator iIt = elemPoints.begin();
387     for ( ; iIt != elemPoints.end(); iIt++ )
388       theFile << " " << *iIt;
389     theFile << endl;
390   }
391
392   theFile << endl;
393   
394   return setErrorCode( ERR_OK );
395 }
396
397 //=======================================================================
398 //function : sortBySize
399 //purpose  : sort theListOfList by size
400 //=======================================================================
401
402 template<typename T> struct TSizeCmp {
403   bool operator ()( const list < T > & l1, const list < T > & l2 )
404     const { return l1.size() < l2.size(); }
405 };
406
407 template<typename T> void sortBySize( list< list < T > > & theListOfList )
408 {
409   if ( theListOfList.size() > 2 ) {
410     TSizeCmp< T > SizeCmp;
411     theListOfList.sort( SizeCmp );
412   }
413 }
414
415 //=======================================================================
416 //function : getOrderedEdges
417 //purpose  : return nb wires and a list of oredered edges
418 //=======================================================================
419
420 static int getOrderedEdges (const TopoDS_Face&   theFace,
421                             const TopoDS_Vertex& theFirstVertex,
422                             list< TopoDS_Edge >& theEdges,
423                             list< int >  &       theNbVertexInWires)
424 {
425   // put wires in a list, so that an outer wire comes first
426   list<TopoDS_Wire> aWireList;
427   TopoDS_Wire anOuterWire = BRepTools::OuterWire( theFace );
428   aWireList.push_back( anOuterWire );
429   for ( TopoDS_Iterator wIt (theFace); wIt.More(); wIt.Next() )
430     if ( !anOuterWire.IsSame( wIt.Value() ))
431       aWireList.push_back( TopoDS::Wire( wIt.Value() ));
432
433   // loop on edges of wires
434   theNbVertexInWires.clear();
435   list<TopoDS_Wire>::iterator wlIt = aWireList.begin();
436   for ( ; wlIt != aWireList.end(); wlIt++ )
437   {
438     int iE;
439     BRepTools_WireExplorer wExp( *wlIt, theFace );
440     for ( iE = 0; wExp.More(); wExp.Next(), iE++ )
441     {
442       TopoDS_Edge edge = wExp.Current();
443       edge = TopoDS::Edge( edge.Oriented( wExp.Orientation() ));
444       theEdges.push_back( edge );
445     }
446     theNbVertexInWires.push_back( iE );
447     iE = 0;
448     if ( wlIt == aWireList.begin() && theEdges.size() > 1 ) { // the outer wire
449       // orient closed edges
450       list< TopoDS_Edge >::iterator eIt, eIt2;
451       for ( eIt = theEdges.begin(); eIt != theEdges.end(); eIt++ )
452       {
453         TopoDS_Edge& edge = *eIt;
454         if ( TopExp::FirstVertex( edge ).IsSame( TopExp::LastVertex( edge ) ))
455         {
456           eIt2 = eIt;
457           bool isNext = ( eIt2 == theEdges.begin() );
458           TopoDS_Edge edge2 = isNext ? *(++eIt2) : *(--eIt2);
459           double f1,l1,f2,l2;
460           Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( edge, theFace, f1,l1 );
461           Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( edge2, theFace, f2,l2 );
462           gp_Pnt2d pf = c1->Value( edge.Orientation() == TopAbs_FORWARD ? f1 : l1 );
463           gp_Pnt2d pl = c1->Value( edge.Orientation() == TopAbs_FORWARD ? l1 : f1 );
464           bool isFirst = ( edge2.Orientation() == TopAbs_FORWARD ? isNext : !isNext );
465           gp_Pnt2d p2 = c2->Value( isFirst ? f2 : l2 );
466           isFirst = ( p2.SquareDistance( pf ) < p2.SquareDistance( pl ));
467           if ( isNext ? isFirst : !isFirst )
468             edge.Reverse();
469         }
470       }
471       // rotate theEdges until it begins from theFirstVertex
472       if ( ! theFirstVertex.IsNull() )
473         while ( !theFirstVertex.IsSame( TopExp::FirstVertex( theEdges.front(), true )))
474         {
475           theEdges.splice(theEdges.end(), theEdges,
476                           theEdges.begin(), ++ theEdges.begin());
477           if ( iE++ > theNbVertexInWires.back() ) 
478             break; // break infinite loop
479         }
480     }
481   }
482
483   return aWireList.size();
484 }
485
486 //=======================================================================
487 //function : project
488 //purpose  : 
489 //=======================================================================
490
491 static gp_XY project (const SMDS_MeshNode* theNode,
492                       Extrema_GenExtPS &   theProjectorPS)
493 {
494   gp_Pnt P( theNode->X(), theNode->Y(), theNode->Z() );
495   theProjectorPS.Perform( P );
496   if ( !theProjectorPS.IsDone() ) {
497     MESSAGE( "SMESH_Pattern: point projection FAILED");
498     return gp_XY(0.,0.);
499   }
500   double u, v, minVal = DBL_MAX;
501   for ( int i = theProjectorPS.NbExt(); i > 0; i-- )
502     if ( theProjectorPS.Value( i ) < minVal ) {
503       minVal = theProjectorPS.Value( i );
504       theProjectorPS.Point( i ).Parameter( u, v );
505     }
506   return gp_XY( u, v );
507 }
508
509 //=======================================================================
510 //function : isMeshBoundToShape
511 //purpose  : return true if all 2d elements are bound to shape
512 //=======================================================================
513
514 static bool isMeshBoundToShape(SMESH_Mesh* theMesh)
515 {
516   // check faces binding
517   SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
518   SMESHDS_SubMesh * aMainSubMesh = aMeshDS->MeshElements( aMeshDS->ShapeToMesh() );
519   if ( aMeshDS->NbFaces() != aMainSubMesh->NbElements() )
520     return false;
521
522   // check face nodes binding
523   SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
524   while ( fIt->more() )
525   {
526     SMDS_ElemIteratorPtr nIt = fIt->next()->nodesIterator();
527     while ( nIt->more() )
528     {
529       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
530       SMDS_PositionPtr pos = node->GetPosition();
531       if ( !pos || !pos->GetShapeId() )
532         return false;
533     }
534   }
535   return true;
536 }
537
538 //=======================================================================
539 //function : Load
540 //purpose  : Create a pattern from the mesh built on <theFace>.
541 //           <theProject>==true makes override nodes positions
542 //           on <theFace> computed by mesher
543 //=======================================================================
544
545 bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
546                           const TopoDS_Face& theFace,
547                           bool               theProject)
548 {
549   MESSAGE(" ::Load(face) " );
550   Clear();
551   myIs2D = true;
552
553   SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
554   SMESHDS_SubMesh * fSubMesh = aMeshDS->MeshElements( theFace );
555
556   int nbNodes = ( !fSubMesh ? 0 : fSubMesh->NbNodes() );
557   int nbElems = ( !fSubMesh ? 0 : fSubMesh->NbElements() );
558   if ( nbElems == 0 && aMeshDS->NbFaces() == 0 )
559   {
560     MESSAGE( "No elements bound to the face");
561     return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
562   }
563
564   // check that face is not closed
565   TopoDS_Vertex bidon;
566   list<TopoDS_Edge> eList;
567   getOrderedEdges( theFace, bidon, eList, myNbKeyPntInBoundary );
568   list<TopoDS_Edge>::iterator elIt = eList.begin();
569   for ( ; elIt != eList.end() ; elIt++ )
570     if ( BRep_Tool::IsClosed( *elIt , theFace ))
571       return setErrorCode( ERR_LOADF_CLOSED_FACE );
572   
573
574   Extrema_GenExtPS projector;
575   GeomAdaptor_Surface aSurface( BRep_Tool::Surface( theFace ));
576   if ( theProject || nbElems == 0 )
577     projector.Initialize( aSurface, 20,20, 1e-5,1e-5 );
578
579   int iPoint = 0;
580   TNodePointIDMap nodePointIDMap;
581
582   if ( nbElems == 0 || (theProject &&
583                         theMesh->IsMainShape( theFace ) &&
584                         !isMeshBoundToShape( theMesh )))
585   {
586     MESSAGE("Project the whole mesh");
587     // ---------------------------------------------------------------
588     // The case where the whole mesh is projected to theFace
589     // ---------------------------------------------------------------
590
591     // put nodes of all faces in the nodePointIDMap and fill myElemPointIDs
592     SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
593     while ( fIt->more() )
594     {
595       myElemPointIDs.push_back( list< int >() );
596       list< int >& elemPoints = myElemPointIDs.back();
597       SMDS_ElemIteratorPtr nIt = fIt->next()->nodesIterator();
598       while ( nIt->more() )
599       {
600         const SMDS_MeshElement* node = nIt->next();
601         TNodePointIDMap::iterator nIdIt = nodePointIDMap.find( node );
602         if ( nIdIt == nodePointIDMap.end() )
603         {
604           elemPoints.push_back( iPoint );
605           nodePointIDMap.insert( make_pair( node, iPoint++ ));
606         }
607         else
608           elemPoints.push_back( (*nIdIt).second );
609       }
610     }
611     myPoints.resize( iPoint );
612
613     // project all nodes of 2d elements to theFace
614     TNodePointIDMap::iterator nIdIt = nodePointIDMap.begin();
615     for ( ; nIdIt != nodePointIDMap.end(); nIdIt++ )
616     {
617       const SMDS_MeshNode* node = 
618         static_cast<const SMDS_MeshNode*>( (*nIdIt).first );
619       TPoint * p = & myPoints[ (*nIdIt).second ];
620       p->myInitUV = project( node, projector );
621       p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
622     }
623     // find key-points: the points most close to UV of vertices
624     TopExp_Explorer vExp( theFace, TopAbs_VERTEX );
625     set<int> foundIndices;
626     for ( ; vExp.More(); vExp.Next() ) {
627       const TopoDS_Vertex v = TopoDS::Vertex( vExp.Current() );
628       gp_Pnt2d uv = BRep_Tool::Parameters( v, theFace );
629       double minDist = DBL_MAX;
630       int index;
631       vector< TPoint >::const_iterator pVecIt = myPoints.begin();
632       for ( iPoint = 0; pVecIt != myPoints.end(); pVecIt++, iPoint++ ) {
633         double dist = uv.SquareDistance( (*pVecIt).myInitUV );
634         if ( dist < minDist ) {
635           minDist = dist;
636           index = iPoint;
637         }
638       }
639       if ( foundIndices.insert( index ).second ) // unique?
640         myKeyPointIDs.push_back( index );
641     }
642     myIsBoundaryPointsFound = false;
643
644   }
645   else
646   {
647     // ---------------------------------------------------------------------
648     // The case where a pattern is being made from the mesh built by mesher
649     // ---------------------------------------------------------------------
650
651     // Load shapes in the consequent order and count nb of points
652
653     // vertices
654     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) {
655       myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
656       SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt );
657       if ( eSubMesh )
658         nbNodes += eSubMesh->NbNodes() + 1;
659     }
660     // edges
661     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
662       myShapeIDMap.Add( *elIt );
663     // the face
664     myShapeIDMap.Add( theFace );
665
666     myPoints.resize( nbNodes );
667
668     // Load U of points on edges
669
670     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
671     {
672       TopoDS_Edge & edge = *elIt;
673       list< TPoint* > & ePoints = getShapePoints( edge );
674       double f, l;
675       Handle(Geom2d_Curve) C2d;
676       if ( !theProject )
677         C2d = BRep_Tool::CurveOnSurface( edge, theFace, f, l );
678       bool isForward = ( edge.Orientation() == TopAbs_FORWARD );
679
680       // the forward key-point
681       TopoDS_Shape v = TopExp::FirstVertex( edge, true );
682       list< TPoint* > & vPoint = getShapePoints( v );
683       if ( vPoint.empty() )
684       {
685         SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
686         if ( vSubMesh && vSubMesh->NbNodes() ) {
687           myKeyPointIDs.push_back( iPoint );
688           SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
689           const SMDS_MeshNode* node = nIt->next();
690           nodePointIDMap.insert( make_pair( node, iPoint ));
691
692           TPoint* keyPoint = &myPoints[ iPoint++ ];
693           vPoint.push_back( keyPoint );
694           if ( theProject )
695             keyPoint->myInitUV = project( node, projector );
696           else
697             keyPoint->myInitUV = C2d->Value( isForward ? f : l ).XY();
698           keyPoint->myInitXYZ.SetCoord (keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0);
699         }
700       }
701       if ( !vPoint.empty() )
702         ePoints.push_back( vPoint.front() );
703
704       // on-edge points
705       SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edge );
706       if ( eSubMesh && eSubMesh->NbNodes() )
707       {
708         // loop on nodes of an edge: sort them by param on edge
709         typedef map < double, const SMDS_MeshNode* > TParamNodeMap;
710         TParamNodeMap paramNodeMap;
711         SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
712         while ( nIt->more() )
713         {
714           const SMDS_MeshNode* node = 
715             static_cast<const SMDS_MeshNode*>( nIt->next() );
716           const SMDS_EdgePosition* epos =
717             static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
718           double u = epos->GetUParameter();
719           paramNodeMap.insert( TParamNodeMap::value_type( u, node ));
720         }
721         // put U in [0,1] so that the first key-point has U==0
722         double du = l - f;
723         TParamNodeMap::iterator         unIt  = paramNodeMap.begin();
724         TParamNodeMap::reverse_iterator unRIt = paramNodeMap.rbegin();
725         while ( unIt != paramNodeMap.end() )
726         {
727           TPoint* p = & myPoints[ iPoint ];
728           ePoints.push_back( p );
729           const SMDS_MeshNode* node = isForward ? (*unIt).second : (*unRIt).second;
730           nodePointIDMap.insert ( make_pair( node, iPoint ));
731
732           if ( theProject )
733             p->myInitUV = project( node, projector );
734           else {
735             double u = isForward ? (*unIt).first : (*unRIt).first;
736             p->myInitU = isForward ? (( u - f ) / du ) : ( 1.0 - ( u - f ) / du );
737             p->myInitUV = C2d->Value( u ).XY();
738           }
739           p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
740           unIt++; unRIt++;
741           iPoint++;
742         }
743       }
744       // the reverse key-point
745       v = TopExp::LastVertex( edge, true ).Reversed();
746       list< TPoint* > & vPoint2 = getShapePoints( v );
747       if ( vPoint2.empty() )
748       {
749         SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
750         if ( vSubMesh && vSubMesh->NbNodes() ) {
751           myKeyPointIDs.push_back( iPoint );
752           SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
753           const SMDS_MeshNode* node = nIt->next();
754           nodePointIDMap.insert( make_pair( node, iPoint ));
755
756           TPoint* keyPoint = &myPoints[ iPoint++ ];
757           vPoint2.push_back( keyPoint );
758           if ( theProject )
759             keyPoint->myInitUV = project( node, projector );
760           else
761             keyPoint->myInitUV = C2d->Value( isForward ? l : f ).XY();
762           keyPoint->myInitXYZ.SetCoord( keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0 );
763         }
764       }
765       if ( !vPoint2.empty() )
766         ePoints.push_back( vPoint2.front() );
767
768       // compute U of edge-points
769       if ( theProject )
770       {
771         double totalDist = 0;
772         list< TPoint* >::iterator pIt = ePoints.begin();
773         TPoint* prevP = *pIt;
774         prevP->myInitU = totalDist;
775         for ( pIt++; pIt != ePoints.end(); pIt++ ) {
776           TPoint* p = *pIt;
777           totalDist += ( p->myInitUV - prevP->myInitUV ).Modulus();
778           p->myInitU = totalDist;
779           prevP = p;
780         }
781         if ( totalDist > DBL_MIN)
782           for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
783             TPoint* p = *pIt;
784             p->myInitU /= totalDist;
785           }
786       }
787     } // loop on edges of a wire
788
789     // Load in-face points and elements
790
791     if ( fSubMesh && fSubMesh->NbElements() )
792     {
793       list< TPoint* > & fPoints = getShapePoints( theFace );
794       SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes();
795       while ( nIt->more() )
796       {
797         const SMDS_MeshNode* node = 
798           static_cast<const SMDS_MeshNode*>( nIt->next() );
799         nodePointIDMap.insert( make_pair( node, iPoint ));
800         TPoint* p = &myPoints[ iPoint++ ];
801         fPoints.push_back( p );
802         if ( theProject )
803           p->myInitUV = project( node, projector );
804         else {
805           const SMDS_FacePosition* pos =
806             static_cast<const SMDS_FacePosition*>(node->GetPosition().get());
807           p->myInitUV.SetCoord( pos->GetUParameter(), pos->GetVParameter() );
808         }
809         p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
810       }
811       // load elements
812       SMDS_ElemIteratorPtr elemIt = fSubMesh->GetElements();
813       while ( elemIt->more() ) {
814         SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
815         myElemPointIDs.push_back( list< int >() );
816         list< int >& elemPoints = myElemPointIDs.back();
817         while ( nIt->more() )
818           elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
819       }
820     }
821
822     myIsBoundaryPointsFound = true;
823   }
824
825   // Assure that U range is proportional to V range
826
827   Bnd_Box2d bndBox;
828   vector< TPoint >::iterator pVecIt = myPoints.begin();
829   for ( ; pVecIt != myPoints.end(); pVecIt++ )
830     bndBox.Add( gp_Pnt2d( (*pVecIt).myInitUV ));
831   double minU, minV, maxU, maxV;
832   bndBox.Get( minU, minV, maxU, maxV );
833   double dU = maxU - minU, dV = maxV - minV;
834   if ( dU <= DBL_MIN || dV <= DBL_MIN ) {
835     Clear();
836     return setErrorCode( ERR_LOADF_NARROW_FACE );
837   }
838   double ratio = dU / dV, maxratio = 3, scale;
839   int iCoord = 0;
840   if ( ratio > maxratio ) {
841     scale = ratio / maxratio;
842     iCoord = 2;
843   }
844   else if ( ratio < 1./maxratio ) {
845     scale = maxratio / ratio;
846     iCoord = 1;
847   }
848   if ( iCoord ) {
849     SCRUTE( scale );
850     for ( pVecIt = myPoints.begin(); pVecIt != myPoints.end(); pVecIt++ ) {
851       TPoint & p = *pVecIt;
852       p.myInitUV.SetCoord( iCoord, p.myInitUV.Coord( iCoord ) * scale );
853       p.myInitXYZ.SetCoord( p.myInitUV.X(), p.myInitUV.Y(), 0 );
854     }
855   }
856   if ( myElemPointIDs.empty() ) {
857     MESSAGE( "No elements bound to the face");
858     return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
859   }
860
861   return setErrorCode( ERR_OK );
862 }
863
864 //=======================================================================
865 //function : computeUVOnEdge
866 //purpose  : compute coordinates of points on theEdge
867 //=======================================================================
868
869 void SMESH_Pattern::computeUVOnEdge (const TopoDS_Edge&      theEdge,
870                                      const list< TPoint* > & ePoints )
871 {
872   bool isForward = ( theEdge.Orientation() == TopAbs_FORWARD );
873   double f, l;
874   Handle(Geom2d_Curve) C2d =
875     BRep_Tool::CurveOnSurface( theEdge, TopoDS::Face( myShape ), f, l );
876
877   ePoints.back()->myInitU = 1.0;
878   list< TPoint* >::const_iterator pIt = ePoints.begin();
879   for ( pIt++; pIt != ePoints.end(); pIt++ )
880   {
881     TPoint* point = *pIt;
882     // U
883     double du = ( isForward ? point->myInitU : 1 - point->myInitU );
884     point->myU = ( f * ( 1 - du ) + l * du );
885     // UV
886     point->myUV = C2d->Value( point->myU ).XY();
887   }
888 }
889
890 //=======================================================================
891 //function : intersectIsolines
892 //purpose  : 
893 //=======================================================================
894
895 static bool intersectIsolines(const gp_XY& uv11, const gp_XY& uv12, const double r1,
896                               const gp_XY& uv21, const gp_XY& uv22, const double r2,
897                               gp_XY& resUV,
898                               bool& isDeformed)
899 {
900   gp_XY loc1 = uv11 * ( 1 - r1 ) + uv12 * r1;
901   gp_XY loc2 = uv21 * ( 1 - r2 ) + uv22 * r2;
902   resUV = 0.5 * ( loc1 + loc2 );
903   isDeformed = ( loc1 - loc2 ).SquareModulus() > 1e-8;
904 //   double len1 = ( uv11 - uv12 ).Modulus();
905 //   double len2 = ( uv21 - uv22 ).Modulus();
906 //   resUV = loc1 * len2 / ( len1 + len2 ) + loc2 * len1 / ( len1 + len2 );
907 //  return true;
908
909   
910 //   gp_Lin2d line1( uv11, uv12 - uv11 );
911 //   gp_Lin2d line2( uv21, uv22 - uv21 );
912 //   double angle = Abs( line1.Angle( line2 ) );
913
914 //     IntAna2d_AnaIntersection inter;
915 //     inter.Perform( line1.Normal( loc1 ), line2.Normal( loc2 ) );
916 //     if ( inter.IsDone() && inter.NbPoints() == 1 )
917 //     {
918 //       gp_Pnt2d interUV = inter.Point(1).Value();
919 //       resUV += interUV.XY();
920 //   inter.Perform( line1, line2 );
921 //   interUV = inter.Point(1).Value();
922 //   resUV += interUV.XY();
923   
924 //   resUV /= 2.;
925 //     }
926   return true;
927 }
928
929 //=======================================================================
930 //function : compUVByIsoIntersection
931 //purpose  : 
932 //=======================================================================
933
934 bool SMESH_Pattern::compUVByIsoIntersection (const list< list< TPoint* > >& theBndPoints,
935                                              const gp_XY&                   theInitUV,
936                                              gp_XY&                         theUV,
937                                              bool &                         theIsDeformed )
938 {
939   // compute UV by intersection of 2 iso lines
940   //gp_Lin2d isoLine[2];
941   gp_XY uv1[2], uv2[2];
942   double ratio[2];
943   const double zero = DBL_MIN;
944   for ( int iIso = 0; iIso < 2; iIso++ )
945   {
946     // to build an iso line:
947     // find 2 pairs of consequent edge-points such that the range of their
948     // initial parameters encloses the in-face point initial parameter
949     gp_XY UV[2], initUV[2];
950     int nbUV = 0, iCoord = iIso + 1;
951     double initParam = theInitUV.Coord( iCoord );
952
953     list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
954     for ( ; bndIt != theBndPoints.end(); bndIt++ )
955     {
956       const list< TPoint* > & bndPoints = * bndIt;
957       TPoint* prevP = bndPoints.back(); // this is the first point
958       list< TPoint* >::const_iterator pIt = bndPoints.begin();
959       bool coincPrev = false; 
960       // loop on the edge-points
961       for ( ; pIt != bndPoints.end(); pIt++ )
962       {
963         double paramDiff     = initParam - (*pIt)->myInitUV.Coord( iCoord );
964         double prevParamDiff = initParam - prevP->myInitUV.Coord( iCoord );
965         double sumOfDiff = Abs(prevParamDiff) + Abs(paramDiff);
966         if (!coincPrev && // ignore if initParam coincides with prev point param
967             sumOfDiff > zero && // ignore if both points coincide with initParam
968             prevParamDiff * paramDiff <= zero )
969         {
970           // find UV in parametric space of theFace
971           double r = Abs(prevParamDiff) / sumOfDiff;
972           gp_XY uvInit = (*pIt)->myInitUV * r + prevP->myInitUV * ( 1 - r );
973           int i = nbUV++;
974           if ( i >= 2 ) {
975             // throw away uv most distant from <theInitUV>
976             gp_XY vec0 = initUV[0] - theInitUV;
977             gp_XY vec1 = initUV[1] - theInitUV;
978             gp_XY vec  = uvInit    - theInitUV;
979             bool isBetween = ( vec0 * vec1 < 0 ); // is theInitUV between initUV[0] and initUV[1]
980             double dist0 = vec0.SquareModulus();
981             double dist1 = vec1.SquareModulus();
982             double dist  = vec .SquareModulus();
983             if ( !isBetween || dist < dist0 || dist < dist1 ) {
984               i = ( dist0 < dist1 ? 1 : 0 );
985               if ( isBetween && vec.Dot( i ? vec1 : vec0 ) < 0 )
986                 i = 3; // theInitUV must remain between
987             }
988           }
989           if ( i < 2 ) {
990             initUV[ i ] = uvInit;
991             UV[ i ]     = (*pIt)->myUV * r + prevP->myUV * ( 1 - r );
992           }
993           coincPrev = ( Abs(paramDiff) <= zero );
994         }
995         else
996           coincPrev = false;
997         prevP = *pIt;
998       }
999     }
1000     if ( nbUV < 2 || (UV[0]-UV[1]).SquareModulus() <= DBL_MIN*DBL_MIN ) {
1001       MESSAGE(" consequent edge-points not found, nb UV found: " << nbUV <<
1002               ", for point: " << theInitUV.X() <<" " << theInitUV.Y() );
1003       return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1004     }
1005     // an iso line should be normal to UV[0] - UV[1] direction
1006     // and be located at the same relative distance as from initial ends
1007     //gp_Lin2d iso( UV[0], UV[0] - UV[1] );
1008     double r =
1009       (initUV[0]-theInitUV).Modulus() / (initUV[0]-initUV[1]).Modulus();
1010     //gp_Pnt2d isoLoc = UV[0] * ( 1 - r ) + UV[1] * r;
1011     //isoLine[ iIso ] = iso.Normal( isoLoc );
1012     uv1[ iIso ] = UV[0];
1013     uv2[ iIso ] = UV[1];
1014     ratio[ iIso ] = r;
1015   }
1016   if ( !intersectIsolines( uv1[0], uv2[0], ratio[0],
1017                           uv1[1], uv2[1], ratio[1], theUV, theIsDeformed )) {
1018     MESSAGE(" Cant intersect isolines for a point "<<theInitUV.X()<<", "<<theInitUV.Y());
1019     return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1020   }
1021
1022   return true;
1023 }
1024
1025
1026 // ==========================================================
1027 // structure representing a node of a grid of iso-poly-lines
1028 // ==========================================================
1029
1030 struct TIsoNode {
1031   bool   myIsMovable;
1032   gp_XY  myInitUV;
1033   gp_XY  myUV;
1034   double myRatio[2];
1035   gp_Dir2d  myDir[2]; // boundary tangent dir for boundary nodes, iso dir for internal ones
1036   TIsoNode* myNext[4]; // order: (iDir=0,isForward=0), (1,0), (0,1), (1,1)
1037   TIsoNode* myBndNodes[4];     // order: (iDir=0,i=0), (1,0), (0,1), (1,1)
1038   TIsoNode(double initU, double initV):
1039     myInitUV( initU, initV ), myUV( 1e100, 1e100 ), myIsMovable(true)
1040   { myNext[0] = myNext[1] = myNext[2] = myNext[3] = 0; }
1041   bool IsUVComputed() const
1042   { return myUV.X() != 1e100; }
1043   bool IsMovable() const
1044   { return myIsMovable && myNext[0] && myNext[1] && myNext[2] && myNext[3]; }
1045   void SetNotMovable()
1046   { myIsMovable = false; }
1047   void SetBoundaryNode(TIsoNode* node, int iDir, int i)
1048   { myBndNodes[ iDir + i * 2 ] = node; }
1049   TIsoNode* GetBoundaryNode(int iDir, int i)
1050   { return myBndNodes[ iDir + i * 2 ]; }
1051   void SetNext(TIsoNode* node, int iDir, int isForward)
1052   { myNext[ iDir + isForward  * 2 ] = node; }
1053   TIsoNode* GetNext(int iDir, int isForward)
1054   { return myNext[ iDir + isForward * 2 ]; }
1055 };
1056
1057 //=======================================================================
1058 //function : getNextNode
1059 //purpose  : 
1060 //=======================================================================
1061
1062 static inline TIsoNode* getNextNode(const TIsoNode* node, int dir )
1063 {
1064   TIsoNode* n = node->myNext[ dir ];
1065   if ( n && !n->IsUVComputed()/* && node->IsMovable()*/ ) {
1066     n = 0;//node->myBndNodes[ dir ];
1067 //     MESSAGE("getNextNode: use bnd for node "<<
1068 //             node->myInitUV.X()<<" "<<node->myInitUV.Y());
1069   }
1070   return n;
1071 }
1072 //=======================================================================
1073 //function : checkQuads
1074 //purpose  : check if newUV destortes quadrangles around node,
1075 //           and if ( crit == FIX_OLD ) fix newUV in this case
1076 //=======================================================================
1077
1078 enum { CHECK_NEW_IN, CHECK_NEW_OK, FIX_OLD };
1079
1080 static bool checkQuads (const TIsoNode* node,
1081                         gp_XY&          newUV,
1082                         const bool      reversed,
1083                         const int       crit = FIX_OLD,
1084                         double          fixSize = 0.)
1085 {
1086   gp_XY oldUV = node->myUV, oldUVFixed[4], oldUVImpr[4];
1087   int nbOldFix = 0, nbOldImpr = 0;
1088   double newBadRate = 0, oldBadRate = 0;
1089   bool newIsOk = true, newIsIn = true, oldIsIn = true, oldIsOk = true;
1090   int i, dir1 = 0, dir2 = 3;
1091   for ( ; dir1 < 4; dir1++, dir2++ )  // loop on 4 quadrangles around <node>
1092   {
1093     if ( dir2 > 3 ) dir2 = 0;
1094     TIsoNode* n[3];
1095     // walking counterclockwise around a quad,
1096     // nodes are in the order: node, n[0], n[1], n[2]
1097     n[0] = getNextNode( node, dir1 );
1098     n[2] = getNextNode( node, dir2 );
1099     if ( !n[0] || !n[2] ) continue;
1100     n[1] = getNextNode( n[0], dir2 );
1101     if ( !n[1] ) n[1] = getNextNode( n[2], dir1 );
1102     bool isTriangle = ( !n[1] );
1103     if ( reversed ) {
1104       TIsoNode* tmp = n[0]; n[0] = n[2]; n[2] = tmp;
1105     }
1106 //     if ( fixSize != 0 ) {
1107 // cout<<"NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1108 // cout<<"\t0: "<<n[0]->myInitUV.X()<<" "<<n[0]->myInitUV.Y()<<" UV: "<<n[0]->myUV.X()<<" "<<n[0]->myUV.Y()<<endl;
1109 // cout<<"\t1: "<<n[1]->myInitUV.X()<<" "<<n[1]->myInitUV.Y()<<" UV: "<<n[1]->myUV.X()<<" "<<n[1]->myUV.Y()<<endl;
1110 // cout<<"\t2: "<<n[2]->myInitUV.X()<<" "<<n[2]->myInitUV.Y()<<" UV: "<<n[2]->myUV.X()<<" "<<n[2]->myUV.Y()<<endl;
1111 // }
1112     // check if a quadrangle is degenerated
1113     if ( !isTriangle &&
1114         ((( n[0]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN ) ||
1115          (( n[2]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN )))
1116       isTriangle = true;
1117     if ( isTriangle &&
1118         ( n[0]->myUV - n[2]->myUV ).SquareModulus() <= DBL_MIN )
1119       continue;
1120
1121     // find min size of the diagonal node-n[1]
1122     double minDiag = fixSize;
1123     if ( minDiag == 0. ) {
1124       double maxLen2 = ( node->myUV - n[0]->myUV ).SquareModulus();
1125       if ( !isTriangle ) {
1126         maxLen2 = Max( maxLen2, ( n[0]->myUV - n[1]->myUV ).SquareModulus() );
1127         maxLen2 = Max( maxLen2, ( n[1]->myUV - n[2]->myUV ).SquareModulus() );
1128       }
1129       maxLen2 = Max( maxLen2, ( n[2]->myUV - node->myUV ).SquareModulus() );
1130       minDiag = sqrt( maxLen2 ) * PI / 60.; // ~ maxLen * Sin( 3 deg )
1131     }
1132
1133     // check if newUV is behind 3 dirs: n[0]-n[1], n[1]-n[2] and n[0]-n[2]
1134     // ( behind means "to the right of")
1135     // it is OK if
1136     // 1. newUV is not behind 01 and 12 dirs
1137     // 2. or newUV is not behind 02 dir and n[2] is convex
1138     bool newIn[3] = { true, true, true }, newOk[3] = { true, true, true };
1139     bool wasIn[3] = { true, true, true }, wasOk[3] = { true, true, true };
1140     gp_Vec2d moveVec[3], outVec[3];
1141     for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1142     {
1143       bool isDiag = ( i == 2 );
1144       if ( isDiag && newOk[0] && newOk[1] && !isTriangle )
1145         break;
1146       gp_Vec2d sideDir;
1147       if ( isDiag )
1148         sideDir = gp_Vec2d( n[0]->myUV, n[2]->myUV );
1149       else
1150         sideDir = gp_Vec2d( n[i]->myUV, n[i+1]->myUV );
1151
1152       gp_Vec2d outDir( sideDir.Y(), -sideDir.X() ); // to the right
1153       outDir.Normalize();
1154       gp_Vec2d newDir( n[i]->myUV, newUV );
1155       gp_Vec2d oldDir( n[i]->myUV, oldUV );
1156       outVec[i] = outDir;
1157       if ( newIsOk ) newOk[i] = ( outDir * newDir < -minDiag );
1158       if ( newIsIn ) newIn[i] = ( outDir * newDir < 0 );
1159       if ( crit == FIX_OLD ) {
1160         wasIn[i] = ( outDir * oldDir < 0 );
1161         wasOk[i] = ( outDir * oldDir < -minDiag );
1162         if ( !newOk[i] )
1163           newBadRate += outDir * newDir;
1164         if ( !wasOk[i] )
1165           oldBadRate += outDir * oldDir;
1166         // push node inside
1167         if ( !wasOk[i] ) {
1168           double oldDist = - outDir * oldDir;//, l2 = outDir * newDir;
1169           //               double r = ( l1 - minDiag ) / ( l1 + l2 );
1170           //               moveVec[i] = r * gp_Vec2d( node->myUV, newUV );
1171           moveVec[i] = ( oldDist - minDiag ) * outDir;
1172         }
1173       }
1174     }
1175
1176     // check if n[2] is convex
1177     bool convex = true;
1178     if ( !isTriangle )
1179       convex = ( outVec[0] * gp_Vec2d( n[1]->myUV, n[2]->myUV ) < 0 );
1180
1181     bool isNewOk = ( newOk[0] && newOk[1] ) || ( newOk[2] && convex );
1182     bool isNewIn = ( newIn[0] && newIn[1] ) || ( newIn[2] && convex );
1183     newIsOk = ( newIsOk && isNewOk );
1184     newIsIn = ( newIsIn && isNewIn );
1185
1186     if ( crit != FIX_OLD ) {
1187       if ( crit == CHECK_NEW_OK && !newIsOk ) break;
1188       if ( crit == CHECK_NEW_IN && !newIsIn ) break;
1189       continue;
1190     }
1191
1192     bool isOldIn = ( wasIn[0] && wasIn[1] ) || ( wasIn[2] && convex );
1193     bool isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1194     oldIsIn = ( oldIsIn && isOldIn );
1195     oldIsOk = ( oldIsOk && isOldIn );
1196
1197
1198     if ( !isOldIn ) { // node is outside a quadrangle
1199       // move newUV inside a quadrangle
1200 //MESSAGE("Quad "<< dir1 << "  WAS IN " << wasIn[0]<<" "<<wasIn[1]<<" "<<wasIn[2]);
1201       // node and newUV are outside: push newUV inside
1202       gp_XY uv;
1203       if ( convex || isTriangle ) {
1204         uv = 0.5 * ( n[0]->myUV + n[2]->myUV ) - minDiag * outVec[2].XY();
1205       }
1206       else {
1207         gp_Vec2d out = outVec[0].Normalized() + outVec[1].Normalized();
1208         double outSize = out.Magnitude();
1209         if ( outSize > DBL_MIN )
1210           out /= outSize;
1211         else
1212           out.SetCoord( -outVec[1].Y(), outVec[1].X() );
1213         uv = n[1]->myUV - minDiag * out.XY();
1214       }
1215       oldUVFixed[ nbOldFix++ ] = uv;
1216       //node->myUV = newUV;
1217     }
1218     else if ( !isOldOk )  {
1219       // try to fix old UV: move node inside as less as possible
1220 //MESSAGE("Quad "<< dir1 << "  old is BAD, try to fix old, minDiag: "<< minDiag);
1221       gp_XY uv1, uv2 = node->myUV;
1222       for ( i = isTriangle ? 2 : 0; i < 3; i++ ) // mark not computed vectors
1223         if ( wasOk[i] )
1224           moveVec[ i ].SetCoord( 1, 2e100); // not use this vector 
1225       while ( !isOldOk ) {
1226         // find the least moveVec
1227         int i, iMin = 4;
1228         double minMove2 = 1e100;
1229         for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1230         {
1231           if ( moveVec[i].Coord(1) < 1e100 ) {
1232             double move2 = moveVec[i].SquareMagnitude();
1233             if ( move2 < minMove2 ) {
1234               minMove2 = move2;
1235               iMin = i;
1236             }
1237           }
1238         }
1239         if ( iMin == 4 ) {
1240           break;
1241         }
1242         // move node to newUV
1243         uv1 = node->myUV + moveVec[ iMin ].XY();
1244         uv2 += moveVec[ iMin ].XY();
1245         moveVec[ iMin ].SetCoord( 1, 2e100); // not use this vector more
1246         // check if uv1 is ok
1247         for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1248           wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv1 ) < -minDiag );
1249         isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1250         if ( isOldOk )
1251           oldUVImpr[ nbOldImpr++ ] = uv1;
1252         else {
1253           // check if uv2 is ok
1254           for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1255             wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv2 ) < -minDiag );
1256           isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1257           if ( isOldOk )
1258             oldUVImpr[ nbOldImpr++ ] = uv2;
1259         }
1260       }
1261     }
1262
1263   } // loop on 4 quadrangles around <node>
1264
1265   if ( crit == CHECK_NEW_OK  )
1266     return newIsOk;
1267   if ( crit == CHECK_NEW_IN  )
1268     return newIsIn;
1269
1270   if ( newIsOk )
1271     return true;
1272
1273   if ( oldIsOk )
1274     newUV = oldUV;
1275   else {
1276     if ( oldIsIn && nbOldImpr ) {
1277 //       MESSAGE(" Try to improve UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1278 //               " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1279       gp_XY uv = oldUVImpr[ 0 ];
1280       for ( int i = 1; i < nbOldImpr; i++ )
1281         uv += oldUVImpr[ i ];
1282       uv /= nbOldImpr;
1283       if ( checkQuads( node, uv, reversed, CHECK_NEW_OK )) {
1284         newUV = uv;
1285         return false;
1286       }
1287       else {
1288         //MESSAGE(" Cant improve UV, uv: "<<uv.X()<<" "<<uv.Y());
1289       }
1290     }
1291     if ( !oldIsIn && nbOldFix ) {
1292 //       MESSAGE(" Try to fix UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1293 //               " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1294       gp_XY uv = oldUVFixed[ 0 ];
1295       for ( int i = 1; i < nbOldFix; i++ )
1296         uv += oldUVFixed[ i ];
1297       uv /= nbOldFix;
1298       if ( checkQuads( node, uv, reversed, CHECK_NEW_IN )) {
1299         newUV = uv;
1300         return false;
1301       }
1302       else {
1303         //MESSAGE(" Cant fix UV, uv: "<<uv.X()<<" "<<uv.Y());
1304       }
1305     }
1306     if ( newIsIn && oldIsIn )
1307       newUV = ( newBadRate < oldBadRate ) ? newUV : oldUV;
1308     else if ( !newIsIn )
1309       newUV = oldUV;
1310   }
1311
1312   return false;
1313 }
1314
1315 //=======================================================================
1316 //function : compUVByElasticIsolines
1317 //purpose  : compute UV as nodes of iso-poly-lines consisting of
1318 //           segments keeping relative size as in the pattern
1319 //=======================================================================
1320 //#define DEB_COMPUVBYELASTICISOLINES
1321 bool SMESH_Pattern::
1322   compUVByElasticIsolines(const list< list< TPoint* > >& theBndPoints,
1323                           const list< TPoint* >&         thePntToCompute)
1324 {
1325 //cout << "============================== KEY POINTS =============================="<<endl;
1326 //   list< int >::iterator kpIt = myKeyPointIDs.begin();
1327 //   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ ) {
1328 //     TPoint& p = myPoints[ *kpIt ];
1329 //     cout << "INIT: " << p.myInitUV.X() << " " << p.myInitUV.Y() <<
1330 //       " UV: " << p.myUV.X() << " " << p.myUV.Y() << endl;
1331 //  }
1332 //cout << "=============================="<<endl;
1333
1334   // Define parameters of iso-grid nodes in U and V dir
1335
1336   set< double > paramSet[ 2 ];
1337   list< list< TPoint* > >::const_iterator pListIt;
1338   list< TPoint* >::const_iterator pIt;
1339   for ( pListIt = theBndPoints.begin(); pListIt != theBndPoints.end(); pListIt++ ) {
1340     const list< TPoint* > & pList = * pListIt;
1341     for ( pIt = pList.begin(); pIt != pList.end(); pIt++ ) {
1342       paramSet[0].insert( (*pIt)->myInitUV.X() );
1343       paramSet[1].insert( (*pIt)->myInitUV.Y() );
1344     }
1345   }
1346   for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1347     paramSet[0].insert( (*pIt)->myInitUV.X() );
1348     paramSet[1].insert( (*pIt)->myInitUV.Y() );
1349   }
1350   // unite close parameters and split too long segments
1351   int iDir;
1352   double tol[ 2 ];
1353   for ( iDir = 0; iDir < 2; iDir++ )
1354   {
1355     set< double > & params = paramSet[ iDir ];
1356     double range = ( *params.rbegin() - *params.begin() );
1357     double toler = range / 1e6;
1358     tol[ iDir ] = toler;
1359 //    double maxSegment = range / params.size() / 2.;
1360 //
1361 //     set< double >::iterator parIt = params.begin();
1362 //     double prevPar = *parIt;
1363 //     for ( parIt++; parIt != params.end(); parIt++ )
1364 //     {
1365 //       double segLen = (*parIt) - prevPar;
1366 //       if ( segLen < toler )
1367 //         ;//params.erase( prevPar ); // unite
1368 //       else if ( segLen > maxSegment )
1369 //         params.insert( prevPar + 0.5 * segLen ); // split
1370 //       prevPar = (*parIt);
1371 //     }
1372   }
1373
1374   // Make nodes of a grid of iso-poly-lines
1375
1376   list < TIsoNode > nodes;
1377   typedef list < TIsoNode *> TIsoLine;
1378   map < double, TIsoLine > isoMap[ 2 ];
1379
1380   set< double > & params0 = paramSet[ 0 ];
1381   set< double >::iterator par0It = params0.begin();
1382   for ( ; par0It != params0.end(); par0It++ )
1383   {
1384     TIsoLine & isoLine0 = isoMap[0][ *par0It ]; // vertical isoline with const U
1385     set< double > & params1 = paramSet[ 1 ];
1386     set< double >::iterator par1It = params1.begin();
1387     for ( ; par1It != params1.end(); par1It++ )
1388     {
1389       nodes.push_back( TIsoNode( *par0It, *par1It ) );
1390       isoLine0.push_back( & nodes.back() );
1391       isoMap[1][ *par1It ].push_back( & nodes.back() );
1392     }
1393   }
1394
1395   // Compute intersections of boundaries with iso-lines:
1396   // only boundary nodes will have computed UV so far
1397
1398   Bnd_Box2d uvBnd;
1399   list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
1400   list< TIsoNode* > bndNodes; // nodes corresponding to outer theBndPoints
1401   for ( ; bndIt != theBndPoints.end(); bndIt++ )
1402   {
1403     const list< TPoint* > & bndPoints = * bndIt;
1404     TPoint* prevP = bndPoints.back(); // this is the first point
1405     list< TPoint* >::const_iterator pIt = bndPoints.begin();
1406     // loop on the edge-points
1407     for ( ; pIt != bndPoints.end(); pIt++ )
1408     {
1409       TPoint* point = *pIt;
1410       for ( iDir = 0; iDir < 2; iDir++ )
1411       {
1412         const int iCoord = iDir + 1;
1413         const int iOtherCoord = 2 - iDir;
1414         double par1 = prevP->myInitUV.Coord( iCoord );
1415         double par2 = point->myInitUV.Coord( iCoord );
1416         double parDif = par2 - par1;
1417         if ( Abs( parDif ) <= DBL_MIN )
1418           continue;
1419         // find iso-lines intersecting a bounadry
1420         double toler = tol[ 1 - iDir ];
1421         double minPar = Min ( par1, par2 );
1422         double maxPar = Max ( par1, par2 );
1423         map < double, TIsoLine >& isos = isoMap[ iDir ];
1424         map < double, TIsoLine >::iterator isoIt = isos.begin();
1425         for ( ; isoIt != isos.end(); isoIt++ )
1426         {
1427           double isoParam = (*isoIt).first;
1428           if ( isoParam < minPar || isoParam > maxPar )
1429             continue;
1430           double r = ( isoParam - par1 ) / parDif;
1431           gp_XY uv = ( 1 - r ) * prevP->myUV + r * point->myUV;
1432           gp_XY initUV = ( 1 - r ) * prevP->myInitUV + r * point->myInitUV;
1433           double otherPar = initUV.Coord( iOtherCoord ); // along isoline
1434           // find existing node with otherPar or insert a new one
1435           TIsoLine & isoLine = (*isoIt).second;
1436           double nodePar;
1437           TIsoLine::iterator nIt = isoLine.begin();
1438           for ( ; nIt != isoLine.end(); nIt++ ) {
1439             nodePar = (*nIt)->myInitUV.Coord( iOtherCoord );
1440             if ( nodePar >= otherPar )
1441               break;
1442           }
1443           TIsoNode * node;
1444           if ( Abs( nodePar - otherPar ) <= toler )
1445             node = ( nIt == isoLine.end() ) ? isoLine.back() : (*nIt);
1446           else {
1447             nodes.push_back( TIsoNode( initUV.X(), initUV.Y() ) );
1448             node = & nodes.back();
1449             isoLine.insert( nIt, node );
1450           }
1451           node->SetNotMovable();
1452           node->myUV = uv;
1453           uvBnd.Add( gp_Pnt2d( uv ));
1454 //  cout << "bnd: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1455           // tangent dir
1456           gp_XY tgt( point->myUV - prevP->myUV );
1457           if ( ::IsEqual( r, 1. ))
1458             node->myDir[ 0 ] = tgt;
1459           else if ( ::IsEqual( r, 0. ))
1460             node->myDir[ 1 ] = tgt;
1461           else
1462             node->myDir[ 1 ] = node->myDir[ 0 ] = tgt;
1463           // keep boundary nodes corresponding to boundary points
1464           if ( bndIt == theBndPoints.begin() && ::IsEqual( r, 1. ))
1465             if ( bndNodes.empty() || bndNodes.back() != node )
1466               bndNodes.push_back( node );
1467         } // loop on isolines
1468       } // loop on 2 directions
1469       prevP = point;
1470     } // loop on boundary points
1471   } // loop on boundaries
1472
1473   // Define orientation
1474
1475   // find the point with the least X
1476   double leastX = DBL_MAX;
1477   TIsoNode * leftNode;
1478   list < TIsoNode >::iterator nodeIt = nodes.begin();
1479   for ( ; nodeIt != nodes.end(); nodeIt++  ) {
1480     TIsoNode & node = *nodeIt;
1481     if ( node.IsUVComputed() && node.myUV.X() < leastX ) {
1482       leastX = node.myUV.X();
1483       leftNode = &node;
1484     }
1485 // if ( node.IsUVComputed() ) {
1486 // cout << "bndNode INIT: " << node.myInitUV.X()<<" "<<node.myInitUV.Y()<<" UV: "<<
1487 //   node.myUV.X()<<" "<<node.myUV.Y()<<endl<<
1488 //    " dir0: "<<node.myDir[0].X()<<" "<<node.myDir[0].Y() <<
1489 //      " dir1: "<<node.myDir[1].X()<<" "<<node.myDir[1].Y() << endl;
1490 // }
1491   }
1492   bool reversed = ( leftNode->myDir[0].Y() + leftNode->myDir[1].Y() > 0 );
1493   //SCRUTE( reversed );
1494
1495   // Prepare internal nodes:
1496   // 1. connect nodes
1497   // 2. compute ratios
1498   // 3. find boundary nodes for each node
1499   // 4. remove nodes out of the boundary
1500   for ( iDir = 0; iDir < 2; iDir++ )
1501   {
1502     const int iCoord = 2 - iDir; // coord changing along an isoline
1503     map < double, TIsoLine >& isos = isoMap[ iDir ];
1504     map < double, TIsoLine >::iterator isoIt = isos.begin();
1505     for ( ; isoIt != isos.end(); isoIt++ )
1506     {
1507       TIsoLine & isoLine = (*isoIt).second;
1508       bool firstCompNodeFound = false;
1509       TIsoLine::iterator lastCompNodePos, nPrevIt, nIt, nNextIt, nIt2;
1510       nPrevIt = nIt = nNextIt = isoLine.begin();
1511       nIt++;
1512       nNextIt++; nNextIt++;
1513       while ( nIt != isoLine.end() )
1514       {
1515         // 1. connect prev - cur
1516         TIsoNode* node = *nIt, * prevNode = *nPrevIt;
1517         if ( !firstCompNodeFound && prevNode->IsUVComputed() ) {
1518           firstCompNodeFound = true;
1519           lastCompNodePos = nPrevIt;
1520         }
1521         if ( firstCompNodeFound ) {
1522           node->SetNext( prevNode, iDir, 0 );
1523           prevNode->SetNext( node, iDir, 1 );
1524         }
1525         // 2. compute ratio
1526         if ( nNextIt != isoLine.end() ) {
1527           double par1 = prevNode->myInitUV.Coord( iCoord );
1528           double par2 = node->myInitUV.Coord( iCoord );
1529           double par3 = (*nNextIt)->myInitUV.Coord( iCoord );
1530           node->myRatio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1531         }
1532         // 3. find boundary nodes
1533         if ( node->IsUVComputed() )
1534           lastCompNodePos = nIt;
1535         else if ( firstCompNodeFound && nNextIt != isoLine.end() ) {
1536           TIsoNode* bndNode1 = *lastCompNodePos, *bndNode2 = 0;
1537           for ( nIt2 = nNextIt; nIt2 != isoLine.end(); nIt2++ )
1538             if ( (*nIt2)->IsUVComputed() )
1539               break;
1540           if ( nIt2 != isoLine.end() ) {
1541             bndNode2 = *nIt2;
1542             node->SetBoundaryNode( bndNode1, iDir, 0 );
1543             node->SetBoundaryNode( bndNode2, iDir, 1 );
1544 // cout << "--------------------------------------------------"<<endl;
1545 //  cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<<endl<<
1546 //   " dir0: "<<bndNode1->myDir[0].X()<<" "<<bndNode1->myDir[0].Y() <<
1547 //     " dir1: "<<bndNode1->myDir[1].X()<<" "<<bndNode1->myDir[1].Y() << endl;
1548 //  cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl<<
1549 //   " dir0: "<<bndNode2->myDir[0].X()<<" "<<bndNode2->myDir[0].Y() <<
1550 //     " dir1: "<<bndNode2->myDir[1].X()<<" "<<bndNode2->myDir[1].Y() << endl;
1551           }
1552         }
1553         nIt++; nPrevIt++;
1554         if ( nNextIt != isoLine.end() ) nNextIt++;
1555         // 4. remove nodes out of the boundary
1556         if ( !firstCompNodeFound )
1557           isoLine.pop_front();
1558       } // loop on isoLine nodes
1559
1560       // remove nodes after the boundary
1561 //       for ( nIt = ++lastCompNodePos; nIt != isoLine.end(); nIt++ )
1562 //         (*nIt)->SetNotMovable();
1563       isoLine.erase( ++lastCompNodePos, isoLine.end() );
1564     } // loop on isolines
1565   } // loop on 2 directions
1566
1567   // Compute local isoline direction for internal nodes
1568
1569   /*
1570   map < double, TIsoLine >& isos = isoMap[ 0 ]; // vertical isolines with const U
1571   map < double, TIsoLine >::iterator isoIt = isos.begin();
1572   for ( ; isoIt != isos.end(); isoIt++ )
1573   {
1574     TIsoLine & isoLine = (*isoIt).second;
1575     TIsoLine::iterator nIt = isoLine.begin();
1576     for ( ; nIt != isoLine.end(); nIt++ )
1577     {
1578       TIsoNode* node = *nIt;
1579       if ( node->IsUVComputed() || !node->IsMovable() )
1580         continue;
1581       gp_Vec2d aTgt[2], aNorm[2];
1582       double ratio[2];
1583       bool OK = true;
1584       for ( iDir = 0; iDir < 2; iDir++ )
1585       {
1586         TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1587         TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1588         if ( !bndNode1 || !bndNode2 ) {
1589           OK = false;
1590           break;
1591         }
1592         const int iCoord = 2 - iDir; // coord changing along an isoline
1593         double par1 = bndNode1->myInitUV.Coord( iCoord );
1594         double par2 = node->myInitUV.Coord( iCoord );
1595         double par3 = bndNode2->myInitUV.Coord( iCoord );
1596         ratio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1597
1598         gp_Vec2d tgt1( bndNode1->myDir[0].XY() + bndNode1->myDir[1].XY() );
1599         gp_Vec2d tgt2( bndNode2->myDir[0].XY() + bndNode2->myDir[1].XY() );
1600         if ( bool( iDir ) == reversed ) tgt2.Reverse(); // along perpend. isoline
1601         else                            tgt1.Reverse();
1602 //cout<<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" | "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1603
1604         if ( ratio[ iDir ] < 0.5 )
1605           aNorm[ iDir ] = gp_Vec2d( -tgt1.Y(), tgt1.X() ); // rotate tgt to the left
1606         else
1607           aNorm[ iDir ] = gp_Vec2d( -tgt2.Y(), tgt2.X() );
1608         if ( iDir == 1 )
1609           aNorm[ iDir ].Reverse();  // along iDir isoline
1610
1611         double angle = tgt1.Angle( tgt2 ); //  [-PI, PI]
1612         // maybe angle is more than |PI|
1613         if ( Abs( angle ) > PI / 2. ) {
1614           // check direction of the last but one perpendicular isoline
1615           TIsoNode* prevNode = bndNode2->GetNext( iDir, 0 );
1616           bndNode1 = prevNode->GetBoundaryNode( 1 - iDir, 0 );
1617           bndNode2 = prevNode->GetBoundaryNode( 1 - iDir, 1 );
1618           gp_Vec2d isoDir( bndNode1->myUV, bndNode2->myUV );
1619           if ( isoDir * tgt2 < 0 )
1620             isoDir.Reverse();
1621           double angle2 = tgt1.Angle( isoDir );
1622           //cout << " isoDir: "<< isoDir.X() <<" "<<isoDir.Y() << " ANGLE: "<< angle << " "<<angle2<<endl;
1623           if (angle2 * angle < 0 && // check the sign of an angle close to PI
1624               Abs ( Abs ( angle ) - PI ) <= PI / 180. ) {
1625             //MESSAGE("REVERSE ANGLE");
1626             angle = -angle;
1627           }
1628           if ( Abs( angle2 ) > Abs( angle ) ||
1629               ( angle2 * angle < 0 && Abs( angle2 ) > Abs( angle - angle2 ))) {
1630             //MESSAGE("Add PI");
1631             // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1632             // cout <<"ISO: " << isoParam << " " << (*iso2It).first << endl;
1633             // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<< endl;
1634             // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl;
1635             // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<"  "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1636             angle += ( angle < 0 ) ? 2. * PI : -2. * PI;
1637           }
1638         }
1639         aTgt[ iDir ] = tgt1.Rotated( angle * ratio[ iDir ] ).XY();
1640       } // loop on 2 dir
1641
1642       if ( OK ) {
1643         for ( iDir = 0; iDir < 2; iDir++ )
1644         {
1645           aTgt[iDir].Normalize();
1646           aNorm[1-iDir].Normalize();
1647           double r = Abs ( ratio[iDir] - 0.5 ) * 2.0; // [0,1] - distance from the middle
1648           r *= r;
1649           
1650           node->myDir[iDir] = //aTgt[iDir];
1651             aNorm[1-iDir] * r + aTgt[iDir] * ( 1. - r );
1652         }
1653 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1654 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" - "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1655 //  cout << " isoDir: "<< node->myDir[0].X() <<" "<<node->myDir[0].Y()<<"  |  "
1656 //    << node->myDir[1].X() <<" "<<node->myDir[1].Y()<<endl;
1657       }
1658     } // loop on iso nodes
1659   } // loop on isolines
1660 */
1661   // Find nodes to start computing UV from
1662
1663   list< TIsoNode* > startNodes;
1664   list< TIsoNode* >::iterator nIt = bndNodes.end();
1665   TIsoNode* node = *(--nIt);
1666   TIsoNode* prevNode = *(--nIt);
1667   for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1668   {
1669     TIsoNode* nextNode = *nIt;
1670     gp_Vec2d initTgt1( prevNode->myInitUV, node->myInitUV );
1671     gp_Vec2d initTgt2( node->myInitUV, nextNode->myInitUV );
1672     double initAngle = initTgt1.Angle( initTgt2 );
1673     double angle = node->myDir[0].Angle( node->myDir[1] );
1674     if ( reversed ) angle = -angle;
1675     if ( initAngle > angle && initAngle - angle > PI / 2.1 ) {
1676       // find a close internal node
1677       TIsoNode* nClose = 0;
1678       list< TIsoNode* > testNodes;
1679       testNodes.push_back( node );
1680       list< TIsoNode* >::iterator it = testNodes.begin();
1681       for ( ; !nClose && it != testNodes.end(); it++ )
1682       {
1683         for (int i = 0; i < 4; i++ )
1684         {
1685           nClose = (*it)->myNext[ i ];
1686           if ( nClose ) {
1687             if ( !nClose->IsUVComputed() )
1688               break;
1689             else {
1690               testNodes.push_back( nClose );
1691               nClose = 0;
1692             }
1693           }
1694         }
1695       }
1696       startNodes.push_back( nClose );
1697 // cout << "START: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<
1698 //   node->myUV.X()<<" "<<node->myUV.Y()<<endl<<
1699 //   "initAngle: " << initAngle << " angle: " << angle << endl;
1700 // cout <<" init tgt: " << initTgt1.X()<<" "<<initTgt1.Y()<<" | "<< initTgt2.X()<<" "<<initTgt2.Y()<<endl;
1701 // cout << " tgt: "<< node->myDir[ 0 ].X() <<" "<<node->myDir[ 0 ].Y()<<" | "<<
1702 //    node->myDir[ 1 ].X() <<" "<<node->myDir[ 1 ].Y()<<endl;
1703 // cout << "CLOSE: "<<nClose->myInitUV.X()<<" "<<nClose->myInitUV.Y()<<endl;
1704     }
1705     prevNode = node;
1706     node = nextNode;
1707   }
1708
1709   // Compute starting UV of internal nodes
1710
1711   list < TIsoNode* > internNodes;
1712   bool needIteration = true;
1713   if ( startNodes.empty() ) {
1714     MESSAGE( " Starting UV by compUVByIsoIntersection()");
1715     needIteration = false;
1716     map < double, TIsoLine >& isos = isoMap[ 0 ];
1717     map < double, TIsoLine >::iterator isoIt = isos.begin();
1718     for ( ; isoIt != isos.end(); isoIt++ )
1719     {
1720       TIsoLine & isoLine = (*isoIt).second;
1721       TIsoLine::iterator nIt = isoLine.begin();
1722       for ( ; !needIteration && nIt != isoLine.end(); nIt++ )
1723       {
1724         TIsoNode* node = *nIt;
1725         if ( !node->IsUVComputed() && node->IsMovable() ) {
1726           internNodes.push_back( node );
1727           //bool isDeformed;
1728           if ( !compUVByIsoIntersection(theBndPoints, node->myInitUV,
1729                                         node->myUV, needIteration ))
1730             node->myUV = node->myInitUV;
1731         }
1732       }
1733     }
1734     if ( needIteration )
1735       for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1736       {
1737         TIsoNode* node = *nIt, *nClose = 0;
1738         list< TIsoNode* > testNodes;
1739         testNodes.push_back( node );
1740         list< TIsoNode* >::iterator it = testNodes.begin();
1741         for ( ; !nClose && it != testNodes.end(); it++ )
1742         {
1743           for (int i = 0; i < 4; i++ )
1744           {
1745             nClose = (*it)->myNext[ i ];
1746             if ( nClose ) {
1747               if ( !nClose->IsUVComputed() && nClose->IsMovable() )
1748                 break;
1749               else {
1750                 testNodes.push_back( nClose );
1751                 nClose = 0;
1752               }
1753             }
1754           }
1755         }
1756         startNodes.push_back( nClose );
1757       }
1758   }
1759
1760   double aMin[2], aMax[2], step[2];
1761   uvBnd.Get( aMin[0], aMin[1], aMax[0], aMax[1] );
1762   double minUvSize = Min ( aMax[0]-aMin[0], aMax[1]-aMin[1] );
1763   step[0] = minUvSize / paramSet[ 0 ].size() / 10;
1764   step[1] = minUvSize / paramSet[ 1 ].size() / 10;
1765 //cout << "STEPS: " << step[0] << " " << step[1]<< endl;
1766
1767   for ( nIt = startNodes.begin(); nIt != startNodes.end(); nIt++ )
1768   {
1769     TIsoNode* prevN[2], *node = *nIt;
1770     if ( node->IsUVComputed() || !node->IsMovable() )
1771       continue;
1772     gp_XY newUV( 0, 0 ), sumDir( 0, 0 );
1773     int nbComp = 0, nbPrev = 0;
1774     for ( iDir = 0; iDir < 2; iDir++ )
1775     {
1776       TIsoNode* prevNode1 = 0, *prevNode2 = 0;
1777       TIsoNode* n = node->GetNext( iDir, 0 );
1778       if ( n->IsUVComputed() )
1779         prevNode1 = n;
1780       else
1781         startNodes.push_back( n );
1782       n = node->GetNext( iDir, 1 );
1783       if ( n->IsUVComputed() )
1784         prevNode2 = n;
1785       else
1786         startNodes.push_back( n );
1787       if ( !prevNode1 ) {
1788         prevNode1 = prevNode2;
1789         prevNode2 = 0;
1790       }
1791       if ( prevNode1 ) nbPrev++;
1792       if ( prevNode2 ) nbPrev++;
1793       if ( prevNode1 ) {
1794         gp_XY dir;
1795           double prevPar = prevNode1->myInitUV.Coord( 2 - iDir );
1796           double par = node->myInitUV.Coord( 2 - iDir );
1797           bool isEnd = ( prevPar > par );
1798 //          dir = node->myDir[ 1 - iDir ].XY() * ( isEnd ? -1. : 1. );
1799         //cout << "__________"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1800           TIsoNode* bndNode = node->GetBoundaryNode( iDir, isEnd );
1801           gp_XY tgt( bndNode->myDir[0].XY() + bndNode->myDir[1].XY() );
1802           dir.SetCoord( 1, tgt.Y() * ( reversed ? 1 : -1 ));
1803           dir.SetCoord( 2, tgt.X() * ( reversed ? -1 : 1 ));
1804         //cout << "bndNode UV: " << bndNode->myUV.X()<<" "<<bndNode->myUV.Y()<< endl;
1805           //  cout << " tgt: "<< bndNode->myDir[ 0 ].X() <<" "<<bndNode->myDir[ 0 ].Y()<<" | "<<
1806           //     bndNode->myDir[ 1 ].X() <<" "<<bndNode->myDir[ 1 ].Y()<<endl;
1807           //cout << "prevNode UV: " << prevNode1->myUV.X()<<" "<<prevNode1->myUV.Y()<<
1808             //" par: " << prevPar << endl;
1809           //           cout <<" tgt: " << tgt.X()<<" "<<tgt.Y()<<endl;
1810         //cout << " DIR: "<< dir.X() <<" "<<dir.Y()<<endl;
1811         if ( prevNode2 ) {
1812           //cout << "____2next______"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1813           gp_XY & uv1 = prevNode1->myUV;
1814           gp_XY & uv2 = prevNode2->myUV;
1815 //           dir = ( uv2 - uv1 );
1816 //           double len = dir.Modulus();
1817 //           if ( len > DBL_MIN )
1818 //             dir /= len * 0.5;
1819           double r = node->myRatio[ iDir ];
1820           newUV += uv1 * ( 1 - r ) + uv2 * r;
1821         }
1822         else {
1823           newUV += prevNode1->myUV + dir * step[ iDir ];
1824         }
1825         sumDir += dir;
1826         prevN[ iDir ] = prevNode1;
1827         nbComp++;
1828       }
1829     }
1830     newUV /= nbComp;
1831     node->myUV = newUV;
1832     //cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1833
1834     // check if a quadrangle is not distorted
1835     if ( nbPrev > 1 ) {
1836       //int crit = ( nbPrev == 4 ) ? FIX_OLD : CHECK_NEW_IN;
1837       if ( !checkQuads( node, newUV, reversed, FIX_OLD, step[0] + step[1] )) {
1838       //cout <<" newUV: " << node->myUV.X() << " "<<node->myUV.Y() << " nbPrev: "<<nbPrev<< endl;
1839       //  cout << "_FIX_INIT_ fixedUV: " << newUV.X() << " "<<newUV.Y() << endl;
1840         node->myUV = newUV;
1841       }
1842     }
1843     internNodes.push_back( node );
1844   }
1845   
1846   // Move nodes
1847
1848   static int maxNbIter = 100;
1849 #ifdef DEB_COMPUVBYELASTICISOLINES
1850 //   maxNbIter++;
1851   bool useNbMoveNode = 0;
1852   static int maxNbNodeMove = 100;
1853   maxNbNodeMove++;
1854   int nbNodeMove = 0;
1855   if ( !useNbMoveNode )
1856     maxNbIter = ( maxNbIter < 0 ) ? 100 : -1;
1857 #endif    
1858   double maxMove;
1859   int nbIter = 0;
1860   do {
1861     if ( !needIteration) break;
1862 #ifdef DEB_COMPUVBYELASTICISOLINES
1863     if ( nbIter >= maxNbIter ) break;
1864 #endif
1865     maxMove = 0.0;
1866     list < TIsoNode* >::iterator nIt = internNodes.begin();
1867     for ( ; nIt != internNodes.end(); nIt++  ) {
1868 #ifdef DEB_COMPUVBYELASTICISOLINES
1869       if (useNbMoveNode )
1870         cout << nbNodeMove <<" =================================================="<<endl;
1871 #endif
1872       TIsoNode * node = *nIt;
1873       // make lines
1874       //gp_Lin2d line[2];
1875       gp_XY loc[2];
1876       for ( iDir = 0; iDir < 2; iDir++ )
1877       {
1878         gp_XY & uv1 = node->GetNext( iDir, 0 )->myUV;
1879         gp_XY & uv2 = node->GetNext( iDir, 1 )->myUV;
1880         double r = node->myRatio[ iDir ];
1881         loc[ iDir ] = uv1 * ( 1 - r ) + uv2 * r;
1882 //         line[ iDir ].SetLocation( loc[ iDir ] );
1883 //         line[ iDir ].SetDirection( node->myDir[ iDir ] );
1884       }
1885       // define ratio
1886       double locR[2] = { 0, 0 };
1887       for ( iDir = 0; iDir < 2; iDir++ )
1888       {
1889         const int iCoord = 2 - iDir; // coord changing along an isoline
1890         TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1891         TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1892         double par1 = bndNode1->myInitUV.Coord( iCoord );
1893         double par2 = node->myInitUV.Coord( iCoord );
1894         double par3 = bndNode2->myInitUV.Coord( iCoord );
1895         double r = ( par2 - par1 ) / ( par3 - par1 );
1896         r = Abs ( r - 0.5 ) * 2.0;  // [0,1] - distance from the middle
1897         locR[ iDir ] = ( 1 - r * r ) * 0.25;
1898       }
1899       //locR[0] = locR[1] = 0.25;
1900       // intersect the 2 lines and move a node
1901       //IntAna2d_AnaIntersection inter( line[0], line[1] );
1902       if ( /*inter.IsDone() && inter.NbPoints() ==*/ 1 )
1903       {
1904 //         double intR = 1 - locR[0] - locR[1];
1905 //         gp_XY newUV = inter.Point(1).Value().XY();
1906 //         if ( !checkQuads( node, newUV, reversed, CHECK_NEW_IN ))
1907 //           newUV = ( locR[0] * loc[0] + locR[1] * loc[1] ) / ( 1 - intR );
1908 //         else
1909 //           newUV = intR * newUV + locR[0] * loc[0] + locR[1] * loc[1];
1910         gp_XY newUV = 0.5 * ( loc[0] +  loc[1] );
1911         // avoid parallel isolines intersection
1912         checkQuads( node, newUV, reversed );
1913
1914         maxMove = Max( maxMove, ( newUV - node->myUV ).SquareModulus());
1915         node->myUV = newUV;
1916       } // intersection found
1917 #ifdef DEB_COMPUVBYELASTICISOLINES
1918       if (useNbMoveNode && ++nbNodeMove >= maxNbNodeMove ) break;
1919 #endif
1920     } // loop on internal nodes
1921 #ifdef DEB_COMPUVBYELASTICISOLINES
1922     if (useNbMoveNode && nbNodeMove >= maxNbNodeMove ) break;
1923 #endif
1924   } while ( maxMove > 1e-8 && nbIter++ < maxNbIter );
1925
1926   MESSAGE( "compUVByElasticIsolines(): Nb iterations " << nbIter << " dist: " << sqrt( maxMove ));
1927
1928   if ( nbIter >= maxNbIter && sqrt(maxMove) > minUvSize * 0.05 ) {
1929     MESSAGE( "compUVByElasticIsolines() failed: "<<sqrt(maxMove)<<">"<<minUvSize * 0.05);
1930 #ifndef DEB_COMPUVBYELASTICISOLINES
1931     return false;
1932 #endif
1933   }
1934
1935   // Set computed UV to points
1936
1937   for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1938     TPoint* point = *pIt;
1939     //gp_XY oldUV = point->myUV;
1940     double minDist = DBL_MAX;
1941     list < TIsoNode >::iterator nIt = nodes.begin();
1942     for ( ; nIt != nodes.end(); nIt++ ) {
1943       double dist = ( (*nIt).myInitUV - point->myInitUV ).SquareModulus();
1944       if ( dist < minDist ) {
1945         minDist = dist;
1946         point->myUV = (*nIt).myUV;
1947       }
1948     }
1949   }
1950       
1951     
1952   return true;
1953 }
1954
1955
1956 //=======================================================================
1957 //function : setFirstEdge
1958 //purpose  : choose the best first edge of theWire; return the summary distance
1959 //           between point UV computed by isolines intersection and
1960 //           eventual UV got from edge p-curves
1961 //=======================================================================
1962
1963 //#define DBG_SETFIRSTEDGE
1964 double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstEdgeID)
1965 {
1966   int iE, nbEdges = theWire.size();
1967   if ( nbEdges == 1 )
1968     return 0;
1969
1970   // Transform UVs computed by iso to fit bnd box of a wire
1971
1972   // max nb of points on an edge
1973   int maxNbPnt = 0;
1974   int eID = theFirstEdgeID;
1975   for ( iE = 0; iE < nbEdges; iE++ )
1976     maxNbPnt = Max ( maxNbPnt, getShapePoints( eID++ ).size() );
1977   
1978   // compute bnd boxes
1979   TopoDS_Face face = TopoDS::Face( myShape );
1980   Bnd_Box2d bndBox, eBndBox;
1981   eID = theFirstEdgeID;
1982   list< TopoDS_Edge >::iterator eIt;
1983   list< TPoint* >::iterator pIt;
1984   for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
1985   {
1986     // UV by isos stored in TPoint.myXYZ
1987     list< TPoint* > & ePoints = getShapePoints( eID++ );
1988     for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
1989       TPoint* p = (*pIt);
1990       bndBox.Add( gp_Pnt2d( p->myXYZ.X(), p->myXYZ.Y() ));
1991     }
1992     // UV by an edge p-curve
1993     double f, l;
1994     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( *eIt, face, f, l );
1995     double dU = ( l - f ) / ( maxNbPnt - 1 );
1996     for ( int i = 0; i < maxNbPnt; i++ )
1997       eBndBox.Add( C2d->Value( f + i * dU ));
1998   }
1999
2000   // transform UVs by isos
2001   double minPar[2], maxPar[2], eMinPar[2], eMaxPar[2];
2002   bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2003   eBndBox.Get( eMinPar[0], eMinPar[1], eMaxPar[0], eMaxPar[1] );
2004 #ifdef DBG_SETFIRSTEDGE
2005   cout << "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
2006     << eMinPar[1] << " - " << eMaxPar[1] << endl;
2007 #endif
2008   for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2009   {
2010     double dMin = eMinPar[i] - minPar[i];
2011     double dMax = eMaxPar[i] - maxPar[i];
2012     double dPar = maxPar[i] - minPar[i];
2013     eID = theFirstEdgeID;
2014     for ( iE = 0; iE < nbEdges; iE++ ) // loop on edges of a boundary
2015     {
2016       list< TPoint* > & ePoints = getShapePoints( eID++ );
2017       for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) // loop on edge points
2018       {
2019         double par = (*pIt)->myXYZ.Coord( iC );
2020         double r = ( par - minPar[i] ) / dPar;
2021         par += ( 1 - r ) * dMin + r * dMax;
2022         (*pIt)->myXYZ.SetCoord( iC, par );
2023       }
2024     }
2025   }
2026
2027   TopoDS_Edge eBest;
2028   double minDist = DBL_MAX;
2029   for ( iE = 0 ; iE < nbEdges; iE++ )
2030   {
2031 #ifdef DBG_SETFIRSTEDGE
2032     cout << " VARIANT " << iE << endl;
2033 #endif
2034     // evaluate the distance between UV computed by the 2 methods:
2035     // by isos intersection ( myXYZ ) and by edge p-curves ( myUV )
2036     double dist = 0;
2037     int eID = theFirstEdgeID;
2038     for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
2039     {
2040       list< TPoint* > & ePoints = getShapePoints( eID++ );
2041       computeUVOnEdge( *eIt, ePoints );
2042       for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
2043         TPoint* p = (*pIt);
2044         dist += ( p->myUV - gp_XY( p->myXYZ.X(), p->myXYZ.Y() )).SquareModulus();
2045 #ifdef DBG_SETFIRSTEDGE
2046         cout << " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
2047           p->myUV.X() << ", " << p->myUV.Y() << ") " << endl;
2048 #endif
2049       }
2050     }
2051 #ifdef DBG_SETFIRSTEDGE
2052     cout << "dist -- " << dist << endl;
2053 #endif
2054     if ( dist < minDist ) {
2055       minDist = dist;
2056       eBest = theWire.front();
2057     }
2058     // check variant with another first edge
2059     theWire.splice( theWire.begin(), theWire, --theWire.end(), theWire.end() );
2060   }
2061   // put the best first edge to the theWire front
2062   if ( eBest != theWire.front() ) {
2063     eIt = find ( theWire.begin(), theWire.end(), eBest );
2064     theWire.splice( theWire.begin(), theWire, eIt, theWire.end() );
2065   }
2066
2067   return minDist;
2068 }
2069
2070 //=======================================================================
2071 //function : sortSameSizeWires
2072 //purpose  : sort wires in theWireList from theFromWire until theToWire,
2073 //           the wires are set in the order to correspond to the order
2074 //           of boundaries; after sorting, edges in the wires are put
2075 //           in a good order, point UVs on edges are computed and points
2076 //           are appended to theEdgesPointsList
2077 //=======================================================================
2078
2079 bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList &                theWireList,
2080                                        const TListOfEdgesList::iterator& theFromWire,
2081                                        const TListOfEdgesList::iterator& theToWire,
2082                                        const int                         theFirstEdgeID,
2083                                        list< list< TPoint* > >&          theEdgesPointsList )
2084 {
2085   TopoDS_Face F = TopoDS::Face( myShape );
2086   int iW, nbWires = 0;
2087   TListOfEdgesList::iterator wlIt = theFromWire;
2088   while ( wlIt++ != theToWire )
2089     nbWires++;
2090
2091   // Recompute key-point UVs by isolines intersection,
2092   // compute CG of key-points for each wire and bnd boxes of GCs
2093
2094   bool aBool;
2095   gp_XY orig( gp::Origin2d().XY() );
2096   vector< gp_XY > vGcVec( nbWires, orig ), gcVec( nbWires, orig );
2097   Bnd_Box2d bndBox, vBndBox;
2098   int eID = theFirstEdgeID;
2099   list< TopoDS_Edge >::iterator eIt;
2100   for ( iW = 0, wlIt = theFromWire; wlIt != theToWire; wlIt++, iW++ )
2101   {
2102     list< TopoDS_Edge > & wire = *wlIt;
2103     for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2104     {
2105       list< TPoint* > & ePoints = getShapePoints( eID++ );
2106       TPoint* p = ePoints.front();
2107       if ( !compUVByIsoIntersection( theEdgesPointsList, p->myInitUV, p->myUV, aBool )) {
2108         MESSAGE("cant sortSameSizeWires()");
2109         return false;
2110       }
2111       gcVec[iW] += p->myUV;
2112       bndBox.Add( gp_Pnt2d( p->myUV ));
2113       TopoDS_Vertex V = TopExp::FirstVertex( *eIt, true );
2114       gp_Pnt2d vXY = BRep_Tool::Parameters( V, F );
2115       vGcVec[iW] += vXY.XY();
2116       vBndBox.Add( vXY );
2117       // keep the computed UV to compare against by setFirstEdge()
2118       p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2119     }
2120     gcVec[iW] /= nbWires;
2121     vGcVec[iW] /= nbWires;
2122 // cout << " Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2123 //   " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2124   }
2125
2126   // Transform GCs computed by isos to fit in bnd box of GCs by vertices
2127
2128   double minPar[2], maxPar[2], vMinPar[2], vMaxPar[2];
2129   bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2130   vBndBox.Get( vMinPar[0], vMinPar[1], vMaxPar[0], vMaxPar[1] );
2131   for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2132   {
2133     double dMin = vMinPar[i] - minPar[i];
2134     double dMax = vMaxPar[i] - maxPar[i];
2135     double dPar = maxPar[i] - minPar[i];
2136     if ( Abs( dPar ) <= DBL_MIN )
2137       continue;
2138     for ( iW = 0; iW < nbWires; iW++ ) { // loop on GCs of wires
2139       double par = gcVec[iW].Coord( iC );
2140       double r = ( par - minPar[i] ) / dPar;
2141       par += ( 1 - r ) * dMin + r * dMax;
2142       gcVec[iW].SetCoord( iC, par );
2143     }
2144   }
2145
2146   // Define boundary - wire correspondence by GC closeness
2147
2148   TListOfEdgesList tmpWList;
2149   tmpWList.splice( tmpWList.end(), theWireList, theFromWire, theToWire );
2150   typedef map< int, TListOfEdgesList::iterator > TIntWirePosMap;
2151   TIntWirePosMap bndIndWirePosMap;
2152   vector< bool > bndFound( nbWires, false );
2153   for ( iW = 0, wlIt = tmpWList.begin(); iW < nbWires; iW++, wlIt++ )
2154   {
2155 // cout << " TRSF Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2156 //   " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2157     double minDist = DBL_MAX;
2158     gp_XY & wGc = vGcVec[ iW ];
2159     int bIndex;
2160     for ( int iB = 0; iB < nbWires; iB++ ) {
2161       if ( bndFound[ iB ] ) continue;
2162       double dist = ( wGc - gcVec[ iB ] ).SquareModulus();
2163       if ( dist < minDist ) {
2164         minDist = dist;
2165         bIndex = iB;
2166       }
2167     }
2168     bndFound[ bIndex ] = true;
2169     bndIndWirePosMap.insert( TIntWirePosMap::value_type( bIndex, wlIt ));
2170   }
2171
2172   // Treat each wire  
2173
2174   TIntWirePosMap::iterator bIndWPosIt = bndIndWirePosMap.begin();
2175   eID = theFirstEdgeID;
2176   for ( ; bIndWPosIt != bndIndWirePosMap.end(); bIndWPosIt++ )
2177   {
2178     TListOfEdgesList::iterator wirePos = (*bIndWPosIt).second;
2179     list < TopoDS_Edge > & wire = ( *wirePos );
2180
2181     // choose the best first edge of a wire
2182     setFirstEdge( wire, eID );
2183     
2184     // compute eventual UV and fill theEdgesPointsList
2185     theEdgesPointsList.push_back( list< TPoint* >() );
2186     list< TPoint* > & edgesPoints = theEdgesPointsList.back();
2187     for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2188     {
2189       list< TPoint* > & ePoints = getShapePoints( eID++ );
2190       computeUVOnEdge( *eIt, ePoints );
2191       edgesPoints.insert( edgesPoints.end(), ePoints.begin(), (--ePoints.end()));
2192     }
2193     // put wire back to theWireList
2194     wlIt = wirePos++;
2195     theWireList.splice( theToWire, tmpWList, wlIt, wirePos );
2196   }
2197
2198   return true;
2199 }
2200
2201 //=======================================================================
2202 //function : Apply
2203 //purpose  : Compute  nodes coordinates applying
2204 //           the loaded pattern to <theFace>. The first key-point
2205 //           will be mapped into <theVertexOnKeyPoint1>
2206 //=======================================================================
2207
2208 bool SMESH_Pattern::Apply (const TopoDS_Face&   theFace,
2209                            const TopoDS_Vertex& theVertexOnKeyPoint1,
2210                            const bool           theReverse)
2211 {
2212   MESSAGE(" ::Apply(face) " );
2213   TopoDS_Face face  = theReverse ? TopoDS::Face( theFace.Reversed() ) : theFace;
2214   if ( !setShapeToMesh( face ))
2215     return false;
2216
2217   // find points on edges, it fills myNbKeyPntInBoundary
2218   if ( !findBoundaryPoints() )
2219     return false;
2220
2221   // Define the edges order so that the first edge starts at
2222   // theVertexOnKeyPoint1
2223
2224   list< TopoDS_Edge > eList;
2225   list< int >         nbVertexInWires;
2226   int nbWires = getOrderedEdges( face, theVertexOnKeyPoint1, eList, nbVertexInWires);
2227   if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true )))
2228   {
2229     MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire ");
2230     return setErrorCode( ERR_APPLF_BAD_VERTEX );
2231   }
2232   // check nb wires and edges
2233   list< int > l1 = myNbKeyPntInBoundary, l2 = nbVertexInWires;
2234   l1.sort(); l2.sort();
2235   if ( l1 != l2 )
2236   {
2237     MESSAGE( "Wrong nb vertices in wires" );
2238     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2239   }
2240
2241   // here shapes get IDs, for the outer wire IDs are OK
2242   list<TopoDS_Edge>::iterator elIt = eList.begin();
2243   for ( ; elIt != eList.end(); elIt++ ) {
2244     myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2245     if ( BRep_Tool::IsClosed( *elIt, theFace ) )
2246       myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));
2247   }
2248   int nbVertices = myShapeIDMap.Extent();
2249
2250   for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2251     myShapeIDMap.Add( *elIt );
2252
2253   myShapeIDMap.Add( face );
2254
2255   if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent()/* + nbSeamShapes*/ ) {
2256     MESSAGE( myShapeIDToPointsMap.size() <<" != " << myShapeIDMap.Extent());
2257     return setErrorCode( ERR_APPLF_INTERNAL_EEROR );
2258   }
2259
2260   // points on edges to be used for UV computation of in-face points
2261   list< list< TPoint* > > edgesPointsList;
2262   edgesPointsList.push_back( list< TPoint* >() );
2263   list< TPoint* > * edgesPoints = & edgesPointsList.back();
2264   list< TPoint* >::iterator pIt;
2265
2266   // compute UV of points on the outer wire
2267   int iE, nbEdgesInOuterWire = nbVertexInWires.front();
2268   for (iE = 0, elIt = eList.begin();
2269        iE < nbEdgesInOuterWire && elIt != eList.end();
2270        iE++, elIt++ )
2271   {
2272     list< TPoint* > & ePoints = getShapePoints( *elIt );
2273     // compute UV
2274     computeUVOnEdge( *elIt, ePoints );
2275     // collect on-edge points (excluding the last one)
2276     edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2277   }
2278
2279   // If there are several wires, define the order of edges of inner wires:
2280   // compute UV of inner edge-points using 2 methods: the one for in-face points
2281   // and the one for on-edge points and then choose the best edge order
2282   // by the best correspondance of the 2 results
2283   if ( nbWires > 1 )
2284   {
2285     // compute UV of inner edge-points using the method for in-face points
2286     // and devide eList into a list of separate wires
2287     bool aBool;
2288     list< list< TopoDS_Edge > > wireList;
2289     list<TopoDS_Edge>::iterator eIt = elIt;
2290     list<int>::iterator nbEIt = nbVertexInWires.begin();
2291     for ( nbEIt++; nbEIt != nbVertexInWires.end(); nbEIt++ )
2292     {
2293       int nbEdges = *nbEIt;
2294       wireList.push_back( list< TopoDS_Edge >() );
2295       list< TopoDS_Edge > & wire = wireList.back();
2296       for ( iE = 0 ; iE < nbEdges; eIt++, iE++ )
2297       {
2298         list< TPoint* > & ePoints = getShapePoints( *eIt );
2299         pIt = ePoints.begin();
2300         for (  pIt++; pIt != ePoints.end(); pIt++ ) {
2301           TPoint* p = (*pIt);
2302           if ( !compUVByIsoIntersection( edgesPointsList, p->myInitUV, p->myUV, aBool )) {
2303             MESSAGE("cant Apply(face)");
2304             return false;
2305           }
2306           // keep the computed UV to compare against by setFirstEdge()
2307           p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2308         }
2309         wire.push_back( *eIt );
2310       }
2311     }
2312     // remove inner edges from eList
2313     eList.erase( elIt, eList.end() );
2314
2315     // sort wireList by nb edges in a wire
2316     sortBySize< TopoDS_Edge > ( wireList );
2317
2318     // an ID of the first edge of a boundary
2319     int id1 = nbVertices + nbEdgesInOuterWire + 1;
2320 //     if ( nbSeamShapes > 0 )
2321 //       id1 += 2; // 2 vertices more
2322
2323     // find points - edge correspondence for wires of unique size,
2324     // edge order within a wire should be defined only
2325
2326     list< list< TopoDS_Edge > >::iterator wlIt = wireList.begin();
2327     while ( wlIt != wireList.end() )
2328     {
2329       list< TopoDS_Edge >& wire = (*wlIt);
2330       int nbEdges = wire.size();
2331       wlIt++;
2332       if ( wlIt == wireList.end() || (*wlIt).size() != nbEdges ) // a unique size wire
2333       {
2334         // choose the best first edge of a wire
2335         setFirstEdge( wire, id1 );
2336
2337         // compute eventual UV and collect on-edge points
2338         edgesPointsList.push_back( list< TPoint* >() );
2339         edgesPoints = & edgesPointsList.back();
2340         int eID = id1;
2341         for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2342         {
2343           list< TPoint* > & ePoints = getShapePoints( eID++ );
2344           computeUVOnEdge( *eIt, ePoints );
2345           edgesPoints->insert( edgesPoints->end(), ePoints.begin(), (--ePoints.end()));
2346         }
2347       }
2348       id1 += nbEdges;
2349     }
2350
2351     // find boundary - wire correspondence for several wires of same size
2352     
2353     id1 = nbVertices + nbEdgesInOuterWire + 1;
2354     wlIt = wireList.begin();
2355     while ( wlIt != wireList.end() )
2356     {
2357       int nbSameSize = 0, nbEdges = (*wlIt).size();
2358       list< list< TopoDS_Edge > >::iterator wlIt2 = wlIt;
2359       wlIt2++;
2360       while ( wlIt2 != wireList.end() && (*wlIt2).size() == nbEdges ) { // a same size wire
2361         nbSameSize++;
2362         wlIt2++;
2363       }
2364       if ( nbSameSize > 0 )
2365         if (!sortSameSizeWires(wireList, wlIt, wlIt2, id1, edgesPointsList))
2366           return false;
2367       wlIt = wlIt2;
2368       id1 += nbEdges * ( nbSameSize + 1 );
2369     }
2370
2371     // add well-ordered edges to eList
2372     
2373     for ( wlIt = wireList.begin(); wlIt != wireList.end(); wlIt++ )
2374     {
2375       list< TopoDS_Edge >& wire = (*wlIt);
2376       eList.splice( eList.end(), wire, wire.begin(), wire.end() );
2377     }
2378
2379     // re-fill myShapeIDMap - all shapes get good IDs
2380
2381     myShapeIDMap.Clear();
2382     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2383       myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2384     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2385       myShapeIDMap.Add( *elIt );
2386     myShapeIDMap.Add( face );
2387     
2388   } // there are inner wires
2389
2390   // Compute XYZ of on-edge points
2391
2392   TopLoc_Location loc;
2393   for ( iE = nbVertices + 1, elIt = eList.begin(); elIt != eList.end(); elIt++ )
2394   {
2395     double f,l;
2396     Handle(Geom_Curve) C3d = BRep_Tool::Curve( *elIt, loc, f, l );
2397     const gp_Trsf & aTrsf = loc.Transformation();
2398     list< TPoint* > & ePoints = getShapePoints( iE++ );
2399     pIt = ePoints.begin();
2400     for ( pIt++; pIt != ePoints.end(); pIt++ )
2401     {
2402       TPoint* point = *pIt;
2403       point->myXYZ = C3d->Value( point->myU );
2404       if ( !loc.IsIdentity() )
2405         aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2406     }
2407   }
2408
2409   // Compute UV and XYZ of in-face points
2410
2411   // try to use a simple algo
2412   list< TPoint* > & fPoints = getShapePoints( face );
2413   bool isDeformed = false;
2414   for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2415     if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2416                                   (*pIt)->myUV, isDeformed )) {
2417       MESSAGE("cant Apply(face)");
2418       return false;
2419     }
2420   // try to use a complex algo if it is a difficult case
2421   if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2422   {
2423     for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2424       if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2425                                     (*pIt)->myUV, isDeformed )) {
2426         MESSAGE("cant Apply(face)");
2427         return false;
2428       }
2429   }
2430
2431   Handle(Geom_Surface) aSurface = BRep_Tool::Surface( face, loc );
2432   const gp_Trsf & aTrsf = loc.Transformation();
2433   for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2434   {
2435     TPoint * point = *pIt;
2436     point->myXYZ = aSurface->Value( point->myUV.X(), point->myUV.Y() );
2437     if ( !loc.IsIdentity() )
2438       aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2439   }
2440
2441   myIsComputed = true;
2442
2443   return setErrorCode( ERR_OK );
2444 }
2445
2446 //=======================================================================
2447 //function : Apply
2448 //purpose  : Compute nodes coordinates applying
2449 //           the loaded pattern to <theFace>. The first key-point
2450 //           will be mapped into <theNodeIndexOnKeyPoint1>-th node
2451 //=======================================================================
2452
2453 bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace,
2454                            const int            theNodeIndexOnKeyPoint1,
2455                            const bool           theReverse)
2456 {
2457   MESSAGE(" ::Apply(MeshFace) " );
2458
2459   if ( !IsLoaded() ) {
2460     MESSAGE( "Pattern not loaded" );
2461     return setErrorCode( ERR_APPL_NOT_LOADED );
2462   }
2463
2464   // check nb of nodes
2465   if (theFace->NbNodes() != myNbKeyPntInBoundary.front() ) {
2466     MESSAGE( myKeyPointIDs.size() << " != " << theFace->NbNodes() );
2467     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2468   }
2469
2470   // find points on edges, it fills myNbKeyPntInBoundary
2471   if ( !findBoundaryPoints() )
2472     return false;
2473
2474   // check that there are no holes in a pattern
2475   if (myNbKeyPntInBoundary.size() > 1 ) {
2476     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2477   }
2478
2479   // Define the nodes order
2480
2481   list< const SMDS_MeshNode* > nodes;
2482   list< const SMDS_MeshNode* >::iterator n = nodes.end();
2483   SMDS_ElemIteratorPtr noIt = theFace->nodesIterator();
2484   int iSub = 0;
2485   while ( noIt->more() ) {
2486     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( noIt->next() );
2487     nodes.push_back( node );
2488     if ( iSub++ == theNodeIndexOnKeyPoint1 )
2489       n = --nodes.end();
2490   }
2491   if ( n != nodes.end() ) {
2492     if ( theReverse ) {
2493       if ( n != --nodes.end() )
2494         nodes.splice( nodes.begin(), nodes, ++n, nodes.end() );
2495       nodes.reverse();
2496     }
2497     else if ( n != nodes.begin() )
2498       nodes.splice( nodes.end(), nodes, nodes.begin(), n );
2499   }
2500   list< gp_XYZ > xyzList;
2501   myOrderedNodes.resize( theFace->NbNodes() );
2502   for ( iSub = 0, n = nodes.begin(); n != nodes.end(); ++n ) {
2503     xyzList.push_back( gp_XYZ( (*n)->X(), (*n)->Y(), (*n)->Z() ));
2504     myOrderedNodes[ iSub++] = *n;
2505   }
2506
2507   // Define a face plane
2508
2509   list< gp_XYZ >::iterator xyzIt = xyzList.begin();
2510   gp_Pnt P ( *xyzIt++ );
2511   gp_Vec Vx( P, *xyzIt++ ), N;
2512   do {
2513     N = Vx ^ gp_Vec( P, *xyzIt++ );
2514   } while ( N.SquareMagnitude() <= DBL_MIN && xyzIt != xyzList.end() );
2515   if ( N.SquareMagnitude() <= DBL_MIN )
2516     return setErrorCode( ERR_APPLF_BAD_FACE_GEOM );
2517   gp_Ax2 pos( P, N, Vx );
2518
2519   // Compute UV of key-points on a plane
2520   for ( xyzIt = xyzList.begin(), iSub = 1; xyzIt != xyzList.end(); xyzIt++, iSub++ )
2521   {
2522     gp_Vec vec ( pos.Location(), *xyzIt );
2523     TPoint* p = getShapePoints( iSub ).front();
2524     p->myUV.SetX( vec * pos.XDirection() );
2525     p->myUV.SetY( vec * pos.YDirection() );
2526     p->myXYZ = *xyzIt;
2527   }
2528
2529   // points on edges to be used for UV computation of in-face points
2530   list< list< TPoint* > > edgesPointsList;
2531   edgesPointsList.push_back( list< TPoint* >() );
2532   list< TPoint* > * edgesPoints = & edgesPointsList.back();
2533   list< TPoint* >::iterator pIt;
2534
2535   // compute UV and XYZ of points on edges
2536
2537   for ( xyzIt = xyzList.begin(); xyzIt != xyzList.end(); iSub++ )
2538   {
2539     gp_XYZ& xyz1 = *xyzIt++;
2540     gp_XYZ& xyz2 = ( xyzIt != xyzList.end() ) ? *xyzIt : xyzList.front();
2541     
2542     list< TPoint* > & ePoints = getShapePoints( iSub );
2543     ePoints.back()->myInitU = 1.0;
2544     list< TPoint* >::const_iterator pIt = ++ePoints.begin();
2545     while ( *pIt != ePoints.back() )
2546     {
2547       TPoint* p = *pIt++;
2548       p->myXYZ = xyz1 * ( 1 - p->myInitU ) + xyz2 * p->myInitU;
2549       gp_Vec vec ( pos.Location(), p->myXYZ );
2550       p->myUV.SetX( vec * pos.XDirection() );
2551       p->myUV.SetY( vec * pos.YDirection() );
2552     }
2553     // collect on-edge points (excluding the last one)
2554     edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2555   }
2556
2557   // Compute UV and XYZ of in-face points
2558
2559   // try to use a simple algo to compute UV
2560   list< TPoint* > & fPoints = getShapePoints( iSub );
2561   bool isDeformed = false;
2562   for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2563     if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2564                                   (*pIt)->myUV, isDeformed )) {
2565       MESSAGE("cant Apply(face)");
2566       return false;
2567     }
2568   // try to use a complex algo if it is a difficult case
2569   if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2570   {
2571     for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2572       if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2573                                     (*pIt)->myUV, isDeformed )) {
2574         MESSAGE("cant Apply(face)");
2575         return false;
2576       }
2577   }
2578
2579   for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2580   {
2581     (*pIt)->myXYZ = ElSLib::PlaneValue( (*pIt)->myUV.X(), (*pIt)->myUV.Y(), pos );
2582   }
2583
2584   myIsComputed = true;
2585
2586   return setErrorCode( ERR_OK );
2587 }
2588
2589 //=======================================================================
2590 //function : undefinedXYZ
2591 //purpose  : 
2592 //=======================================================================
2593
2594 static const gp_XYZ& undefinedXYZ()
2595 {
2596   static gp_XYZ xyz( 1.e100, 0., 0. );
2597   return xyz;
2598 }
2599
2600 //=======================================================================
2601 //function : isDefined
2602 //purpose  : 
2603 //=======================================================================
2604
2605 inline static bool isDefined(const gp_XYZ& theXYZ)
2606 {
2607   return theXYZ.X() < 1.e100;
2608 }
2609
2610 //=======================================================================
2611 //function : mergePoints
2612 //purpose  : Look for coincident points between myXYZs indexed with
2613 //           list<int> of each element of xyzIndGroups. Coincident indices
2614 //           are merged in myElemXYZIDs.
2615 //=======================================================================
2616
2617 void SMESH_Pattern::mergePoints (map<TNodeSet, list<list<int> > >&  indGroups,
2618                                  map< int, list< list< int >* > > & reverseConnectivity)
2619 {
2620   map< TNodeSet, list< list< int > > >::iterator indListIt;
2621   for ( indListIt = indGroups.begin(); indListIt != indGroups.end(); indListIt++ )
2622   {
2623     list<list< int > > groups = indListIt->second;
2624     if ( groups.size() < 2 )
2625       continue;
2626
2627 //     const TNodeSet & nodes = indListIt->first;
2628 //     TNodeSet::const_iterator n = nodes.begin();
2629 //     for ( ; n != nodes.end(); n++ )
2630 //       cout << *n ;
2631
2632     // find tolerance
2633     Bnd_Box box;
2634     list< int >& indices = groups.front();
2635     list< int >::iterator ind, ind1, ind2;
2636     for ( ind = indices.begin(); ind != indices.end(); ind++ )
2637       box.Add( gp_Pnt( myXYZ[ *ind ]));
2638     double x, y, z, X, Y, Z;
2639     box.Get( x, y, z, X, Y, Z );
2640     gp_Pnt p( x, y, z ), P( X, Y, Z );
2641     double tol2 = 1.e-4 * p.SquareDistance( P );
2642
2643     // compare points, replace indices
2644
2645     list< list< int > >::iterator grpIt1, grpIt2;
2646     for ( grpIt1 = groups.begin(); grpIt1 != groups.end(); grpIt1++ )
2647     {
2648       list< int >& indices1 = *grpIt1;
2649       grpIt2 = grpIt1;
2650       for ( grpIt2++; grpIt2 != groups.end(); grpIt2++ )
2651       {
2652         list< int >& indices2 = *grpIt2;
2653         for ( ind1 = indices1.begin(); ind1 != indices1.end(); ind1++ )
2654         {
2655           gp_XYZ& p1 = myXYZ[ *ind1 ];
2656           ind2 = indices2.begin();
2657           while ( ind2 != indices2.end() )
2658           {
2659             gp_XYZ& p2 = myXYZ[ *ind2 ];
2660             //MESSAGE("COMP: " << *ind1 << " " << *ind2 << " X: " << p2.X() << " tol2: " << tol2);
2661             if ( ( p1 - p2 ).SquareModulus() <= tol2 )
2662             {
2663               ASSERT( reverseConnectivity.find( *ind2 ) != reverseConnectivity.end() );
2664               list< list< int >* > & elemXYZIDsList = reverseConnectivity[ *ind2 ];
2665               list< list< int >* >::iterator elemXYZIDs = elemXYZIDsList.begin();
2666               for ( ; elemXYZIDs != elemXYZIDsList.end(); elemXYZIDs++ )
2667               {
2668                 ind = find( (*elemXYZIDs)->begin(), (*elemXYZIDs)->end(), *ind2 );
2669                 //MESSAGE( " Replace " << *ind << " with " << *ind1 );
2670                 myXYZ[ *ind ] = undefinedXYZ();
2671                 *ind = *ind1;
2672               }
2673               ind2 = indices2.erase( ind2 );
2674             }
2675             else
2676               ind2++;
2677           }
2678         }
2679       }
2680     }
2681   }
2682 }
2683
2684 //=======================================================================
2685 //function : Apply
2686 //purpose  : Compute nodes coordinates applying
2687 //           the loaded pattern to <theFaces>. The first key-point
2688 //           will be mapped into <theNodeIndexOnKeyPoint1>-th node
2689 //=======================================================================
2690
2691 bool SMESH_Pattern::Apply (std::set<const SMDS_MeshFace*> theFaces,
2692                            const int                      theNodeIndexOnKeyPoint1,
2693                            const bool                     theReverse)
2694 {
2695   MESSAGE(" ::Apply(set<MeshFace>) " );
2696
2697   if ( !IsLoaded() ) {
2698     MESSAGE( "Pattern not loaded" );
2699     return setErrorCode( ERR_APPL_NOT_LOADED );
2700   }
2701
2702   // find points on edges, it fills myNbKeyPntInBoundary
2703   if ( !findBoundaryPoints() )
2704     return false;
2705
2706   // check that there are no holes in a pattern
2707   if (myNbKeyPntInBoundary.size() > 1 ) {
2708     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2709   }
2710
2711   myXYZ.clear();
2712   myElemXYZIDs.clear();
2713   myXYZIdToNodeMap.clear();
2714   myElements.clear();
2715
2716   myXYZ.resize( myPoints.size() * theFaces.size(), undefinedXYZ() );
2717   myElements.reserve( theFaces.size() );
2718
2719   // to find point index
2720   map< TPoint*, int > pointIndex;
2721   for ( int i = 0; i < myPoints.size(); i++ )
2722     pointIndex.insert( make_pair( & myPoints[ i ], i ));
2723
2724   // to merge nodes on edges of the elements being refined
2725   typedef set<const SMDS_MeshNode*> TLink;
2726   map< TLink, list< list< int > > > linkPointIndListMap;
2727   map< int, list< list< int >* > >  reverseConnectivity;
2728
2729   int ind1 = 0; // lowest point index for a face
2730
2731   // apply to each face in theFaces set
2732   set<const SMDS_MeshFace*>::iterator face = theFaces.begin();
2733   for ( ; face != theFaces.end(); ++face )
2734   {
2735     if ( !Apply( *face, theNodeIndexOnKeyPoint1, theReverse )) {
2736       MESSAGE( "Failed on " << *face );
2737       continue;
2738     }
2739     myElements.push_back( *face );
2740
2741     // store computed points belonging to elements
2742     list< list< int > >::iterator ll = myElemPointIDs.begin();
2743     for ( ; ll != myElemPointIDs.end(); ++ll )
2744     {
2745       myElemXYZIDs.push_back();
2746       list< int >& xyzIds = myElemXYZIDs.back();
2747       list< int >& pIds = *ll;
2748       for ( list<int>::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
2749         int pIndex = *id + ind1;
2750         xyzIds.push_back( pIndex );
2751         myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
2752         reverseConnectivity[ pIndex ].push_back( & xyzIds );
2753       }
2754     }
2755     // put points on links to linkPointIndListMap
2756     int nbNodes = (*face)->NbNodes(), eID = nbNodes + 1;
2757     for ( int i = 0; i < nbNodes; i++ )
2758     {
2759       const SMDS_MeshNode* n1 = myOrderedNodes[ i ];
2760       const SMDS_MeshNode* n2 = myOrderedNodes[ i + 1 == nbNodes ? 0 : i + 1 ];
2761       // make a link of node pointers
2762       TLink link;
2763       link.insert( n1 );
2764       link.insert( n2 );
2765       // add the link to the map
2766       list< list< int > >& groups = linkPointIndListMap[ link ];
2767       groups.push_back();
2768       list< int >& indList = groups.back();
2769       list< TPoint* > & linkPoints = getShapePoints( eID++ );
2770       list< TPoint* >::iterator p = linkPoints.begin();
2771       // map the first link point to n1
2772       myXYZIdToNodeMap[ pointIndex[ *p ] + ind1 ] = n1;
2773       // add points to the map excluding the end points
2774       for ( p++; *p != linkPoints.back(); p++ )
2775         indList.push_back( pointIndex[ *p ] + ind1 );
2776     }
2777     ind1 += myPoints.size();
2778   }
2779
2780   mergePoints( linkPointIndListMap, reverseConnectivity );
2781
2782   return !myElemXYZIDs.empty();
2783 }
2784
2785 //=======================================================================
2786 //function : Apply
2787 //purpose  : Compute nodes coordinates applying
2788 //           the loaded pattern to <theVolumes>. The (0,0,0) key-point
2789 //           will be mapped into <theNode000Index>-th node. The
2790 //           (0,0,1) key-point will be mapped into <theNode000Index>-th
2791 //           node.
2792 //=======================================================================
2793
2794 bool SMESH_Pattern::Apply (std::set<const SMDS_MeshVolume*> theVolumes,
2795                            const int                        theNode000Index,
2796                            const int                        theNode001Index)
2797 {
2798   MESSAGE(" ::Apply(set<MeshVolumes>) " );
2799
2800   if ( !IsLoaded() ) {
2801     MESSAGE( "Pattern not loaded" );
2802     return setErrorCode( ERR_APPL_NOT_LOADED );
2803   }
2804
2805    // bind ID to points
2806   if ( !findBoundaryPoints() )
2807     return false;
2808
2809   // check that there are no holes in a pattern
2810   if (myNbKeyPntInBoundary.size() > 1 ) {
2811     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2812   }
2813
2814   myXYZ.clear();
2815   myElemXYZIDs.clear();
2816   myXYZIdToNodeMap.clear();
2817   myElements.clear();
2818
2819   myXYZ.resize( myPoints.size() * theVolumes.size(), undefinedXYZ() );
2820   myElements.reserve( theVolumes.size() );
2821
2822   // to find point index
2823   map< TPoint*, int > pointIndex;
2824   for ( int i = 0; i < myPoints.size(); i++ )
2825     pointIndex.insert( make_pair( & myPoints[ i ], i ));
2826
2827   // to merge nodes on edges and faces of the elements being refined
2828   map< TNodeSet, list< list< int > > > subPointIndListMap;
2829   map< int, list< list< int >* > >  reverseConnectivity;
2830
2831   int ind1 = 0; // lowest point index for an element
2832
2833   // apply to each element in theVolumes set
2834   set<const SMDS_MeshVolume*>::iterator vol = theVolumes.begin();
2835   for ( ; vol != theVolumes.end(); ++vol )
2836   {
2837     if ( !Apply( *vol, theNode000Index, theNode001Index )) {
2838       MESSAGE( "Failed on " << *vol );
2839       continue;
2840     }
2841     myElements.push_back( *vol );
2842
2843     // store computed points belonging to elements
2844     list< list< int > >::iterator ll = myElemPointIDs.begin();
2845     for ( ; ll != myElemPointIDs.end(); ++ll )
2846     {
2847       myElemXYZIDs.push_back();
2848       list< int >& xyzIds = myElemXYZIDs.back();
2849       list< int >& pIds = *ll;
2850       for ( list<int>::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
2851         int pIndex = *id + ind1;
2852         xyzIds.push_back( pIndex );
2853         myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
2854         reverseConnectivity[ pIndex ].push_back( & xyzIds );
2855       }
2856     }
2857     // put points on edges and faces to subPointIndListMap
2858     for ( int Id = SMESH_Block::ID_V000; Id <= SMESH_Block::ID_F1yz; Id++ )
2859     {
2860       // make a set of sub-points
2861       TNodeSet subNodes;
2862       vector< int > subIDs;
2863       if ( SMESH_Block::IsVertexID( Id )) {
2864         // use nodes of refined volumes for merge
2865       }
2866       else if ( SMESH_Block::IsEdgeID( Id )) {
2867         SMESH_Block::GetEdgeVertexIDs( Id, subIDs );
2868         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2869         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2870       }
2871       else {
2872         SMESH_Block::GetFaceEdgesIDs( Id, subIDs );
2873         int e1 = subIDs[ 0 ], e2 = subIDs[ 1 ];
2874         SMESH_Block::GetEdgeVertexIDs( e1, subIDs );
2875         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2876         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2877         SMESH_Block::GetEdgeVertexIDs( e2, subIDs );
2878         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2879         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2880       }
2881       list< list< int > >& groups = subPointIndListMap[ subNodes ];
2882       groups.push_back();
2883       list< int >& indList = groups.back();
2884       // add points
2885       list< TPoint* > & points = getShapePoints( Id );
2886       list< TPoint* >::iterator p = points.begin();
2887       if ( subNodes.empty() ) // vertex case
2888         myXYZIdToNodeMap[ pointIndex[ *p ] + ind1 ] = myOrderedNodes[ Id - 1 ];
2889       else
2890         for ( ; p != points.end(); p++ )
2891           indList.push_back( pointIndex[ *p ] + ind1 );
2892     }
2893     ind1 += myPoints.size();
2894   }
2895
2896   mergePoints( subPointIndListMap, reverseConnectivity );
2897
2898   return !myElemXYZIDs.empty();
2899 }
2900
2901 //=======================================================================
2902 //function : Load
2903 //purpose  : Create a pattern from the mesh built on <theBlock>
2904 //=======================================================================
2905
2906 bool SMESH_Pattern::Load (SMESH_Mesh*         theMesh,
2907                           const TopoDS_Shell& theBlock)
2908 {
2909   MESSAGE(" ::Load(volume) " );
2910   Clear();
2911   myIs2D = false;
2912   SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
2913
2914   // load shapes in myShapeIDMap
2915   SMESH_Block block;
2916   TopoDS_Vertex v1, v2;
2917   if ( !block.LoadBlockShapes( theBlock, v1, v2, myShapeIDMap ))
2918     return setErrorCode( ERR_LOADV_BAD_SHAPE );
2919
2920   // count nodes
2921   int nbNodes = 0, shapeID;
2922   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2923   {
2924     const TopoDS_Shape& S = myShapeIDMap( shapeID );
2925     SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2926     if ( aSubMesh )
2927       nbNodes += aSubMesh->NbNodes();
2928   }
2929   myPoints.resize( nbNodes );
2930
2931   // load U of points on edges
2932   TNodePointIDMap nodePointIDMap;
2933   int iPoint = 0;
2934   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2935   {
2936     const TopoDS_Shape& S = myShapeIDMap( shapeID );
2937     list< TPoint* > & shapePoints = getShapePoints( shapeID );
2938     SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2939     if ( ! aSubMesh ) continue;
2940     SMDS_NodeIteratorPtr nIt = aSubMesh->GetNodes();
2941     if ( !nIt->more() ) continue;
2942
2943       // store a node and a point
2944     while ( nIt->more() ) {
2945       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
2946       nodePointIDMap.insert( make_pair( node, iPoint ));
2947       if ( block.IsVertexID( shapeID ))
2948         myKeyPointIDs.push_back( iPoint );
2949       TPoint* p = & myPoints[ iPoint++ ];
2950       shapePoints.push_back( p );
2951       p->myXYZ.SetCoord( node->X(), node->Y(), node->Z() );
2952       p->myInitXYZ.SetCoord( 0,0,0 );
2953     }
2954     list< TPoint* >::iterator pIt = shapePoints.begin();
2955
2956     // compute init XYZ
2957     switch ( S.ShapeType() )
2958     {
2959     case TopAbs_VERTEX:
2960     case TopAbs_EDGE: {
2961
2962       for ( ; pIt != shapePoints.end(); pIt++ ) {
2963         double * coef = block.GetShapeCoef( shapeID );
2964         for ( int iCoord = 1; iCoord <= 3; iCoord++ )
2965           if ( coef[ iCoord - 1] > 0 )
2966             (*pIt)->myInitXYZ.SetCoord( iCoord, 1. );
2967       }
2968       if ( S.ShapeType() == TopAbs_VERTEX )
2969         break;
2970
2971       const TopoDS_Edge& edge = TopoDS::Edge( S );
2972       double f,l;
2973       BRep_Tool::Range( edge, f, l );
2974       int iCoord     = SMESH_Block::GetCoordIndOnEdge( shapeID );
2975       bool isForward = SMESH_Block::IsForwardEdge( edge, myShapeIDMap );
2976       pIt = shapePoints.begin();
2977       nIt = aSubMesh->GetNodes();
2978       for ( ; nIt->more(); pIt++ )
2979       {
2980         const SMDS_MeshNode* node = 
2981           static_cast<const SMDS_MeshNode*>( nIt->next() );
2982         const SMDS_EdgePosition* epos =
2983           static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
2984         double u = ( epos->GetUParameter() - f ) / ( l - f );
2985         (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u );
2986       }
2987       break;
2988     }
2989     default:
2990       for ( ; pIt != shapePoints.end(); pIt++ )
2991       {
2992         if ( !block.ComputeParameters( (*pIt)->myXYZ, (*pIt)->myInitXYZ, shapeID )) {
2993           MESSAGE( "!block.ComputeParameters()" );
2994           return setErrorCode( ERR_LOADV_COMPUTE_PARAMS );
2995         }
2996       }
2997     }
2998   } // loop on block sub-shapes
2999
3000   // load elements
3001
3002   SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( theBlock );
3003   if ( aSubMesh )
3004   {
3005     SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements();
3006     while ( elemIt->more() ) {
3007       SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
3008       myElemPointIDs.push_back( list< int >() );
3009       list< int >& elemPoints = myElemPointIDs.back();
3010       while ( nIt->more() )
3011         elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
3012     }
3013   }
3014
3015   myIsBoundaryPointsFound = true;
3016
3017   return setErrorCode( ERR_OK );
3018 }
3019
3020 //=======================================================================
3021 //function : Apply
3022 //purpose  : Compute nodes coordinates applying
3023 //           the loaded pattern to <theBlock>. The (0,0,0) key-point
3024 //           will be mapped into <theVertex000>. The (0,0,1)
3025 //           fifth key-point will be mapped into <theVertex001>.
3026 //=======================================================================
3027
3028 bool SMESH_Pattern::Apply (const TopoDS_Shell&  theBlock,
3029                            const TopoDS_Vertex& theVertex000,
3030                            const TopoDS_Vertex& theVertex001)
3031 {
3032   MESSAGE(" ::Apply(volume) " );
3033
3034   if (!findBoundaryPoints()     || // bind ID to points
3035       !setShapeToMesh( theBlock )) // check theBlock is a suitable shape
3036     return false;
3037
3038   SMESH_Block block;  // bind ID to shape
3039   if (!block.LoadBlockShapes( theBlock, theVertex000, theVertex001, myShapeIDMap ))
3040     return setErrorCode( ERR_APPLV_BAD_SHAPE );
3041
3042   // compute XYZ of points on shapes
3043
3044   for ( int shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
3045   {
3046     list< TPoint* > & shapePoints = getShapePoints( shapeID );
3047     list< TPoint* >::iterator pIt = shapePoints.begin();
3048     const TopoDS_Shape& S = myShapeIDMap( shapeID );
3049     switch ( S.ShapeType() )
3050     {
3051     case TopAbs_VERTEX: {
3052
3053       for ( ; pIt != shapePoints.end(); pIt++ )
3054         block.VertexPoint( shapeID, (*pIt)->myXYZ.ChangeCoord() );
3055       break;
3056     }
3057     case TopAbs_EDGE: {
3058
3059       for ( ; pIt != shapePoints.end(); pIt++ )
3060         block.EdgePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3061       break;
3062     }
3063     case TopAbs_FACE: {
3064
3065       for ( ; pIt != shapePoints.end(); pIt++ )
3066         block.FacePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3067       break;
3068     }
3069     default:
3070       for ( ; pIt != shapePoints.end(); pIt++ )
3071         block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3072     }
3073   } // loop on block sub-shapes
3074
3075   myIsComputed = true;
3076
3077   return setErrorCode( ERR_OK );
3078 }
3079
3080 //=======================================================================
3081 //function : Apply
3082 //purpose  : Compute nodes coordinates applying
3083 //           the loaded pattern to <theVolume>. The (0,0,0) key-point
3084 //           will be mapped into <theNode000Index>-th node. The
3085 //           (0,0,1) key-point will be mapped into <theNode000Index>-th
3086 //           node.
3087 //=======================================================================
3088
3089 bool SMESH_Pattern::Apply (const SMDS_MeshVolume* theVolume,
3090                            const int              theNode000Index,
3091                            const int              theNode001Index)
3092 {
3093   MESSAGE(" ::Apply(MeshVolume) " );
3094
3095   if (!findBoundaryPoints()) // bind ID to points
3096     return false;
3097
3098   SMESH_Block block;  // bind ID to shape
3099   if (!block.LoadMeshBlock( theVolume, theNode000Index, theNode001Index, myOrderedNodes ))
3100     return setErrorCode( ERR_APPLV_BAD_SHAPE );
3101   // compute XYZ of points on shapes
3102
3103   for ( int ID = SMESH_Block::ID_V000; ID <= SMESH_Block::ID_Shell; ID++ )
3104   {
3105     list< TPoint* > & shapePoints = getShapePoints( ID );
3106     list< TPoint* >::iterator pIt = shapePoints.begin();
3107
3108     if ( block.IsVertexID( ID ))
3109       for ( ; pIt != shapePoints.end(); pIt++ ) {
3110         block.VertexPoint( ID, (*pIt)->myXYZ.ChangeCoord() );
3111       }
3112     else if ( block.IsEdgeID( ID ))
3113       for ( ; pIt != shapePoints.end(); pIt++ ) {
3114         block.EdgePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3115       }
3116     else if ( block.IsFaceID( ID ))
3117       for ( ; pIt != shapePoints.end(); pIt++ ) {
3118         block.FacePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3119       }
3120     else
3121       for ( ; pIt != shapePoints.end(); pIt++ )
3122         block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3123   } // loop on block sub-shapes
3124
3125   myIsComputed = true;
3126
3127   return setErrorCode( ERR_OK );
3128 }
3129
3130 //=======================================================================
3131 //function : MakeMesh
3132 //purpose  : Create nodes and elements in <theMesh> using nodes
3133 //           coordinates computed by either of Apply...() methods
3134 //=======================================================================
3135
3136 bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh)
3137 {
3138   MESSAGE(" ::MakeMesh() " );
3139   if ( !myIsComputed )
3140     return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
3141
3142   SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
3143   SMESH_MeshEditor editor( theMesh ); 
3144
3145   // clear elements and nodes existing on myShape
3146
3147   if ( !myShape.IsNull() )
3148   {
3149     SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( myShape );
3150     SMESHDS_SubMesh * aSubMeshDS = aMeshDS->MeshElements( myShape );
3151     if ( aSubMesh )
3152       aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
3153     else if ( aSubMeshDS )
3154     {
3155       SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
3156       while ( eIt->more() )
3157         aMeshDS->RemoveElement( eIt->next() );
3158       SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
3159       while ( nIt->more() )
3160         aMeshDS->RemoveNode( static_cast<const SMDS_MeshNode*>( nIt->next() ));
3161     }
3162   }
3163
3164   bool onMeshElements = ( !myElements.empty() );
3165
3166   // loop on sub-shapes of myShape: create nodes and build point-node map
3167
3168   vector< const SMDS_MeshNode* >       nodesVector;
3169   map< TPoint*, const SMDS_MeshNode* > pointNodeMap;
3170   if ( onMeshElements )
3171   {
3172     nodesVector.resize( myXYZ.size() );
3173     for ( int i = 0; i < myXYZ.size(); ++i ) {
3174       map< int, const SMDS_MeshNode*>::iterator idNode = myXYZIdToNodeMap.find( i );
3175       if ( idNode != myXYZIdToNodeMap.end() )
3176         nodesVector[ i ] = idNode->second;
3177       else if ( isDefined( myXYZ[ i ] ))
3178         nodesVector[ i ] = aMeshDS->AddNode (myXYZ[ i ].X(),
3179                                              myXYZ[ i ].Y(),
3180                                              myXYZ[ i ].Z());
3181     }
3182   }
3183   else
3184   {
3185     map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
3186     for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
3187     {
3188       TopoDS_Shape S;
3189       SMESHDS_SubMesh * subMeshDS = 0;
3190       if ( !myShapeIDMap.IsEmpty() ) {
3191         S = myShapeIDMap( idPointIt->first );
3192         subMeshDS = aMeshDS->MeshElements( S );
3193       }
3194       list< TPoint* > & points = idPointIt->second;
3195       list< TPoint* >::iterator pIt = points.begin();
3196       for ( ; pIt != points.end(); pIt++ )
3197       {
3198         TPoint* point = *pIt;
3199         if ( pointNodeMap.find( point ) != pointNodeMap.end() )
3200           continue;
3201         SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
3202                                                 point->myXYZ.Y(),
3203                                                 point->myXYZ.Z());
3204         pointNodeMap.insert( make_pair( point, node ));
3205         if ( subMeshDS ) {
3206           switch ( S.ShapeType() ) {
3207           case TopAbs_VERTEX: {
3208             aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S ));
3209             break;
3210           }
3211           case TopAbs_EDGE: {
3212             aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ));
3213             SMDS_EdgePosition* epos =
3214               dynamic_cast<SMDS_EdgePosition *>(node->GetPosition().get());
3215             epos->SetUParameter( point->myU );
3216             break;
3217           }
3218           case TopAbs_FACE: {
3219             aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ));
3220             SMDS_FacePosition* pos =
3221               dynamic_cast<SMDS_FacePosition *>(node->GetPosition().get());
3222             pos->SetUParameter( point->myUV.X() );
3223             pos->SetVParameter( point->myUV.Y() );
3224             break;
3225           }
3226           default:
3227             aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
3228           }
3229         }
3230       }
3231     }
3232   }
3233   
3234   // create elements
3235
3236   // shapes and groups myElements are on
3237   vector< int > shapeIDs;
3238   vector< list< SMESHDS_Group* > > groups;
3239   if ( onMeshElements )
3240   {
3241     shapeIDs.resize( myElements.size() );
3242     groups.resize( myElements.size() );
3243     const set<SMESHDS_GroupBase*>& allGroups = aMeshDS->GetGroups();
3244     set<SMESHDS_GroupBase*>::const_iterator grIt;
3245     for ( int i = 0; i < myElements.size(); i++ )
3246     {
3247       shapeIDs[ i ] = editor.FindShape( myElements[ i ] );
3248       for ( grIt = allGroups.begin(); grIt != allGroups.end(); grIt++ ) {
3249         SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
3250         if ( group && group->SMDSGroup().Contains( myElements[ i ] ))
3251           groups[ i ].push_back( group );
3252       }
3253     }
3254   }
3255   int nbElems = myElemPointIDs.size(); // nb elements in a pattern
3256
3257   list<list< int > >::iterator epIt, epEnd;
3258   if ( onMeshElements ) {
3259     epIt  = myElemXYZIDs.begin();
3260     epEnd = myElemXYZIDs.end();
3261   }
3262   else {
3263     epIt  = myElemPointIDs.begin();
3264     epEnd = myElemPointIDs.end();
3265   }
3266   for ( int iElem = 0; epIt != epEnd; epIt++, iElem++ )
3267   {
3268     list< int > & elemPoints = *epIt;
3269     // retrieve nodes
3270     const SMDS_MeshNode* nodes[ 8 ];
3271     list< int >::iterator iIt = elemPoints.begin();
3272     int nbNodes;
3273     for ( nbNodes = 0; iIt != elemPoints.end(); iIt++ ) {
3274       if ( onMeshElements )
3275         nodes[ nbNodes++ ] = nodesVector[ *iIt ];
3276       else
3277         nodes[ nbNodes++ ] = pointNodeMap[ & myPoints[ *iIt ]];
3278     }
3279     // add an element
3280     const SMDS_MeshElement* elem = 0;
3281     if ( myIs2D ) {
3282       switch ( nbNodes ) {
3283       case 3:
3284         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
3285       case 4:
3286         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
3287       default:
3288         ASSERT( nbNodes < 8 );
3289       }
3290     }
3291     else {
3292       switch ( nbNodes ) {
3293       case 4:
3294         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
3295       case 5:
3296         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3297                                    nodes[4] ); break;
3298       case 6:
3299         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3300                                    nodes[4], nodes[5] ); break;
3301       case 8:
3302         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3303                                    nodes[4], nodes[5], nodes[6], nodes[7] ); break;
3304       default:
3305         ASSERT( nbNodes < 8 );
3306       }
3307     }
3308     // set element on a shape
3309     if ( elem && onMeshElements )
3310     {
3311       int elemIndex = iElem / nbElems;
3312       if ( shapeIDs[ elemIndex ] > 0 )
3313         aMeshDS->SetMeshElementOnShape( elem, shapeIDs[ elemIndex ] );
3314       // add elem in groups
3315       list< SMESHDS_Group* >::iterator g = groups[ elemIndex ].begin();
3316       for ( ; g != groups[ elemIndex ].end(); ++g )
3317         (*g)->SMDSGroup().Add( elem );
3318     }
3319     if ( elem && !myShape.IsNull() )
3320       aMeshDS->SetMeshElementOnShape( elem, myShape );
3321   }
3322
3323   // make that SMESH_subMesh::_computeState = COMPUTE_OK
3324   // so that operations with hypotheses will erase the mesh being built
3325
3326   SMESH_subMesh * subMesh;
3327   if ( !myShape.IsNull() ) {
3328     subMesh = theMesh->GetSubMeshContaining( myShape );
3329     if ( subMesh )
3330       subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3331   }
3332   if ( onMeshElements ) {
3333     list< int > elemIDs;
3334     for ( int i = 0; i < myElements.size(); i++ )
3335     {
3336       int shapeID = shapeIDs[ i ];
3337       if ( shapeID > 0 ) {
3338         TopoDS_Shape S = aMeshDS->IndexToShape( shapeID );
3339         subMesh = theMesh->GetSubMeshContaining( S );
3340         if ( subMesh )
3341           subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3342       }
3343       elemIDs.push_back( myElements[ i ]->GetID() );
3344     }
3345     // remove refined elements and their nodes
3346     editor.Remove( elemIDs, false );
3347   }
3348
3349   return setErrorCode( ERR_OK );
3350 }
3351
3352
3353 //=======================================================================
3354 //function : arrangeBoundaries
3355 //purpose  : if there are several wires, arrange boundaryPoints so that
3356 //           the outer wire goes first and fix inner wires orientation
3357 //           update myKeyPointIDs to correspond to the order of key-points
3358 //           in boundaries; sort internal boundaries by the nb of key-points
3359 //=======================================================================
3360
3361 void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
3362 {
3363   typedef list< list< TPoint* > >::iterator TListOfListIt;
3364   TListOfListIt bndIt;
3365   list< TPoint* >::iterator pIt;
3366
3367   int nbBoundaries = boundaryList.size();
3368   if ( nbBoundaries > 1 )
3369   {
3370     // sort boundaries by nb of key-points
3371     if ( nbBoundaries > 2 )
3372     {
3373       // move boundaries in tmp list
3374       list< list< TPoint* > > tmpList; 
3375       tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
3376       // make a map nb-key-points to boundary-position-in-tmpList,
3377       // boundary-positions get ordered in it
3378       typedef map< int, TListOfListIt > TNbKpBndPosMap;
3379       TNbKpBndPosMap nbKpBndPosMap;
3380       bndIt = tmpList.begin();
3381       list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
3382       for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
3383         int nb = *nbKpIt * nbBoundaries;
3384         while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
3385           nb++;
3386         nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
3387       }
3388       // move boundaries back to boundaryList
3389       TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
3390       for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
3391         TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
3392         TListOfListIt bndPos1 = bndPos2++;
3393         boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
3394       }
3395     }
3396
3397     // Look for the outer boundary: the one with the point with the least X
3398     double leastX = DBL_MAX;
3399     TListOfListIt outerBndPos;
3400     for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
3401     {
3402       list< TPoint* >& boundary = (*bndIt);
3403       for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
3404       {
3405         TPoint* point = *pIt;
3406         if ( point->myInitXYZ.X() < leastX ) {
3407           leastX = point->myInitXYZ.X();
3408           outerBndPos = bndIt;
3409         }
3410       }
3411     }
3412
3413     if ( outerBndPos != boundaryList.begin() )
3414       boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos );
3415
3416   } // if nbBoundaries > 1
3417                  
3418   // Check boundaries orientation and re-fill myKeyPointIDs
3419
3420   set< TPoint* > keyPointSet;
3421   list< int >::iterator kpIt = myKeyPointIDs.begin();
3422   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
3423     keyPointSet.insert( & myPoints[ *kpIt ]);
3424   myKeyPointIDs.clear();
3425
3426   // update myNbKeyPntInBoundary also
3427   list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
3428
3429   for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
3430   {
3431     // find the point with the least X
3432     double leastX = DBL_MAX;
3433     list< TPoint* >::iterator xpIt;
3434     list< TPoint* >& boundary = (*bndIt);
3435     for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
3436     {
3437       TPoint* point = *pIt;
3438       if ( point->myInitXYZ.X() < leastX ) {
3439         leastX = point->myInitXYZ.X();
3440         xpIt = pIt;
3441       }
3442     }
3443     // find points next to the point with the least X
3444     TPoint* p = *xpIt, *pPrev, *pNext;
3445     if ( p == boundary.front() )
3446       pPrev = *(++boundary.rbegin());
3447     else {
3448       xpIt--;
3449       pPrev = *xpIt;
3450       xpIt++;
3451     }
3452     if ( p == boundary.back() )
3453       pNext = *(++boundary.begin());
3454     else {
3455       xpIt++;
3456       pNext = *xpIt;
3457     }
3458     // vectors of boundary direction near <p>
3459     gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
3460     double sqMag1 = v1.SquareMagnitude(), sqMag2 = v2.SquareMagnitude();
3461     if ( sqMag1 > DBL_MIN && sqMag2 > DBL_MIN ) {
3462       double yPrev = v1.Y() / sqrt( sqMag1 );
3463       double yNext = v2.Y() / sqrt( sqMag2 );
3464       double sumY = yPrev + yNext;
3465       bool reverse;
3466       if ( bndIt == boundaryList.begin() ) // outer boundary
3467         reverse = sumY > 0;
3468       else
3469         reverse = sumY < 0;
3470       if ( reverse )
3471         boundary.reverse();
3472     }
3473
3474     // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
3475     (*nbKpIt) = 0; // count nb of key-points again
3476     pIt = boundary.begin();
3477     for ( ; pIt != boundary.end(); pIt++)
3478     {
3479       TPoint* point = *pIt;
3480       if ( keyPointSet.find( point ) == keyPointSet.end() )
3481         continue;
3482       // find an index of a keypoint
3483       int index = 0;
3484       vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3485       for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
3486         if ( &(*pVecIt) == point )
3487           break;
3488       myKeyPointIDs.push_back( index );
3489       (*nbKpIt)++;
3490     }
3491     myKeyPointIDs.pop_back(); // remove the first key-point from the back
3492     (*nbKpIt)--;
3493
3494   } // loop on a list of boundaries
3495
3496   ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
3497 }
3498