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