Salome HOME
Do not remove nodes of refined elements
[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.resize( myPoints.size() * theFaces.size(), undefinedXYZ() );
2712   myElements.reserve( theFaces.size() );
2713   myElemXYZIDs.clear();
2714
2715   // to find point index
2716   map< TPoint*, int > pointIndex;
2717   for ( int i = 0; i < myPoints.size(); i++ )
2718     pointIndex.insert( make_pair( & myPoints[ i ], i ));
2719
2720   // to merge nodes on edges of the elements being refined
2721   typedef set<const SMDS_MeshNode*> TLink;
2722   map< TLink, list< list< int > > > linkPointIndListMap;
2723   map< int, list< list< int >* > >  reverseConnectivity;
2724
2725   int ind1 = 0; // lowest point index for a face
2726
2727   // apply to each face in theFaces set
2728   set<const SMDS_MeshFace*>::iterator face = theFaces.begin();
2729   for ( ; face != theFaces.end(); ++face )
2730   {
2731     if ( !Apply( *face, theNodeIndexOnKeyPoint1, theReverse )) {
2732       MESSAGE( "Failed on " << *face );
2733       continue;
2734     }
2735     myElements.push_back( *face );
2736
2737     // store computed points belonging to elements
2738     list< list< int > >::iterator ll = myElemPointIDs.begin();
2739     for ( ; ll != myElemPointIDs.end(); ++ll )
2740     {
2741       myElemXYZIDs.push_back();
2742       list< int >& xyzIds = myElemXYZIDs.back();
2743       list< int >& pIds = *ll;
2744       for ( list<int>::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
2745         int pIndex = *id + ind1;
2746         xyzIds.push_back( pIndex );
2747         myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
2748         reverseConnectivity[ pIndex ].push_back( & xyzIds );
2749       }
2750     }
2751     // put points on links to linkPointIndListMap
2752     int nbNodes = (*face)->NbNodes(), eID = nbNodes + 1;
2753     for ( int i = 0; i < nbNodes; i++ )
2754     {
2755       const SMDS_MeshNode* n1 = myOrderedNodes[ i ];
2756       const SMDS_MeshNode* n2 = myOrderedNodes[ i + 1 == nbNodes ? 0 : i + 1 ];
2757       // make a link of node pointers
2758       TLink link;
2759       link.insert( n1 );
2760       link.insert( n2 );
2761       // add the link to the map
2762       list< list< int > >& groups = linkPointIndListMap[ link ];
2763       groups.push_back();
2764       list< int >& indList = groups.back();
2765       list< TPoint* > & linkPoints = getShapePoints( eID++ );
2766       list< TPoint* >::iterator p = linkPoints.begin();
2767       // map the first link point to n1
2768       myXYZIdToNodeMap[ pointIndex[ *p ] + ind1 ] = n1;
2769       // add points to the map excluding the end points
2770       for ( p++; *p != linkPoints.back(); p++ )
2771         indList.push_back( pointIndex[ *p ] + ind1 );
2772     }
2773     ind1 += myPoints.size();
2774   }
2775
2776   mergePoints( linkPointIndListMap, reverseConnectivity );
2777
2778   return !myElemXYZIDs.empty();
2779 }
2780
2781 //=======================================================================
2782 //function : Apply
2783 //purpose  : Compute nodes coordinates applying
2784 //           the loaded pattern to <theVolumes>. The (0,0,0) key-point
2785 //           will be mapped into <theNode000Index>-th node. The
2786 //           (0,0,1) key-point will be mapped into <theNode000Index>-th
2787 //           node.
2788 //=======================================================================
2789
2790 bool SMESH_Pattern::Apply (std::set<const SMDS_MeshVolume*> theVolumes,
2791                            const int                        theNode000Index,
2792                            const int                        theNode001Index)
2793 {
2794   MESSAGE(" ::Apply(set<MeshVolumes>) " );
2795
2796   if ( !IsLoaded() ) {
2797     MESSAGE( "Pattern not loaded" );
2798     return setErrorCode( ERR_APPL_NOT_LOADED );
2799   }
2800
2801    // bind ID to points
2802   if ( !findBoundaryPoints() )
2803     return false;
2804
2805   // check that there are no holes in a pattern
2806   if (myNbKeyPntInBoundary.size() > 1 ) {
2807     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2808   }
2809
2810   myXYZ.resize( myPoints.size() * theVolumes.size(), undefinedXYZ() );
2811   myElements.reserve( theVolumes.size() );
2812   myElemXYZIDs.clear();
2813
2814   // to find point index
2815   map< TPoint*, int > pointIndex;
2816   for ( int i = 0; i < myPoints.size(); i++ )
2817     pointIndex.insert( make_pair( & myPoints[ i ], i ));
2818
2819   // to merge nodes on edges and faces of the elements being refined
2820   map< TNodeSet, list< list< int > > > subPointIndListMap;
2821   map< int, list< list< int >* > >  reverseConnectivity;
2822
2823   int ind1 = 0; // lowest point index for an element
2824
2825   // apply to each element in theVolumes set
2826   set<const SMDS_MeshVolume*>::iterator vol = theVolumes.begin();
2827   for ( ; vol != theVolumes.end(); ++vol )
2828   {
2829     if ( !Apply( *vol, theNode000Index, theNode001Index )) {
2830       MESSAGE( "Failed on " << *vol );
2831       continue;
2832     }
2833     myElements.push_back( *vol );
2834
2835     // store computed points belonging to elements
2836     list< list< int > >::iterator ll = myElemPointIDs.begin();
2837     for ( ; ll != myElemPointIDs.end(); ++ll )
2838     {
2839       myElemXYZIDs.push_back();
2840       list< int >& xyzIds = myElemXYZIDs.back();
2841       list< int >& pIds = *ll;
2842       for ( list<int>::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
2843         int pIndex = *id + ind1;
2844         xyzIds.push_back( pIndex );
2845         myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
2846         reverseConnectivity[ pIndex ].push_back( & xyzIds );
2847       }
2848     }
2849     // put points on edges and faces to subPointIndListMap
2850     for ( int Id = SMESH_Block::ID_V000; Id <= SMESH_Block::ID_F1yz; Id++ )
2851     {
2852       // make a set of sub-points
2853       TNodeSet subNodes;
2854       vector< int > subIDs;
2855       if ( SMESH_Block::IsVertexID( Id )) {
2856         // use nodes of refined volumes for merge
2857       }
2858       else if ( SMESH_Block::IsEdgeID( Id )) {
2859         SMESH_Block::GetEdgeVertexIDs( Id, subIDs );
2860         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2861         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2862       }
2863       else {
2864         SMESH_Block::GetFaceEdgesIDs( Id, subIDs );
2865         int e1 = subIDs[ 0 ], e2 = subIDs[ 1 ];
2866         SMESH_Block::GetEdgeVertexIDs( e1, subIDs );
2867         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2868         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2869         SMESH_Block::GetEdgeVertexIDs( e2, subIDs );
2870         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
2871         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
2872       }
2873       list< list< int > >& groups = subPointIndListMap[ subNodes ];
2874       groups.push_back();
2875       list< int >& indList = groups.back();
2876       // add points
2877       list< TPoint* > & points = getShapePoints( Id );
2878       list< TPoint* >::iterator p = points.begin();
2879       if ( subNodes.empty() ) // vertex case
2880         myXYZIdToNodeMap[ pointIndex[ *p ] + ind1 ] = myOrderedNodes[ Id - 1 ];
2881       else
2882         for ( ; p != points.end(); p++ )
2883           indList.push_back( pointIndex[ *p ] + ind1 );
2884     }
2885     ind1 += myPoints.size();
2886   }
2887
2888   mergePoints( subPointIndListMap, reverseConnectivity );
2889
2890   return !myElemXYZIDs.empty();
2891 }
2892
2893 //=======================================================================
2894 //function : Load
2895 //purpose  : Create a pattern from the mesh built on <theBlock>
2896 //=======================================================================
2897
2898 bool SMESH_Pattern::Load (SMESH_Mesh*         theMesh,
2899                           const TopoDS_Shell& theBlock)
2900 {
2901   MESSAGE(" ::Load(volume) " );
2902   Clear();
2903   myIs2D = false;
2904   SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
2905
2906   // load shapes in myShapeIDMap
2907   SMESH_Block block;
2908   TopoDS_Vertex v1, v2;
2909   if ( !block.LoadBlockShapes( theBlock, v1, v2, myShapeIDMap ))
2910     return setErrorCode( ERR_LOADV_BAD_SHAPE );
2911
2912   // count nodes
2913   int nbNodes = 0, shapeID;
2914   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2915   {
2916     const TopoDS_Shape& S = myShapeIDMap( shapeID );
2917     SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2918     if ( aSubMesh )
2919       nbNodes += aSubMesh->NbNodes();
2920   }
2921   myPoints.resize( nbNodes );
2922
2923   // load U of points on edges
2924   TNodePointIDMap nodePointIDMap;
2925   int iPoint = 0;
2926   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2927   {
2928     const TopoDS_Shape& S = myShapeIDMap( shapeID );
2929     list< TPoint* > & shapePoints = getShapePoints( shapeID );
2930     SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2931     if ( ! aSubMesh ) continue;
2932     SMDS_NodeIteratorPtr nIt = aSubMesh->GetNodes();
2933     if ( !nIt->more() ) continue;
2934
2935       // store a node and a point
2936     while ( nIt->more() ) {
2937       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
2938       nodePointIDMap.insert( make_pair( node, iPoint ));
2939       if ( block.IsVertexID( shapeID ))
2940         myKeyPointIDs.push_back( iPoint );
2941       TPoint* p = & myPoints[ iPoint++ ];
2942       shapePoints.push_back( p );
2943       p->myXYZ.SetCoord( node->X(), node->Y(), node->Z() );
2944       p->myInitXYZ.SetCoord( 0,0,0 );
2945     }
2946     list< TPoint* >::iterator pIt = shapePoints.begin();
2947
2948     // compute init XYZ
2949     switch ( S.ShapeType() )
2950     {
2951     case TopAbs_VERTEX:
2952     case TopAbs_EDGE: {
2953
2954       for ( ; pIt != shapePoints.end(); pIt++ ) {
2955         double * coef = block.GetShapeCoef( shapeID );
2956         for ( int iCoord = 1; iCoord <= 3; iCoord++ )
2957           if ( coef[ iCoord - 1] > 0 )
2958             (*pIt)->myInitXYZ.SetCoord( iCoord, 1. );
2959       }
2960       if ( S.ShapeType() == TopAbs_VERTEX )
2961         break;
2962
2963       const TopoDS_Edge& edge = TopoDS::Edge( S );
2964       double f,l;
2965       BRep_Tool::Range( edge, f, l );
2966       int iCoord     = SMESH_Block::GetCoordIndOnEdge( shapeID );
2967       bool isForward = SMESH_Block::IsForwardEdge( edge, myShapeIDMap );
2968       pIt = shapePoints.begin();
2969       nIt = aSubMesh->GetNodes();
2970       for ( ; nIt->more(); pIt++ )
2971       {
2972         const SMDS_MeshNode* node = 
2973           static_cast<const SMDS_MeshNode*>( nIt->next() );
2974         const SMDS_EdgePosition* epos =
2975           static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
2976         double u = ( epos->GetUParameter() - f ) / ( l - f );
2977         (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u );
2978       }
2979       break;
2980     }
2981     default:
2982       for ( ; pIt != shapePoints.end(); pIt++ )
2983       {
2984         if ( !block.ComputeParameters( (*pIt)->myXYZ, (*pIt)->myInitXYZ, shapeID )) {
2985           MESSAGE( "!block.ComputeParameters()" );
2986           return setErrorCode( ERR_LOADV_COMPUTE_PARAMS );
2987         }
2988       }
2989     }
2990   } // loop on block sub-shapes
2991
2992   // load elements
2993
2994   SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( theBlock );
2995   if ( aSubMesh )
2996   {
2997     SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements();
2998     while ( elemIt->more() ) {
2999       SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
3000       myElemPointIDs.push_back( list< int >() );
3001       list< int >& elemPoints = myElemPointIDs.back();
3002       while ( nIt->more() )
3003         elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
3004     }
3005   }
3006
3007   myIsBoundaryPointsFound = true;
3008
3009   return setErrorCode( ERR_OK );
3010 }
3011
3012 //=======================================================================
3013 //function : Apply
3014 //purpose  : Compute nodes coordinates applying
3015 //           the loaded pattern to <theBlock>. The (0,0,0) key-point
3016 //           will be mapped into <theVertex000>. The (0,0,1)
3017 //           fifth key-point will be mapped into <theVertex001>.
3018 //=======================================================================
3019
3020 bool SMESH_Pattern::Apply (const TopoDS_Shell&  theBlock,
3021                            const TopoDS_Vertex& theVertex000,
3022                            const TopoDS_Vertex& theVertex001)
3023 {
3024   MESSAGE(" ::Apply(volume) " );
3025
3026   if (!findBoundaryPoints()     || // bind ID to points
3027       !setShapeToMesh( theBlock )) // check theBlock is a suitable shape
3028     return false;
3029
3030   SMESH_Block block;  // bind ID to shape
3031   if (!block.LoadBlockShapes( theBlock, theVertex000, theVertex001, myShapeIDMap ))
3032     return setErrorCode( ERR_APPLV_BAD_SHAPE );
3033
3034   // compute XYZ of points on shapes
3035
3036   for ( int shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
3037   {
3038     list< TPoint* > & shapePoints = getShapePoints( shapeID );
3039     list< TPoint* >::iterator pIt = shapePoints.begin();
3040     const TopoDS_Shape& S = myShapeIDMap( shapeID );
3041     switch ( S.ShapeType() )
3042     {
3043     case TopAbs_VERTEX: {
3044
3045       for ( ; pIt != shapePoints.end(); pIt++ )
3046         block.VertexPoint( shapeID, (*pIt)->myXYZ.ChangeCoord() );
3047       break;
3048     }
3049     case TopAbs_EDGE: {
3050
3051       for ( ; pIt != shapePoints.end(); pIt++ )
3052         block.EdgePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3053       break;
3054     }
3055     case TopAbs_FACE: {
3056
3057       for ( ; pIt != shapePoints.end(); pIt++ )
3058         block.FacePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3059       break;
3060     }
3061     default:
3062       for ( ; pIt != shapePoints.end(); pIt++ )
3063         block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3064     }
3065   } // loop on block sub-shapes
3066
3067   myIsComputed = true;
3068
3069   return setErrorCode( ERR_OK );
3070 }
3071
3072 //=======================================================================
3073 //function : Apply
3074 //purpose  : Compute nodes coordinates applying
3075 //           the loaded pattern to <theVolume>. The (0,0,0) key-point
3076 //           will be mapped into <theNode000Index>-th node. The
3077 //           (0,0,1) key-point will be mapped into <theNode000Index>-th
3078 //           node.
3079 //=======================================================================
3080
3081 bool SMESH_Pattern::Apply (const SMDS_MeshVolume* theVolume,
3082                            const int              theNode000Index,
3083                            const int              theNode001Index)
3084 {
3085   MESSAGE(" ::Apply(MeshVolume) " );
3086
3087   if (!findBoundaryPoints()) // bind ID to points
3088     return false;
3089
3090   SMESH_Block block;  // bind ID to shape
3091   if (!block.LoadMeshBlock( theVolume, theNode000Index, theNode001Index, myOrderedNodes ))
3092     return setErrorCode( ERR_APPLV_BAD_SHAPE );
3093   // compute XYZ of points on shapes
3094
3095   for ( int ID = SMESH_Block::ID_V000; ID <= SMESH_Block::ID_Shell; ID++ )
3096   {
3097     list< TPoint* > & shapePoints = getShapePoints( ID );
3098     list< TPoint* >::iterator pIt = shapePoints.begin();
3099
3100     if ( block.IsVertexID( ID ))
3101       for ( ; pIt != shapePoints.end(); pIt++ ) {
3102         block.VertexPoint( ID, (*pIt)->myXYZ.ChangeCoord() );
3103       }
3104     else if ( block.IsEdgeID( ID ))
3105       for ( ; pIt != shapePoints.end(); pIt++ ) {
3106         block.EdgePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3107       }
3108     else if ( block.IsFaceID( ID ))
3109       for ( ; pIt != shapePoints.end(); pIt++ ) {
3110         block.FacePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3111       }
3112     else
3113       for ( ; pIt != shapePoints.end(); pIt++ )
3114         block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
3115   } // loop on block sub-shapes
3116
3117   myIsComputed = true;
3118
3119   return setErrorCode( ERR_OK );
3120 }
3121
3122 //=======================================================================
3123 //function : MakeMesh
3124 //purpose  : Create nodes and elements in <theMesh> using nodes
3125 //           coordinates computed by either of Apply...() methods
3126 //=======================================================================
3127
3128 bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh)
3129 {
3130   MESSAGE(" ::MakeMesh() " );
3131   if ( !myIsComputed )
3132     return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
3133
3134   SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
3135   SMESH_MeshEditor editor( theMesh ); 
3136
3137   // clear elements and nodes existing on myShape
3138
3139   if ( !myShape.IsNull() )
3140   {
3141     SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( myShape );
3142     SMESHDS_SubMesh * aSubMeshDS = aMeshDS->MeshElements( myShape );
3143     if ( aSubMesh )
3144       aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
3145     else if ( aSubMeshDS )
3146     {
3147       SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
3148       while ( eIt->more() )
3149         aMeshDS->RemoveElement( eIt->next() );
3150       SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
3151       while ( nIt->more() )
3152         aMeshDS->RemoveNode( static_cast<const SMDS_MeshNode*>( nIt->next() ));
3153     }
3154   }
3155
3156   bool onMeshElements = ( !myElements.empty() );
3157
3158   // loop on sub-shapes of myShape: create nodes and build point-node map
3159
3160   vector< const SMDS_MeshNode* >       nodesVector;
3161   map< TPoint*, const SMDS_MeshNode* > pointNodeMap;
3162   if ( onMeshElements )
3163   {
3164     nodesVector.resize( myXYZ.size() );
3165     for ( int i = 0; i < myXYZ.size(); ++i ) {
3166       map< int, const SMDS_MeshNode*>::iterator idNode = myXYZIdToNodeMap.find( i );
3167       if ( idNode != myXYZIdToNodeMap.end() )
3168         nodesVector[ i ] = idNode->second;
3169       else if ( isDefined( myXYZ[ i ] ))
3170         nodesVector[ i ] = aMeshDS->AddNode (myXYZ[ i ].X(),
3171                                              myXYZ[ i ].Y(),
3172                                              myXYZ[ i ].Z());
3173     }
3174   }
3175   else
3176   {
3177     map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
3178     for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
3179     {
3180       TopoDS_Shape S;
3181       SMESHDS_SubMesh * subMeshDS = 0;
3182       if ( !myShapeIDMap.IsEmpty() ) {
3183         S = myShapeIDMap( idPointIt->first );
3184         subMeshDS = aMeshDS->MeshElements( S );
3185       }
3186       list< TPoint* > & points = idPointIt->second;
3187       list< TPoint* >::iterator pIt = points.begin();
3188       for ( ; pIt != points.end(); pIt++ )
3189       {
3190         TPoint* point = *pIt;
3191         if ( pointNodeMap.find( point ) != pointNodeMap.end() )
3192           continue;
3193         SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
3194                                                 point->myXYZ.Y(),
3195                                                 point->myXYZ.Z());
3196         pointNodeMap.insert( make_pair( point, node ));
3197         if ( subMeshDS ) {
3198           switch ( S.ShapeType() ) {
3199           case TopAbs_VERTEX: {
3200             aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S ));
3201             break;
3202           }
3203           case TopAbs_EDGE: {
3204             aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ));
3205             SMDS_EdgePosition* epos =
3206               dynamic_cast<SMDS_EdgePosition *>(node->GetPosition().get());
3207             epos->SetUParameter( point->myU );
3208             break;
3209           }
3210           case TopAbs_FACE: {
3211             aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ));
3212             SMDS_FacePosition* pos =
3213               dynamic_cast<SMDS_FacePosition *>(node->GetPosition().get());
3214             pos->SetUParameter( point->myUV.X() );
3215             pos->SetVParameter( point->myUV.Y() );
3216             break;
3217           }
3218           default:
3219             aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
3220           }
3221         }
3222       }
3223     }
3224   }
3225   
3226   // create elements
3227
3228   // shapes and groups myElements are on
3229   vector< int > shapeIDs;
3230   vector< list< SMESHDS_Group* > > groups;
3231   if ( onMeshElements )
3232   {
3233     shapeIDs.resize( myElements.size() );
3234     groups.resize( myElements.size() );
3235     const set<SMESHDS_GroupBase*>& allGroups = aMeshDS->GetGroups();
3236     set<SMESHDS_GroupBase*>::const_iterator grIt;
3237     for ( int i = 0; i < myElements.size(); i++ )
3238     {
3239       shapeIDs[ i ] = editor.FindShape( myElements[ i ] );
3240       for ( grIt = allGroups.begin(); grIt != allGroups.end(); grIt++ ) {
3241         SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
3242         if ( group && group->SMDSGroup().Contains( myElements[ i ] ))
3243           groups[ i ].push_back( group );
3244       }
3245     }
3246   }
3247   int nbElems = myElemPointIDs.size(); // nb elements in a pattern
3248
3249   list<list< int > >::iterator epIt, epEnd;
3250   if ( onMeshElements ) {
3251     epIt  = myElemXYZIDs.begin();
3252     epEnd = myElemXYZIDs.end();
3253   }
3254   else {
3255     epIt  = myElemPointIDs.begin();
3256     epEnd = myElemPointIDs.end();
3257   }
3258   for ( int iElem = 0; epIt != epEnd; epIt++, iElem++ )
3259   {
3260     list< int > & elemPoints = *epIt;
3261     // retrieve nodes
3262     const SMDS_MeshNode* nodes[ 8 ];
3263     list< int >::iterator iIt = elemPoints.begin();
3264     int nbNodes;
3265     for ( nbNodes = 0; iIt != elemPoints.end(); iIt++ ) {
3266       if ( onMeshElements )
3267         nodes[ nbNodes++ ] = nodesVector[ *iIt ];
3268       else
3269         nodes[ nbNodes++ ] = pointNodeMap[ & myPoints[ *iIt ]];
3270     }
3271     // add an element
3272     const SMDS_MeshElement* elem = 0;
3273     if ( myIs2D ) {
3274       switch ( nbNodes ) {
3275       case 3:
3276         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
3277       case 4:
3278         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
3279       default:
3280         ASSERT( nbNodes < 8 );
3281       }
3282     }
3283     else {
3284       switch ( nbNodes ) {
3285       case 4:
3286         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
3287       case 5:
3288         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3289                                    nodes[4] ); break;
3290       case 6:
3291         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3292                                    nodes[4], nodes[5] ); break;
3293       case 8:
3294         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
3295                                    nodes[4], nodes[5], nodes[6], nodes[7] ); break;
3296       default:
3297         ASSERT( nbNodes < 8 );
3298       }
3299     }
3300     // set element on a shape
3301     if ( elem && onMeshElements )
3302     {
3303       int elemIndex = iElem / nbElems;
3304       if ( shapeIDs[ elemIndex ] > 0 )
3305         aMeshDS->SetMeshElementOnShape( elem, shapeIDs[ elemIndex ] );
3306       // add elem in groups
3307       list< SMESHDS_Group* >::iterator g = groups[ elemIndex ].begin();
3308       for ( ; g != groups[ elemIndex ].end(); ++g )
3309         (*g)->SMDSGroup().Add( elem );
3310     }
3311     if ( elem && !myShape.IsNull() )
3312       aMeshDS->SetMeshElementOnShape( elem, myShape );
3313   }
3314
3315   // make that SMESH_subMesh::_computeState = COMPUTE_OK
3316   // so that operations with hypotheses will erase the mesh being built
3317
3318   SMESH_subMesh * subMesh;
3319   if ( !myShape.IsNull() ) {
3320     subMesh = theMesh->GetSubMeshContaining( myShape );
3321     if ( subMesh )
3322       subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3323   }
3324   if ( onMeshElements ) {
3325     list< int > elemIDs;
3326     for ( int i = 0; i < myElements.size(); i++ )
3327     {
3328       int shapeID = shapeIDs[ i ];
3329       if ( shapeID > 0 ) {
3330         TopoDS_Shape S = aMeshDS->IndexToShape( shapeID );
3331         subMesh = theMesh->GetSubMeshContaining( S );
3332         if ( subMesh )
3333           subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
3334       }
3335       elemIDs.push_back( myElements[ i ]->GetID() );
3336     }
3337     // remove refined elements and their nodes
3338     editor.Remove( elemIDs, false );
3339   }
3340
3341   return setErrorCode( ERR_OK );
3342 }
3343
3344
3345 //=======================================================================
3346 //function : arrangeBoundaries
3347 //purpose  : if there are several wires, arrange boundaryPoints so that
3348 //           the outer wire goes first and fix inner wires orientation
3349 //           update myKeyPointIDs to correspond to the order of key-points
3350 //           in boundaries; sort internal boundaries by the nb of key-points
3351 //=======================================================================
3352
3353 void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
3354 {
3355   typedef list< list< TPoint* > >::iterator TListOfListIt;
3356   TListOfListIt bndIt;
3357   list< TPoint* >::iterator pIt;
3358
3359   int nbBoundaries = boundaryList.size();
3360   if ( nbBoundaries > 1 )
3361   {
3362     // sort boundaries by nb of key-points
3363     if ( nbBoundaries > 2 )
3364     {
3365       // move boundaries in tmp list
3366       list< list< TPoint* > > tmpList; 
3367       tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
3368       // make a map nb-key-points to boundary-position-in-tmpList,
3369       // boundary-positions get ordered in it
3370       typedef map< int, TListOfListIt > TNbKpBndPosMap;
3371       TNbKpBndPosMap nbKpBndPosMap;
3372       bndIt = tmpList.begin();
3373       list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
3374       for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
3375         int nb = *nbKpIt * nbBoundaries;
3376         while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
3377           nb++;
3378         nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
3379       }
3380       // move boundaries back to boundaryList
3381       TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
3382       for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
3383         TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
3384         TListOfListIt bndPos1 = bndPos2++;
3385         boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
3386       }
3387     }
3388
3389     // Look for the outer boundary: the one with the point with the least X
3390     double leastX = DBL_MAX;
3391     TListOfListIt outerBndPos;
3392     for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
3393     {
3394       list< TPoint* >& boundary = (*bndIt);
3395       for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
3396       {
3397         TPoint* point = *pIt;
3398         if ( point->myInitXYZ.X() < leastX ) {
3399           leastX = point->myInitXYZ.X();
3400           outerBndPos = bndIt;
3401         }
3402       }
3403     }
3404
3405     if ( outerBndPos != boundaryList.begin() )
3406       boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos );
3407
3408   } // if nbBoundaries > 1
3409                  
3410   // Check boundaries orientation and re-fill myKeyPointIDs
3411
3412   set< TPoint* > keyPointSet;
3413   list< int >::iterator kpIt = myKeyPointIDs.begin();
3414   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
3415     keyPointSet.insert( & myPoints[ *kpIt ]);
3416   myKeyPointIDs.clear();
3417
3418   // update myNbKeyPntInBoundary also
3419   list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
3420
3421   for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
3422   {
3423     // find the point with the least X
3424     double leastX = DBL_MAX;
3425     list< TPoint* >::iterator xpIt;
3426     list< TPoint* >& boundary = (*bndIt);
3427     for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
3428     {
3429       TPoint* point = *pIt;
3430       if ( point->myInitXYZ.X() < leastX ) {
3431         leastX = point->myInitXYZ.X();
3432         xpIt = pIt;
3433       }
3434     }
3435     // find points next to the point with the least X
3436     TPoint* p = *xpIt, *pPrev, *pNext;
3437     if ( p == boundary.front() )
3438       pPrev = *(++boundary.rbegin());
3439     else {
3440       xpIt--;
3441       pPrev = *xpIt;
3442       xpIt++;
3443     }
3444     if ( p == boundary.back() )
3445       pNext = *(++boundary.begin());
3446     else {
3447       xpIt++;
3448       pNext = *xpIt;
3449     }
3450     // vectors of boundary direction near <p>
3451     gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
3452     double sqMag1 = v1.SquareMagnitude(), sqMag2 = v2.SquareMagnitude();
3453     if ( sqMag1 > DBL_MIN && sqMag2 > DBL_MIN ) {
3454       double yPrev = v1.Y() / sqrt( sqMag1 );
3455       double yNext = v2.Y() / sqrt( sqMag2 );
3456       double sumY = yPrev + yNext;
3457       bool reverse;
3458       if ( bndIt == boundaryList.begin() ) // outer boundary
3459         reverse = sumY > 0;
3460       else
3461         reverse = sumY < 0;
3462       if ( reverse )
3463         boundary.reverse();
3464     }
3465
3466     // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
3467     (*nbKpIt) = 0; // count nb of key-points again
3468     pIt = boundary.begin();
3469     for ( ; pIt != boundary.end(); pIt++)
3470     {
3471       TPoint* point = *pIt;
3472       if ( keyPointSet.find( point ) == keyPointSet.end() )
3473         continue;
3474       // find an index of a keypoint
3475       int index = 0;
3476       vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3477       for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
3478         if ( &(*pVecIt) == point )
3479           break;
3480       myKeyPointIDs.push_back( index );
3481       (*nbKpIt)++;
3482     }
3483     myKeyPointIDs.pop_back(); // remove the first key-point from the back
3484     (*nbKpIt)--;
3485
3486   } // loop on a list of boundaries
3487
3488   ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
3489 }
3490
3491 //=======================================================================
3492 //function : findBoundaryPoints
3493 //purpose  : if loaded from file, find points to map on edges and faces and
3494 //           compute their parameters
3495 //=======================================================================
3496
3497 bool SMESH_Pattern::findBoundaryPoints()
3498 {
3499   if ( myIsBoundaryPointsFound ) return true;
3500
3501   MESSAGE(" findBoundaryPoints() ");
3502
3503   if ( myIs2D )
3504   {
3505     set< TPoint* > pointsInElems;
3506
3507     // Find free links of elements:
3508     // put links of all elements in a set and remove links encountered twice
3509
3510     typedef pair< TPoint*, TPoint*> TLink;
3511     set< TLink > linkSet;
3512     list<list< int > >::iterator epIt = myElemPointIDs.begin();
3513     for ( ; epIt != myElemPointIDs.end(); epIt++ )
3514     {
3515       list< int > & elemPoints = *epIt;
3516       list< int >::iterator pIt = elemPoints.begin();
3517       int prevP = elemPoints.back();
3518       for ( ; pIt != elemPoints.end(); pIt++ ) {
3519         TPoint* p1 = & myPoints[ prevP ];
3520         TPoint* p2 = & myPoints[ *pIt ];
3521         TLink link(( p1 < p2 ? p1 : p2 ), ( p1 < p2 ? p2 : p1 ));
3522         ASSERT( link.first != link.second );
3523         pair<set< TLink >::iterator,bool> itUniq = linkSet.insert( link );
3524         if ( !itUniq.second )
3525           linkSet.erase( itUniq.first );
3526         prevP = *pIt;
3527
3528         pointsInElems.insert( p1 );
3529       }
3530     }
3531     // Now linkSet contains only free links,
3532     // find the points order that they have in boundaries
3533
3534     // 1. make a map of key-points
3535     set< TPoint* > keyPointSet;
3536     list< int >::iterator kpIt = myKeyPointIDs.begin();
3537     for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
3538       keyPointSet.insert( & myPoints[ *kpIt ]);
3539
3540     // 2. chain up boundary points
3541     list< list< TPoint* > > boundaryList;
3542     boundaryList.push_back( list< TPoint* >() );
3543     list< TPoint* > * boundary = & boundaryList.back();
3544
3545     TPoint *point1, *point2, *keypoint1;
3546     kpIt = myKeyPointIDs.begin();
3547     point1 = keypoint1 = & myPoints[ *kpIt++ ];
3548     // loop on free links: look for the next point
3549     int iKeyPoint = 0;
3550     set< TLink >::iterator lIt = linkSet.begin();
3551     while ( lIt != linkSet.end() )
3552     {
3553       if ( (*lIt).first == point1 )
3554         point2 = (*lIt).second;
3555       else if ( (*lIt).second == point1 )
3556         point2 = (*lIt).first;
3557       else {
3558         lIt++;
3559         continue;
3560       }
3561       linkSet.erase( lIt );
3562       lIt = linkSet.begin();
3563
3564       if ( keyPointSet.find( point2 ) == keyPointSet.end() ) // not a key-point
3565       {
3566         boundary->push_back( point2 );
3567       }
3568       else // a key-point found
3569       {
3570         keyPointSet.erase( point2 ); // keyPointSet contains not found key-points only
3571         iKeyPoint++;
3572         if ( point2 != keypoint1 ) // its not the boundary end
3573         {
3574           boundary->push_back( point2 );
3575         }
3576         else  // the boundary end reached
3577         {
3578           boundary->push_front( keypoint1 );
3579           boundary->push_back( keypoint1 );
3580           myNbKeyPntInBoundary.push_back( iKeyPoint );
3581           if ( keyPointSet.empty() )
3582             break; // all boundaries containing key-points are found
3583
3584           // prepare to search for the next boundary
3585           boundaryList.push_back( list< TPoint* >() );
3586           boundary = & boundaryList.back();
3587           point2 = keypoint1 = (*keyPointSet.begin());
3588         }
3589       }
3590       point1 = point2;
3591     } // loop on the free links set
3592
3593     if ( boundary->empty() ) {
3594       MESSAGE(" a separate key-point");
3595       return setErrorCode( ERR_READ_BAD_KEY_POINT );
3596     }
3597
3598     // if there are several wires, arrange boundaryPoints so that
3599     // the outer wire goes first and fix inner wires orientation;
3600     // sort myKeyPointIDs to correspond to the order of key-points
3601     // in boundaries
3602     arrangeBoundaries( boundaryList );
3603
3604     // Find correspondence shape ID - points,
3605     // compute points parameter on edge
3606
3607     keyPointSet.clear();
3608     for ( kpIt = myKeyPointIDs.begin(); kpIt != myKeyPointIDs.end(); kpIt++ )
3609       keyPointSet.insert( & myPoints[ *kpIt ]);
3610
3611     set< TPoint* > edgePointSet; // to find in-face points
3612     int vertexID = 1; // the first index in TopTools_IndexedMapOfShape
3613     int edgeID = myKeyPointIDs.size() + 1;
3614
3615     list< list< TPoint* > >::iterator bndIt = boundaryList.begin();
3616     for ( ; bndIt != boundaryList.end(); bndIt++ )
3617     {
3618       boundary = & (*bndIt);
3619       double edgeLength = 0;
3620       list< TPoint* >::iterator pIt = boundary->begin();
3621       getShapePoints( edgeID ).push_back( *pIt );
3622       getShapePoints( vertexID++ ).push_back( *pIt );
3623       for ( pIt++; pIt != boundary->end(); pIt++)
3624       {
3625         list< TPoint* > & edgePoints = getShapePoints( edgeID );
3626         TPoint* prevP = edgePoints.empty() ? 0 : edgePoints.back();
3627         TPoint* point = *pIt;
3628         edgePointSet.insert( point );
3629         if ( keyPointSet.find( point ) == keyPointSet.end() ) // inside-edge point
3630         {
3631           edgePoints.push_back( point );
3632           edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3633           point->myInitU = edgeLength;
3634         }
3635         else // a key-point
3636         {
3637           // treat points on the edge which ends up: compute U [0,1]
3638           edgePoints.push_back( point );
3639           if ( edgePoints.size() > 2 ) {
3640             edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3641             list< TPoint* >::iterator epIt = edgePoints.begin();
3642             for ( ; epIt != edgePoints.end(); epIt++ )
3643               (*epIt)->myInitU /= edgeLength;
3644           }
3645           // begin the next edge treatment
3646           edgeLength = 0;
3647           edgeID++;
3648           if ( point != boundary->front() ) { // not the first key-point again
3649             getShapePoints( edgeID ).push_back( point );
3650             getShapePoints( vertexID++ ).push_back( point );
3651           }
3652         }
3653       }
3654     }
3655
3656     // find in-face points
3657     list< TPoint* > & facePoints = getShapePoints( edgeID );
3658     vector< TPoint >::iterator pVecIt = myPoints.begin();
3659     for ( ; pVecIt != myPoints.end(); pVecIt++ ) {
3660       TPoint* point = &(*pVecIt);
3661       if ( edgePointSet.find( point ) == edgePointSet.end() &&
3662           pointsInElems.find( point ) != pointsInElems.end())
3663         facePoints.push_back( point );
3664     }
3665
3666   } // 2D case
3667
3668   else // 3D case
3669   {
3670     // bind points to shapes according to point parameters
3671     vector< TPoint >::iterator pVecIt = myPoints.begin();
3672     for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
3673       TPoint* point = &(*pVecIt);
3674       int shapeID = SMESH_Block::GetShapeIDByParams( point->myInitXYZ );
3675       getShapePoints( shapeID ).push_back( point );
3676       // detect key-points
3677       if ( SMESH_Block::IsVertexID( shapeID ))
3678         myKeyPointIDs.push_back( i );        
3679     }
3680   }
3681
3682   myIsBoundaryPointsFound = true;
3683   return myIsBoundaryPointsFound;
3684 }
3685
3686 //=======================================================================
3687 //function : Clear
3688 //purpose  : clear fields
3689 //=======================================================================
3690
3691 void SMESH_Pattern::Clear()
3692 {
3693   myIsComputed = myIsBoundaryPointsFound = false;
3694
3695   myPoints.clear();
3696   myKeyPointIDs.clear();
3697   myElemPointIDs.clear();
3698   myShapeIDToPointsMap.clear();
3699   myShapeIDMap.Clear();
3700   myShape.Nullify();
3701   myNbKeyPntInBoundary.clear();
3702 }
3703
3704 //=======================================================================
3705 //function : setShapeToMesh
3706 //purpose  : set a shape to be meshed. Return True if meshing is possible
3707 //=======================================================================
3708
3709 bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape)
3710 {
3711   if ( !IsLoaded() ) {
3712     MESSAGE( "Pattern not loaded" );
3713     return setErrorCode( ERR_APPL_NOT_LOADED );
3714   }
3715
3716   TopAbs_ShapeEnum aType = theShape.ShapeType();
3717   bool dimOk = ( myIs2D ? aType == TopAbs_FACE : aType == TopAbs_SHELL );
3718   if ( !dimOk ) {
3719     MESSAGE( "Pattern dimention mismatch" );
3720     return setErrorCode( ERR_APPL_BAD_DIMENTION );
3721   }
3722
3723   // check if a face is closed
3724   int nbNodeOnSeamEdge = 0;
3725   if ( myIs2D ) {
3726     TopoDS_Face face = TopoDS::Face( theShape );
3727     TopExp_Explorer eExp( theShape, TopAbs_EDGE );
3728     for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() )
3729       if ( BRep_Tool::IsClosed( TopoDS::Edge( eExp.Current() ), face ))
3730         nbNodeOnSeamEdge = 2;
3731   }
3732     
3733   // check nb of vertices
3734   TopTools_IndexedMapOfShape vMap;
3735   TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
3736   if ( vMap.Extent() + nbNodeOnSeamEdge != myKeyPointIDs.size() ) {
3737     MESSAGE( myKeyPointIDs.size() << " != " << vMap.Extent() );
3738     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
3739   }
3740
3741   myShapeIDMap.Clear();
3742   myShape = theShape;
3743   return true;
3744 }
3745
3746 //=======================================================================
3747 //function : GetMappedPoints
3748 //purpose  : Return nodes coordinates computed by Apply() method
3749 //=======================================================================
3750
3751 bool SMESH_Pattern::GetMappedPoints ( list< const gp_XYZ * > & thePoints ) const
3752 {
3753   thePoints.clear();
3754   if ( !myIsComputed )
3755     return false;
3756
3757   if ( myElements.empty() ) { // applied to shape
3758     vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3759     for ( ; pVecIt != myPoints.end(); pVecIt++ )
3760       thePoints.push_back( & (*pVecIt).myXYZ.XYZ() );
3761   }
3762   else { // applied to mesh elements
3763     vector<gp_XYZ>::const_iterator xyz = myXYZ.begin();
3764     for ( ; xyz != myXYZ.end(); ++xyz )
3765       thePoints.push_back( & (*xyz) );
3766   }
3767   return !thePoints.empty();
3768 }
3769
3770
3771 //=======================================================================
3772 //function : GetPoints
3773 //purpose  : Return nodes coordinates of the pattern
3774 //=======================================================================
3775
3776 bool SMESH_Pattern::GetPoints ( list< const gp_XYZ * > & thePoints ) const
3777 {
3778   thePoints.clear();
3779
3780   if ( !IsLoaded() )
3781     return false;
3782
3783   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3784   for ( ; pVecIt != myPoints.end(); pVecIt++ )
3785     thePoints.push_back( & (*pVecIt).myInitXYZ );
3786
3787   return ( thePoints.size() > 0 );
3788 }
3789
3790 //=======================================================================
3791 //function : getShapePoints
3792 //purpose  : return list of points located on theShape
3793 //=======================================================================
3794
3795 list< SMESH_Pattern::TPoint* > &
3796   SMESH_Pattern::getShapePoints(const TopoDS_Shape& theShape)
3797 {
3798   int aShapeID;
3799   if ( !myShapeIDMap.Contains( theShape ))
3800     aShapeID = myShapeIDMap.Add( theShape );
3801   else
3802     aShapeID = myShapeIDMap.FindIndex( theShape );
3803
3804   return myShapeIDToPointsMap[ aShapeID ];
3805 }
3806
3807 //=======================================================================
3808 //function : getShapePoints
3809 //purpose  : return list of points located on the shape
3810 //=======================================================================
3811
3812 list< SMESH_Pattern::TPoint* > & SMESH_Pattern::getShapePoints(const int theShapeID)
3813 {
3814   return myShapeIDToPointsMap[ theShapeID ];
3815 }
3816
3817 //=======================================================================
3818 //function : DumpPoints
3819 //purpose  : Debug
3820 //=======================================================================
3821
3822 void SMESH_Pattern::DumpPoints() const
3823 {
3824 #ifdef _DEBUG_
3825   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3826   for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ )
3827     cout << i << ": " << *pVecIt;
3828 #endif
3829 }
3830
3831 //=======================================================================
3832 //function : TPoint()
3833 //purpose  : 
3834 //=======================================================================
3835
3836 SMESH_Pattern::TPoint::TPoint()
3837 {
3838 #ifdef _DEBUG_
3839   myInitXYZ.SetCoord(0,0,0);
3840   myInitUV.SetCoord(0.,0.);
3841   myInitU = 0;
3842   myXYZ.SetCoord(0,0,0);
3843   myUV.SetCoord(0.,0.);
3844   myU = 0;
3845 #endif
3846 }
3847
3848 //=======================================================================
3849 //function : operator <<
3850 //purpose  : 
3851 //=======================================================================
3852
3853 ostream & operator <<(ostream & OS, const SMESH_Pattern::TPoint& p)
3854 {
3855   gp_XYZ xyz = p.myInitXYZ;
3856   OS << "\tinit( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3857   gp_XY xy = p.myInitUV;
3858   OS << " uv( " <<  xy.X() << " " << xy.Y() << " )";
3859   double u = p.myInitU;
3860   OS << " u( " <<  u << " )) " << &p << endl;
3861   xyz = p.myXYZ.XYZ();
3862   OS << "\t    ( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3863   xy = p.myUV;
3864   OS << " uv( " <<  xy.X() << " " << xy.Y() << " )";
3865   u = p.myU;
3866   OS << " u( " <<  u << " ))" << endl;
3867   
3868   return OS;
3869 }