Salome HOME
7f20a5cad0f97a57c5ed29fa2597704481299df7
[modules/smesh.git] / src / SMESH / SMESH_Pattern.cxx
1 // File      : SMESH_Pattern.cxx
2 // Created   : Thu Aug  5 11:09:29 2004
3 // Author    : Edward AGAPOV (eap)
4 // Copyright : Open CASCADE
5
6
7 #include "SMESH_Pattern.hxx"
8
9 #include <Bnd_Box2d.hxx>
10 #include <BRepTools.hxx>
11 #include <BRepTools_WireExplorer.hxx>
12 #include <BRep_Tool.hxx>
13 #include <Geom2d_Curve.hxx>
14 #include <Geom_Curve.hxx>
15 #include <Geom_Surface.hxx>
16 #include <IntAna2d_AnaIntersection.hxx>
17 #include <TopAbs_ShapeEnum.hxx>
18 #include <TopExp.hxx>
19 #include <TopLoc_Location.hxx>
20 #include <TopoDS.hxx>
21 #include <TopoDS_Edge.hxx>
22 #include <TopoDS_Face.hxx>
23 #include <TopoDS_Iterator.hxx>
24 #include <TopoDS_Shell.hxx>
25 #include <TopoDS_Vertex.hxx>
26 #include <TopoDS_Wire.hxx>
27 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
28 #include <TopTools_ListIteratorOfListOfShape.hxx>
29 #include <TopTools_ListOfShape.hxx>
30 #include <gp_Lin2d.hxx>
31 #include <gp_Pnt2d.hxx>
32 #include <gp_Trsf.hxx>
33 #include <gp_XY.hxx>
34 #include <gp_XYZ.hxx>
35 #include <math_FunctionSetRoot.hxx>
36 #include <math_FunctionSetWithDerivatives.hxx>
37 #include <math_Matrix.hxx>
38 #include <math_Vector.hxx>
39 #include <Extrema_GenExtPS.hxx>
40 #include <Extrema_POnSurf.hxx>
41 #include <GeomAdaptor_Surface.hxx>
42
43 #include "SMDS_EdgePosition.hxx"
44 #include "SMDS_FacePosition.hxx"
45 #include "SMDS_MeshElement.hxx"
46 #include "SMDS_MeshNode.hxx"
47 #include "SMESHDS_Mesh.hxx"
48 #include "SMESHDS_SubMesh.hxx"
49 #include "SMESH_Mesh.hxx"
50
51 #include "utilities.h"
52
53 using namespace std;
54
55 typedef map< const SMDS_MeshElement*, int > TNodePointIDMap;
56
57 #define SQRT_FUNC 1
58
59 //=======================================================================
60 //function : SMESH_Pattern
61 //purpose  : 
62 //=======================================================================
63
64 SMESH_Pattern::SMESH_Pattern ()
65 {
66 }
67 //=======================================================================
68 //function : getInt
69 //purpose  : 
70 //=======================================================================
71
72 static inline int getInt( const char * theSring )
73 {
74   if ( *theSring < '0' || *theSring > '9' )
75     return -1;
76
77   char *ptr;
78   int val = strtol( theSring, &ptr, 10 );
79   if ( ptr == theSring ||
80       // there must not be neither '.' nor ',' nor 'E' ...
81       (*ptr != ' ' && *ptr != '\n' && *ptr != '\0'))
82     return -1;
83
84   return val;
85 }
86
87 //=======================================================================
88 //function : getDouble
89 //purpose  : 
90 //=======================================================================
91
92 static inline double getDouble( const char * theSring )
93 {
94   char *ptr;
95   return strtod( theSring, &ptr );
96 }
97
98 //=======================================================================
99 //function : readLine
100 //purpose  : Put token starting positions in theFields until '\n' or '\0'
101 //           Return the number of the found tokens
102 //=======================================================================
103
104 static int readLine (list <const char*> & theFields,
105                      const char*        & theLineBeg,
106                      const bool           theClearFields )
107 {
108   if ( theClearFields )
109     theFields.clear();
110
111   //  algo:
112   /*  loop                                                       */
113   /*    switch ( symbol ) {                                      */
114   /*    case white-space:                                        */
115   /*      look for a non-space symbol;                           */
116   /*    case string-end:                                         */
117   /*    case line-end:                                           */
118   /*      exit;                                                  */
119   /*    case comment beginning:                                  */
120   /*      skip all till a line-end;                              */
121   /*    case a number                                            */
122   /*      put its position in theFields, skip till a white-space;*/
123   /*    default:                                                 */
124   /*      abort;                                                 */
125   /*  till line-end                                              */
126
127   int nbRead = 0;
128   bool stopReading = false;
129   do {
130     bool goOn = true;
131     bool isNumber = false;
132     switch ( *theLineBeg )
133     {
134     case ' ':  // white space
135     case '\t': // tab
136     case 13:   // ^M
137       break;
138
139     case '\n': // a line ends
140       stopReading = ( nbRead > 0 );
141       break;
142
143     case '!':  // comment
144       do theLineBeg++;
145       while ( *theLineBeg != '\n' && *theLineBeg != '\0' );
146       goOn = false;
147       break;
148
149     case '\0': // file ends
150       return nbRead;
151
152     case '-': // real number
153     case '+':
154     case '.':
155       isNumber = true;
156     default: // data
157       isNumber = isNumber || ( *theLineBeg >= '0' && *theLineBeg <= '9' );
158       if ( isNumber ) {
159         theFields.push_back( theLineBeg );
160         nbRead++;
161         do theLineBeg++;
162         while (*theLineBeg != ' ' &&
163                *theLineBeg != '\n' &&
164                *theLineBeg != '\0');
165         goOn = false;
166       }
167       else
168         return 0; // incorrect file format
169     }
170
171     if ( goOn )
172       theLineBeg++;
173
174   } while ( !stopReading );
175
176   return nbRead;
177 }
178
179 //=======================================================================
180 //function : Load
181 //purpose  : Load a pattern from <theFile>
182 //=======================================================================
183
184 bool SMESH_Pattern::Load (const char* theFileContents)
185 {
186   MESSAGE("Load( file ) ");
187
188   // file structure:
189
190   // ! This is a comment
191   // NB_POINTS               ! 1 integer - the number of points in the pattern.
192   //   X1 Y1 [Z1]            ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
193   //   X2 Y2 [Z2]            ! the pattern dimention is defined by the number of coordinates
194   //   ...
195   // [ ID1 ID2 ... IDn ]     ! Indices of key-points for a 2D pattern (only).
196   // ! elements description goes after all
197   // ID1 ID2 ... IDn         ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
198   // ...
199
200   Clear();
201
202   const char* lineBeg = theFileContents;
203   list <const char*> fields;
204   const bool clearFields = true;
205
206   // NB_POINTS               ! 1 integer - the number of points in the pattern.
207
208   if ( readLine( fields, lineBeg, clearFields ) != 1 ) {
209     MESSAGE("Error reading NB_POINTS");
210     return setErrorCode( ERR_READ_NB_POINTS );
211   }
212   int nbPoints = getInt( fields.front() );
213
214   //   X1 Y1 [Z1]            ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
215
216   // read the first point coordinates to define pattern dimention
217   int dim = readLine( fields, lineBeg, clearFields );
218   if ( dim == 2 )
219     myIs2D = true;
220   else if ( dim == 3 )
221     myIs2D = false;
222   else {
223     MESSAGE("Error reading points: wrong nb of coordinates");
224     return setErrorCode( ERR_READ_POINT_COORDS );
225   }
226   if ( nbPoints <= dim ) {
227     MESSAGE(" Too few points ");
228     return setErrorCode( ERR_READ_TOO_FEW_POINTS );
229   }
230     
231   // read the rest points
232   int iPoint;
233   for ( iPoint = 1; iPoint < nbPoints; iPoint++ )
234     if ( readLine( fields, lineBeg, !clearFields ) != dim ) {
235       MESSAGE("Error reading  points : wrong nb of coordinates ");
236       return setErrorCode( ERR_READ_POINT_COORDS );
237     }
238   // store point coordinates
239   myPoints.resize( nbPoints );
240   list <const char*>::iterator fIt = fields.begin();
241   for ( iPoint = 0; iPoint < nbPoints; iPoint++ )
242   {
243     TPoint & p = myPoints[ iPoint ];
244     for ( int iCoord = 1; iCoord <= dim; iCoord++, fIt++ )
245     {
246       double coord = getDouble( *fIt );
247       if ( !myIs2D && ( coord < 0.0 || coord > 1.0 )) {
248         MESSAGE("Error reading 3D points, value should be in [0,1]: " << coord);
249         Clear();
250         return setErrorCode( ERR_READ_3D_COORD );
251       }
252       p.myInitXYZ.SetCoord( iCoord, coord );
253       if ( myIs2D )
254         p.myInitUV.SetCoord( iCoord, coord );
255     }
256   }
257
258   // [ ID1 ID2 ... IDn ]     ! Indices of key-points for a 2D pattern (only).
259   if ( myIs2D )
260   {
261     if ( readLine( fields, lineBeg, clearFields ) == 0 ) {
262       MESSAGE("Error: missing key-points");
263       Clear();
264       return setErrorCode( ERR_READ_NO_KEYPOINT );
265     }
266     set<int> idSet;
267     for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
268     {
269       int pointIndex = getInt( *fIt );
270       if ( pointIndex >= nbPoints || pointIndex < 0 ) {
271         MESSAGE("Error: invalid point index " << pointIndex );
272         Clear();
273         return setErrorCode( ERR_READ_BAD_INDEX );
274       }
275       if ( idSet.insert( pointIndex ).second ) // unique?
276         myKeyPointIDs.push_back( pointIndex );
277     }
278   }
279
280   // ID1 ID2 ... IDn         ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
281
282   while ( readLine( fields, lineBeg, clearFields ))
283   {
284     myElemPointIDs.push_back( list< int >() );
285     list< int >& elemPoints = myElemPointIDs.back();
286     for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
287     {
288       int pointIndex = getInt( *fIt );
289       if ( pointIndex >= nbPoints || pointIndex < 0 ) {
290         MESSAGE("Error: invalid point index " << pointIndex );
291         Clear();
292         return setErrorCode( ERR_READ_BAD_INDEX );
293       }
294       elemPoints.push_back( pointIndex );
295     }
296     // check the nb of nodes in element
297     bool Ok = true;
298     switch ( elemPoints.size() ) {
299     case 3: if ( !myIs2D ) Ok = false; break;
300     case 4: break;
301     case 5:
302     case 6:
303     case 8: if ( myIs2D ) Ok = false; break;
304     default: Ok = false;
305     }
306     if ( !Ok ) {
307       MESSAGE("Error: wrong nb of nodes in element " << elemPoints.size() );
308       Clear();
309       return setErrorCode( ERR_READ_ELEM_POINTS );
310     }
311   }
312   if ( myElemPointIDs.empty() ) {
313     MESSAGE("Error: no elements");
314     Clear();
315     return setErrorCode( ERR_READ_NO_ELEMS );
316   }
317
318   findBoundaryPoints(); // sort key-points
319
320   return setErrorCode( ERR_OK );
321 }
322
323 //=======================================================================
324 //function : Save
325 //purpose  : Save the loaded pattern into the file <theFileName>
326 //=======================================================================
327
328 bool SMESH_Pattern::Save (ostream& theFile)
329 {
330   MESSAGE(" ::Save(file) " );
331   if ( !IsLoaded() ) {
332     MESSAGE(" Pattern not loaded ");
333     return setErrorCode( ERR_SAVE_NOT_LOADED );
334   }
335
336   theFile << "!!! SALOME Mesh Pattern file" << endl;
337   theFile << "!!!" << endl;
338   theFile << "!!! Nb of points:" << endl;
339   theFile << myPoints.size() << endl;
340
341   // point coordinates
342   const int width = 8;
343 //  theFile.width( 8 );
344 //  theFile.setf(ios::fixed);// use 123.45 floating notation
345 //  theFile.setf(ios::right);
346 //  theFile.flags( theFile.flags() & ~ios::showpoint); // do not show trailing zeros
347 //   theFile.setf(ios::showpoint); // do not show trailing zeros
348   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
349   for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
350     const gp_XYZ & xyz = (*pVecIt).myInitXYZ;
351     theFile << " " << setw( width ) << xyz.X() << " " << setw( width ) << xyz.Y();
352     if ( !myIs2D ) theFile  << " " << setw( width ) << xyz.Z();
353     theFile  << "  !- " << i << endl; // point id to ease reading by a human being
354   }
355   // key-points
356   if ( myIs2D ) {
357     theFile << "!!! Indices of " << myKeyPointIDs.size() << " key-points:" << endl;
358     list< int >::const_iterator kpIt = myKeyPointIDs.begin();
359     for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
360       theFile << " " << *kpIt;
361     if ( !myKeyPointIDs.empty() )
362       theFile << endl;
363   }
364   // elements
365   theFile << "!!! Indices of points of " << myElemPointIDs.size() << " elements:" << endl;
366   list<list< int > >::const_iterator epIt = myElemPointIDs.begin();
367   for ( ; epIt != myElemPointIDs.end(); epIt++ )
368   {
369     const list< int > & elemPoints = *epIt;
370     list< int >::const_iterator iIt = elemPoints.begin();
371     for ( ; iIt != elemPoints.end(); iIt++ )
372       theFile << " " << *iIt;
373     theFile << endl;
374   }
375
376   theFile << endl;
377   
378   return setErrorCode( ERR_OK );
379 }
380
381 //=======================================================================
382 //function : sortBySize
383 //purpose  : sort theListOfList by size
384 //=======================================================================
385
386 template<typename T> struct TSizeCmp {
387   bool operator ()( const list < T > & l1, const list < T > & l2 )
388     const { return l1.size() < l2.size(); }
389 };
390
391 template<typename T> void sortBySize( list< list < T > > & theListOfList )
392 {
393   if ( theListOfList.size() > 2 ) {
394     // keep the car
395     //list < T > & aFront = theListOfList.front();
396     // sort the whole list
397     TSizeCmp< T > SizeCmp;
398     theListOfList.sort( SizeCmp );
399   }
400 }
401
402 //=======================================================================
403 //function : getOrderedEdges
404 //purpose  : return nb wires and a list of oredered edges
405 //=======================================================================
406
407 static int getOrderedEdges (const TopoDS_Face&   theFace,
408                             const TopoDS_Vertex& theFirstVertex,
409                             list< TopoDS_Edge >& theEdges,
410                             list< int >  &       theNbVertexInWires)
411 {
412   // put wires in a list, so that an outer wire comes first
413   list<TopoDS_Wire> aWireList;
414   TopoDS_Wire anOuterWire = BRepTools::OuterWire( theFace );
415   aWireList.push_back( anOuterWire );
416   for ( TopoDS_Iterator wIt (theFace); wIt.More(); wIt.Next() )
417     if ( !anOuterWire.IsSame( wIt.Value() ))
418       aWireList.push_back( TopoDS::Wire( wIt.Value() ));
419
420   // loop on edges of wires
421   theNbVertexInWires.clear();
422   list<TopoDS_Wire>::iterator wlIt = aWireList.begin();
423   for ( ; wlIt != aWireList.end(); wlIt++ )
424   {
425     int iE;
426     BRepTools_WireExplorer wExp( *wlIt, theFace );
427     for ( iE = 0; wExp.More(); wExp.Next(), iE++ )
428     {
429       TopoDS_Edge edge = wExp.Current();
430       edge = TopoDS::Edge( edge.Oriented( wExp.Orientation() ));
431       theEdges.push_back( edge );
432     }
433     theNbVertexInWires.push_back( iE );
434     iE = 0;
435     if ( wlIt == aWireList.begin() && theEdges.size() > 1 ) { // the outer wire
436       // orient closed edges
437       list< TopoDS_Edge >::iterator eIt, eIt2;
438       for ( eIt = theEdges.begin(); eIt != theEdges.end(); eIt++ )
439       {
440         TopoDS_Edge& edge = *eIt;
441         if ( TopExp::FirstVertex( edge ).IsSame( TopExp::LastVertex( edge ) ))
442         {
443           eIt2 = eIt;
444           bool isNext = ( eIt2 == theEdges.begin() );
445           TopoDS_Edge edge2 = isNext ? *(++eIt2) : *(--eIt2);
446           double f1,l1,f2,l2;
447           Handle(Geom2d_Curve) c1 = BRep_Tool::CurveOnSurface( edge, theFace, f1,l1 );
448           Handle(Geom2d_Curve) c2 = BRep_Tool::CurveOnSurface( edge2, theFace, f2,l2 );
449           gp_Pnt2d pf = c1->Value( edge.Orientation() == TopAbs_FORWARD ? f1 : l1 );
450           gp_Pnt2d pl = c1->Value( edge.Orientation() == TopAbs_FORWARD ? l1 : f1 );
451           bool isFirst = ( edge2.Orientation() == TopAbs_FORWARD ? isNext : !isNext );
452           gp_Pnt2d p2 = c2->Value( isFirst ? f2 : l2 );
453           isFirst = ( p2.SquareDistance( pf ) < p2.SquareDistance( pl ));
454           if ( isNext ? isFirst : !isFirst )
455             edge.Reverse();
456         }
457       }
458       // rotate theEdges until it begins from theFirstVertex
459       if ( ! theFirstVertex.IsNull() )
460         while ( !theFirstVertex.IsSame( TopExp::FirstVertex( theEdges.front(), true )))
461         {
462           theEdges.splice(theEdges.end(), theEdges,
463                           theEdges.begin(), ++ theEdges.begin());
464           if ( iE++ > theNbVertexInWires.back() ) 
465             break; // break infinite loop
466         }
467     }
468   }
469
470   return aWireList.size();
471 }
472
473 //=======================================================================
474 //function : project
475 //purpose  : 
476 //=======================================================================
477
478 static gp_XY project (const SMDS_MeshNode* theNode,
479                       Extrema_GenExtPS &   theProjectorPS)
480 {
481   gp_Pnt P( theNode->X(), theNode->Y(), theNode->Z() );
482   theProjectorPS.Perform( P );
483   if ( !theProjectorPS.IsDone() ) {
484     MESSAGE( "SMESH_Pattern: point projection FAILED");
485     return gp_XY(0.,0.);
486   }
487   double u, v, minVal = DBL_MAX;
488   for ( int i = theProjectorPS.NbExt(); i > 0; i-- )
489     if ( theProjectorPS.Value( i ) < minVal ) {
490       minVal = theProjectorPS.Value( i );
491       theProjectorPS.Point( i ).Parameter( u, v );
492     }
493   return gp_XY( u, v );
494 }
495
496 //=======================================================================
497 //function : isMeshBoundToShape
498 //purpose  : return true if all 2d elements are bound to shape
499 //=======================================================================
500
501 static bool isMeshBoundToShape(SMESH_Mesh* theMesh)
502 {
503   // check faces binding
504   SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
505   SMESHDS_SubMesh * aMainSubMesh = aMeshDS->MeshElements( aMeshDS->ShapeToMesh() );
506   if ( aMeshDS->NbFaces() != aMainSubMesh->NbElements() )
507     return false;
508
509   // check face nodes binding
510   SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
511   while ( fIt->more() )
512   {
513     SMDS_ElemIteratorPtr nIt = fIt->next()->nodesIterator();
514     while ( nIt->more() )
515     {
516       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
517       SMDS_PositionPtr pos = node->GetPosition();
518       if ( !pos || !pos->GetShapeId() )
519         return false;
520     }
521   }
522   return true;
523 }
524
525 //=======================================================================
526 //function : Load
527 //purpose  : Create a pattern from the mesh built on <theFace>.
528 //           <theProject>==true makes override nodes positions
529 //           on <theFace> computed by mesher
530 //=======================================================================
531
532 bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
533                           const TopoDS_Face& theFace,
534                           bool               theProject)
535 {
536   MESSAGE(" ::Load(face) " );
537   Clear();
538   myIs2D = true;
539
540   SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
541   SMESHDS_SubMesh * fSubMesh = aMeshDS->MeshElements( theFace );
542
543   int nbNodes = ( !fSubMesh ? 0 : fSubMesh->NbNodes() );
544   int nbElems = ( !fSubMesh ? 0 : fSubMesh->NbElements() );
545   if ( nbElems == 0 && aMeshDS->NbFaces() == 0 )
546   {
547     MESSAGE( "No elements bound to the face");
548     return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
549   }
550
551   // check that face is not closed
552   TopoDS_Vertex bidon;
553   list<TopoDS_Edge> eList;
554   getOrderedEdges( theFace, bidon, eList, myNbKeyPntInBoundary );
555   list<TopoDS_Edge>::iterator elIt = eList.begin();
556   for ( ; elIt != eList.end() ; elIt++ )
557     if ( BRep_Tool::IsClosed( *elIt , theFace ))
558       return setErrorCode( ERR_LOADF_CLOSED_FACE );
559   
560
561   Extrema_GenExtPS projector;
562   GeomAdaptor_Surface aSurface( BRep_Tool::Surface( theFace ));
563   if ( theProject || nbElems == 0 )
564     projector.Initialize( aSurface, 20,20, 1e-5,1e-5 );
565
566   int iPoint = 0;
567   TNodePointIDMap nodePointIDMap;
568
569   if ( nbElems == 0 || (theProject &&
570                         theMesh->IsMainShape( theFace ) &&
571                         !isMeshBoundToShape( theMesh )))
572   {
573     MESSAGE("Project the whole mesh");
574     // ---------------------------------------------------------------
575     // The case where the whole mesh is projected to theFace
576     // ---------------------------------------------------------------
577
578     // put nodes of all faces in the nodePointIDMap and fill myElemPointIDs
579     SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
580     while ( fIt->more() )
581     {
582       myElemPointIDs.push_back( list< int >() );
583       list< int >& elemPoints = myElemPointIDs.back();
584       SMDS_ElemIteratorPtr nIt = fIt->next()->nodesIterator();
585       while ( nIt->more() )
586       {
587         const SMDS_MeshElement* node = nIt->next();
588         TNodePointIDMap::iterator nIdIt = nodePointIDMap.find( node );
589         if ( nIdIt == nodePointIDMap.end() )
590         {
591           elemPoints.push_back( iPoint );
592           nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint++ ));
593         }
594         else
595           elemPoints.push_back( (*nIdIt).second );
596       }
597     }
598     myPoints.resize( iPoint );
599
600     // project all nodes of 2d elements to theFace
601     TNodePointIDMap::iterator nIdIt = nodePointIDMap.begin();
602     for ( ; nIdIt != nodePointIDMap.end(); nIdIt++ )
603     {
604       const SMDS_MeshNode* node = 
605         static_cast<const SMDS_MeshNode*>( (*nIdIt).first );
606       TPoint * p = & myPoints[ (*nIdIt).second ];
607       p->myInitUV = project( node, projector );
608       p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
609     }
610     // find key-points: the points most close to UV of vertices
611     TopExp_Explorer vExp( theFace, TopAbs_VERTEX );
612     set<int> foundIndices;
613     for ( ; vExp.More(); vExp.Next() ) {
614       const TopoDS_Vertex v = TopoDS::Vertex( vExp.Current() );
615       gp_Pnt2d uv = BRep_Tool::Parameters( v, theFace );
616       double minDist = DBL_MAX;
617       int index;
618       vector< TPoint >::const_iterator pVecIt = myPoints.begin();
619       for ( iPoint = 0; pVecIt != myPoints.end(); pVecIt++, iPoint++ ) {
620         double dist = uv.SquareDistance( (*pVecIt).myInitUV );
621         if ( dist < minDist ) {
622           minDist = dist;
623           index = iPoint;
624         }
625       }
626       if ( foundIndices.insert( index ).second ) // unique?
627         myKeyPointIDs.push_back( index );
628     }
629     myIsBoundaryPointsFound = false;
630
631   }
632   else
633   {
634     // ---------------------------------------------------------------------
635     // The case where a pattern is being made from the mesh built by mesher
636     // ---------------------------------------------------------------------
637
638     // Load shapes in the consequent order and count nb of points
639
640     // vertices
641     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) {
642       myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
643       SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt );
644       if ( eSubMesh )
645         nbNodes += eSubMesh->NbNodes() + 1;
646     }
647     // edges
648     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
649       myShapeIDMap.Add( *elIt );
650     // the face
651     myShapeIDMap.Add( theFace );
652
653     myPoints.resize( nbNodes );
654
655     // Load U of points on edges
656
657     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
658     {
659       TopoDS_Edge & edge = *elIt;
660       list< TPoint* > & ePoints = getShapePoints( edge );
661       double f, l;
662       Handle(Geom2d_Curve) C2d;
663       if ( !theProject )
664         C2d = BRep_Tool::CurveOnSurface( edge, theFace, f, l );
665       bool isForward = ( edge.Orientation() == TopAbs_FORWARD );
666
667       // the forward key-point
668       TopoDS_Shape v = TopExp::FirstVertex( edge, true );
669       list< TPoint* > & vPoint = getShapePoints( v );
670       if ( vPoint.empty() )
671       {
672         SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
673         if ( vSubMesh && vSubMesh->NbNodes() ) {
674           myKeyPointIDs.push_back( iPoint );
675           SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
676           const SMDS_MeshNode* node = nIt->next();
677           nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint ));
678
679           TPoint* keyPoint = &myPoints[ iPoint++ ];
680           vPoint.push_back( keyPoint );
681           if ( theProject )
682             keyPoint->myInitUV = project( node, projector );
683           else
684             keyPoint->myInitUV = C2d->Value( isForward ? f : l ).XY();
685           keyPoint->myInitXYZ.SetCoord (keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0);
686         }
687       }
688       if ( !vPoint.empty() )
689         ePoints.push_back( vPoint.front() );
690
691       // on-edge points
692       SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edge );
693       if ( eSubMesh && eSubMesh->NbNodes() )
694       {
695         // loop on nodes of an edge: sort them by param on edge
696         typedef map < double, const SMDS_MeshNode* > TParamNodeMap;
697         TParamNodeMap paramNodeMap;
698         SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
699         while ( nIt->more() )
700         {
701           const SMDS_MeshNode* node = 
702             static_cast<const SMDS_MeshNode*>( nIt->next() );
703           const SMDS_EdgePosition* epos =
704             static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
705           double u = epos->GetUParameter();
706           paramNodeMap.insert( TParamNodeMap::value_type( u, node ));
707         }
708         // put U in [0,1] so that the first key-point has U==0
709         double du = l - f;
710         TParamNodeMap::iterator         unIt  = paramNodeMap.begin();
711         TParamNodeMap::reverse_iterator unRIt = paramNodeMap.rbegin();
712         while ( unIt != paramNodeMap.end() )
713         {
714           TPoint* p = & myPoints[ iPoint ];
715           ePoints.push_back( p );
716           const SMDS_MeshNode* node = isForward ? (*unIt).second : (*unRIt).second;
717           nodePointIDMap.insert ( TNodePointIDMap::value_type( node, iPoint ));
718
719           if ( theProject )
720             p->myInitUV = project( node, projector );
721           else {
722             double u = isForward ? (*unIt).first : (*unRIt).first;
723             p->myInitU = isForward ? (( u - f ) / du ) : ( 1.0 - ( u - f ) / du );
724             p->myInitUV = C2d->Value( u ).XY();
725           }
726           p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
727           unIt++; unRIt++;
728           iPoint++;
729         }
730       }
731       // the reverse key-point
732       v = TopExp::LastVertex( edge, true ).Reversed();
733       list< TPoint* > & vPoint2 = getShapePoints( v );
734       if ( vPoint2.empty() )
735       {
736         SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v );
737         if ( vSubMesh && vSubMesh->NbNodes() ) {
738           myKeyPointIDs.push_back( iPoint );
739           SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
740           const SMDS_MeshNode* node = nIt->next();
741           nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint ));
742
743           TPoint* keyPoint = &myPoints[ iPoint++ ];
744           vPoint2.push_back( keyPoint );
745           if ( theProject )
746             keyPoint->myInitUV = project( node, projector );
747           else
748             keyPoint->myInitUV = C2d->Value( isForward ? l : f ).XY();
749           keyPoint->myInitXYZ.SetCoord( keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0 );
750         }
751       }
752       if ( !vPoint2.empty() )
753         ePoints.push_back( vPoint2.front() );
754
755       // compute U of edge-points
756       if ( theProject )
757       {
758         double totalDist = 0;
759         list< TPoint* >::iterator pIt = ePoints.begin();
760         TPoint* prevP = *pIt;
761         prevP->myInitU = totalDist;
762         for ( pIt++; pIt != ePoints.end(); pIt++ ) {
763           TPoint* p = *pIt;
764           totalDist += ( p->myInitUV - prevP->myInitUV ).Modulus();
765           p->myInitU = totalDist;
766           prevP = p;
767         }
768         if ( totalDist > DBL_MIN)
769           for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
770             TPoint* p = *pIt;
771             p->myInitU /= totalDist;
772           }
773       }
774     } // loop on edges of a wire
775
776     // Load in-face points and elements
777
778     if ( fSubMesh && fSubMesh->NbElements() )
779     {
780       list< TPoint* > & fPoints = getShapePoints( theFace );
781       SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes();
782       while ( nIt->more() )
783       {
784         const SMDS_MeshNode* node = 
785           static_cast<const SMDS_MeshNode*>( nIt->next() );
786         nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint ));
787         TPoint* p = &myPoints[ iPoint++ ];
788         fPoints.push_back( p );
789         if ( theProject )
790           p->myInitUV = project( node, projector );
791         else {
792           const SMDS_FacePosition* pos =
793             static_cast<const SMDS_FacePosition*>(node->GetPosition().get());
794           p->myInitUV.SetCoord( pos->GetUParameter(), pos->GetVParameter() );
795         }
796         p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
797       }
798       // load elements
799       SMDS_ElemIteratorPtr elemIt = fSubMesh->GetElements();
800       while ( elemIt->more() ) {
801         SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
802         myElemPointIDs.push_back( list< int >() );
803         list< int >& elemPoints = myElemPointIDs.back();
804         while ( nIt->more() )
805           elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
806       }
807     }
808
809     myIsBoundaryPointsFound = true;
810   }
811
812   // Assure that U range is proportional to V range
813
814   Bnd_Box2d bndBox;
815   vector< TPoint >::iterator pVecIt = myPoints.begin();
816   for ( ; pVecIt != myPoints.end(); pVecIt++ )
817     bndBox.Add( gp_Pnt2d( (*pVecIt).myInitUV ));
818   double minU, minV, maxU, maxV;
819   bndBox.Get( minU, minV, maxU, maxV );
820   double dU = maxU - minU, dV = maxV - minV;
821   if ( dU <= DBL_MIN || dV <= DBL_MIN ) {
822     Clear();
823     return setErrorCode( ERR_LOADF_NARROW_FACE );
824   }
825   double ratio = dU / dV, maxratio = 3, scale;
826   int iCoord = 0;
827   if ( ratio > maxratio ) {
828     scale = ratio / maxratio;
829     iCoord = 2;
830   }
831   else if ( ratio < 1./maxratio ) {
832     scale = maxratio / ratio;
833     iCoord = 1;
834   }
835   if ( iCoord ) {
836     SCRUTE( scale );
837     for ( pVecIt = myPoints.begin(); pVecIt != myPoints.end(); pVecIt++ ) {
838       TPoint & p = *pVecIt;
839       p.myInitUV.SetCoord( iCoord, p.myInitUV.Coord( iCoord ) * scale );
840       p.myInitXYZ.SetCoord( p.myInitUV.X(), p.myInitUV.Y(), 0 );
841     }
842   }
843   if ( myElemPointIDs.empty() ) {
844     MESSAGE( "No elements bound to the face");
845     return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
846   }
847
848   return setErrorCode( ERR_OK );
849 }
850
851 //=======================================================================
852 //function : computeUVOnEdge
853 //purpose  : compute coordinates of points on theEdge
854 //=======================================================================
855
856 void SMESH_Pattern::computeUVOnEdge (const TopoDS_Edge&      theEdge,
857                                      const list< TPoint* > & ePoints )
858 {
859   bool isForward = ( theEdge.Orientation() == TopAbs_FORWARD );
860   double f, l;
861   Handle(Geom2d_Curve) C2d =
862     BRep_Tool::CurveOnSurface( theEdge, TopoDS::Face( myShape ), f, l );
863
864   ePoints.back()->myInitU = 1.0;
865   list< TPoint* >::const_iterator pIt = ePoints.begin();
866   for ( pIt++; pIt != ePoints.end(); pIt++ )
867   {
868     TPoint* point = *pIt;
869     // U
870     double du = ( isForward ? point->myInitU : 1 - point->myInitU );
871     point->myU = ( f * ( 1 - du ) + l * du );
872     // UV
873     point->myUV = C2d->Value( point->myU ).XY();
874   }
875 }
876
877 //=======================================================================
878 //function : intersectIsolines
879 //purpose  : 
880 //=======================================================================
881
882 static bool intersectIsolines(const gp_XY& uv11, const gp_XY& uv12, const double r1,
883                               const gp_XY& uv21, const gp_XY& uv22, const double r2,
884                               gp_XY& resUV,
885                               bool& isDeformed)
886 {
887   gp_XY loc1 = uv11 * ( 1 - r1 ) + uv12 * r1;
888   gp_XY loc2 = uv21 * ( 1 - r2 ) + uv22 * r2;
889   resUV = 0.5 * ( loc1 + loc2 );
890   isDeformed = ( loc1 - loc2 ).SquareModulus() > 1e-8;
891 //   double len1 = ( uv11 - uv12 ).Modulus();
892 //   double len2 = ( uv21 - uv22 ).Modulus();
893 //   resUV = loc1 * len2 / ( len1 + len2 ) + loc2 * len1 / ( len1 + len2 );
894 //  return true;
895
896   
897 //   gp_Lin2d line1( uv11, uv12 - uv11 );
898 //   gp_Lin2d line2( uv21, uv22 - uv21 );
899 //   double angle = Abs( line1.Angle( line2 ) );
900
901 //     IntAna2d_AnaIntersection inter;
902 //     inter.Perform( line1.Normal( loc1 ), line2.Normal( loc2 ) );
903 //     if ( inter.IsDone() && inter.NbPoints() == 1 )
904 //     {
905 //       gp_Pnt2d interUV = inter.Point(1).Value();
906 //       resUV += interUV.XY();
907 //   inter.Perform( line1, line2 );
908 //   interUV = inter.Point(1).Value();
909 //   resUV += interUV.XY();
910   
911 //   resUV /= 2.;
912 //     }
913   return true;
914 }
915
916 //=======================================================================
917 //function : compUVByIsoIntersection
918 //purpose  : 
919 //=======================================================================
920
921 bool SMESH_Pattern::compUVByIsoIntersection (const list< list< TPoint* > >& theBndPoints,
922                                              const gp_XY&                   theInitUV,
923                                              gp_XY&                         theUV,
924                                              bool &                         theIsDeformed )
925 {
926   // compute UV by intersection of 2 iso lines
927   //gp_Lin2d isoLine[2];
928   gp_XY uv1[2], uv2[2];
929   double ratio[2];
930   const double zero = DBL_MIN;
931   for ( int iIso = 0; iIso < 2; iIso++ )
932   {
933     // to build an iso line:
934     // find 2 pairs of consequent edge-points such that the range of their
935     // initial parameters encloses the in-face point initial parameter
936     gp_XY UV[2], initUV[2];
937     int nbUV = 0, iCoord = iIso + 1;
938     double initParam = theInitUV.Coord( iCoord );
939
940     list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
941     for ( ; bndIt != theBndPoints.end(); bndIt++ )
942     {
943       const list< TPoint* > & bndPoints = * bndIt;
944       TPoint* prevP = bndPoints.back(); // this is the first point
945       list< TPoint* >::const_iterator pIt = bndPoints.begin();
946       bool coincPrev = false; 
947       // loop on the edge-points
948       for ( ; pIt != bndPoints.end(); pIt++ )
949       {
950         double paramDiff     = initParam - (*pIt)->myInitUV.Coord( iCoord );
951         double prevParamDiff = initParam - prevP->myInitUV.Coord( iCoord );
952         double sumOfDiff = Abs(prevParamDiff) + Abs(paramDiff);
953         if (!coincPrev && // ignore if initParam coincides with prev point param
954             sumOfDiff > zero && // ignore if both points coincide with initParam
955             prevParamDiff * paramDiff <= zero )
956         {
957           // find UV in parametric space of theFace
958           double r = Abs(prevParamDiff) / sumOfDiff;
959           gp_XY uvInit = (*pIt)->myInitUV * r + prevP->myInitUV * ( 1 - r );
960           int i = nbUV++;
961           if ( i >= 2 ) {
962             // throw away uv most distant from <theInitUV>
963             gp_XY vec0 = initUV[0] - theInitUV;
964             gp_XY vec1 = initUV[1] - theInitUV;
965             gp_XY vec  = uvInit    - theInitUV;
966             bool isBetween = ( vec0 * vec1 < 0 ); // is theInitUV between initUV[0] and initUV[1]
967             double dist0 = vec0.SquareModulus();
968             double dist1 = vec1.SquareModulus();
969             double dist  = vec .SquareModulus();
970             if ( !isBetween || dist < dist0 || dist < dist1 ) {
971               i = ( dist0 < dist1 ? 1 : 0 );
972               if ( isBetween && vec.Dot( i ? vec1 : vec0 ) < 0 )
973                 i = 3; // theInitUV must remain between
974             }
975           }
976           if ( i < 2 ) {
977             initUV[ i ] = uvInit;
978             UV[ i ]     = (*pIt)->myUV * r + prevP->myUV * ( 1 - r );
979           }
980           coincPrev = ( Abs(paramDiff) <= zero );
981         }
982         else
983           coincPrev = false;
984         prevP = *pIt;
985       }
986     }
987     if ( nbUV < 2 || (UV[0]-UV[1]).SquareModulus() <= DBL_MIN*DBL_MIN ) {
988       MESSAGE(" consequent edge-points not found, nb UV found: " << nbUV <<
989               ", for point: " << theInitUV.X() <<" " << theInitUV.Y() );
990       return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
991     }
992     // an iso line should be normal to UV[0] - UV[1] direction
993     // and be located at the same relative distance as from initial ends
994     //gp_Lin2d iso( UV[0], UV[0] - UV[1] );
995     double r =
996       (initUV[0]-theInitUV).Modulus() / (initUV[0]-initUV[1]).Modulus();
997     //gp_Pnt2d isoLoc = UV[0] * ( 1 - r ) + UV[1] * r;
998     //isoLine[ iIso ] = iso.Normal( isoLoc );
999     uv1[ iIso ] = UV[0];
1000     uv2[ iIso ] = UV[1];
1001     ratio[ iIso ] = r;
1002   }
1003   if ( !intersectIsolines( uv1[0], uv2[0], ratio[0],
1004                           uv1[1], uv2[1], ratio[1], theUV, theIsDeformed )) {
1005     MESSAGE(" Cant intersect isolines for a point "<<theInitUV.X()<<", "<<theInitUV.Y());
1006     return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
1007   }
1008
1009   return true;
1010 }
1011
1012
1013 // ==========================================================
1014 // structure representing a node of a grid of iso-poly-lines
1015 // ==========================================================
1016
1017 struct TIsoNode {
1018   bool   myIsMovable;
1019   gp_XY  myInitUV;
1020   gp_XY  myUV;
1021   double myRatio[2];
1022   gp_Dir2d  myDir[2]; // boundary tangent dir for boundary nodes, iso dir for internal ones
1023   TIsoNode* myNext[4]; // order: (iDir=0,isForward=0), (1,0), (0,1), (1,1)
1024   TIsoNode* myBndNodes[4];     // order: (iDir=0,i=0), (1,0), (0,1), (1,1)
1025   TIsoNode(double initU, double initV):
1026     myInitUV( initU, initV ), myUV( 1e100, 1e100 ), myIsMovable(true)
1027   { myNext[0] = myNext[1] = myNext[2] = myNext[3] = 0; }
1028   bool IsUVComputed() const
1029   { return myUV.X() != 1e100; }
1030   bool IsMovable() const
1031   { return myIsMovable && myNext[0] && myNext[1] && myNext[2] && myNext[3]; }
1032   void SetNotMovable()
1033   { myIsMovable = false; }
1034   void SetBoundaryNode(TIsoNode* node, int iDir, int i)
1035   { myBndNodes[ iDir + i * 2 ] = node; }
1036   TIsoNode* GetBoundaryNode(int iDir, int i)
1037   { return myBndNodes[ iDir + i * 2 ]; }
1038   void SetNext(TIsoNode* node, int iDir, int isForward)
1039   { myNext[ iDir + isForward  * 2 ] = node; }
1040   TIsoNode* GetNext(int iDir, int isForward)
1041   { return myNext[ iDir + isForward * 2 ]; }
1042 };
1043
1044 //=======================================================================
1045 //function : getNextNode
1046 //purpose  : 
1047 //=======================================================================
1048
1049 static inline TIsoNode* getNextNode(const TIsoNode* node, int dir )
1050 {
1051   TIsoNode* n = node->myNext[ dir ];
1052   if ( n && !n->IsUVComputed()/* && node->IsMovable()*/ ) {
1053     n = 0;//node->myBndNodes[ dir ];
1054 //     MESSAGE("getNextNode: use bnd for node "<<
1055 //             node->myInitUV.X()<<" "<<node->myInitUV.Y());
1056   }
1057   return n;
1058 }
1059 //=======================================================================
1060 //function : checkQuads
1061 //purpose  : check if newUV destortes quadrangles around node,
1062 //           and if ( crit == FIX_OLD ) fix newUV in this case
1063 //=======================================================================
1064
1065 enum { CHECK_NEW_IN, CHECK_NEW_OK, FIX_OLD };
1066
1067 static bool checkQuads (const TIsoNode* node,
1068                         gp_XY&          newUV,
1069                         const bool      reversed,
1070                         const int       crit = FIX_OLD,
1071                         double          fixSize = 0.)
1072 {
1073   gp_XY oldUV = node->myUV, oldUVFixed[4], oldUVImpr[4];
1074   int nbOldFix = 0, nbOldImpr = 0;
1075   double newBadRate = 0, oldBadRate = 0;
1076   bool newIsOk = true, newIsIn = true, oldIsIn = true, oldIsOk = true;
1077   int i, dir1 = 0, dir2 = 3;
1078   for ( ; dir1 < 4; dir1++, dir2++ )  // loop on 4 quadrangles around <node>
1079   {
1080     if ( dir2 > 3 ) dir2 = 0;
1081     TIsoNode* n[3];
1082     // walking counterclockwise around a quad,
1083     // nodes are in the order: node, n[0], n[1], n[2]
1084     n[0] = getNextNode( node, dir1 );
1085     n[2] = getNextNode( node, dir2 );
1086     if ( !n[0] || !n[2] ) continue;
1087     n[1] = getNextNode( n[0], dir2 );
1088     if ( !n[1] ) n[1] = getNextNode( n[2], dir1 );
1089     bool isTriangle = ( !n[1] );
1090     if ( reversed ) {
1091       TIsoNode* tmp = n[0]; n[0] = n[2]; n[2] = tmp;
1092     }
1093 //     if ( fixSize != 0 ) {
1094 // cout<<"NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1095 // cout<<"\t0: "<<n[0]->myInitUV.X()<<" "<<n[0]->myInitUV.Y()<<" UV: "<<n[0]->myUV.X()<<" "<<n[0]->myUV.Y()<<endl;
1096 // cout<<"\t1: "<<n[1]->myInitUV.X()<<" "<<n[1]->myInitUV.Y()<<" UV: "<<n[1]->myUV.X()<<" "<<n[1]->myUV.Y()<<endl;
1097 // cout<<"\t2: "<<n[2]->myInitUV.X()<<" "<<n[2]->myInitUV.Y()<<" UV: "<<n[2]->myUV.X()<<" "<<n[2]->myUV.Y()<<endl;
1098 // }
1099     // check if a quadrangle is degenerated
1100     if ( !isTriangle &&
1101         ((( n[0]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN ) ||
1102          (( n[2]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN )))
1103       isTriangle = true;
1104     if ( isTriangle &&
1105         ( n[0]->myUV - n[2]->myUV ).SquareModulus() <= DBL_MIN )
1106       continue;
1107
1108     // find min size of the diagonal node-n[1]
1109     double minDiag = fixSize;
1110     if ( minDiag == 0. ) {
1111       double maxLen2 = ( node->myUV - n[0]->myUV ).SquareModulus();
1112       if ( !isTriangle ) {
1113         maxLen2 = Max( maxLen2, ( n[0]->myUV - n[1]->myUV ).SquareModulus() );
1114         maxLen2 = Max( maxLen2, ( n[1]->myUV - n[2]->myUV ).SquareModulus() );
1115       }
1116       maxLen2 = Max( maxLen2, ( n[2]->myUV - node->myUV ).SquareModulus() );
1117       minDiag = sqrt( maxLen2 ) * PI / 60.; // ~ maxLen * Sin( 3 deg )
1118     }
1119
1120     // check if newUV is behind 3 dirs: n[0]-n[1], n[1]-n[2] and n[0]-n[2]
1121     // ( behind means "to the right of")
1122     // it is OK if
1123     // 1. newUV is not behind 01 and 12 dirs
1124     // 2. or newUV is not behind 02 dir and n[2] is convex
1125     bool newIn[3] = { true, true, true }, newOk[3] = { true, true, true };
1126     bool wasIn[3] = { true, true, true }, wasOk[3] = { true, true, true };
1127     gp_Vec2d moveVec[3], outVec[3];
1128     for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1129     {
1130       bool isDiag = ( i == 2 );
1131       if ( isDiag && newOk[0] && newOk[1] && !isTriangle )
1132         break;
1133       gp_Vec2d sideDir;
1134       if ( isDiag )
1135         sideDir = gp_Vec2d( n[0]->myUV, n[2]->myUV );
1136       else
1137         sideDir = gp_Vec2d( n[i]->myUV, n[i+1]->myUV );
1138
1139       gp_Vec2d outDir( sideDir.Y(), -sideDir.X() ); // to the right
1140       outDir.Normalize();
1141       gp_Vec2d newDir( n[i]->myUV, newUV );
1142       gp_Vec2d oldDir( n[i]->myUV, oldUV );
1143       outVec[i] = outDir;
1144       if ( newIsOk ) newOk[i] = ( outDir * newDir < -minDiag );
1145       if ( newIsIn ) newIn[i] = ( outDir * newDir < 0 );
1146       if ( crit == FIX_OLD ) {
1147         wasIn[i] = ( outDir * oldDir < 0 );
1148         wasOk[i] = ( outDir * oldDir < -minDiag );
1149         if ( !newOk[i] )
1150           newBadRate += outDir * newDir;
1151         if ( !wasOk[i] )
1152           oldBadRate += outDir * oldDir;
1153         // push node inside
1154         if ( !wasOk[i] ) {
1155           double oldDist = - outDir * oldDir;//, l2 = outDir * newDir;
1156           //               double r = ( l1 - minDiag ) / ( l1 + l2 );
1157           //               moveVec[i] = r * gp_Vec2d( node->myUV, newUV );
1158           moveVec[i] = ( oldDist - minDiag ) * outDir;
1159         }
1160       }
1161     }
1162
1163     // check if n[2] is convex
1164     bool convex = true;
1165     if ( !isTriangle )
1166       convex = ( outVec[0] * gp_Vec2d( n[1]->myUV, n[2]->myUV ) < 0 );
1167
1168     bool isNewOk = ( newOk[0] && newOk[1] ) || ( newOk[2] && convex );
1169     bool isNewIn = ( newIn[0] && newIn[1] ) || ( newIn[2] && convex );
1170     newIsOk = ( newIsOk && isNewOk );
1171     newIsIn = ( newIsIn && isNewIn );
1172
1173     if ( crit != FIX_OLD ) {
1174       if ( crit == CHECK_NEW_OK && !newIsOk ) break;
1175       if ( crit == CHECK_NEW_IN && !newIsIn ) break;
1176       continue;
1177     }
1178
1179     bool isOldIn = ( wasIn[0] && wasIn[1] ) || ( wasIn[2] && convex );
1180     bool isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1181     oldIsIn = ( oldIsIn && isOldIn );
1182     oldIsOk = ( oldIsOk && isOldIn );
1183
1184
1185     if ( !isOldIn ) { // node is outside a quadrangle
1186       // move newUV inside a quadrangle
1187 //MESSAGE("Quad "<< dir1 << "  WAS IN " << wasIn[0]<<" "<<wasIn[1]<<" "<<wasIn[2]);
1188       // node and newUV are outside: push newUV inside
1189       gp_XY uv;
1190       if ( convex || isTriangle ) {
1191         uv = 0.5 * ( n[0]->myUV + n[2]->myUV ) - minDiag * outVec[2].XY();
1192       }
1193       else {
1194         gp_Vec2d out = outVec[0].Normalized() + outVec[1].Normalized();
1195         double outSize = out.Magnitude();
1196         if ( outSize > DBL_MIN )
1197           out /= outSize;
1198         else
1199           out.SetCoord( -outVec[1].Y(), outVec[1].X() );
1200         uv = n[1]->myUV - minDiag * out.XY();
1201       }
1202       oldUVFixed[ nbOldFix++ ] = uv;
1203       //node->myUV = newUV;
1204     }
1205     else if ( !isOldOk )  {
1206       // try to fix old UV: move node inside as less as possible
1207 //MESSAGE("Quad "<< dir1 << "  old is BAD, try to fix old, minDiag: "<< minDiag);
1208       gp_XY uv1, uv2 = node->myUV;
1209       for ( i = isTriangle ? 2 : 0; i < 3; i++ ) // mark not computed vectors
1210         if ( wasOk[i] )
1211           moveVec[ i ].SetCoord( 1, 2e100); // not use this vector 
1212       while ( !isOldOk ) {
1213         // find the least moveVec
1214         int i, iMin = 4;
1215         double minMove2 = 1e100;
1216         for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1217         {
1218           if ( moveVec[i].Coord(1) < 1e100 ) {
1219             double move2 = moveVec[i].SquareMagnitude();
1220             if ( move2 < minMove2 ) {
1221               minMove2 = move2;
1222               iMin = i;
1223             }
1224           }
1225         }
1226         if ( iMin == 4 ) {
1227           break;
1228         }
1229         // move node to newUV
1230         uv1 = node->myUV + moveVec[ iMin ].XY();
1231         uv2 += moveVec[ iMin ].XY();
1232         moveVec[ iMin ].SetCoord( 1, 2e100); // not use this vector more
1233         // check if uv1 is ok
1234         for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1235           wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv1 ) < -minDiag );
1236         isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1237         if ( isOldOk )
1238           oldUVImpr[ nbOldImpr++ ] = uv1;
1239         else {
1240           // check if uv2 is ok
1241           for ( i = isTriangle ? 2 : 0; i < 3; i++ )
1242             wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv2 ) < -minDiag );
1243           isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
1244           if ( isOldOk )
1245             oldUVImpr[ nbOldImpr++ ] = uv2;
1246         }
1247       }
1248     }
1249
1250   } // loop on 4 quadrangles around <node>
1251
1252   if ( crit == CHECK_NEW_OK  )
1253     return newIsOk;
1254   if ( crit == CHECK_NEW_IN  )
1255     return newIsIn;
1256
1257   if ( newIsOk )
1258     return true;
1259
1260   if ( oldIsOk )
1261     newUV = oldUV;
1262   else {
1263     if ( oldIsIn && nbOldImpr ) {
1264 //       MESSAGE(" Try to improve UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1265 //               " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1266       gp_XY uv = oldUVImpr[ 0 ];
1267       for ( int i = 1; i < nbOldImpr; i++ )
1268         uv += oldUVImpr[ i ];
1269       uv /= nbOldImpr;
1270       if ( checkQuads( node, uv, reversed, CHECK_NEW_OK )) {
1271         newUV = uv;
1272         return false;
1273       }
1274       else {
1275         //MESSAGE(" Cant improve UV, uv: "<<uv.X()<<" "<<uv.Y());
1276       }
1277     }
1278     if ( !oldIsIn && nbOldFix ) {
1279 //       MESSAGE(" Try to fix UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
1280 //               " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
1281       gp_XY uv = oldUVFixed[ 0 ];
1282       for ( int i = 1; i < nbOldFix; i++ )
1283         uv += oldUVFixed[ i ];
1284       uv /= nbOldFix;
1285       if ( checkQuads( node, uv, reversed, CHECK_NEW_IN )) {
1286         newUV = uv;
1287         return false;
1288       }
1289       else {
1290         //MESSAGE(" Cant fix UV, uv: "<<uv.X()<<" "<<uv.Y());
1291       }
1292     }
1293     if ( newIsIn && oldIsIn )
1294       newUV = ( newBadRate < oldBadRate ) ? newUV : oldUV;
1295     else if ( !newIsIn )
1296       newUV = oldUV;
1297   }
1298
1299   return false;
1300 }
1301
1302 //=======================================================================
1303 //function : compUVByElasticIsolines
1304 //purpose  : compute UV as nodes of iso-poly-lines consisting of
1305 //           segments keeping relative size as in the pattern
1306 //=======================================================================
1307 //#define DEB_COMPUVBYELASTICISOLINES
1308 bool SMESH_Pattern::
1309   compUVByElasticIsolines(const list< list< TPoint* > >& theBndPoints,
1310                           const list< TPoint* >&         thePntToCompute)
1311 {
1312 //cout << "============================== KEY POINTS =============================="<<endl;
1313 //   list< int >::iterator kpIt = myKeyPointIDs.begin();
1314 //   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ ) {
1315 //     TPoint& p = myPoints[ *kpIt ];
1316 //     cout << "INIT: " << p.myInitUV.X() << " " << p.myInitUV.Y() <<
1317 //       " UV: " << p.myUV.X() << " " << p.myUV.Y() << endl;
1318 //  }
1319 //cout << "=============================="<<endl;
1320
1321   // Define parameters of iso-grid nodes in U and V dir
1322
1323   set< double > paramSet[ 2 ];
1324   list< list< TPoint* > >::const_iterator pListIt;
1325   list< TPoint* >::const_iterator pIt;
1326   for ( pListIt = theBndPoints.begin(); pListIt != theBndPoints.end(); pListIt++ ) {
1327     const list< TPoint* > & pList = * pListIt;
1328     for ( pIt = pList.begin(); pIt != pList.end(); pIt++ ) {
1329       paramSet[0].insert( (*pIt)->myInitUV.X() );
1330       paramSet[1].insert( (*pIt)->myInitUV.Y() );
1331     }
1332   }
1333   for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1334     paramSet[0].insert( (*pIt)->myInitUV.X() );
1335     paramSet[1].insert( (*pIt)->myInitUV.Y() );
1336   }
1337   // unite close parameters and split too long segments
1338   int iDir;
1339   double tol[ 2 ];
1340   for ( iDir = 0; iDir < 2; iDir++ )
1341   {
1342     set< double > & params = paramSet[ iDir ];
1343     double range = ( *params.rbegin() - *params.begin() );
1344     double toler = range / 1e6;
1345     tol[ iDir ] = toler;
1346 //    double maxSegment = range / params.size() / 2.;
1347 //
1348 //     set< double >::iterator parIt = params.begin();
1349 //     double prevPar = *parIt;
1350 //     for ( parIt++; parIt != params.end(); parIt++ )
1351 //     {
1352 //       double segLen = (*parIt) - prevPar;
1353 //       if ( segLen < toler )
1354 //         ;//params.erase( prevPar ); // unite
1355 //       else if ( segLen > maxSegment )
1356 //         params.insert( prevPar + 0.5 * segLen ); // split
1357 //       prevPar = (*parIt);
1358 //     }
1359   }
1360
1361   // Make nodes of a grid of iso-poly-lines
1362
1363   list < TIsoNode > nodes;
1364   typedef list < TIsoNode *> TIsoLine;
1365   map < double, TIsoLine > isoMap[ 2 ];
1366
1367   set< double > & params0 = paramSet[ 0 ];
1368   set< double >::iterator par0It = params0.begin();
1369   for ( ; par0It != params0.end(); par0It++ )
1370   {
1371     TIsoLine & isoLine0 = isoMap[0][ *par0It ]; // vertical isoline with const U
1372     set< double > & params1 = paramSet[ 1 ];
1373     set< double >::iterator par1It = params1.begin();
1374     for ( ; par1It != params1.end(); par1It++ )
1375     {
1376       nodes.push_back( TIsoNode( *par0It, *par1It ) );
1377       isoLine0.push_back( & nodes.back() );
1378       isoMap[1][ *par1It ].push_back( & nodes.back() );
1379     }
1380   }
1381
1382   // Compute intersections of boundaries with iso-lines:
1383   // only boundary nodes will have computed UV so far
1384
1385   Bnd_Box2d uvBnd;
1386   list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
1387   list< TIsoNode* > bndNodes; // nodes corresponding to outer theBndPoints
1388   for ( ; bndIt != theBndPoints.end(); bndIt++ )
1389   {
1390     const list< TPoint* > & bndPoints = * bndIt;
1391     TPoint* prevP = bndPoints.back(); // this is the first point
1392     list< TPoint* >::const_iterator pIt = bndPoints.begin();
1393     // loop on the edge-points
1394     for ( ; pIt != bndPoints.end(); pIt++ )
1395     {
1396       TPoint* point = *pIt;
1397       for ( iDir = 0; iDir < 2; iDir++ )
1398       {
1399         const int iCoord = iDir + 1;
1400         const int iOtherCoord = 2 - iDir;
1401         double par1 = prevP->myInitUV.Coord( iCoord );
1402         double par2 = point->myInitUV.Coord( iCoord );
1403         double parDif = par2 - par1;
1404         if ( Abs( parDif ) <= DBL_MIN )
1405           continue;
1406         // find iso-lines intersecting a bounadry
1407         double toler = tol[ 1 - iDir ];
1408         double minPar = Min ( par1, par2 );
1409         double maxPar = Max ( par1, par2 );
1410         map < double, TIsoLine >& isos = isoMap[ iDir ];
1411         map < double, TIsoLine >::iterator isoIt = isos.begin();
1412         for ( ; isoIt != isos.end(); isoIt++ )
1413         {
1414           double isoParam = (*isoIt).first;
1415           if ( isoParam < minPar || isoParam > maxPar )
1416             continue;
1417           double r = ( isoParam - par1 ) / parDif;
1418           gp_XY uv = ( 1 - r ) * prevP->myUV + r * point->myUV;
1419           gp_XY initUV = ( 1 - r ) * prevP->myInitUV + r * point->myInitUV;
1420           double otherPar = initUV.Coord( iOtherCoord ); // along isoline
1421           // find existing node with otherPar or insert a new one
1422           TIsoLine & isoLine = (*isoIt).second;
1423           double nodePar;
1424           TIsoLine::iterator nIt = isoLine.begin();
1425           for ( ; nIt != isoLine.end(); nIt++ ) {
1426             nodePar = (*nIt)->myInitUV.Coord( iOtherCoord );
1427             if ( nodePar >= otherPar )
1428               break;
1429           }
1430           TIsoNode * node;
1431           if ( Abs( nodePar - otherPar ) <= toler )
1432             node = ( nIt == isoLine.end() ) ? isoLine.back() : (*nIt);
1433           else {
1434             nodes.push_back( TIsoNode( initUV.X(), initUV.Y() ) );
1435             node = & nodes.back();
1436             isoLine.insert( nIt, node );
1437           }
1438           node->SetNotMovable();
1439           node->myUV = uv;
1440           uvBnd.Add( gp_Pnt2d( uv ));
1441 //  cout << "bnd: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
1442           // tangent dir
1443           gp_XY tgt( point->myUV - prevP->myUV );
1444           if ( ::IsEqual( r, 1. ))
1445             node->myDir[ 0 ] = tgt;
1446           else if ( ::IsEqual( r, 0. ))
1447             node->myDir[ 1 ] = tgt;
1448           else
1449             node->myDir[ 1 ] = node->myDir[ 0 ] = tgt;
1450           // keep boundary nodes corresponding to boundary points
1451           if ( bndIt == theBndPoints.begin() && ::IsEqual( r, 1. ))
1452             if ( bndNodes.empty() || bndNodes.back() != node )
1453               bndNodes.push_back( node );
1454         } // loop on isolines
1455       } // loop on 2 directions
1456       prevP = point;
1457     } // loop on boundary points
1458   } // loop on boundaries
1459
1460   // Define orientation
1461
1462   // find the point with the least X
1463   double leastX = DBL_MAX;
1464   TIsoNode * leftNode;
1465   list < TIsoNode >::iterator nodeIt = nodes.begin();
1466   for ( ; nodeIt != nodes.end(); nodeIt++  ) {
1467     TIsoNode & node = *nodeIt;
1468     if ( node.IsUVComputed() && node.myUV.X() < leastX ) {
1469       leastX = node.myUV.X();
1470       leftNode = &node;
1471     }
1472 // if ( node.IsUVComputed() ) {
1473 // cout << "bndNode INIT: " << node.myInitUV.X()<<" "<<node.myInitUV.Y()<<" UV: "<<
1474 //   node.myUV.X()<<" "<<node.myUV.Y()<<endl<<
1475 //    " dir0: "<<node.myDir[0].X()<<" "<<node.myDir[0].Y() <<
1476 //      " dir1: "<<node.myDir[1].X()<<" "<<node.myDir[1].Y() << endl;
1477 // }
1478   }
1479   bool reversed = ( leftNode->myDir[0].Y() + leftNode->myDir[1].Y() > 0 );
1480   //SCRUTE( reversed );
1481
1482   // Prepare internal nodes:
1483   // 1. connect nodes
1484   // 2. compute ratios
1485   // 3. find boundary nodes for each node
1486   // 4. remove nodes out of the boundary
1487   for ( iDir = 0; iDir < 2; iDir++ )
1488   {
1489     const int iCoord = 2 - iDir; // coord changing along an isoline
1490     map < double, TIsoLine >& isos = isoMap[ iDir ];
1491     map < double, TIsoLine >::iterator isoIt = isos.begin();
1492     for ( ; isoIt != isos.end(); isoIt++ )
1493     {
1494       TIsoLine & isoLine = (*isoIt).second;
1495       bool firstCompNodeFound = false;
1496       TIsoLine::iterator lastCompNodePos, nPrevIt, nIt, nNextIt, nIt2;
1497       nPrevIt = nIt = nNextIt = isoLine.begin();
1498       nIt++;
1499       nNextIt++; nNextIt++;
1500       while ( nIt != isoLine.end() )
1501       {
1502         // 1. connect prev - cur
1503         TIsoNode* node = *nIt, * prevNode = *nPrevIt;
1504         if ( !firstCompNodeFound && prevNode->IsUVComputed() ) {
1505           firstCompNodeFound = true;
1506           lastCompNodePos = nPrevIt;
1507         }
1508         if ( firstCompNodeFound ) {
1509           node->SetNext( prevNode, iDir, 0 );
1510           prevNode->SetNext( node, iDir, 1 );
1511         }
1512         // 2. compute ratio
1513         if ( nNextIt != isoLine.end() ) {
1514           double par1 = prevNode->myInitUV.Coord( iCoord );
1515           double par2 = node->myInitUV.Coord( iCoord );
1516           double par3 = (*nNextIt)->myInitUV.Coord( iCoord );
1517           node->myRatio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1518         }
1519         // 3. find boundary nodes
1520         if ( node->IsUVComputed() )
1521           lastCompNodePos = nIt;
1522         else if ( firstCompNodeFound && nNextIt != isoLine.end() ) {
1523           TIsoNode* bndNode1 = *lastCompNodePos, *bndNode2 = 0;
1524           for ( nIt2 = nNextIt; nIt2 != isoLine.end(); nIt2++ )
1525             if ( (*nIt2)->IsUVComputed() )
1526               break;
1527           if ( nIt2 != isoLine.end() ) {
1528             bndNode2 = *nIt2;
1529             node->SetBoundaryNode( bndNode1, iDir, 0 );
1530             node->SetBoundaryNode( bndNode2, iDir, 1 );
1531 // cout << "--------------------------------------------------"<<endl;
1532 //  cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<<endl<<
1533 //   " dir0: "<<bndNode1->myDir[0].X()<<" "<<bndNode1->myDir[0].Y() <<
1534 //     " dir1: "<<bndNode1->myDir[1].X()<<" "<<bndNode1->myDir[1].Y() << endl;
1535 //  cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl<<
1536 //   " dir0: "<<bndNode2->myDir[0].X()<<" "<<bndNode2->myDir[0].Y() <<
1537 //     " dir1: "<<bndNode2->myDir[1].X()<<" "<<bndNode2->myDir[1].Y() << endl;
1538           }
1539         }
1540         nIt++; nPrevIt++;
1541         if ( nNextIt != isoLine.end() ) nNextIt++;
1542         // 4. remove nodes out of the boundary
1543         if ( !firstCompNodeFound )
1544           isoLine.pop_front();
1545       } // loop on isoLine nodes
1546
1547       // remove nodes after the boundary
1548 //       for ( nIt = ++lastCompNodePos; nIt != isoLine.end(); nIt++ )
1549 //         (*nIt)->SetNotMovable();
1550       isoLine.erase( ++lastCompNodePos, isoLine.end() );
1551     } // loop on isolines
1552   } // loop on 2 directions
1553
1554   // Compute local isoline direction for internal nodes
1555
1556   /*
1557   map < double, TIsoLine >& isos = isoMap[ 0 ]; // vertical isolines with const U
1558   map < double, TIsoLine >::iterator isoIt = isos.begin();
1559   for ( ; isoIt != isos.end(); isoIt++ )
1560   {
1561     TIsoLine & isoLine = (*isoIt).second;
1562     TIsoLine::iterator nIt = isoLine.begin();
1563     for ( ; nIt != isoLine.end(); nIt++ )
1564     {
1565       TIsoNode* node = *nIt;
1566       if ( node->IsUVComputed() || !node->IsMovable() )
1567         continue;
1568       gp_Vec2d aTgt[2], aNorm[2];
1569       double ratio[2];
1570       bool OK = true;
1571       for ( iDir = 0; iDir < 2; iDir++ )
1572       {
1573         TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1574         TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1575         if ( !bndNode1 || !bndNode2 ) {
1576           OK = false;
1577           break;
1578         }
1579         const int iCoord = 2 - iDir; // coord changing along an isoline
1580         double par1 = bndNode1->myInitUV.Coord( iCoord );
1581         double par2 = node->myInitUV.Coord( iCoord );
1582         double par3 = bndNode2->myInitUV.Coord( iCoord );
1583         ratio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
1584
1585         gp_Vec2d tgt1( bndNode1->myDir[0].XY() + bndNode1->myDir[1].XY() );
1586         gp_Vec2d tgt2( bndNode2->myDir[0].XY() + bndNode2->myDir[1].XY() );
1587         if ( bool( iDir ) == reversed ) tgt2.Reverse(); // along perpend. isoline
1588         else                            tgt1.Reverse();
1589 //cout<<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" | "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1590
1591         if ( ratio[ iDir ] < 0.5 )
1592           aNorm[ iDir ] = gp_Vec2d( -tgt1.Y(), tgt1.X() ); // rotate tgt to the left
1593         else
1594           aNorm[ iDir ] = gp_Vec2d( -tgt2.Y(), tgt2.X() );
1595         if ( iDir == 1 )
1596           aNorm[ iDir ].Reverse();  // along iDir isoline
1597
1598         double angle = tgt1.Angle( tgt2 ); //  [-PI, PI]
1599         // maybe angle is more than |PI|
1600         if ( Abs( angle ) > PI / 2. ) {
1601           // check direction of the last but one perpendicular isoline
1602           TIsoNode* prevNode = bndNode2->GetNext( iDir, 0 );
1603           bndNode1 = prevNode->GetBoundaryNode( 1 - iDir, 0 );
1604           bndNode2 = prevNode->GetBoundaryNode( 1 - iDir, 1 );
1605           gp_Vec2d isoDir( bndNode1->myUV, bndNode2->myUV );
1606           if ( isoDir * tgt2 < 0 )
1607             isoDir.Reverse();
1608           double angle2 = tgt1.Angle( isoDir );
1609           //cout << " isoDir: "<< isoDir.X() <<" "<<isoDir.Y() << " ANGLE: "<< angle << " "<<angle2<<endl;
1610           if (angle2 * angle < 0 && // check the sign of an angle close to PI
1611               Abs ( Abs ( angle ) - PI ) <= PI / 180. ) {
1612             //MESSAGE("REVERSE ANGLE");
1613             angle = -angle;
1614           }
1615           if ( Abs( angle2 ) > Abs( angle ) ||
1616               ( angle2 * angle < 0 && Abs( angle2 ) > Abs( angle - angle2 ))) {
1617             //MESSAGE("Add PI");
1618             // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1619             // cout <<"ISO: " << isoParam << " " << (*iso2It).first << endl;
1620             // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<< endl;
1621             // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl;
1622             // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<"  "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1623             angle += ( angle < 0 ) ? 2. * PI : -2. * PI;
1624           }
1625         }
1626         aTgt[ iDir ] = tgt1.Rotated( angle * ratio[ iDir ] ).XY();
1627       } // loop on 2 dir
1628
1629       if ( OK ) {
1630         for ( iDir = 0; iDir < 2; iDir++ )
1631         {
1632           aTgt[iDir].Normalize();
1633           aNorm[1-iDir].Normalize();
1634           double r = Abs ( ratio[iDir] - 0.5 ) * 2.0; // [0,1] - distance from the middle
1635           r *= r;
1636           
1637           node->myDir[iDir] = //aTgt[iDir];
1638             aNorm[1-iDir] * r + aTgt[iDir] * ( 1. - r );
1639         }
1640 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1641 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" - "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
1642 //  cout << " isoDir: "<< node->myDir[0].X() <<" "<<node->myDir[0].Y()<<"  |  "
1643 //    << node->myDir[1].X() <<" "<<node->myDir[1].Y()<<endl;
1644       }
1645     } // loop on iso nodes
1646   } // loop on isolines
1647 */
1648   // Find nodes to start computing UV from
1649
1650   list< TIsoNode* > startNodes;
1651   list< TIsoNode* >::iterator nIt = bndNodes.end();
1652   TIsoNode* node = *(--nIt);
1653   TIsoNode* prevNode = *(--nIt);
1654   for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1655   {
1656     TIsoNode* nextNode = *nIt;
1657     gp_Vec2d initTgt1( prevNode->myInitUV, node->myInitUV );
1658     gp_Vec2d initTgt2( node->myInitUV, nextNode->myInitUV );
1659     double initAngle = initTgt1.Angle( initTgt2 );
1660     double angle = node->myDir[0].Angle( node->myDir[1] );
1661     if ( reversed ) angle = -angle;
1662     if ( initAngle > angle && initAngle - angle > PI / 2.1 ) {
1663       // find a close internal node
1664       TIsoNode* nClose = 0;
1665       list< TIsoNode* > testNodes;
1666       testNodes.push_back( node );
1667       list< TIsoNode* >::iterator it = testNodes.begin();
1668       for ( ; !nClose && it != testNodes.end(); it++ )
1669       {
1670         for (int i = 0; i < 4; i++ )
1671         {
1672           nClose = (*it)->myNext[ i ];
1673           if ( nClose ) {
1674             if ( !nClose->IsUVComputed() )
1675               break;
1676             else {
1677               testNodes.push_back( nClose );
1678               nClose = 0;
1679             }
1680           }
1681         }
1682       }
1683       startNodes.push_back( nClose );
1684 // cout << "START: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<
1685 //   node->myUV.X()<<" "<<node->myUV.Y()<<endl<<
1686 //   "initAngle: " << initAngle << " angle: " << angle << endl;
1687 // cout <<" init tgt: " << initTgt1.X()<<" "<<initTgt1.Y()<<" | "<< initTgt2.X()<<" "<<initTgt2.Y()<<endl;
1688 // cout << " tgt: "<< node->myDir[ 0 ].X() <<" "<<node->myDir[ 0 ].Y()<<" | "<<
1689 //    node->myDir[ 1 ].X() <<" "<<node->myDir[ 1 ].Y()<<endl;
1690 // cout << "CLOSE: "<<nClose->myInitUV.X()<<" "<<nClose->myInitUV.Y()<<endl;
1691     }
1692     prevNode = node;
1693     node = nextNode;
1694   }
1695
1696   // Compute starting UV of internal nodes
1697
1698   list < TIsoNode* > internNodes;
1699   bool needIteration = true;
1700   if ( startNodes.empty() ) {
1701     MESSAGE( " Starting UV by compUVByIsoIntersection()");
1702     needIteration = false;
1703     map < double, TIsoLine >& isos = isoMap[ 0 ];
1704     map < double, TIsoLine >::iterator isoIt = isos.begin();
1705     for ( ; isoIt != isos.end(); isoIt++ )
1706     {
1707       TIsoLine & isoLine = (*isoIt).second;
1708       TIsoLine::iterator nIt = isoLine.begin();
1709       for ( ; !needIteration && nIt != isoLine.end(); nIt++ )
1710       {
1711         TIsoNode* node = *nIt;
1712         if ( !node->IsUVComputed() && node->IsMovable() ) {
1713           internNodes.push_back( node );
1714           //bool isDeformed;
1715           if ( !compUVByIsoIntersection(theBndPoints, node->myInitUV,
1716                                         node->myUV, needIteration ))
1717             node->myUV = node->myInitUV;
1718         }
1719       }
1720     }
1721     if ( needIteration )
1722       for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
1723       {
1724         TIsoNode* node = *nIt, *nClose = 0;
1725         list< TIsoNode* > testNodes;
1726         testNodes.push_back( node );
1727         list< TIsoNode* >::iterator it = testNodes.begin();
1728         for ( ; !nClose && it != testNodes.end(); it++ )
1729         {
1730           for (int i = 0; i < 4; i++ )
1731           {
1732             nClose = (*it)->myNext[ i ];
1733             if ( nClose ) {
1734               if ( !nClose->IsUVComputed() && nClose->IsMovable() )
1735                 break;
1736               else {
1737                 testNodes.push_back( nClose );
1738                 nClose = 0;
1739               }
1740             }
1741           }
1742         }
1743         startNodes.push_back( nClose );
1744       }
1745   }
1746
1747   double aMin[2], aMax[2], step[2];
1748   uvBnd.Get( aMin[0], aMin[1], aMax[0], aMax[1] );
1749   double minUvSize = Min ( aMax[0]-aMin[0], aMax[1]-aMin[1] );
1750   step[0] = minUvSize / paramSet[ 0 ].size() / 10;
1751   step[1] = minUvSize / paramSet[ 1 ].size() / 10;
1752 //cout << "STEPS: " << step[0] << " " << step[1]<< endl;
1753
1754   for ( nIt = startNodes.begin(); nIt != startNodes.end(); nIt++ )
1755   {
1756     TIsoNode* prevN[2], *node = *nIt;
1757     if ( node->IsUVComputed() || !node->IsMovable() )
1758       continue;
1759     gp_XY newUV( 0, 0 ), sumDir( 0, 0 );
1760     int nbComp = 0, nbPrev = 0;
1761     for ( iDir = 0; iDir < 2; iDir++ )
1762     {
1763       TIsoNode* prevNode1 = 0, *prevNode2 = 0;
1764       TIsoNode* n = node->GetNext( iDir, 0 );
1765       if ( n->IsUVComputed() )
1766         prevNode1 = n;
1767       else
1768         startNodes.push_back( n );
1769       n = node->GetNext( iDir, 1 );
1770       if ( n->IsUVComputed() )
1771         prevNode2 = n;
1772       else
1773         startNodes.push_back( n );
1774       if ( !prevNode1 ) {
1775         prevNode1 = prevNode2;
1776         prevNode2 = 0;
1777       }
1778       if ( prevNode1 ) nbPrev++;
1779       if ( prevNode2 ) nbPrev++;
1780       if ( prevNode1 ) {
1781         gp_XY dir;
1782           double prevPar = prevNode1->myInitUV.Coord( 2 - iDir );
1783           double par = node->myInitUV.Coord( 2 - iDir );
1784           bool isEnd = ( prevPar > par );
1785 //          dir = node->myDir[ 1 - iDir ].XY() * ( isEnd ? -1. : 1. );
1786         //cout << "__________"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1787           TIsoNode* bndNode = node->GetBoundaryNode( iDir, isEnd );
1788           gp_XY tgt( bndNode->myDir[0].XY() + bndNode->myDir[1].XY() );
1789           dir.SetCoord( 1, tgt.Y() * ( reversed ? 1 : -1 ));
1790           dir.SetCoord( 2, tgt.X() * ( reversed ? -1 : 1 ));
1791         //cout << "bndNode UV: " << bndNode->myUV.X()<<" "<<bndNode->myUV.Y()<< endl;
1792           //  cout << " tgt: "<< bndNode->myDir[ 0 ].X() <<" "<<bndNode->myDir[ 0 ].Y()<<" | "<<
1793           //     bndNode->myDir[ 1 ].X() <<" "<<bndNode->myDir[ 1 ].Y()<<endl;
1794           //cout << "prevNode UV: " << prevNode1->myUV.X()<<" "<<prevNode1->myUV.Y()<<
1795             //" par: " << prevPar << endl;
1796           //           cout <<" tgt: " << tgt.X()<<" "<<tgt.Y()<<endl;
1797         //cout << " DIR: "<< dir.X() <<" "<<dir.Y()<<endl;
1798         if ( prevNode2 ) {
1799           //cout << "____2next______"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1800           gp_XY & uv1 = prevNode1->myUV;
1801           gp_XY & uv2 = prevNode2->myUV;
1802 //           dir = ( uv2 - uv1 );
1803 //           double len = dir.Modulus();
1804 //           if ( len > DBL_MIN )
1805 //             dir /= len * 0.5;
1806           double r = node->myRatio[ iDir ];
1807           newUV += uv1 * ( 1 - r ) + uv2 * r;
1808         }
1809         else {
1810           newUV += prevNode1->myUV + dir * step[ iDir ];
1811         }
1812         sumDir += dir;
1813         prevN[ iDir ] = prevNode1;
1814         nbComp++;
1815       }
1816     }
1817     newUV /= nbComp;
1818     node->myUV = newUV;
1819     //cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
1820
1821     // check if a quadrangle is not distorted
1822     if ( nbPrev > 1 ) {
1823       //int crit = ( nbPrev == 4 ) ? FIX_OLD : CHECK_NEW_IN;
1824       if ( !checkQuads( node, newUV, reversed, FIX_OLD, step[0] + step[1] )) {
1825       //cout <<" newUV: " << node->myUV.X() << " "<<node->myUV.Y() << " nbPrev: "<<nbPrev<< endl;
1826       //  cout << "_FIX_INIT_ fixedUV: " << newUV.X() << " "<<newUV.Y() << endl;
1827         node->myUV = newUV;
1828       }
1829     }
1830     internNodes.push_back( node );
1831   }
1832   
1833   // Move nodes
1834
1835   static int maxNbIter = 100;
1836 #ifdef DEB_COMPUVBYELASTICISOLINES
1837 //   maxNbIter++;
1838   bool useNbMoveNode = 0;
1839   static int maxNbNodeMove = 100;
1840   maxNbNodeMove++;
1841   int nbNodeMove = 0;
1842   if ( !useNbMoveNode )
1843     maxNbIter = ( maxNbIter < 0 ) ? 100 : -1;
1844 #endif    
1845   double maxMove;
1846   int nbIter = 0;
1847   do {
1848     if ( !needIteration) break;
1849 #ifdef DEB_COMPUVBYELASTICISOLINES
1850     if ( nbIter >= maxNbIter ) break;
1851 #endif
1852     maxMove = 0.0;
1853     list < TIsoNode* >::iterator nIt = internNodes.begin();
1854     for ( ; nIt != internNodes.end(); nIt++  ) {
1855 #ifdef DEB_COMPUVBYELASTICISOLINES
1856       if (useNbMoveNode )
1857         cout << nbNodeMove <<" =================================================="<<endl;
1858 #endif
1859       TIsoNode * node = *nIt;
1860       // make lines
1861       //gp_Lin2d line[2];
1862       gp_XY loc[2];
1863       for ( iDir = 0; iDir < 2; iDir++ )
1864       {
1865         gp_XY & uv1 = node->GetNext( iDir, 0 )->myUV;
1866         gp_XY & uv2 = node->GetNext( iDir, 1 )->myUV;
1867         double r = node->myRatio[ iDir ];
1868         loc[ iDir ] = uv1 * ( 1 - r ) + uv2 * r;
1869 //         line[ iDir ].SetLocation( loc[ iDir ] );
1870 //         line[ iDir ].SetDirection( node->myDir[ iDir ] );
1871       }
1872       // define ratio
1873       double locR[2] = { 0, 0 };
1874       for ( iDir = 0; iDir < 2; iDir++ )
1875       {
1876         const int iCoord = 2 - iDir; // coord changing along an isoline
1877         TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
1878         TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
1879         double par1 = bndNode1->myInitUV.Coord( iCoord );
1880         double par2 = node->myInitUV.Coord( iCoord );
1881         double par3 = bndNode2->myInitUV.Coord( iCoord );
1882         double r = ( par2 - par1 ) / ( par3 - par1 );
1883         r = Abs ( r - 0.5 ) * 2.0;  // [0,1] - distance from the middle
1884         locR[ iDir ] = ( 1 - r * r ) * 0.25;
1885       }
1886       //locR[0] = locR[1] = 0.25;
1887       // intersect the 2 lines and move a node
1888       //IntAna2d_AnaIntersection inter( line[0], line[1] );
1889       if ( /*inter.IsDone() && inter.NbPoints() ==*/ 1 )
1890       {
1891 //         double intR = 1 - locR[0] - locR[1];
1892 //         gp_XY newUV = inter.Point(1).Value().XY();
1893 //         if ( !checkQuads( node, newUV, reversed, CHECK_NEW_IN ))
1894 //           newUV = ( locR[0] * loc[0] + locR[1] * loc[1] ) / ( 1 - intR );
1895 //         else
1896 //           newUV = intR * newUV + locR[0] * loc[0] + locR[1] * loc[1];
1897         gp_XY newUV = 0.5 * ( loc[0] +  loc[1] );
1898         // avoid parallel isolines intersection
1899         checkQuads( node, newUV, reversed );
1900
1901         maxMove = Max( maxMove, ( newUV - node->myUV ).SquareModulus());
1902         node->myUV = newUV;
1903       } // intersection found
1904 #ifdef DEB_COMPUVBYELASTICISOLINES
1905       if (useNbMoveNode && ++nbNodeMove >= maxNbNodeMove ) break;
1906 #endif
1907     } // loop on internal nodes
1908 #ifdef DEB_COMPUVBYELASTICISOLINES
1909     if (useNbMoveNode && nbNodeMove >= maxNbNodeMove ) break;
1910 #endif
1911   } while ( maxMove > 1e-8 && nbIter++ < maxNbIter );
1912
1913   MESSAGE( "compUVByElasticIsolines(): Nb iterations " << nbIter << " dist: " << sqrt( maxMove ));
1914
1915   if ( nbIter >= maxNbIter && sqrt(maxMove) > minUvSize * 0.05 ) {
1916     MESSAGE( "compUVByElasticIsolines() failed: "<<sqrt(maxMove)<<">"<<minUvSize * 0.05);
1917 #ifndef DEB_COMPUVBYELASTICISOLINES
1918     return false;
1919 #endif
1920   }
1921
1922   // Set computed UV to points
1923
1924   for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
1925     TPoint* point = *pIt;
1926     //gp_XY oldUV = point->myUV;
1927     double minDist = DBL_MAX;
1928     list < TIsoNode >::iterator nIt = nodes.begin();
1929     for ( ; nIt != nodes.end(); nIt++ ) {
1930       double dist = ( (*nIt).myInitUV - point->myInitUV ).SquareModulus();
1931       if ( dist < minDist ) {
1932         minDist = dist;
1933         point->myUV = (*nIt).myUV;
1934       }
1935     }
1936   }
1937       
1938     
1939   return true;
1940 }
1941
1942
1943 //=======================================================================
1944 //function : setFirstEdge
1945 //purpose  : choose the best first edge of theWire; return the summary distance
1946 //           between point UV computed by isolines intersection and
1947 //           eventual UV got from edge p-curves
1948 //=======================================================================
1949
1950 //#define DBG_SETFIRSTEDGE
1951 double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstEdgeID)
1952 {
1953   int iE, nbEdges = theWire.size();
1954   if ( nbEdges == 1 )
1955     return 0;
1956
1957   // Transform UVs computed by iso to fit bnd box of a wire
1958
1959   // max nb of points on an edge
1960   int maxNbPnt = 0;
1961   int eID = theFirstEdgeID;
1962   for ( iE = 0; iE < nbEdges; iE++ )
1963     maxNbPnt = Max ( maxNbPnt, getShapePoints( eID++ ).size() );
1964   
1965   // compute bnd boxes
1966   TopoDS_Face face = TopoDS::Face( myShape );
1967   Bnd_Box2d bndBox, eBndBox;
1968   eID = theFirstEdgeID;
1969   list< TopoDS_Edge >::iterator eIt;
1970   list< TPoint* >::iterator pIt;
1971   for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
1972   {
1973     // UV by isos stored in TPoint.myXYZ
1974     list< TPoint* > & ePoints = getShapePoints( eID++ );
1975     for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
1976       TPoint* p = (*pIt);
1977       bndBox.Add( gp_Pnt2d( p->myXYZ.X(), p->myXYZ.Y() ));
1978     }
1979     // UV by an edge p-curve
1980     double f, l;
1981     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( *eIt, face, f, l );
1982     double dU = ( l - f ) / ( maxNbPnt - 1 );
1983     for ( int i = 0; i < maxNbPnt; i++ )
1984       eBndBox.Add( C2d->Value( f + i * dU ));
1985   }
1986
1987   // transform UVs by isos
1988   double minPar[2], maxPar[2], eMinPar[2], eMaxPar[2];
1989   bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
1990   eBndBox.Get( eMinPar[0], eMinPar[1], eMaxPar[0], eMaxPar[1] );
1991 #ifdef DBG_SETFIRSTEDGE
1992   cout << "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
1993     << eMinPar[1] << " - " << eMaxPar[1] << endl;
1994 #endif
1995   for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
1996   {
1997     double dMin = eMinPar[i] - minPar[i];
1998     double dMax = eMaxPar[i] - maxPar[i];
1999     double dPar = maxPar[i] - minPar[i];
2000     eID = theFirstEdgeID;
2001     for ( iE = 0; iE < nbEdges; iE++ ) // loop on edges of a boundary
2002     {
2003       list< TPoint* > & ePoints = getShapePoints( eID++ );
2004       for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) // loop on edge points
2005       {
2006         double par = (*pIt)->myXYZ.Coord( iC );
2007         double r = ( par - minPar[i] ) / dPar;
2008         par += ( 1 - r ) * dMin + r * dMax;
2009         (*pIt)->myXYZ.SetCoord( iC, par );
2010       }
2011     }
2012   }
2013
2014   TopoDS_Edge eBest;
2015   double minDist = DBL_MAX;
2016   for ( iE = 0 ; iE < nbEdges; iE++ )
2017   {
2018 #ifdef DBG_SETFIRSTEDGE
2019     cout << " VARIANT " << iE << endl;
2020 #endif
2021     // evaluate the distance between UV computed by the 2 methods:
2022     // by isos intersection ( myXYZ ) and by edge p-curves ( myUV )
2023     double dist = 0;
2024     int eID = theFirstEdgeID;
2025     for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
2026     {
2027       list< TPoint* > & ePoints = getShapePoints( eID++ );
2028       computeUVOnEdge( *eIt, ePoints );
2029       for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
2030         TPoint* p = (*pIt);
2031         dist += ( p->myUV - gp_XY( p->myXYZ.X(), p->myXYZ.Y() )).SquareModulus();
2032 #ifdef DBG_SETFIRSTEDGE
2033         cout << " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
2034           p->myUV.X() << ", " << p->myUV.Y() << ") " << endl;
2035 #endif
2036       }
2037     }
2038 #ifdef DBG_SETFIRSTEDGE
2039     cout << "dist -- " << dist << endl;
2040 #endif
2041     if ( dist < minDist ) {
2042       minDist = dist;
2043       eBest = theWire.front();
2044     }
2045     // check variant with another first edge
2046     theWire.splice( theWire.begin(), theWire, --theWire.end(), theWire.end() );
2047   }
2048   // put the best first edge to the theWire front
2049   if ( eBest != theWire.front() ) {
2050     eIt = find ( theWire.begin(), theWire.end(), eBest );
2051     theWire.splice( theWire.begin(), theWire, eIt, theWire.end() );
2052   }
2053
2054   return minDist;
2055 }
2056
2057 //=======================================================================
2058 //function : sortSameSizeWires
2059 //purpose  : sort wires in theWireList from theFromWire until theToWire,
2060 //           the wires are set in the order to correspond to the order
2061 //           of boundaries; after sorting, edges in the wires are put
2062 //           in a good order, point UVs on edges are computed and points
2063 //           are appended to theEdgesPointsList
2064 //=======================================================================
2065
2066 bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList &                theWireList,
2067                                        const TListOfEdgesList::iterator& theFromWire,
2068                                        const TListOfEdgesList::iterator& theToWire,
2069                                        const int                         theFirstEdgeID,
2070                                        list< list< TPoint* > >&          theEdgesPointsList )
2071 {
2072   TopoDS_Face F = TopoDS::Face( myShape );
2073   int iW, nbWires = 0;
2074   TListOfEdgesList::iterator wlIt = theFromWire;
2075   while ( wlIt++ != theToWire )
2076     nbWires++;
2077
2078   // Recompute key-point UVs by isolines intersection,
2079   // compute CG of key-points for each wire and bnd boxes of GCs
2080
2081   bool aBool;
2082   gp_XY orig( gp::Origin2d().XY() );
2083   vector< gp_XY > vGcVec( nbWires, orig ), gcVec( nbWires, orig );
2084   Bnd_Box2d bndBox, vBndBox;
2085   int eID = theFirstEdgeID;
2086   list< TopoDS_Edge >::iterator eIt;
2087   for ( iW = 0, wlIt = theFromWire; wlIt != theToWire; wlIt++, iW++ )
2088   {
2089     list< TopoDS_Edge > & wire = *wlIt;
2090     for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2091     {
2092       list< TPoint* > & ePoints = getShapePoints( eID++ );
2093       TPoint* p = ePoints.front();
2094       if ( !compUVByIsoIntersection( theEdgesPointsList, p->myInitUV, p->myUV, aBool )) {
2095         MESSAGE("cant sortSameSizeWires()");
2096         return false;
2097       }
2098       gcVec[iW] += p->myUV;
2099       bndBox.Add( gp_Pnt2d( p->myUV ));
2100       TopoDS_Vertex V = TopExp::FirstVertex( *eIt, true );
2101       gp_Pnt2d vXY = BRep_Tool::Parameters( V, F );
2102       vGcVec[iW] += vXY.XY();
2103       vBndBox.Add( vXY );
2104       // keep the computed UV to compare against by setFirstEdge()
2105       p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2106     }
2107     gcVec[iW] /= nbWires;
2108     vGcVec[iW] /= nbWires;
2109 // cout << " Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2110 //   " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2111   }
2112
2113   // Transform GCs computed by isos to fit in bnd box of GCs by vertices
2114
2115   double minPar[2], maxPar[2], vMinPar[2], vMaxPar[2];
2116   bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
2117   vBndBox.Get( vMinPar[0], vMinPar[1], vMaxPar[0], vMaxPar[1] );
2118   for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
2119   {
2120     double dMin = vMinPar[i] - minPar[i];
2121     double dMax = vMaxPar[i] - maxPar[i];
2122     double dPar = maxPar[i] - minPar[i];
2123     if ( Abs( dPar ) <= DBL_MIN )
2124       continue;
2125     for ( iW = 0; iW < nbWires; iW++ ) { // loop on GCs of wires
2126       double par = gcVec[iW].Coord( iC );
2127       double r = ( par - minPar[i] ) / dPar;
2128       par += ( 1 - r ) * dMin + r * dMax;
2129       gcVec[iW].SetCoord( iC, par );
2130     }
2131   }
2132
2133   // Define boundary - wire correspondence by GC closeness
2134
2135   TListOfEdgesList tmpWList;
2136   tmpWList.splice( tmpWList.end(), theWireList, theFromWire, theToWire );
2137   typedef map< int, TListOfEdgesList::iterator > TIntWirePosMap;
2138   TIntWirePosMap bndIndWirePosMap;
2139   vector< bool > bndFound( nbWires, false );
2140   for ( iW = 0, wlIt = tmpWList.begin(); iW < nbWires; iW++, wlIt++ )
2141   {
2142 // cout << " TRSF Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
2143 //   " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
2144     double minDist = DBL_MAX;
2145     gp_XY & wGc = vGcVec[ iW ];
2146     int bIndex;
2147     for ( int iB = 0; iB < nbWires; iB++ ) {
2148       if ( bndFound[ iB ] ) continue;
2149       double dist = ( wGc - gcVec[ iB ] ).SquareModulus();
2150       if ( dist < minDist ) {
2151         minDist = dist;
2152         bIndex = iB;
2153       }
2154     }
2155     bndFound[ bIndex ] = true;
2156     bndIndWirePosMap.insert( TIntWirePosMap::value_type( bIndex, wlIt ));
2157   }
2158
2159   // Treat each wire  
2160
2161   TIntWirePosMap::iterator bIndWPosIt = bndIndWirePosMap.begin();
2162   eID = theFirstEdgeID;
2163   for ( ; bIndWPosIt != bndIndWirePosMap.end(); bIndWPosIt++ )
2164   {
2165     TListOfEdgesList::iterator wirePos = (*bIndWPosIt).second;
2166     list < TopoDS_Edge > & wire = ( *wirePos );
2167
2168     // choose the best first edge of a wire
2169     setFirstEdge( wire, eID );
2170     
2171     // compute eventual UV and fill theEdgesPointsList
2172     theEdgesPointsList.push_back( list< TPoint* >() );
2173     list< TPoint* > & edgesPoints = theEdgesPointsList.back();
2174     for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2175     {
2176       list< TPoint* > & ePoints = getShapePoints( eID++ );
2177       computeUVOnEdge( *eIt, ePoints );
2178       edgesPoints.insert( edgesPoints.end(), ePoints.begin(), (--ePoints.end()));
2179     }
2180     // put wire back to theWireList
2181     wlIt = wirePos++;
2182     theWireList.splice( theToWire, tmpWList, wlIt, wirePos );
2183   }
2184
2185   return true;
2186 }
2187
2188 //=======================================================================
2189 //function : Apply
2190 //purpose  : Compute  nodes coordinates applying
2191 //           the loaded pattern to <theFace>. The first key-point
2192 //           will be mapped into <theVertexOnKeyPoint1>
2193 //=======================================================================
2194
2195 bool SMESH_Pattern::Apply (const TopoDS_Face&   theFace,
2196                            const TopoDS_Vertex& theVertexOnKeyPoint1,
2197                            const bool           theReverse)
2198 {
2199   MESSAGE(" ::Apply(face) " );
2200   TopoDS_Face face  = theReverse ? TopoDS::Face( theFace.Reversed() ) : theFace;
2201   if ( !setShapeToMesh( face ))
2202     return false;
2203
2204   // find points on edges, it fills myNbKeyPntInBoundary
2205   if ( !findBoundaryPoints() )
2206     return false;
2207
2208   // Define the edges order so that the first edge starts at
2209   // theVertexOnKeyPoint1
2210
2211   list< TopoDS_Edge > eList;
2212   list< int >         nbVertexInWires;
2213   int nbWires = getOrderedEdges( face, theVertexOnKeyPoint1, eList, nbVertexInWires);
2214   if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true )))
2215   {
2216     MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire ");
2217     return setErrorCode( ERR_APPLF_BAD_VERTEX );
2218   }
2219   // check nb wires and edges
2220   list< int > l1 = myNbKeyPntInBoundary, l2 = nbVertexInWires;
2221   l1.sort(); l2.sort();
2222   if ( l1 != l2 )
2223   {
2224     MESSAGE( "Wrong nb vertices in wires" );
2225     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
2226   }
2227
2228   // here shapes get IDs, for the outer wire IDs are OK
2229   list<TopoDS_Edge>::iterator elIt = eList.begin();
2230   for ( ; elIt != eList.end(); elIt++ ) {
2231     myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2232     if ( BRep_Tool::IsClosed( *elIt, theFace ) )
2233       myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));
2234   }
2235   int nbVertices = myShapeIDMap.Extent();
2236
2237   //int nbSeamShapes = 0; // count twice seam edge and its vertices 
2238   for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2239     myShapeIDMap.Add( *elIt );
2240
2241   myShapeIDMap.Add( face );
2242
2243   if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent()/* + nbSeamShapes*/ ) {
2244     MESSAGE( myShapeIDToPointsMap.size() <<" != " << myShapeIDMap.Extent());
2245     return setErrorCode( ERR_APPLF_INTERNAL_EEROR );
2246   }
2247
2248   // points on edges to be used for UV computation of in-face points
2249   list< list< TPoint* > > edgesPointsList;
2250   edgesPointsList.push_back( list< TPoint* >() );
2251   list< TPoint* > * edgesPoints = & edgesPointsList.back();
2252   list< TPoint* >::iterator pIt;
2253
2254   // compute UV of points on the outer wire
2255   int iE, nbEdgesInOuterWire = nbVertexInWires.front();
2256   for (iE = 0, elIt = eList.begin();
2257        iE < nbEdgesInOuterWire && elIt != eList.end();
2258        iE++, elIt++ )
2259   {
2260     list< TPoint* > & ePoints = getShapePoints( *elIt );
2261     // compute UV
2262     computeUVOnEdge( *elIt, ePoints );
2263     // collect on-edge points (excluding the last one)
2264     edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
2265   }
2266
2267   // If there are several wires, define the order of edges of inner wires:
2268   // compute UV of inner edge-points using 2 methods: the one for in-face points
2269   // and the one for on-edge points and then choose the best edge order
2270   // by the best correspondance of the 2 results
2271   if ( nbWires > 1 )
2272   {
2273     // compute UV of inner edge-points using the method for in-face points
2274     // and devide eList into a list of separate wires
2275     bool aBool;
2276     list< list< TopoDS_Edge > > wireList;
2277     list<TopoDS_Edge>::iterator eIt = elIt;
2278     list<int>::iterator nbEIt = nbVertexInWires.begin();
2279     for ( nbEIt++; nbEIt != nbVertexInWires.end(); nbEIt++ )
2280     {
2281       int nbEdges = *nbEIt;
2282       wireList.push_back( list< TopoDS_Edge >() );
2283       list< TopoDS_Edge > & wire = wireList.back();
2284       for ( iE = 0 ; iE < nbEdges; eIt++, iE++ )
2285       {
2286         list< TPoint* > & ePoints = getShapePoints( *eIt );
2287         pIt = ePoints.begin();
2288         for (  pIt++; pIt != ePoints.end(); pIt++ ) {
2289           TPoint* p = (*pIt);
2290           if ( !compUVByIsoIntersection( edgesPointsList, p->myInitUV, p->myUV, aBool )) {
2291             MESSAGE("cant Apply(face)");
2292             return false;
2293           }
2294           // keep the computed UV to compare against by setFirstEdge()
2295           p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
2296         }
2297         wire.push_back( *eIt );
2298       }
2299     }
2300     // remove inner edges from eList
2301     eList.erase( elIt, eList.end() );
2302
2303     // sort wireList by nb edges in a wire
2304     sortBySize< TopoDS_Edge > ( wireList );
2305
2306     // an ID of the first edge of a boundary
2307     int id1 = nbVertices + nbEdgesInOuterWire + 1;
2308 //     if ( nbSeamShapes > 0 )
2309 //       id1 += 2; // 2 vertices more
2310
2311     // find points - edge correspondence for wires of unique size,
2312     // edge order within a wire should be defined only
2313
2314     list< list< TopoDS_Edge > >::iterator wlIt = wireList.begin();
2315     while ( wlIt != wireList.end() )
2316     {
2317       list< TopoDS_Edge >& wire = (*wlIt);
2318       int nbEdges = wire.size();
2319       wlIt++;
2320       if ( wlIt == wireList.end() || (*wlIt).size() != nbEdges ) // a unique size wire
2321       {
2322         // choose the best first edge of a wire
2323         setFirstEdge( wire, id1 );
2324
2325         // compute eventual UV and collect on-edge points
2326         edgesPointsList.push_back( list< TPoint* >() );
2327         edgesPoints = & edgesPointsList.back();
2328         int eID = id1;
2329         for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
2330         {
2331           list< TPoint* > & ePoints = getShapePoints( eID++ );
2332           computeUVOnEdge( *eIt, ePoints );
2333           edgesPoints->insert( edgesPoints->end(), ePoints.begin(), (--ePoints.end()));
2334         }
2335       }
2336       id1 += nbEdges;
2337     }
2338
2339     // find boundary - wire correspondence for several wires of same size
2340     
2341     id1 = nbVertices + nbEdgesInOuterWire + 1;
2342     wlIt = wireList.begin();
2343     while ( wlIt != wireList.end() )
2344     {
2345       int nbSameSize = 0, nbEdges = (*wlIt).size();
2346       list< list< TopoDS_Edge > >::iterator wlIt2 = wlIt;
2347       wlIt2++;
2348       while ( wlIt2 != wireList.end() && (*wlIt2).size() == nbEdges ) { // a same size wire
2349         nbSameSize++;
2350         wlIt2++;
2351       }
2352       if ( nbSameSize > 0 )
2353         if (!sortSameSizeWires(wireList, wlIt, wlIt2, id1, edgesPointsList))
2354           return false;
2355       wlIt = wlIt2;
2356       id1 += nbEdges * ( nbSameSize + 1 );
2357     }
2358
2359     // add well-ordered edges to eList
2360     
2361     for ( wlIt = wireList.begin(); wlIt != wireList.end(); wlIt++ )
2362     {
2363       list< TopoDS_Edge >& wire = (*wlIt);
2364       eList.splice( eList.end(), wire, wire.begin(), wire.end() );
2365     }
2366
2367     // re-fill myShapeIDMap - all shapes get good IDs
2368
2369     myShapeIDMap.Clear();
2370     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2371       myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
2372     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
2373       myShapeIDMap.Add( *elIt );
2374     myShapeIDMap.Add( face );
2375     
2376   } // there are inner wires
2377
2378   // Compute XYZ of on-edge points
2379
2380   TopLoc_Location loc;
2381   for ( iE = nbVertices + 1, elIt = eList.begin(); elIt != eList.end(); elIt++ )
2382   {
2383     double f,l;
2384     Handle(Geom_Curve) C3d = BRep_Tool::Curve( *elIt, loc, f, l );
2385     const gp_Trsf & aTrsf = loc.Transformation();
2386     list< TPoint* > & ePoints = getShapePoints( iE++ );
2387     pIt = ePoints.begin();
2388     for ( pIt++; pIt != ePoints.end(); pIt++ )
2389     {
2390       TPoint* point = *pIt;
2391       point->myXYZ = C3d->Value( point->myU );
2392       if ( !loc.IsIdentity() )
2393         aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2394     }
2395   }
2396
2397   // Compute UV and XYZ of in-face points
2398
2399   // try to use a simple algo
2400   list< TPoint* > & fPoints = getShapePoints( face );
2401   bool isDeformed = false;
2402   for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
2403     if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2404                                   (*pIt)->myUV, isDeformed )) {
2405       MESSAGE("cant Apply(face)");
2406       return false;
2407     }
2408   // try to use a complex algo if it is a difficult case
2409   if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
2410   {
2411     for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
2412       if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
2413                                     (*pIt)->myUV, isDeformed )) {
2414         MESSAGE("cant Apply(face)");
2415         return false;
2416       }
2417   }
2418
2419   Handle(Geom_Surface) aSurface = BRep_Tool::Surface( face, loc );
2420   const gp_Trsf & aTrsf = loc.Transformation();
2421   for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
2422   {
2423     TPoint * point = *pIt;
2424     point->myXYZ = aSurface->Value( point->myUV.X(), point->myUV.Y() );
2425     if ( !loc.IsIdentity() )
2426       aTrsf.Transforms( point->myXYZ.ChangeCoord() );
2427   }
2428
2429   myIsComputed = true;
2430
2431   return setErrorCode( ERR_OK );
2432 }
2433
2434 // =========================================================
2435 // class calculating coordinates of 3D points by normalized
2436 // parameters inside the block and vice versa
2437 // =========================================================
2438
2439 class TBlock: public math_FunctionSetWithDerivatives
2440 {
2441  public:
2442   enum TBlockShapeID { // ids of the block sub-shapes
2443     ID_V000 = 1, ID_V100, ID_V010, ID_V110, ID_V001, ID_V101, ID_V011, ID_V111,
2444
2445     ID_Ex00, ID_Ex10, ID_Ex01, ID_Ex11,
2446     ID_E0y0, ID_E1y0, ID_E0y1, ID_E1y1,
2447     ID_E00z, ID_E10z, ID_E01z, ID_E11z,
2448
2449     ID_Fxy0, ID_Fxy1, ID_Fx0z, ID_Fx1z, ID_F0yz, ID_F1yz,
2450
2451     ID_Shell
2452     };
2453   static inline 
2454 bool IsVertexID( int theShapeID )
2455   { return ( theShapeID >= ID_V000 && theShapeID <= ID_V111 ); }
2456   static inline bool IsEdgeID( int theShapeID )
2457   { return ( theShapeID >= ID_Ex00 && theShapeID <= ID_E11z ); }
2458   static inline bool IsFaceID( int theShapeID )
2459   { return ( theShapeID >= ID_Fxy0 && theShapeID <= ID_F1yz ); }
2460
2461
2462   TBlock (const TopoDS_Shell& theBlock):
2463     myShell( theBlock ), myNbIterations(0), mySumDist(0.) {}
2464
2465   bool LoadBlockShapes(const TopoDS_Vertex&        theVertex000,
2466                        const TopoDS_Vertex&        theVertex001,
2467 //                       TopTools_IndexedMapOfShape& theShapeIDMap
2468                        TopTools_IndexedMapOfOrientedShape& theShapeIDMap );
2469   // add sub-shapes of theBlock to theShapeIDMap so that they get
2470   // IDs acoording to enum TBlockShapeID
2471
2472   static int GetShapeIDByParams ( const gp_XYZ& theParams );
2473   // define an id of the block sub-shape by point parameters
2474
2475   bool VertexPoint( const int theVertexID, gp_XYZ& thePoint ) const {
2476     if ( !IsVertexID( theVertexID ))           return false;
2477     thePoint = myPnt[ theVertexID - ID_V000 ]; return true;
2478   }
2479   // return vertex coordinates
2480
2481   bool EdgePoint( const int theEdgeID, const gp_XYZ& theParams, gp_XYZ& thePoint ) const {
2482     if ( !IsEdgeID( theEdgeID ))                                 return false;
2483     thePoint = myEdge[ theEdgeID - ID_Ex00 ].Point( theParams ); return true;
2484   }
2485   // return coordinates of a point on edge
2486
2487   bool FacePoint( const int theFaceID, const gp_XYZ& theParams, gp_XYZ& thePoint ) const {
2488     if ( !IsFaceID ( theFaceID ))                                return false;
2489     thePoint = myFace[ theFaceID - ID_Fxy0 ].Point( theParams ); return true;
2490   }
2491   // return coordinates of a point on face
2492
2493   bool ShellPoint( const gp_XYZ& theParams, gp_XYZ& thePoint ) const;
2494   // return coordinates of a point in shell
2495
2496   bool ComputeParameters (const gp_Pnt& thePoint,
2497                           gp_XYZ&       theParams,
2498                           const int     theShapeID = ID_Shell);
2499   // compute point parameters in the block
2500
2501   static void GetFaceEdgesIDs (const int faceID, vector< int >& edgeVec );
2502   // return edges IDs of a face in the order u0, u1, 0v, 1v
2503
2504   static int GetCoordIndOnEdge (const int theEdgeID)
2505   { return (theEdgeID < ID_E0y0) ? 1 : (theEdgeID < ID_E00z) ? 2 : 3; }
2506   // return an index of a coordinate which varies along the edge
2507
2508   static double* GetShapeCoef (const int theShapeID);
2509   // for theShapeID( TBlockShapeID ), returns 3 coefficients used
2510   // to compute an addition of an on-theShape point to coordinates
2511   // of an in-shell point. If an in-shell point has parameters (Px,Py,Pz),
2512   // then the addition of a point P is computed as P*kx*ky*kz and ki is
2513   // defined by the returned coef like this:
2514   // ki = (coef[i] == 0) ? 1 : (coef[i] < 0) ? 1 - Pi : Pi
2515
2516   static bool IsForwardEdge (const TopoDS_Edge &         theEdge, 
2517                              //TopTools_IndexedMapOfShape& theShapeIDMap
2518                              TopTools_IndexedMapOfOrientedShape& theShapeIDMap) {
2519     int v1ID = theShapeIDMap.FindIndex( TopExp::FirstVertex( theEdge ).Oriented( TopAbs_FORWARD ));
2520     int v2ID = theShapeIDMap.FindIndex( TopExp::LastVertex( theEdge ).Oriented( TopAbs_FORWARD ));
2521     return ( v1ID < v2ID );
2522   }
2523   // Return true if an in-block parameter increases along theEdge curve
2524
2525   static void Swap(double& a, double& b) { double tmp = a; a = b; b = tmp; }
2526
2527   // methods of math_FunctionSetWithDerivatives
2528   Standard_Integer NbVariables() const;
2529   Standard_Integer NbEquations() const;
2530   Standard_Boolean Value(const math_Vector& X,math_Vector& F) ;
2531   Standard_Boolean Derivatives(const math_Vector& X,math_Matrix& D) ;
2532   Standard_Boolean Values(const math_Vector& X,math_Vector& F,math_Matrix& D) ;
2533   Standard_Integer GetStateNumber ();
2534
2535   static ostream& DumpShapeID (const int theBlockShapeID, ostream& stream);
2536   // DEBUG: dump an id of a block sub-shape
2537
2538  private:
2539
2540   struct TEdge {
2541     int                myCoordInd;
2542     double             myFirst;
2543     double             myLast;
2544     Handle(Geom_Curve) myC3d;
2545     gp_Trsf            myTrsf;
2546     double GetU( const gp_XYZ& theParams ) const;
2547     gp_XYZ Point( const gp_XYZ& theParams ) const;
2548   };
2549
2550   struct TFace {
2551     // 4 edges in the order u0, u1, 0v, 1v
2552     int                  myCoordInd[ 4 ];
2553     double               myFirst   [ 4 ];
2554     double               myLast    [ 4 ];
2555     Handle(Geom2d_Curve) myC2d     [ 4 ];
2556     // 4 corner points in the order 00, 10, 11, 01
2557     gp_XY                myCorner  [ 4 ];
2558     // surface
2559     Handle(Geom_Surface) myS;
2560     gp_Trsf              myTrsf;
2561     gp_XY  GetUV( const gp_XYZ& theParams ) const;
2562     gp_XYZ Point( const gp_XYZ& theParams ) const;
2563     int GetUInd() const { return myCoordInd[ 0 ]; }
2564     int GetVInd() const { return myCoordInd[ 2 ]; }
2565   };
2566
2567   TopoDS_Shell myShell;
2568   // geometry:
2569   // 8 vertices
2570   gp_XYZ myPnt[ 8 ];
2571   // 12 edges
2572   TEdge  myEdge[ 12 ];
2573   // 6 faces
2574   TFace  myFace[ 6 ];
2575
2576   // for param computation
2577
2578   int      myFaceIndex;
2579   double   myFaceParam;
2580   int      myNbIterations;
2581   double   mySumDist;
2582
2583   gp_XYZ   myPoint; // the given point
2584   gp_XYZ   myParam; // the best parameters guess
2585   double   myValues[ 4 ]; // values computed at myParam
2586
2587   typedef pair<gp_XYZ,gp_XYZ> TxyzPair;
2588   TxyzPair my3x3x3GridNodes[ 27 ];
2589   bool     myGridComputed;
2590 };
2591
2592 //=======================================================================
2593 //function : Load
2594 //purpose  : Create a pattern from the mesh built on <theBlock>
2595 //=======================================================================
2596
2597 bool SMESH_Pattern::Load (SMESH_Mesh*         theMesh,
2598                           const TopoDS_Shell& theBlock)
2599 {
2600   MESSAGE(" ::Load(volume) " );
2601   Clear();
2602   myIs2D = false;
2603   SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
2604
2605   // load shapes in myShapeIDMap
2606   TBlock block( theBlock );
2607   TopoDS_Vertex v1, v2;
2608   if ( !block.LoadBlockShapes( v1, v2, myShapeIDMap ))
2609     return setErrorCode( ERR_LOADV_BAD_SHAPE );
2610
2611   // count nodes
2612   int nbNodes = 0, shapeID;
2613   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2614   {
2615     const TopoDS_Shape& S = myShapeIDMap( shapeID );
2616     SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2617     if ( aSubMesh )
2618       nbNodes += aSubMesh->NbNodes();
2619   }
2620   myPoints.resize( nbNodes );
2621
2622   // load U of points on edges
2623   TNodePointIDMap nodePointIDMap;
2624   int iPoint = 0;
2625   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2626   {
2627     const TopoDS_Shape& S = myShapeIDMap( shapeID );
2628     list< TPoint* > & shapePoints = getShapePoints( shapeID );
2629     SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( S );
2630     if ( ! aSubMesh ) continue;
2631     SMDS_NodeIteratorPtr nIt = aSubMesh->GetNodes();
2632     if ( !nIt->more() ) continue;
2633
2634       // store a node and a point
2635     while ( nIt->more() ) {
2636       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nIt->next() );
2637       nodePointIDMap.insert( TNodePointIDMap::value_type( node, iPoint ));
2638       if ( block.IsVertexID( shapeID ))
2639         myKeyPointIDs.push_back( iPoint );
2640       TPoint* p = & myPoints[ iPoint++ ];
2641       shapePoints.push_back( p );
2642       p->myXYZ.SetCoord( node->X(), node->Y(), node->Z() );
2643       p->myInitXYZ.SetCoord( 0,0,0 );
2644     }
2645     list< TPoint* >::iterator pIt = shapePoints.begin();
2646
2647     // compute init XYZ
2648     switch ( S.ShapeType() )
2649     {
2650     case TopAbs_VERTEX:
2651     case TopAbs_EDGE: {
2652
2653       for ( ; pIt != shapePoints.end(); pIt++ ) {
2654         double * coef = block.GetShapeCoef( shapeID );
2655         for ( int iCoord = 1; iCoord <= 3; iCoord++ )
2656           if ( coef[ iCoord - 1] > 0 )
2657             (*pIt)->myInitXYZ.SetCoord( iCoord, 1. );
2658       }
2659       if ( S.ShapeType() == TopAbs_VERTEX )
2660         break;
2661
2662       const TopoDS_Edge& edge = TopoDS::Edge( S );
2663       double f,l;
2664       BRep_Tool::Range( edge, f, l );
2665       int iCoord     = TBlock::GetCoordIndOnEdge( shapeID );
2666       bool isForward = TBlock::IsForwardEdge( edge, myShapeIDMap );
2667       pIt = shapePoints.begin();
2668       nIt = aSubMesh->GetNodes();
2669       for ( ; nIt->more(); pIt++ )
2670       {
2671         const SMDS_MeshNode* node = 
2672           static_cast<const SMDS_MeshNode*>( nIt->next() );
2673         const SMDS_EdgePosition* epos =
2674           static_cast<const SMDS_EdgePosition*>(node->GetPosition().get());
2675         double u = ( epos->GetUParameter() - f ) / ( l - f );
2676         (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u );
2677       }
2678       break;
2679     }
2680     default:
2681       for ( ; pIt != shapePoints.end(); pIt++ )
2682       {
2683         if ( !block.ComputeParameters( (*pIt)->myXYZ, (*pIt)->myInitXYZ, shapeID )) {
2684           MESSAGE( "!block.ComputeParameters()" );
2685           return setErrorCode( ERR_LOADV_COMPUTE_PARAMS );
2686         }
2687       }
2688     }
2689   } // loop on block sub-shapes
2690
2691   // load elements
2692
2693   SMESHDS_SubMesh * aSubMesh = aMeshDS->MeshElements( theBlock );
2694   if ( aSubMesh )
2695   {
2696     SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements();
2697     while ( elemIt->more() ) {
2698       SMDS_ElemIteratorPtr nIt = elemIt->next()->nodesIterator();
2699       myElemPointIDs.push_back( list< int >() );
2700       list< int >& elemPoints = myElemPointIDs.back();
2701       while ( nIt->more() )
2702         elemPoints.push_back( nodePointIDMap[ nIt->next() ]);
2703     }
2704   }
2705
2706   myIsBoundaryPointsFound = true;
2707
2708   return setErrorCode( ERR_OK );
2709 }
2710
2711 //=======================================================================
2712 //function : Apply
2713 //purpose  : Compute nodes coordinates applying
2714 //           the loaded pattern to <theBlock>. The (0,0,0) key-point
2715 //           will be mapped into <theVertex000>. The (0,0,1)
2716 //           fifth key-point will be mapped into <theVertex001>.
2717 //=======================================================================
2718
2719 bool SMESH_Pattern::Apply (const TopoDS_Shell&  theBlock,
2720                            const TopoDS_Vertex& theVertex000,
2721                            const TopoDS_Vertex& theVertex001)
2722 {
2723   MESSAGE(" ::Apply(volume) " );
2724
2725   TBlock block( theBlock );
2726
2727   if (!findBoundaryPoints()     || // bind ID to points
2728       !setShapeToMesh( theBlock )) // check theBlock is a suitable shape
2729     return false;
2730
2731   if (!block.LoadBlockShapes( theVertex000, theVertex001, myShapeIDMap )) // bind ID to shape
2732     return setErrorCode( ERR_APPLV_BAD_SHAPE );
2733
2734   // compute XYZ of points on shapes
2735
2736   for ( int shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
2737   {
2738     list< TPoint* > & shapePoints = getShapePoints( shapeID );
2739     list< TPoint* >::iterator pIt = shapePoints.begin();
2740     const TopoDS_Shape& S = myShapeIDMap( shapeID );
2741     switch ( S.ShapeType() )
2742     {
2743     case TopAbs_VERTEX: {
2744
2745       for ( ; pIt != shapePoints.end(); pIt++ )
2746         block.VertexPoint( shapeID, (*pIt)->myXYZ.ChangeCoord() );
2747       break;
2748     }
2749     case TopAbs_EDGE: {
2750
2751       for ( ; pIt != shapePoints.end(); pIt++ )
2752         block.EdgePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
2753       break;
2754     }
2755     case TopAbs_FACE: {
2756
2757       for ( ; pIt != shapePoints.end(); pIt++ )
2758         block.FacePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
2759       break;
2760     }
2761     default:
2762       for ( ; pIt != shapePoints.end(); pIt++ )
2763         block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
2764     }
2765   } // loop on block sub-shapes
2766
2767   myIsComputed = true;
2768
2769   return setErrorCode( ERR_OK );
2770 }
2771
2772 //=======================================================================
2773 //function : MakeMesh
2774 //purpose  : Create nodes and elements in <theMesh> using nodes
2775 //           coordinates computed by either of Apply...() methods
2776 //=======================================================================
2777
2778 bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh)
2779 {
2780   MESSAGE(" ::MakeMesh() " );
2781   if ( !myIsComputed )
2782     return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
2783
2784   SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
2785
2786   // clear elements and nodes existing on myShape
2787   SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( myShape );
2788   SMESHDS_SubMesh * aSubMeshDS = aMeshDS->MeshElements( myShape );
2789   if ( aSubMesh )
2790     aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
2791   else if ( aSubMeshDS )
2792   {
2793     SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
2794     while ( eIt->more() )
2795       aMeshDS->RemoveElement( eIt->next() );
2796     SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
2797     while ( nIt->more() )
2798       aMeshDS->RemoveNode( static_cast<const SMDS_MeshNode*>( nIt->next() ));
2799   }
2800
2801   // loop on sub-shapes of myShape: create nodes and build point-node map
2802   typedef map< TPoint*, const SMDS_MeshNode* > TPointNodeMap;
2803   TPointNodeMap pointNodeMap;
2804   map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
2805   for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
2806   {
2807     const TopoDS_Shape & S = myShapeIDMap( (*idPointIt).first );
2808     list< TPoint* > & points = (*idPointIt).second;
2809     SMESHDS_SubMesh * subMeshDS = aMeshDS->MeshElements( S );
2810     SMESH_subMesh * subMesh = theMesh->GetSubMeshContaining( myShape );
2811     list< TPoint* >::iterator pIt = points.begin();
2812     for ( ; pIt != points.end(); pIt++ )
2813     {
2814       TPoint* point = *pIt;
2815       if ( pointNodeMap.find( point ) != pointNodeMap.end() )
2816         continue;
2817       SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
2818                                               point->myXYZ.Y(),
2819                                               point->myXYZ.Z());
2820       pointNodeMap.insert( TPointNodeMap::value_type( point, node ));
2821       if ( subMeshDS ) {
2822         switch ( S.ShapeType() ) {
2823         case TopAbs_VERTEX: {
2824           aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S ));
2825           break;
2826         }
2827         case TopAbs_EDGE: {
2828           aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ));
2829           SMDS_EdgePosition* epos =
2830             dynamic_cast<SMDS_EdgePosition *>(node->GetPosition().get());
2831           epos->SetUParameter( point->myU );
2832           break;
2833         }
2834         case TopAbs_FACE: {
2835           aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ));
2836           SMDS_FacePosition* pos =
2837             dynamic_cast<SMDS_FacePosition *>(node->GetPosition().get());
2838           pos->SetUParameter( point->myUV.X() );
2839           pos->SetVParameter( point->myUV.Y() );
2840           break;
2841         }
2842         default:
2843           aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
2844         }
2845       }
2846     }
2847     // make that SMESH_subMesh::_computeState = COMPUTE_OK
2848     // so that operations with hypotheses will erase the mesh
2849     // being built
2850     if ( subMesh )
2851       subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
2852   }
2853
2854   // create elements
2855   list<list< int > >::iterator epIt = myElemPointIDs.begin();
2856   for ( ; epIt != myElemPointIDs.end(); epIt++ )
2857   {
2858     list< int > & elemPoints = *epIt;
2859     // retrieve nodes
2860     const SMDS_MeshNode* nodes[ 8 ];
2861     list< int >::iterator iIt = elemPoints.begin();
2862     int nbNodes;
2863     for ( nbNodes = 0; iIt != elemPoints.end(); iIt++ ) {
2864       nodes[ nbNodes++ ] = pointNodeMap[ & myPoints[ *iIt ]];
2865     }
2866     // add an element
2867     const SMDS_MeshElement* elem = 0;
2868     if ( myIs2D ) {
2869       switch ( nbNodes ) {
2870       case 3:
2871         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
2872       case 4:
2873         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
2874       default:;
2875       }
2876     }
2877     else {
2878       switch ( nbNodes ) {
2879       case 4:
2880         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
2881       case 5:
2882         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
2883                                    nodes[4] ); break;
2884       case 6:
2885         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
2886                                    nodes[4], nodes[5] ); break;
2887       case 8:
2888         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
2889                                    nodes[4], nodes[5], nodes[6], nodes[7] ); break;
2890       default:;
2891       }
2892     }
2893     if ( elem )
2894       aMeshDS->SetMeshElementOnShape( elem, myShape );
2895   }
2896
2897   return setErrorCode( ERR_OK );
2898 }
2899
2900
2901 //=======================================================================
2902 //function : arrangeBoundaries
2903 //purpose  : if there are several wires, arrange boundaryPoints so that
2904 //           the outer wire goes first and fix inner wires orientation
2905 //           update myKeyPointIDs to correspond to the order of key-points
2906 //           in boundaries; sort internal boundaries by the nb of key-points
2907 //=======================================================================
2908
2909 void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
2910 {
2911   typedef list< list< TPoint* > >::iterator TListOfListIt;
2912   TListOfListIt bndIt;
2913   list< TPoint* >::iterator pIt;
2914
2915   int nbBoundaries = boundaryList.size();
2916   if ( nbBoundaries > 1 )
2917   {
2918     // sort boundaries by nb of key-points
2919     if ( nbBoundaries > 2 )
2920     {
2921       // move boundaries in tmp list
2922       list< list< TPoint* > > tmpList; 
2923       tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
2924       // make a map nb-key-points to boundary-position-in-tmpList,
2925       // boundary-positions get ordered in it
2926       typedef map< int, TListOfListIt > TNbKpBndPosMap;
2927       TNbKpBndPosMap nbKpBndPosMap;
2928       bndIt = tmpList.begin();
2929       list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
2930       for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
2931         int nb = *nbKpIt * nbBoundaries;
2932         while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
2933           nb++;
2934         nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
2935       }
2936       // move boundaries back to boundaryList
2937       TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
2938       for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
2939         TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
2940         TListOfListIt bndPos1 = bndPos2++;
2941         boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
2942       }
2943     }
2944
2945     // Look for the outer boundary: the one with the point with the least X
2946     double leastX = DBL_MAX;
2947     TListOfListIt outerBndPos;
2948     for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
2949     {
2950       list< TPoint* >& boundary = (*bndIt);
2951       for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
2952       {
2953         TPoint* point = *pIt;
2954         if ( point->myInitXYZ.X() < leastX ) {
2955           leastX = point->myInitXYZ.X();
2956           outerBndPos = bndIt;
2957         }
2958       }
2959     }
2960
2961     if ( outerBndPos != boundaryList.begin() )
2962       boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos );
2963
2964   } // if nbBoundaries > 1
2965                  
2966   // Check boundaries orientation and re-fill myKeyPointIDs
2967
2968   set< TPoint* > keyPointSet;
2969   list< int >::iterator kpIt = myKeyPointIDs.begin();
2970   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
2971     keyPointSet.insert( & myPoints[ *kpIt ]);
2972   myKeyPointIDs.clear();
2973
2974   // update myNbKeyPntInBoundary also
2975   list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
2976
2977   for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
2978   {
2979     // find the point with the least X
2980     double leastX = DBL_MAX;
2981     list< TPoint* >::iterator xpIt;
2982     list< TPoint* >& boundary = (*bndIt);
2983     for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
2984     {
2985       TPoint* point = *pIt;
2986       if ( point->myInitXYZ.X() < leastX ) {
2987         leastX = point->myInitXYZ.X();
2988         xpIt = pIt;
2989       }
2990     }
2991     // find points next to the point with the least X
2992     TPoint* p = *xpIt, *pPrev, *pNext;
2993     if ( p == boundary.front() )
2994       pPrev = *(++boundary.rbegin());
2995     else {
2996       xpIt--;
2997       pPrev = *xpIt;
2998       xpIt++;
2999     }
3000     if ( p == boundary.back() )
3001       pNext = *(++boundary.begin());
3002     else {
3003       xpIt++;
3004       pNext = *xpIt;
3005     }
3006     // vectors of boundary direction near <p>
3007     gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
3008     // rotate vectors counterclockwise
3009     v1.SetCoord( -v1.Y(), v1.X() );
3010     v2.SetCoord( -v2.Y(), v2.X() );
3011     // in-face direction
3012     gp_Vec2d dirInFace = v1 + v2;
3013     // for the outer boundary dirInFace should go to the right
3014     bool reverse;
3015     if ( bndIt == boundaryList.begin() ) // outer boundary
3016       reverse = dirInFace.X() < 0;
3017     else
3018       reverse = dirInFace.X() > 0;
3019     if ( reverse )
3020       boundary.reverse();
3021
3022     // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
3023     (*nbKpIt) = 0; // count nb of key-points again
3024     pIt = boundary.begin();
3025     for ( ; pIt != boundary.end(); pIt++)
3026     {
3027       TPoint* point = *pIt;
3028       if ( keyPointSet.find( point ) == keyPointSet.end() )
3029         continue;
3030       // find an index of a keypoint
3031       int index = 0;
3032       vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3033       for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
3034         if ( &(*pVecIt) == point )
3035           break;
3036       myKeyPointIDs.push_back( index );
3037       (*nbKpIt)++;
3038     }
3039     myKeyPointIDs.pop_back(); // remove the first key-point from the back
3040     (*nbKpIt)--;
3041
3042   } // loop on a list of boundaries
3043
3044   ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
3045 }
3046
3047 //=======================================================================
3048 //function : findBoundaryPoints
3049 //purpose  : if loaded from file, find points to map on edges and faces and
3050 //           compute their parameters
3051 //=======================================================================
3052
3053 bool SMESH_Pattern::findBoundaryPoints()
3054 {
3055   if ( myIsBoundaryPointsFound ) return true;
3056
3057   MESSAGE(" findBoundaryPoints() ");
3058
3059   if ( myIs2D )
3060   {
3061     set< TPoint* > pointsInElems;
3062
3063     // Find free links of elements:
3064     // put links of all elements in a set and remove links encountered twice
3065
3066     typedef pair< TPoint*, TPoint*> TLink;
3067     set< TLink > linkSet;
3068     list<list< int > >::iterator epIt = myElemPointIDs.begin();
3069     for ( ; epIt != myElemPointIDs.end(); epIt++ )
3070     {
3071       list< int > & elemPoints = *epIt;
3072       list< int >::iterator pIt = elemPoints.begin();
3073       int prevP = elemPoints.back();
3074       for ( ; pIt != elemPoints.end(); pIt++ ) {
3075         TPoint* p1 = & myPoints[ prevP ];
3076         TPoint* p2 = & myPoints[ *pIt ];
3077         TLink link(( p1 < p2 ? p1 : p2 ), ( p1 < p2 ? p2 : p1 ));
3078         ASSERT( link.first != link.second );
3079         pair<set< TLink >::iterator,bool> itUniq = linkSet.insert( link );
3080         if ( !itUniq.second )
3081           linkSet.erase( itUniq.first );
3082         prevP = *pIt;
3083
3084         pointsInElems.insert( p1 );
3085       }
3086     }
3087     // Now linkSet contains only free links,
3088     // find the points order that they have in boundaries
3089
3090     // 1. make a map of key-points
3091     set< TPoint* > keyPointSet;
3092     list< int >::iterator kpIt = myKeyPointIDs.begin();
3093     for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
3094       keyPointSet.insert( & myPoints[ *kpIt ]);
3095
3096     // 2. chain up boundary points
3097     list< list< TPoint* > > boundaryList;
3098     boundaryList.push_back( list< TPoint* >() );
3099     list< TPoint* > * boundary = & boundaryList.back();
3100
3101     TPoint *point1, *point2, *keypoint1;
3102     kpIt = myKeyPointIDs.begin();
3103     point1 = keypoint1 = & myPoints[ *kpIt++ ];
3104     // loop on free links: look for the next point
3105     int iKeyPoint = 0;
3106     set< TLink >::iterator lIt = linkSet.begin();
3107     while ( lIt != linkSet.end() )
3108     {
3109       if ( (*lIt).first == point1 )
3110         point2 = (*lIt).second;
3111       else if ( (*lIt).second == point1 )
3112         point2 = (*lIt).first;
3113       else {
3114         lIt++;
3115         continue;
3116       }
3117       linkSet.erase( lIt );
3118       lIt = linkSet.begin();
3119
3120       if ( keyPointSet.find( point2 ) == keyPointSet.end() ) // not a key-point
3121       {
3122         boundary->push_back( point2 );
3123       }
3124       else // a key-point found
3125       {
3126         keyPointSet.erase( point2 ); // keyPointSet contains not found key-points only
3127         iKeyPoint++;
3128         if ( point2 != keypoint1 ) // its not the boundary end
3129         {
3130           boundary->push_back( point2 );
3131         }
3132         else  // the boundary end reached
3133         {
3134           boundary->push_front( keypoint1 );
3135           boundary->push_back( keypoint1 );
3136           myNbKeyPntInBoundary.push_back( iKeyPoint );
3137           if ( keyPointSet.empty() )
3138             break; // all boundaries containing key-points are found
3139
3140           // prepare to search for the next boundary
3141           boundaryList.push_back( list< TPoint* >() );
3142           boundary = & boundaryList.back();
3143           point2 = keypoint1 = (*keyPointSet.begin());
3144         }
3145       }
3146       point1 = point2;
3147     } // loop on the free links set
3148
3149     if ( boundary->empty() ) {
3150       MESSAGE(" a separate key-point");
3151       return setErrorCode( ERR_READ_BAD_KEY_POINT );
3152     }
3153
3154     // if there are several wires, arrange boundaryPoints so that
3155     // the outer wire goes first and fix inner wires orientation;
3156     // sort myKeyPointIDs to correspond to the order of key-points
3157     // in boundaries
3158     arrangeBoundaries( boundaryList );
3159
3160     // Find correspondence shape ID - points,
3161     // compute points parameter on edge
3162
3163     keyPointSet.clear();
3164     for ( kpIt = myKeyPointIDs.begin(); kpIt != myKeyPointIDs.end(); kpIt++ )
3165       keyPointSet.insert( & myPoints[ *kpIt ]);
3166
3167     set< TPoint* > edgePointSet; // to find in-face points
3168     int vertexID = 1; // the first index in TopTools_IndexedMapOfShape
3169     int edgeID = myKeyPointIDs.size() + 1;
3170
3171     list< list< TPoint* > >::iterator bndIt = boundaryList.begin();
3172     for ( ; bndIt != boundaryList.end(); bndIt++ )
3173     {
3174       boundary = & (*bndIt);
3175       double edgeLength = 0;
3176       list< TPoint* >::iterator pIt = boundary->begin();
3177       getShapePoints( edgeID ).push_back( *pIt );
3178       for ( pIt++; pIt != boundary->end(); pIt++)
3179       {
3180         list< TPoint* > & edgePoints = getShapePoints( edgeID );
3181         TPoint* prevP = edgePoints.empty() ? 0 : edgePoints.back();
3182         TPoint* point = *pIt;
3183         edgePointSet.insert( point );
3184         if ( keyPointSet.find( point ) == keyPointSet.end() ) // inside-edge point
3185         {
3186           edgePoints.push_back( point );
3187           edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3188           point->myInitU = edgeLength;
3189         }
3190         else // a key-point
3191         {
3192           // treat points on the edge which ends up: compute U [0,1]
3193           edgePoints.push_back( point );
3194           if ( edgePoints.size() > 2 ) {
3195             edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
3196             list< TPoint* >::iterator epIt = edgePoints.begin();
3197             for ( ; epIt != edgePoints.end(); epIt++ )
3198               (*epIt)->myInitU /= edgeLength;
3199           }
3200           // begin the next edge treatment
3201           edgeLength = 0;
3202           getShapePoints( vertexID++ ).push_back( point );
3203           edgeID++;
3204           if ( point != boundary->front() )
3205             getShapePoints( edgeID ).push_back( point );
3206         }
3207       }
3208     }
3209
3210     // find in-face points
3211     list< TPoint* > & facePoints = getShapePoints( edgeID );
3212     vector< TPoint >::iterator pVecIt = myPoints.begin();
3213     for ( ; pVecIt != myPoints.end(); pVecIt++ ) {
3214       TPoint* point = &(*pVecIt);
3215       if ( edgePointSet.find( point ) == edgePointSet.end() &&
3216           pointsInElems.find( point ) != pointsInElems.end())
3217         facePoints.push_back( point );
3218     }
3219
3220   } // 2D case
3221
3222   else // 3D case
3223   {
3224     // bind points to shapes according to point parameters
3225     vector< TPoint >::iterator pVecIt = myPoints.begin();
3226     for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
3227       TPoint* point = &(*pVecIt);
3228       int shapeID = TBlock::GetShapeIDByParams( point->myInitXYZ );
3229       getShapePoints( shapeID ).push_back( point );
3230       // detect key-points
3231       if ( TBlock::IsVertexID( shapeID ))
3232         myKeyPointIDs.push_back( i );        
3233     }
3234   }
3235
3236   myIsBoundaryPointsFound = true;
3237   return myIsBoundaryPointsFound;
3238 }
3239
3240 //=======================================================================
3241 //function : Clear
3242 //purpose  : clear fields
3243 //=======================================================================
3244
3245 void SMESH_Pattern::Clear()
3246 {
3247   myIsComputed = myIsBoundaryPointsFound = false;
3248
3249   myPoints.clear();
3250   myKeyPointIDs.clear();
3251   myElemPointIDs.clear();
3252   myShapeIDToPointsMap.clear();
3253   myShapeIDMap.Clear();
3254   myShape.Nullify();
3255   myNbKeyPntInBoundary.clear();
3256 }
3257
3258 //=======================================================================
3259 //function : setShapeToMesh
3260 //purpose  : set a shape to be meshed. Return True if meshing is possible
3261 //=======================================================================
3262
3263 bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape)
3264 {
3265   if ( !IsLoaded() ) {
3266     MESSAGE( "Pattern not loaded" );
3267     return setErrorCode( ERR_APPL_NOT_LOADED );
3268   }
3269
3270   TopAbs_ShapeEnum aType = theShape.ShapeType();
3271   bool dimOk = ( myIs2D ? aType == TopAbs_FACE : aType == TopAbs_SHELL );
3272   if ( !dimOk ) {
3273     MESSAGE( "Pattern dimention mismatch" );
3274     return setErrorCode( ERR_APPL_BAD_DIMENTION );
3275   }
3276
3277   // check if a face is closed
3278   int nbNodeOnSeamEdge = 0;
3279   if ( myIs2D ) {
3280     TopoDS_Face face = TopoDS::Face( theShape );
3281     TopExp_Explorer eExp( theShape, TopAbs_EDGE );
3282     for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() )
3283       if ( BRep_Tool::IsClosed( TopoDS::Edge( eExp.Current() ), face ))
3284         nbNodeOnSeamEdge = 2;
3285   }
3286     
3287   // check nb of vertices
3288   TopTools_IndexedMapOfShape vMap;
3289   TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
3290   if ( vMap.Extent() + nbNodeOnSeamEdge != myKeyPointIDs.size() ) {
3291     MESSAGE( myKeyPointIDs.size() << " != " << vMap.Extent() );
3292     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
3293   }
3294
3295   myShapeIDMap.Clear();
3296   myShape = theShape;
3297   return true;
3298 }
3299
3300 //=======================================================================
3301 //function : GetMappedPoints
3302 //purpose  : Return nodes coordinates computed by Apply() method
3303 //=======================================================================
3304
3305 bool SMESH_Pattern::GetMappedPoints ( list< const gp_XYZ * > & thePoints )
3306 {
3307   thePoints.clear();
3308   if ( !myIsComputed )
3309     return false;
3310
3311   vector< TPoint >::iterator pVecIt = myPoints.begin();
3312   for ( ; pVecIt != myPoints.end(); pVecIt++ )
3313     thePoints.push_back( & (*pVecIt).myXYZ.XYZ() );
3314
3315   return ( thePoints.size() > 0 );
3316 }
3317
3318
3319 //=======================================================================
3320 //function : GetPoints
3321 //purpose  : Return nodes coordinates of the pattern
3322 //=======================================================================
3323
3324 bool SMESH_Pattern::GetPoints ( list< const gp_XYZ * > & thePoints ) const
3325 {
3326   thePoints.clear();
3327
3328   if ( !IsLoaded() )
3329     return false;
3330
3331   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3332   for ( ; pVecIt != myPoints.end(); pVecIt++ )
3333     thePoints.push_back( & (*pVecIt).myInitXYZ );
3334
3335   return ( thePoints.size() > 0 );
3336 }
3337
3338 //=======================================================================
3339 //function : getShapePoints
3340 //purpose  : return list of points located on theShape
3341 //=======================================================================
3342
3343 list< SMESH_Pattern::TPoint* > &
3344   SMESH_Pattern::getShapePoints(const TopoDS_Shape& theShape)
3345 {
3346   int aShapeID;
3347   if ( !myShapeIDMap.Contains( theShape ))
3348     aShapeID = myShapeIDMap.Add( theShape );
3349   else
3350     aShapeID = myShapeIDMap.FindIndex( theShape );
3351
3352   return myShapeIDToPointsMap[ aShapeID ];
3353 }
3354
3355 //=======================================================================
3356 //function : getShapePoints
3357 //purpose  : return list of points located on the shape
3358 //=======================================================================
3359
3360 list< SMESH_Pattern::TPoint* > & SMESH_Pattern::getShapePoints(const int theShapeID)
3361 {
3362   return myShapeIDToPointsMap[ theShapeID ];
3363 }
3364
3365 //=======================================================================
3366 //function : DumpPoints
3367 //purpose  : Debug
3368 //=======================================================================
3369
3370 void SMESH_Pattern::DumpPoints() const
3371 {
3372 #ifdef _DEBUG_
3373   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
3374   for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ )
3375     cout << i << ": " << *pVecIt;
3376 #endif
3377 }
3378
3379 //=======================================================================
3380 //function : TPoint()
3381 //purpose  : 
3382 //=======================================================================
3383
3384 SMESH_Pattern::TPoint::TPoint()
3385 {
3386 #ifdef _DEBUG_
3387   myInitXYZ.SetCoord(0,0,0);
3388   myInitUV.SetCoord(0.,0.);
3389   myInitU = 0;
3390   myXYZ.SetCoord(0,0,0);
3391   myUV.SetCoord(0.,0.);
3392   myU = 0;
3393 #endif
3394 }
3395
3396 //=======================================================================
3397 //function : operator <<
3398 //purpose  : 
3399 //=======================================================================
3400
3401 ostream & operator <<(ostream & OS, const SMESH_Pattern::TPoint& p)
3402 {
3403   gp_XYZ xyz = p.myInitXYZ;
3404   OS << "\tinit( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3405   gp_XY xy = p.myInitUV;
3406   OS << " uv( " <<  xy.X() << " " << xy.Y() << " )";
3407   double u = p.myInitU;
3408   OS << " u( " <<  u << " )) " << &p << endl;
3409   xyz = p.myXYZ.XYZ();
3410   OS << "\t    ( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
3411   xy = p.myUV;
3412   OS << " uv( " <<  xy.X() << " " << xy.Y() << " )";
3413   u = p.myU;
3414   OS << " u( " <<  u << " ))" << endl;
3415   
3416   return OS;
3417 }
3418
3419 //=======================================================================
3420 //function : TBlock::TEdge::GetU
3421 //purpose  : 
3422 //=======================================================================
3423
3424 double TBlock::TEdge::GetU( const gp_XYZ& theParams ) const
3425 {
3426   double u = theParams.Coord( myCoordInd );
3427   return ( 1 - u ) * myFirst + u * myLast;
3428 }
3429
3430 //=======================================================================
3431 //function : TBlock::TEdge::Point
3432 //purpose  : 
3433 //=======================================================================
3434
3435 gp_XYZ TBlock::TEdge::Point( const gp_XYZ& theParams ) const
3436 {
3437   gp_XYZ p = myC3d->Value( GetU( theParams )).XYZ();
3438   if ( myTrsf.Form() != gp_Identity )
3439     myTrsf.Transforms( p );
3440   return p;
3441 }
3442
3443 //=======================================================================
3444 //function : TBlock::TFace::GetUV
3445 //purpose  : 
3446 //=======================================================================
3447
3448 gp_XY TBlock::TFace::GetUV( const gp_XYZ& theParams ) const
3449 {
3450   gp_XY uv(0.,0.);
3451   double dU = theParams.Coord( GetUInd() );
3452   double dV = theParams.Coord( GetVInd() );
3453   for ( int iE = 0; iE < 4; iE++ ) // loop on 4 edges
3454   {
3455     double Ecoef = 0, Vcoef = 0;
3456     switch ( iE ) {
3457     case 0:
3458       Ecoef = ( 1 - dV ); // u0
3459       Vcoef = ( 1 - dU ) * ( 1 - dV ); break; // 00
3460     case 1:
3461       Ecoef = dV; // u1
3462       Vcoef = dU * ( 1 - dV ); break; // 10
3463     case 2:
3464       Ecoef = ( 1 - dU ); // 0v
3465       Vcoef = dU * dV  ; break; // 11
3466     case 3:
3467       Ecoef = dU  ; // 1v
3468       Vcoef = ( 1 - dU ) * dV  ; break; // 01
3469     default:;
3470     }
3471     // edge addition
3472     double u = theParams.Coord( myCoordInd[ iE ] );
3473     u = ( 1 - u ) * myFirst[ iE ] + u * myLast[ iE ];
3474     uv += Ecoef * myC2d[ iE ]->Value( u ).XY();
3475     // corner addition
3476     uv -= Vcoef * myCorner[ iE ];
3477   }
3478   return uv;
3479 }
3480
3481 //=======================================================================
3482 //function : TBlock::TFace::Point
3483 //purpose  : 
3484 //=======================================================================
3485
3486 gp_XYZ TBlock::TFace::Point( const gp_XYZ& theParams ) const
3487 {
3488   gp_XY uv = GetUV( theParams );
3489   gp_XYZ p = myS->Value( uv.X(), uv.Y() ).XYZ();
3490   if ( myTrsf.Form() != gp_Identity )
3491     myTrsf.Transforms( p );
3492   return p;
3493 }
3494
3495 //=======================================================================
3496 //function : GetShapeCoef
3497 //purpose  : 
3498 //=======================================================================
3499
3500 double* TBlock::GetShapeCoef (const int theShapeID)
3501 {
3502   static double shapeCoef[][3] = {
3503     //    V000,        V100,        V010,         V110
3504     { -1,-1,-1 }, {  1,-1,-1 }, { -1, 1,-1 }, {  1, 1,-1 },
3505     //    V001,        V101,        V011,         V111,
3506     { -1,-1, 1 }, {  1,-1, 1 }, { -1, 1, 1 }, {  1, 1, 1 },
3507     //    Ex00,        Ex10,        Ex01,         Ex11,
3508     {  0,-1,-1 }, {  0, 1,-1 }, {  0,-1, 1 }, {  0, 1, 1 },
3509     //    E0y0,        E1y0,        E0y1,         E1y1,
3510     { -1, 0,-1 }, {  1, 0,-1 }, { -1, 0, 1 }, {  1, 0, 1 },
3511     //    E00z,        E10z,        E01z,         E11z,
3512     { -1,-1, 0 }, {  1,-1, 0 }, { -1, 1, 0 }, {  1, 1, 0 },
3513     //    Fxy0,        Fxy1,        Fx0z,         Fx1z,         F0yz,           F1yz,
3514     {  0, 0,-1 }, {  0, 0, 1 }, {  0,-1, 0 }, {  0, 1, 0 }, { -1, 0, 0 }, {  1, 0, 0 },
3515     // ID_Shell
3516     {  0, 0, 0 }
3517   };
3518   if ( theShapeID < ID_V000 || theShapeID > ID_F1yz )
3519     return shapeCoef[ ID_Shell - 1 ];
3520
3521   return shapeCoef[ theShapeID - 1 ];
3522 }
3523
3524 //=======================================================================
3525 //function : ShellPoint
3526 //purpose  : return coordinates of a point in shell
3527 //=======================================================================
3528
3529 bool TBlock::ShellPoint( const gp_XYZ& theParams, gp_XYZ& thePoint ) const
3530 {
3531   thePoint.SetCoord( 0., 0., 0. );
3532   for ( int shapeID = ID_V000; shapeID < ID_Shell; shapeID++ )
3533   {
3534     // coef
3535     double* coefs = GetShapeCoef( shapeID );
3536     double k = 1;
3537     for ( int iCoef = 0; iCoef < 3; iCoef++ ) {
3538       if ( coefs[ iCoef ] != 0 ) {
3539         if ( coefs[ iCoef ] < 0 )
3540           k *= ( 1. - theParams.Coord( iCoef + 1 ));
3541         else
3542           k *= theParams.Coord( iCoef + 1 );
3543       }
3544     }
3545     // point on a shape
3546     gp_XYZ Ps;
3547     if ( shapeID < ID_Ex00 ) // vertex
3548       VertexPoint( shapeID, Ps );
3549     else if ( shapeID < ID_Fxy0 ) { // edge
3550       EdgePoint( shapeID, theParams, Ps );
3551       k = -k;
3552     } else // face
3553       FacePoint( shapeID, theParams, Ps );
3554
3555     thePoint += k * Ps;
3556   }
3557   return true;
3558 }
3559
3560 //=======================================================================
3561 //function : NbVariables
3562 //purpose  : 
3563 //=======================================================================
3564
3565 Standard_Integer TBlock::NbVariables() const
3566 {
3567   return 3;
3568 }
3569
3570 //=======================================================================
3571 //function : NbEquations
3572 //purpose  : 
3573 //=======================================================================
3574
3575 Standard_Integer TBlock::NbEquations() const
3576 {
3577   return 1;
3578 }
3579
3580 //=======================================================================
3581 //function : Value
3582 //purpose  : 
3583 //=======================================================================
3584
3585 Standard_Boolean TBlock::Value(const math_Vector& theXYZ, math_Vector& theFxyz) 
3586 {
3587   gp_XYZ P, params( theXYZ(1), theXYZ(2), theXYZ(3) );
3588   if ( params.IsEqual( myParam, DBL_MIN )) { // same param
3589     theFxyz( 1 ) = myValues[ 0 ];
3590   }
3591   else {
3592     ShellPoint( params, P );
3593     gp_Vec dP( P - myPoint );
3594     theFxyz(1) = SQRT_FUNC ? dP.SquareMagnitude() : dP.Magnitude();
3595   }
3596   return true;
3597 }
3598
3599 //=======================================================================
3600 //function : Derivatives
3601 //purpose  : 
3602 //=======================================================================
3603
3604 Standard_Boolean TBlock::Derivatives(const math_Vector& XYZ,math_Matrix& Df) 
3605 {
3606   MESSAGE( "TBlock::Derivatives()");
3607   math_Vector F(1,3);
3608   return Values(XYZ,F,Df);
3609 }
3610
3611 //=======================================================================
3612 //function : Values
3613 //purpose  : 
3614 //=======================================================================
3615
3616 Standard_Boolean TBlock::Values(const math_Vector& theXYZ,
3617                                 math_Vector&       theFxyz,
3618                                 math_Matrix&       theDf) 
3619 {
3620 //  MESSAGE( endl<<"TBlock::Values( "<<theXYZ(1)<<", "<<theXYZ(2)<<", "<<theXYZ(3)<<")");
3621
3622   gp_XYZ P, params( theXYZ(1), theXYZ(2), theXYZ(3) );
3623   if ( params.IsEqual( myParam, DBL_MIN )) { // same param
3624     theFxyz( 1 ) = myValues[ 0 ];
3625     theDf( 1,1 ) = myValues[ 1 ];
3626     theDf( 1,2 ) = myValues[ 2 ];
3627     theDf( 1,3 ) = myValues[ 3 ];
3628     return true;
3629   }
3630
3631   ShellPoint( params, P );
3632   //myNbIterations++; // how many time call ShellPoint()
3633
3634   gp_Vec dP( P - myPoint );
3635   theFxyz(1) = SQRT_FUNC ? dP.SquareMagnitude() : dP.Magnitude();
3636   if ( theFxyz(1) < 1e-6 ) {
3637     myParam      = params;
3638     myValues[ 0 ]= 0;
3639     theDf( 1,1 ) = 0;
3640     theDf( 1,2 ) = 0;
3641     theDf( 1,3 ) = 0;
3642     return true;
3643   }
3644
3645   if ( theFxyz(1) < myValues[0] )
3646   {
3647     // 3 partial derivatives
3648     gp_Vec drv[ 3 ];
3649     for ( int iP = 1; iP <= 3; iP++ ) {
3650       gp_XYZ Pi;
3651       params.SetCoord( iP, theXYZ( iP ) + 0.001 );
3652       ShellPoint( params, Pi );
3653       params.SetCoord( iP, theXYZ( iP ) ); // restore params
3654       gp_Vec dPi ( P, Pi );
3655       double mag = dPi.Magnitude();
3656       if ( mag > DBL_MIN )
3657         dPi /= mag;
3658       drv[ iP - 1 ] = dPi;
3659     }
3660     for ( int iP = 0; iP < 3; iP++ ) {
3661       if ( iP == myFaceIndex )
3662         theDf( 1, iP + 1 ) = myFaceParam;
3663       else {
3664         // like IntAna_IntConicQuad::Perform (const gp_Lin& L, const gp_Pln& P)
3665         // where L is (P -> myPoint), P is defined by the 2 other derivative direction
3666         int iPrev = ( iP ? iP - 1 : 2 );
3667         int iNext = ( iP == 2 ? 0 : iP + 1 );
3668         gp_Vec plnNorm = drv[ iPrev ].Crossed( drv [ iNext ] );
3669         double Direc = plnNorm * drv[ iP ];
3670         if ( Abs(Direc) <= DBL_MIN )
3671           theDf( 1, iP + 1 ) = dP * drv[ iP ];
3672         else {
3673           double Dis = plnNorm * P - plnNorm * myPoint;
3674           theDf( 1, iP + 1 ) = Dis/Direc;
3675         }
3676       }
3677     }
3678     //myNbIterations +=3; // how many time call ShellPoint()
3679
3680     // store better values
3681     myParam    = params;
3682     myValues[0]= theFxyz(1);
3683     myValues[1]= theDf(1,1);
3684     myValues[2]= theDf(1,2);
3685     myValues[3]= theDf(1,3);
3686
3687 //     SCRUTE( theFxyz(1)  );
3688 //     SCRUTE( theDf( 1,1 ));
3689 //     SCRUTE( theDf( 1,2 ));
3690 //     SCRUTE( theDf( 1,3 ));
3691   }
3692
3693   return true;
3694 }
3695
3696 //=======================================================================
3697 //function : ComputeParameters
3698 //purpose  : compute point parameters in the block
3699 //=======================================================================
3700
3701 bool TBlock::ComputeParameters(const gp_Pnt& thePoint,
3702                                gp_XYZ&       theParams,
3703                                const int     theShapeID)
3704 {
3705 //   MESSAGE( endl<<"TBlock::ComputeParameters( "
3706 //           <<thePoint.X()<<", "<<thePoint.Y()<<", "<<thePoint.Z()<<")");
3707
3708   myPoint = thePoint.XYZ();
3709
3710   myParam.SetCoord( -1,-1,-1 );
3711   myValues[0] = 1e100;
3712
3713   const bool isOnFace = IsFaceID( theShapeID );
3714   double * coef = GetShapeCoef( theShapeID );
3715
3716   // the first guess
3717   math_Vector start( 1, 3, 0.0 );
3718   if ( !myGridComputed )
3719   {
3720     // define the first guess by thePoint projection on lines
3721     // connecting vertices
3722     bool needGrid = false;
3723     gp_XYZ par000( 0, 0, 0 ), par111( 1, 1, 1 );
3724     double zero = DBL_MIN * DBL_MIN;
3725     for ( int iEdge = 0, iParam = 1; iParam <= 3 && !needGrid; iParam++ )
3726     {
3727       if ( isOnFace && coef[ iParam - 1 ] != 0 ) {
3728         iEdge += 4;
3729         continue;
3730       }
3731       for ( int iE = 0; iE < 4; iE++, iEdge++ ) { // loop on 4 parallel edges
3732         gp_Pnt p0 = myEdge[ iEdge ].Point( par000 );
3733         gp_Pnt p1 = myEdge[ iEdge ].Point( par111 );
3734         gp_Vec v01( p0, p1 ), v0P( p0, thePoint );
3735         double len2 = v01.SquareMagnitude();
3736         double par = 0;
3737         if ( len2 > zero ) {
3738           par = v0P.Dot( v01 ) / len2;
3739           if ( par < 0 || par > 1 ) {
3740             needGrid = true;
3741             break;
3742           }
3743         }
3744         start( iParam ) += par;
3745       }
3746       start( iParam ) /= 4.;
3747     }
3748     if ( needGrid ) {
3749       // compute nodes of 3 x 3 x 3 grid
3750       int iNode = 0;
3751       for ( double x = 0.25; x < 0.9; x += 0.25 )
3752         for ( double y = 0.25; y < 0.9; y += 0.25 )
3753           for ( double z = 0.25; z < 0.9; z += 0.25 ) {
3754             TxyzPair & prmPtn = my3x3x3GridNodes[ iNode++ ];
3755             prmPtn.first.SetCoord( x, y, z );
3756             ShellPoint( prmPtn.first, prmPtn.second );
3757           }
3758       myGridComputed = true;
3759     }
3760   }
3761   if ( myGridComputed ) {
3762     double minDist = DBL_MAX;
3763     gp_XYZ* bestParam = 0;
3764     for ( int iNode = 0; iNode < 27; iNode++ ) {
3765       TxyzPair & prmPtn = my3x3x3GridNodes[ iNode ];
3766       double dist = ( thePoint.XYZ() - prmPtn.second ).SquareModulus();
3767       if ( dist < minDist ) {
3768         minDist = dist;
3769         bestParam = & prmPtn.first;
3770       }
3771     }
3772     start( 1 ) = bestParam->X();
3773     start( 2 ) = bestParam->Y();
3774     start( 3 ) = bestParam->Z();
3775   }
3776
3777   int myFaceIndex = -1;
3778   if ( isOnFace ) {
3779     // put a point on the face
3780     for ( int iCoord = 0; iCoord < 3; iCoord++ )
3781       if ( coef[ iCoord ] ) {
3782         myFaceIndex = iCoord;
3783         myFaceParam = ( coef[ myFaceIndex ] < 0.5 ) ? 0.0 : 1.0;
3784         start( iCoord + 1 ) = myFaceParam;
3785       }
3786   }
3787   math_Vector low  ( 1, 3, 0.0 );
3788   math_Vector up   ( 1, 3, 1.0 );
3789   math_Vector tol  ( 1, 3, 1e-4 );
3790   math_FunctionSetRoot paramSearch( *this, tol );
3791
3792   int nbLoops = 0;
3793   while ( myValues[0] > 1e-1 && nbLoops++ < 10 ) {
3794     paramSearch.Perform ( *this, start, low, up );
3795     if ( !paramSearch.IsDone() ) {
3796       //MESSAGE( " !paramSearch.IsDone() " );
3797     }
3798     else {
3799       //MESSAGE( " NB ITERATIONS: " << paramSearch.NbIterations() );
3800     }
3801     start( 1 ) = myParam.X();
3802     start( 2 ) = myParam.Y();
3803     start( 3 ) = myParam.Z();
3804     //MESSAGE( "Distance: " << ( SQRT_FUNC ? sqrt(myValues[0]) : myValues[0] ));
3805   }
3806 //   MESSAGE( endl << myParam.X() << " " << myParam.Y() << " " << myParam.Z() << endl);
3807 //   mySumDist += myValues[0];
3808 //   MESSAGE( " TOTAL NB ITERATIONS: " << myNbIterations <<
3809 //             " DIST: " << ( SQRT_FUNC ? sqrt(mySumDist) : mySumDist ));
3810
3811
3812   theParams = myParam;
3813
3814   return true;
3815 }
3816
3817 //=======================================================================
3818 //function : GetStateNumber
3819 //purpose  : 
3820 //=======================================================================
3821
3822 Standard_Integer TBlock::GetStateNumber ()
3823 {
3824 //   MESSAGE( endl<<"TBlock::GetStateNumber( "<<myParam.X()<<", "<<
3825 //           myParam.Y()<<", "<<myParam.Z()<<") DISTANCE: " << myValues[0]);
3826   return myValues[0] < 1e-1;
3827 }
3828
3829 //=======================================================================
3830 //function : DumpShapeID
3831 //purpose  : debug an id of a block sub-shape
3832 //=======================================================================
3833
3834 #define CASEDUMP(id,strm) case id: strm << #id; break;
3835
3836 ostream& TBlock::DumpShapeID (const int id, ostream& stream)
3837 {
3838   switch ( id ) {
3839   CASEDUMP( ID_V000, stream );
3840   CASEDUMP( ID_V100, stream );
3841   CASEDUMP( ID_V010, stream );
3842   CASEDUMP( ID_V110, stream );
3843   CASEDUMP( ID_V001, stream );
3844   CASEDUMP( ID_V101, stream );
3845   CASEDUMP( ID_V011, stream );
3846   CASEDUMP( ID_V111, stream );
3847   CASEDUMP( ID_Ex00, stream );
3848   CASEDUMP( ID_Ex10, stream );
3849   CASEDUMP( ID_Ex01, stream );
3850   CASEDUMP( ID_Ex11, stream );
3851   CASEDUMP( ID_E0y0, stream );
3852   CASEDUMP( ID_E1y0, stream );
3853   CASEDUMP( ID_E0y1, stream );
3854   CASEDUMP( ID_E1y1, stream );
3855   CASEDUMP( ID_E00z, stream );
3856   CASEDUMP( ID_E10z, stream );
3857   CASEDUMP( ID_E01z, stream );
3858   CASEDUMP( ID_E11z, stream );
3859   CASEDUMP( ID_Fxy0, stream );
3860   CASEDUMP( ID_Fxy1, stream );
3861   CASEDUMP( ID_Fx0z, stream );
3862   CASEDUMP( ID_Fx1z, stream );
3863   CASEDUMP( ID_F0yz, stream );
3864   CASEDUMP( ID_F1yz, stream );
3865   CASEDUMP( ID_Shell, stream );
3866   default: stream << "ID_INVALID";
3867   }
3868   return stream;
3869 }
3870
3871 //=======================================================================
3872 //function : GetShapeIDByParams
3873 //purpose  : define an id of the block sub-shape by normlized point coord
3874 //=======================================================================
3875
3876 int TBlock::GetShapeIDByParams ( const gp_XYZ& theCoord )
3877 {
3878   //   id ( 0 - 26 ) computation:
3879
3880   //   vertex     ( 0 - 7 )  : id = 1*x + 2*y + 4*z
3881
3882   //   edge || X  ( 8 - 11 ) : id = 8   + 1*y + 2*z
3883   //   edge || Y  ( 12 - 15 ): id = 1*x + 12  + 2*z
3884   //   edge || Z  ( 16 - 19 ): id = 1*x + 2*y + 16 
3885
3886   //   face || XY ( 20 - 21 ): id = 8   + 12  + 1*z - 0
3887   //   face || XZ ( 22 - 23 ): id = 8   + 1*y + 16  - 2
3888   //   face || YZ ( 24 - 25 ): id = 1*x + 12  + 16  - 4
3889
3890   static int iAddBnd[]    = { 1, 2, 4 };
3891   static int iAddNotBnd[] = { 8, 12, 16 };
3892   static int iFaceSubst[] = { 0, 2, 4 };
3893
3894   int id = 0;
3895   int iOnBoundary = 0;
3896   for ( int iCoord = 0; iCoord < 3; iCoord++ )
3897   {
3898     double val = theCoord.Coord( iCoord + 1 );
3899     if ( val == 0.0 )
3900       iOnBoundary++;
3901     else if ( val == 1.0 )
3902       id += iAddBnd[ iOnBoundary++ ];
3903     else
3904       id += iAddNotBnd[ iCoord ];
3905   }
3906   if ( iOnBoundary == 1 ) // face
3907     id -= iFaceSubst[ (id - 20) / 4 ];
3908   else if ( iOnBoundary == 0 ) // shell
3909     id = 26;
3910
3911   if ( id > 26 || id < 0 ) {
3912     MESSAGE( "GetShapeIDByParams() = " << id
3913             <<" "<< theCoord.X() <<" "<< theCoord.Y() <<" "<< theCoord.Z() );
3914   }
3915
3916   return id + 1; // shape ids start at 1
3917 }
3918
3919 //=======================================================================
3920 //function : LoadBlockShapes
3921 //purpose  : add sub-shapes of theBlock to theShapeIDMap so that they get
3922 //           IDs acoording to enum TBlockShapeID
3923 //=======================================================================
3924
3925 bool TBlock::LoadBlockShapes(const TopoDS_Vertex&        theVertex000,
3926                              const TopoDS_Vertex&        theVertex001,
3927 //                             TopTools_IndexedMapOfShape& theShapeIDMap
3928                              TopTools_IndexedMapOfOrientedShape& theShapeIDMap )
3929 {
3930   MESSAGE(" ::LoadBlockShapes()");
3931   myGridComputed = false;
3932
3933   // 6 vertices
3934   TopoDS_Shape V000, V100, V010, V110, V001, V101, V011, V111;
3935   // 12 edges
3936   TopoDS_Shape Ex00, Ex10, Ex01, Ex11;
3937   TopoDS_Shape E0y0, E1y0, E0y1, E1y1;
3938   TopoDS_Shape E00z, E10z, E01z, E11z;
3939   // 6 faces
3940   TopoDS_Shape Fxy0, Fx0z, F0yz, Fxy1, Fx1z, F1yz;
3941
3942   // nb of faces bound to a vertex in TopTools_IndexedDataMapOfShapeListOfShape
3943   // filled by TopExp::MapShapesAndAncestors()
3944   const int NB_FACES_BY_VERTEX = 6;
3945
3946   TopTools_IndexedDataMapOfShapeListOfShape vfMap;
3947   TopExp::MapShapesAndAncestors( myShell, TopAbs_VERTEX, TopAbs_FACE, vfMap );
3948   if ( vfMap.Extent() != 8 ) {
3949     MESSAGE(" Wrong nb of vertices in the block: " << vfMap.Extent() );
3950     return false;
3951   }
3952
3953   V000 = theVertex000;
3954   V001 = theVertex001;
3955
3956   if ( V000.IsNull() ) {
3957     // find vertex 000 - the one with smallest coordinates
3958     double minVal = DBL_MAX, minX, val;
3959     for ( int i = 1; i <= 8; i++ ) {
3960       const TopoDS_Vertex& v = TopoDS::Vertex( vfMap.FindKey( i ));
3961       gp_Pnt P = BRep_Tool::Pnt( v );
3962       val = P.X() + P.Y() + P.Z();
3963       if ( val < minVal || ( val == minVal && P.X() < minX )) {
3964         V000 = v;
3965         minVal = val;
3966         minX = P.X();
3967       }
3968     }
3969     // find vertex 001 - the one on the most vertical edge passing through V000
3970     TopTools_IndexedDataMapOfShapeListOfShape veMap;
3971     TopExp::MapShapesAndAncestors( myShell, TopAbs_VERTEX, TopAbs_EDGE, veMap );
3972     gp_Vec dir001 = gp::DZ();
3973     gp_Pnt p000 = BRep_Tool::Pnt( TopoDS::Vertex( V000 ));
3974     double maxVal = -DBL_MAX;
3975     TopTools_ListIteratorOfListOfShape eIt ( veMap.FindFromKey( V000 ));
3976     for (  ; eIt.More(); eIt.Next() ) {
3977       const TopoDS_Edge& e = TopoDS::Edge( eIt.Value() );
3978       TopoDS_Vertex v = TopExp::FirstVertex( e );
3979       if ( v.IsSame( V000 ))
3980         v = TopExp::LastVertex( e );
3981       val = dir001 * gp_Vec( p000, BRep_Tool::Pnt( v )).Normalized();
3982       if ( val > maxVal ) {
3983         V001 = v;
3984         maxVal = val;
3985       }
3986     }
3987   }
3988
3989   // find the bottom (Fxy0), Fx0z and F0yz faces
3990
3991   const TopTools_ListOfShape& f000List = vfMap.FindFromKey( V000 );
3992   const TopTools_ListOfShape& f001List = vfMap.FindFromKey( V001 );
3993   if (f000List.Extent() != NB_FACES_BY_VERTEX ||
3994       f001List.Extent() != NB_FACES_BY_VERTEX ) {
3995     MESSAGE(" LoadBlockShapes() " << f000List.Extent() << " " << f001List.Extent());
3996     return false;
3997   }
3998   TopTools_ListIteratorOfListOfShape f001It, f000It ( f000List );
3999   int i, j, iFound1, iFound2;
4000   for ( j = 0; f000It.More(); f000It.Next(), j++ )
4001   {
4002     if ( NB_FACES_BY_VERTEX == 6 && j % 2 ) continue; // each face encounters twice
4003     const TopoDS_Shape& F = f000It.Value();
4004     for ( i = 0, f001It.Initialize( f001List ); f001It.More(); f001It.Next(), i++ ) {
4005       if ( NB_FACES_BY_VERTEX == 6 && i % 2 ) continue; // each face encounters twice
4006       if ( F.IsSame( f001It.Value() ))
4007         break;
4008     }
4009     if ( f001It.More() ) // Fx0z or F0yz found
4010       if ( Fx0z.IsNull() ) {
4011         Fx0z = F;
4012         iFound1 = i;
4013       } else {
4014         F0yz = F;
4015         iFound2 = i;
4016       }
4017     else // F is the bottom face
4018       Fxy0 = F;
4019   }
4020   if ( Fxy0.IsNull() || Fx0z.IsNull() || F0yz.IsNull() ) {
4021     MESSAGE( Fxy0.IsNull() <<" "<< Fx0z.IsNull() <<" "<< F0yz.IsNull() );
4022     return false;
4023   }
4024
4025   // choose the top face (Fxy1)
4026   for ( i = 0, f001It.Initialize( f001List ); f001It.More(); f001It.Next(), i++ ) {
4027     if ( NB_FACES_BY_VERTEX == 6 && i % 2 ) continue; // each face encounters twice
4028     if ( i != iFound1 && i != iFound2 )
4029       break;
4030   }
4031   Fxy1 = f001It.Value();
4032   if ( Fxy1.IsNull() ) {
4033     MESSAGE(" LoadBlockShapes() error ");
4034     return false;
4035   }
4036
4037   // find bottom edges and veritices
4038   list< TopoDS_Edge > eList;
4039   list< int >         nbVertexInWires;
4040   getOrderedEdges( TopoDS::Face( Fxy0 ), TopoDS::Vertex( V000 ), eList, nbVertexInWires );
4041   if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) {
4042     MESSAGE(" LoadBlockShapes() error ");
4043     return false;
4044   }
4045   list< TopoDS_Edge >::iterator elIt = eList.begin();
4046   for ( i = 0; elIt != eList.end(); elIt++, i++ )
4047     switch ( i ) {
4048     case 0: E0y0 = *elIt; V010 = TopExp::LastVertex( *elIt, true ); break;
4049     case 1: Ex10 = *elIt; V110 = TopExp::LastVertex( *elIt, true ); break;
4050     case 2: E1y0 = *elIt; V100 = TopExp::LastVertex( *elIt, true ); break;
4051     case 3: Ex00 = *elIt; break;
4052     default:;
4053     }
4054   if ( i != 4 || E0y0.IsNull() || Ex10.IsNull() || E1y0.IsNull() || Ex00.IsNull() ) {
4055     MESSAGE(" LoadBlockShapes() error, eList.size()=" << eList.size());
4056     return false;
4057   }
4058
4059
4060   // find top edges and veritices
4061   eList.clear();
4062   getOrderedEdges( TopoDS::Face( Fxy1 ), TopoDS::Vertex( V001 ), eList, nbVertexInWires );
4063   if ( nbVertexInWires.size() != 1 || nbVertexInWires.front() != 4 ) {
4064     MESSAGE(" LoadBlockShapes() error ");
4065     return false;
4066   }
4067   for ( i = 0, elIt = eList.begin(); elIt != eList.end(); elIt++, i++ )
4068     switch ( i ) {
4069     case 0: Ex01 = *elIt; V101 = TopExp::LastVertex( *elIt, true ); break;
4070     case 1: E1y1 = *elIt; V111 = TopExp::LastVertex( *elIt, true ); break;
4071     case 2: Ex11 = *elIt; V011 = TopExp::LastVertex( *elIt, true ); break;
4072     case 3: E0y1 = *elIt; break;
4073     default:;
4074     }
4075   if ( i != 4 || Ex01.IsNull() || E1y1.IsNull() || Ex11.IsNull() || E0y1.IsNull() ) {
4076     MESSAGE(" LoadBlockShapes() error, eList.size()=" << eList.size());
4077     return false;
4078   }
4079
4080   // swap Fx0z and F0yz if necessary
4081   TopExp_Explorer exp( Fx0z, TopAbs_VERTEX );
4082   for ( ; exp.More(); exp.Next() ) // Fx0z shares V101 and V100
4083     if ( V101.IsSame( exp.Current() ) || V100.IsSame( exp.Current() ))
4084       break; // V101 or V100 found
4085   if ( !exp.More() ) { // not found
4086     TopoDS_Shape f = Fx0z; Fx0z = F0yz; F0yz = f;
4087   }
4088
4089   // find Fx1z and F1yz faces
4090   const TopTools_ListOfShape& f111List = vfMap.FindFromKey( V111 );
4091   const TopTools_ListOfShape& f110List = vfMap.FindFromKey( V110 );
4092   if (f111List.Extent() != NB_FACES_BY_VERTEX ||
4093       f110List.Extent() != NB_FACES_BY_VERTEX ) {
4094     MESSAGE(" LoadBlockShapes() " << f111List.Extent() << " " << f110List.Extent());
4095     return false;
4096   }
4097   TopTools_ListIteratorOfListOfShape f111It, f110It ( f110List);
4098   for ( j = 0 ; f110It.More(); f110It.Next(), j++ ) {
4099     if ( NB_FACES_BY_VERTEX == 6 && j % 2 ) continue; // each face encounters twice
4100     const TopoDS_Shape& F = f110It.Value();
4101     for ( i = 0, f111It.Initialize( f111List ); f111It.More(); f111It.Next(), i++ ) {
4102       if ( NB_FACES_BY_VERTEX == 6 && i % 2 ) continue; // each face encounters twice
4103       if ( F.IsSame( f111It.Value() )) { // Fx1z or F1yz found
4104         if ( Fx1z.IsNull() )
4105           Fx1z = F;
4106         else
4107           F1yz = F;
4108       }
4109     }
4110   }
4111   if ( Fx1z.IsNull() || F1yz.IsNull() ) {
4112     MESSAGE(" LoadBlockShapes() error ");
4113     return false;
4114   }
4115
4116   // swap Fx1z and F1yz if necessary
4117   for ( exp.Init( Fx1z, TopAbs_VERTEX ); exp.More(); exp.Next() )
4118     if ( V010.IsSame( exp.Current() ) || V011.IsSame( exp.Current() ))
4119       break;
4120   if ( !exp.More() ) {
4121     TopoDS_Shape f = Fx1z; Fx1z = F1yz; F1yz = f;
4122   }
4123
4124   // find vertical edges
4125   for ( exp.Init( Fx0z, TopAbs_EDGE ); exp.More(); exp.Next() ) {
4126     const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
4127     const TopoDS_Shape& vFirst = TopExp::FirstVertex( edge, true );
4128     if ( vFirst.IsSame( V001 ))
4129       E00z = edge;
4130     else if ( vFirst.IsSame( V100 ))
4131       E10z = edge;
4132   }
4133   if ( E00z.IsNull() || E10z.IsNull() ) {
4134     MESSAGE(" LoadBlockShapes() error ");
4135     return false;
4136   }
4137   for ( exp.Init( Fx1z, TopAbs_EDGE ); exp.More(); exp.Next() ) {
4138     const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
4139     const TopoDS_Shape& vFirst = TopExp::FirstVertex( edge, true );
4140     if ( vFirst.IsSame( V111 ))
4141       E11z = edge;
4142     else if ( vFirst.IsSame( V010 ))
4143       E01z = edge;
4144   }
4145   if ( E01z.IsNull() || E11z.IsNull() ) {
4146     MESSAGE(" LoadBlockShapes() error ");
4147     return false;
4148   }
4149
4150   // load shapes in theShapeIDMap
4151
4152   theShapeIDMap.Clear();
4153   
4154   theShapeIDMap.Add(V000.Oriented( TopAbs_FORWARD ));
4155   theShapeIDMap.Add(V100.Oriented( TopAbs_FORWARD ));
4156   theShapeIDMap.Add(V010.Oriented( TopAbs_FORWARD ));
4157   theShapeIDMap.Add(V110.Oriented( TopAbs_FORWARD ));
4158   theShapeIDMap.Add(V001.Oriented( TopAbs_FORWARD ));
4159   theShapeIDMap.Add(V101.Oriented( TopAbs_FORWARD ));
4160   theShapeIDMap.Add(V011.Oriented( TopAbs_FORWARD ));
4161   theShapeIDMap.Add(V111.Oriented( TopAbs_FORWARD ));
4162
4163   theShapeIDMap.Add(Ex00);
4164   theShapeIDMap.Add(Ex10);
4165   theShapeIDMap.Add(Ex01);
4166   theShapeIDMap.Add(Ex11);
4167
4168   theShapeIDMap.Add(E0y0);
4169   theShapeIDMap.Add(E1y0);
4170   theShapeIDMap.Add(E0y1);
4171   theShapeIDMap.Add(E1y1);
4172
4173   theShapeIDMap.Add(E00z);
4174   theShapeIDMap.Add(E10z);
4175   theShapeIDMap.Add(E01z);
4176   theShapeIDMap.Add(E11z);
4177
4178   theShapeIDMap.Add(Fxy0);
4179   theShapeIDMap.Add(Fxy1);
4180   theShapeIDMap.Add(Fx0z);
4181   theShapeIDMap.Add(Fx1z);
4182   theShapeIDMap.Add(F0yz);
4183   theShapeIDMap.Add(F1yz);
4184   
4185   theShapeIDMap.Add(myShell);
4186
4187   if ( theShapeIDMap.Extent() != 27 ) {
4188     MESSAGE("LoadBlockShapes() " << theShapeIDMap.Extent() );
4189     return false;
4190   }
4191
4192   // store shapes geometry
4193   for ( int shapeID = 1; shapeID < theShapeIDMap.Extent(); shapeID++ )
4194   {
4195     const TopoDS_Shape& S = theShapeIDMap( shapeID );
4196     switch ( S.ShapeType() )
4197     {
4198     case TopAbs_VERTEX: {
4199
4200       if ( shapeID > ID_V111 ) {
4201         MESSAGE(" shapeID =" << shapeID );
4202         return false;
4203       }
4204       myPnt[ shapeID - ID_V000 ] =
4205         BRep_Tool::Pnt( TopoDS::Vertex( S )).XYZ();
4206       break;
4207     }
4208     case TopAbs_EDGE: {
4209
4210       const TopoDS_Edge& edge = TopoDS::Edge( S );
4211       if ( shapeID < ID_Ex00 || shapeID > ID_E11z || edge.IsNull() ) {
4212         MESSAGE(" shapeID =" << shapeID );
4213         return false;
4214       }
4215       TEdge& tEdge = myEdge[ shapeID - ID_Ex00 ];
4216       tEdge.myCoordInd = GetCoordIndOnEdge( shapeID );
4217       TopLoc_Location loc;
4218       tEdge.myC3d = BRep_Tool::Curve( edge, loc, tEdge.myFirst, tEdge.myLast );
4219       if ( !IsForwardEdge( edge, theShapeIDMap ))
4220         Swap( tEdge.myFirst, tEdge.myLast );
4221       tEdge.myTrsf = loc;
4222       break;
4223     }
4224     case TopAbs_FACE: {
4225
4226       const TopoDS_Face& face = TopoDS::Face( S );
4227       if ( shapeID < ID_Fxy0 || shapeID > ID_F1yz || face.IsNull() ) {
4228         MESSAGE(" shapeID =" << shapeID );
4229         return false;
4230       }
4231       TFace& tFace = myFace[ shapeID - ID_Fxy0 ];
4232       // pcurves
4233       vector< int > edgeIdVec(4, -1);
4234       GetFaceEdgesIDs( shapeID, edgeIdVec );
4235       for ( int iE = 0; iE < 4; iE++ ) // loop on 4 edges
4236       {
4237         const TopoDS_Edge& edge = TopoDS::Edge( theShapeIDMap( edgeIdVec[ iE ]));
4238         tFace.myCoordInd[ iE ] = GetCoordIndOnEdge( edgeIdVec[ iE ] );
4239         tFace.myC2d[ iE ] =
4240           BRep_Tool::CurveOnSurface( edge, face, tFace.myFirst[iE], tFace.myLast[iE] );
4241         if ( !IsForwardEdge( edge, theShapeIDMap ))
4242           Swap( tFace.myFirst[ iE ], tFace.myLast[ iE ] );
4243       }
4244       // 2d corners
4245       tFace.myCorner[ 0 ] = tFace.myC2d[ 0 ]->Value( tFace.myFirst[0] ).XY();
4246       tFace.myCorner[ 1 ] = tFace.myC2d[ 0 ]->Value( tFace.myLast[0] ).XY();
4247       tFace.myCorner[ 2 ] = tFace.myC2d[ 1 ]->Value( tFace.myLast[1] ).XY();
4248       tFace.myCorner[ 3 ] = tFace.myC2d[ 1 ]->Value( tFace.myFirst[1] ).XY();
4249       // sufrace
4250       TopLoc_Location loc;
4251       tFace.myS = BRep_Tool::Surface( face, loc );
4252       tFace.myTrsf = loc;
4253       break;
4254     }
4255     default: break;
4256     }
4257   } // loop on shapes in theShapeIDMap
4258
4259   return true;
4260 }
4261
4262 //=======================================================================
4263 //function : GetFaceEdgesIDs
4264 //purpose  : return edges IDs in the order u0, u1, 0v, 1v
4265 //           u0 means "|| u, v == 0"
4266 //=======================================================================
4267
4268 void TBlock::GetFaceEdgesIDs (const int faceID, vector< int >& edgeVec )
4269 {
4270   switch ( faceID ) {
4271   case ID_Fxy0:
4272     edgeVec[ 0 ] = ID_Ex00;
4273     edgeVec[ 1 ] = ID_Ex10;
4274     edgeVec[ 2 ] = ID_E0y0;
4275     edgeVec[ 3 ] = ID_E1y0;
4276     break;
4277   case ID_Fxy1:
4278     edgeVec[ 0 ] = ID_Ex01;
4279     edgeVec[ 1 ] = ID_Ex11;
4280     edgeVec[ 2 ] = ID_E0y1;
4281     edgeVec[ 3 ] = ID_E1y1;
4282     break;
4283   case ID_Fx0z:
4284     edgeVec[ 0 ] = ID_Ex00;
4285     edgeVec[ 1 ] = ID_Ex01;
4286     edgeVec[ 2 ] = ID_E00z;
4287     edgeVec[ 3 ] = ID_E10z;
4288     break;
4289   case ID_Fx1z:
4290     edgeVec[ 0 ] = ID_Ex10;
4291     edgeVec[ 1 ] = ID_Ex11;
4292     edgeVec[ 2 ] = ID_E01z;
4293     edgeVec[ 3 ] = ID_E11z;
4294     break;
4295   case ID_F0yz:
4296     edgeVec[ 0 ] = ID_E0y0;
4297     edgeVec[ 1 ] = ID_E0y1;
4298     edgeVec[ 2 ] = ID_E00z;
4299     edgeVec[ 3 ] = ID_E01z;
4300     break;
4301   case ID_F1yz:
4302     edgeVec[ 0 ] = ID_E1y0;
4303     edgeVec[ 1 ] = ID_E1y1;
4304     edgeVec[ 2 ] = ID_E10z;
4305     edgeVec[ 3 ] = ID_E11z;
4306     break;
4307   default:
4308     MESSAGE(" GetFaceEdgesIDs(), wrong face ID: " << faceID );
4309   }
4310 }