Version: 6.3.1

src/SMESH/SMESH_Pattern.cxx

Go to the documentation of this file.
00001 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 // File      : SMESH_Pattern.hxx
00024 // Created   : Mon Aug  2 10:30:00 2004
00025 // Author    : Edward AGAPOV (eap)
00026 //
00027 #include "SMESH_Pattern.hxx"
00028 
00029 #include <BRepAdaptor_Curve.hxx>
00030 #include <BRepTools.hxx>
00031 #include <BRepTools_WireExplorer.hxx>
00032 #include <BRep_Tool.hxx>
00033 #include <Bnd_Box.hxx>
00034 #include <Bnd_Box2d.hxx>
00035 #include <ElSLib.hxx>
00036 #include <Extrema_ExtPC.hxx>
00037 #include <Extrema_GenExtPS.hxx>
00038 #include <Extrema_POnSurf.hxx>
00039 #include <Geom2d_Curve.hxx>
00040 #include <GeomAdaptor_Surface.hxx>
00041 #include <Geom_Curve.hxx>
00042 #include <Geom_Surface.hxx>
00043 #include <Precision.hxx>
00044 #include <TopAbs_ShapeEnum.hxx>
00045 #include <TopExp.hxx>
00046 #include <TopExp_Explorer.hxx>
00047 #include <TopLoc_Location.hxx>
00048 #include <TopTools_ListIteratorOfListOfShape.hxx>
00049 #include <TopoDS.hxx>
00050 #include <TopoDS_Edge.hxx>
00051 #include <TopoDS_Face.hxx>
00052 #include <TopoDS_Iterator.hxx>
00053 #include <TopoDS_Shell.hxx>
00054 #include <TopoDS_Vertex.hxx>
00055 #include <TopoDS_Wire.hxx>
00056 #include <gp_Ax2.hxx>
00057 #include <gp_Lin2d.hxx>
00058 #include <gp_Pnt2d.hxx>
00059 #include <gp_Trsf.hxx>
00060 #include <gp_XY.hxx>
00061 #include <gp_XYZ.hxx>
00062 
00063 #include "SMDS_EdgePosition.hxx"
00064 #include "SMDS_FacePosition.hxx"
00065 #include "SMDS_MeshElement.hxx"
00066 #include "SMDS_MeshFace.hxx"
00067 #include "SMDS_MeshNode.hxx"
00068 #include "SMDS_VolumeTool.hxx"
00069 #include "SMESHDS_Group.hxx"
00070 #include "SMESHDS_Mesh.hxx"
00071 #include "SMESHDS_SubMesh.hxx"
00072 #include "SMESH_Block.hxx"
00073 #include "SMESH_Mesh.hxx"
00074 #include "SMESH_MesherHelper.hxx"
00075 #include "SMESH_subMesh.hxx"
00076 
00077 #include <Basics_Utils.hxx>
00078 #include "utilities.h"
00079 
00080 using namespace std;
00081 
00082 typedef map< const SMDS_MeshElement*, int > TNodePointIDMap;
00083 
00084 #define smdsNode( elem ) static_cast<const SMDS_MeshNode*>( elem )
00085 
00086 //=======================================================================
00087 //function : SMESH_Pattern
00088 //purpose  : 
00089 //=======================================================================
00090 
00091 SMESH_Pattern::SMESH_Pattern ()
00092 {
00093 }
00094 //=======================================================================
00095 //function : getInt
00096 //purpose  : 
00097 //=======================================================================
00098 
00099 static inline int getInt( const char * theSring )
00100 {
00101   if ( *theSring < '0' || *theSring > '9' )
00102     return -1;
00103 
00104   char *ptr;
00105   int val = strtol( theSring, &ptr, 10 );
00106   if ( ptr == theSring ||
00107       // there must not be neither '.' nor ',' nor 'E' ...
00108       (*ptr != ' ' && *ptr != '\n' && *ptr != '\0'))
00109     return -1;
00110 
00111   return val;
00112 }
00113 
00114 //=======================================================================
00115 //function : getDouble
00116 //purpose  : 
00117 //=======================================================================
00118 
00119 static inline double getDouble( const char * theSring )
00120 {
00121   char *ptr;
00122   return strtod( theSring, &ptr );
00123 }
00124 
00125 //=======================================================================
00126 //function : readLine
00127 //purpose  : Put token starting positions in theFields until '\n' or '\0'
00128 //           Return the number of the found tokens
00129 //=======================================================================
00130 
00131 static int readLine (list <const char*> & theFields,
00132                      const char*        & theLineBeg,
00133                      const bool           theClearFields )
00134 {
00135   if ( theClearFields )
00136     theFields.clear();
00137 
00138   //  algo:
00139   /*  loop                                                       */
00140   /*    switch ( symbol ) {                                      */
00141   /*    case white-space:                                        */
00142   /*      look for a non-space symbol;                           */
00143   /*    case string-end:                                         */
00144   /*    case line-end:                                           */
00145   /*      exit;                                                  */
00146   /*    case comment beginning:                                  */
00147   /*      skip all till a line-end;                              */
00148   /*    case a number                                            */
00149   /*      put its position in theFields, skip till a white-space;*/
00150   /*    default:                                                 */
00151   /*      abort;                                                 */
00152   /*  till line-end                                              */
00153 
00154   int nbRead = 0;
00155   bool stopReading = false;
00156   do {
00157     bool goOn = true;
00158     bool isNumber = false;
00159     switch ( *theLineBeg )
00160     {
00161     case ' ':  // white space
00162     case '\t': // tab
00163     case 13:   // ^M
00164       break;
00165 
00166     case '\n': // a line ends
00167       stopReading = ( nbRead > 0 );
00168       break;
00169 
00170     case '!':  // comment
00171       do theLineBeg++;
00172       while ( *theLineBeg != '\n' && *theLineBeg != '\0' );
00173       goOn = false;
00174       break;
00175 
00176     case '\0': // file ends
00177       return nbRead;
00178 
00179     case '-': // real number
00180     case '+':
00181     case '.':
00182       isNumber = true;
00183     default: // data
00184       isNumber = isNumber || ( *theLineBeg >= '0' && *theLineBeg <= '9' );
00185       if ( isNumber ) {
00186         theFields.push_back( theLineBeg );
00187         nbRead++;
00188         do theLineBeg++;
00189         while (*theLineBeg != ' ' &&
00190                *theLineBeg != '\n' &&
00191                *theLineBeg != '\0');
00192         goOn = false;
00193       }
00194       else
00195         return 0; // incorrect file format
00196     }
00197 
00198     if ( goOn )
00199       theLineBeg++;
00200 
00201   } while ( !stopReading );
00202 
00203   return nbRead;
00204 }
00205 
00206 //=======================================================================
00207 //function : Load
00208 //purpose  : Load a pattern from <theFile>
00209 //=======================================================================
00210 
00211 bool SMESH_Pattern::Load (const char* theFileContents)
00212 {
00213   MESSAGE("Load( file ) ");
00214 
00215   Kernel_Utils::Localizer loc;
00216   
00217   // file structure:
00218 
00219   // ! This is a comment
00220   // NB_POINTS               ! 1 integer - the number of points in the pattern.
00221   //   X1 Y1 [Z1]            ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
00222   //   X2 Y2 [Z2]            ! the pattern dimention is defined by the number of coordinates
00223   //   ...
00224   // [ ID1 ID2 ... IDn ]     ! Indices of key-points for a 2D pattern (only).
00225   // ! elements description goes after all
00226   // ID1 ID2 ... IDn         ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
00227   // ...
00228 
00229   Clear();
00230 
00231   const char* lineBeg = theFileContents;
00232   list <const char*> fields;
00233   const bool clearFields = true;
00234 
00235   // NB_POINTS               ! 1 integer - the number of points in the pattern.
00236 
00237   if ( readLine( fields, lineBeg, clearFields ) != 1 ) {
00238     MESSAGE("Error reading NB_POINTS");
00239     return setErrorCode( ERR_READ_NB_POINTS );
00240   }
00241   int nbPoints = getInt( fields.front() );
00242 
00243   //   X1 Y1 [Z1]            ! 2 or 3 reals - nodes coordinates within 2D or 3D domain:
00244 
00245   // read the first point coordinates to define pattern dimention
00246   int dim = readLine( fields, lineBeg, clearFields );
00247   if ( dim == 2 )
00248     myIs2D = true;
00249   else if ( dim == 3 )
00250     myIs2D = false;
00251   else {
00252     MESSAGE("Error reading points: wrong nb of coordinates");
00253     return setErrorCode( ERR_READ_POINT_COORDS );
00254   }
00255   if ( nbPoints <= dim ) {
00256     MESSAGE(" Too few points ");
00257     return setErrorCode( ERR_READ_TOO_FEW_POINTS );
00258   }
00259 
00260   // read the rest points
00261   int iPoint;
00262   for ( iPoint = 1; iPoint < nbPoints; iPoint++ )
00263     if ( readLine( fields, lineBeg, !clearFields ) != dim ) {
00264       MESSAGE("Error reading  points : wrong nb of coordinates ");
00265       return setErrorCode( ERR_READ_POINT_COORDS );
00266     }
00267   // store point coordinates
00268   myPoints.resize( nbPoints );
00269   list <const char*>::iterator fIt = fields.begin();
00270   for ( iPoint = 0; iPoint < nbPoints; iPoint++ )
00271   {
00272     TPoint & p = myPoints[ iPoint ];
00273     for ( int iCoord = 1; iCoord <= dim; iCoord++, fIt++ )
00274     {
00275       double coord = getDouble( *fIt );
00276       if ( !myIs2D && ( coord < 0.0 || coord > 1.0 )) {
00277         MESSAGE("Error reading 3D points, value should be in [0,1]: " << coord);
00278         Clear();
00279         return setErrorCode( ERR_READ_3D_COORD );
00280       }
00281       p.myInitXYZ.SetCoord( iCoord, coord );
00282       if ( myIs2D )
00283         p.myInitUV.SetCoord( iCoord, coord );
00284     }
00285   }
00286 
00287   // [ ID1 ID2 ... IDn ]     ! Indices of key-points for a 2D pattern (only).
00288   if ( myIs2D )
00289   {
00290     if ( readLine( fields, lineBeg, clearFields ) == 0 ) {
00291       MESSAGE("Error: missing key-points");
00292       Clear();
00293       return setErrorCode( ERR_READ_NO_KEYPOINT );
00294     }
00295     set<int> idSet;
00296     for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
00297     {
00298       int pointIndex = getInt( *fIt );
00299       if ( pointIndex >= nbPoints || pointIndex < 0 ) {
00300         MESSAGE("Error: invalid point index " << pointIndex );
00301         Clear();
00302         return setErrorCode( ERR_READ_BAD_INDEX );
00303       }
00304       if ( idSet.insert( pointIndex ).second ) // unique?
00305         myKeyPointIDs.push_back( pointIndex );
00306     }
00307   }
00308 
00309   // ID1 ID2 ... IDn         ! 2-4 or 4-8 integers - nodal connectivity of a 2D or 3D element.
00310 
00311   while ( readLine( fields, lineBeg, clearFields ))
00312   {
00313     myElemPointIDs.push_back( TElemDef() );
00314     TElemDef& elemPoints = myElemPointIDs.back();
00315     for ( fIt = fields.begin(); fIt != fields.end(); fIt++ )
00316     {
00317       int pointIndex = getInt( *fIt );
00318       if ( pointIndex >= nbPoints || pointIndex < 0 ) {
00319         MESSAGE("Error: invalid point index " << pointIndex );
00320         Clear();
00321         return setErrorCode( ERR_READ_BAD_INDEX );
00322       }
00323       elemPoints.push_back( pointIndex );
00324     }
00325     // check the nb of nodes in element
00326     bool Ok = true;
00327     switch ( elemPoints.size() ) {
00328     case 3: if ( !myIs2D ) Ok = false; break;
00329     case 4: break;
00330     case 5:
00331     case 6:
00332     case 8: if ( myIs2D ) Ok = false; break;
00333     default: Ok = false;
00334     }
00335     if ( !Ok ) {
00336       MESSAGE("Error: wrong nb of nodes in element " << elemPoints.size() );
00337       Clear();
00338       return setErrorCode( ERR_READ_ELEM_POINTS );
00339     }
00340   }
00341   if ( myElemPointIDs.empty() ) {
00342     MESSAGE("Error: no elements");
00343     Clear();
00344     return setErrorCode( ERR_READ_NO_ELEMS );
00345   }
00346 
00347   findBoundaryPoints(); // sort key-points
00348 
00349   return setErrorCode( ERR_OK );
00350 }
00351 
00352 //=======================================================================
00353 //function : Save
00354 //purpose  : Save the loaded pattern into the file <theFileName>
00355 //=======================================================================
00356 
00357 bool SMESH_Pattern::Save (ostream& theFile)
00358 {
00359   MESSAGE(" ::Save(file) " );
00360   
00361   Kernel_Utils::Localizer loc;
00362     
00363   if ( !IsLoaded() ) {
00364     MESSAGE(" Pattern not loaded ");
00365     return setErrorCode( ERR_SAVE_NOT_LOADED );
00366   }
00367 
00368   theFile << "!!! SALOME Mesh Pattern file" << endl;
00369   theFile << "!!!" << endl;
00370   theFile << "!!! Nb of points:" << endl;
00371   theFile << myPoints.size() << endl;
00372 
00373   // point coordinates
00374   const int width = 8;
00375 //  theFile.width( 8 );
00376 //  theFile.setf(ios::fixed);// use 123.45 floating notation
00377 //  theFile.setf(ios::right);
00378 //  theFile.flags( theFile.flags() & ~ios::showpoint); // do not show trailing zeros
00379 //   theFile.setf(ios::showpoint); // do not show trailing zeros
00380   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
00381   for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
00382     const gp_XYZ & xyz = (*pVecIt).myInitXYZ;
00383     theFile << " " << setw( width ) << xyz.X() << " " << setw( width ) << xyz.Y();
00384     if ( !myIs2D ) theFile  << " " << setw( width ) << xyz.Z();
00385     theFile  << "  !- " << i << endl; // point id to ease reading by a human being
00386   }
00387   // key-points
00388   if ( myIs2D ) {
00389     theFile << "!!! Indices of " << myKeyPointIDs.size() << " key-points:" << endl;
00390     list< int >::const_iterator kpIt = myKeyPointIDs.begin();
00391     for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
00392       theFile << " " << *kpIt;
00393     if ( !myKeyPointIDs.empty() )
00394       theFile << endl;
00395   }
00396   // elements
00397   theFile << "!!! Indices of points of " << myElemPointIDs.size() << " elements:" << endl;
00398   list<TElemDef >::const_iterator epIt = myElemPointIDs.begin();
00399   for ( ; epIt != myElemPointIDs.end(); epIt++ )
00400   {
00401     const TElemDef & elemPoints = *epIt;
00402     TElemDef::const_iterator iIt = elemPoints.begin();
00403     for ( ; iIt != elemPoints.end(); iIt++ )
00404       theFile << " " << *iIt;
00405     theFile << endl;
00406   }
00407 
00408   theFile << endl;
00409 
00410   return setErrorCode( ERR_OK );
00411 }
00412 
00413 //=======================================================================
00414 //function : sortBySize
00415 //purpose  : sort theListOfList by size
00416 //=======================================================================
00417 
00418 template<typename T> struct TSizeCmp {
00419   bool operator ()( const list < T > & l1, const list < T > & l2 )
00420     const { return l1.size() < l2.size(); }
00421 };
00422 
00423 template<typename T> void sortBySize( list< list < T > > & theListOfList )
00424 {
00425   if ( theListOfList.size() > 2 ) {
00426     TSizeCmp< T > SizeCmp;
00427     theListOfList.sort( SizeCmp );
00428   }
00429 }
00430 
00431 //=======================================================================
00432 //function : project
00433 //purpose  : 
00434 //=======================================================================
00435 
00436 static gp_XY project (const SMDS_MeshNode* theNode,
00437                       Extrema_GenExtPS &   theProjectorPS)
00438 {
00439   gp_Pnt P( theNode->X(), theNode->Y(), theNode->Z() );
00440   theProjectorPS.Perform( P );
00441   if ( !theProjectorPS.IsDone() ) {
00442     MESSAGE( "SMESH_Pattern: point projection FAILED");
00443     return gp_XY(0.,0.);
00444   }
00445   double u, v, minVal = DBL_MAX;
00446   for ( int i = theProjectorPS.NbExt(); i > 0; i-- )
00447     if ( theProjectorPS.Value( i ) < minVal ) {
00448       minVal = theProjectorPS.Value( i );
00449       theProjectorPS.Point( i ).Parameter( u, v );
00450     }
00451   return gp_XY( u, v );
00452 }
00453 
00454 //=======================================================================
00455 //function : areNodesBound
00456 //purpose  : true if all nodes of faces are bound to shapes
00457 //=======================================================================
00458 
00459 template <class TFaceIterator> bool areNodesBound( TFaceIterator & faceItr )
00460 {
00461   while ( faceItr->more() )
00462   {
00463     SMDS_ElemIteratorPtr nIt = faceItr->next()->nodesIterator();
00464     while ( nIt->more() )
00465     {
00466       const SMDS_MeshNode* node = smdsNode( nIt->next() );
00467       if (node->getshapeId() <1) {
00468         return false;
00469       }
00470     }
00471   }
00472   return true;
00473 }
00474 
00475 //=======================================================================
00476 //function : isMeshBoundToShape
00477 //purpose  : return true if all 2d elements are bound to shape
00478 //           if aFaceSubmesh != NULL, then check faces bound to it
00479 //           else check all faces in aMeshDS
00480 //=======================================================================
00481 
00482 static bool isMeshBoundToShape(SMESHDS_Mesh *     aMeshDS,
00483                                SMESHDS_SubMesh *  aFaceSubmesh,
00484                                const bool         isMainShape)
00485 {
00486   if ( isMainShape ) {
00487     // check that all faces are bound to aFaceSubmesh
00488     if ( aMeshDS->NbFaces() != aFaceSubmesh->NbElements() )
00489       return false;
00490   }
00491 
00492   // check face nodes binding
00493   if ( aFaceSubmesh ) {
00494     SMDS_ElemIteratorPtr fIt = aFaceSubmesh->GetElements();
00495     return areNodesBound( fIt );
00496   }
00497   SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
00498   return areNodesBound( fIt );
00499 }
00500 
00501 //=======================================================================
00502 //function : Load
00503 //purpose  : Create a pattern from the mesh built on <theFace>.
00504 //           <theProject>==true makes override nodes positions
00505 //           on <theFace> computed by mesher
00506 //=======================================================================
00507 
00508 bool SMESH_Pattern::Load (SMESH_Mesh*        theMesh,
00509                           const TopoDS_Face& theFace,
00510                           bool               theProject)
00511 {
00512   MESSAGE(" ::Load(face) " );
00513   Clear();
00514   myIs2D = true;
00515 
00516   SMESHDS_Mesh * aMeshDS = theMesh->GetMeshDS();
00517   SMESHDS_SubMesh * fSubMesh = aMeshDS->MeshElements( theFace );
00518   const bool isQuadMesh = aMeshDS->GetMeshInfo().NbFaces( ORDER_QUADRATIC );
00519   SMESH_MesherHelper helper( *theMesh );
00520   helper.SetSubShape( theFace );
00521 
00522   int nbNodes = ( !fSubMesh ? 0 : fSubMesh->NbNodes() );
00523   int nbElems = ( !fSubMesh ? 0 : fSubMesh->NbElements() );
00524   if ( nbElems == 0 && aMeshDS->NbFaces() == 0 )
00525   {
00526     MESSAGE( "No elements bound to the face");
00527     return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
00528   }
00529 
00530   TopoDS_Face face = TopoDS::Face( theFace.Oriented( TopAbs_FORWARD ));
00531 
00532   // check if face is closed
00533   bool isClosed = helper.HasSeam();
00534   TopoDS_Vertex bidon;
00535   list<TopoDS_Edge> eList;
00536   list<TopoDS_Edge>::iterator elIt;
00537   SMESH_Block::GetOrderedEdges( face, bidon, eList, myNbKeyPntInBoundary );
00538 
00539   // check that requested or needed projection is possible
00540   bool isMainShape = theMesh->IsMainShape( face );
00541   bool needProject = !isMeshBoundToShape( aMeshDS, fSubMesh, isMainShape );
00542   bool canProject  = ( nbElems ? true : isMainShape );
00543   if ( isClosed )
00544     canProject = false; // so far
00545 
00546   if ( ( theProject || needProject ) && !canProject )
00547     return setErrorCode( ERR_LOADF_CANT_PROJECT );
00548 
00549   Extrema_GenExtPS projector;
00550   GeomAdaptor_Surface aSurface( BRep_Tool::Surface( face ));
00551   if ( theProject || needProject )
00552     projector.Initialize( aSurface, 20,20, 1e-5,1e-5 );
00553 
00554   int iPoint = 0;
00555   TNodePointIDMap nodePointIDMap;
00556   TNodePointIDMap closeNodePointIDMap; // for nodes on seam edges
00557 
00558   if ( needProject )
00559   {
00560     MESSAGE("Project the submesh");
00561     // ---------------------------------------------------------------
00562     // The case where the submesh is projected to theFace
00563     // ---------------------------------------------------------------
00564 
00565     // get all faces
00566     list< const SMDS_MeshElement* > faces;
00567     if ( nbElems > 0 ) {
00568       SMDS_ElemIteratorPtr fIt = fSubMesh->GetElements();
00569       while ( fIt->more() ) {
00570         const SMDS_MeshElement* f = fIt->next();
00571         if ( f && f->GetType() == SMDSAbs_Face )
00572           faces.push_back( f );
00573       }
00574     }
00575     else {
00576       SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator();
00577       while ( fIt->more() )
00578         faces.push_back( fIt->next() );
00579     }
00580 
00581     // put nodes of all faces into the nodePointIDMap and fill myElemPointIDs
00582     list< const SMDS_MeshElement* >::iterator fIt = faces.begin();
00583     for ( ; fIt != faces.end(); ++fIt )
00584     {
00585       myElemPointIDs.push_back( TElemDef() );
00586       TElemDef& elemPoints = myElemPointIDs.back();
00587       int nbNodes = (*fIt)->NbCornerNodes();
00588       for ( int i = 0;i < nbNodes; ++i )
00589       {
00590         const SMDS_MeshElement* node = (*fIt)->GetNode( i );
00591         TNodePointIDMap::iterator nIdIt = nodePointIDMap.insert( make_pair( node, -1 )).first;
00592         if ( nIdIt->second == -1 )
00593         {
00594           elemPoints.push_back( iPoint );
00595           nIdIt->second = iPoint++;
00596         }
00597         else
00598           elemPoints.push_back( (*nIdIt).second );
00599       }
00600     }
00601     myPoints.resize( iPoint );
00602 
00603     // project all nodes of 2d elements to theFace
00604     TNodePointIDMap::iterator nIdIt = nodePointIDMap.begin();
00605     for ( ; nIdIt != nodePointIDMap.end(); nIdIt++ )
00606     {
00607       const SMDS_MeshNode* node = smdsNode( (*nIdIt).first );
00608       TPoint * p = & myPoints[ (*nIdIt).second ];
00609       p->myInitUV = project( node, projector );
00610       p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
00611     }
00612     // find key-points: the points most close to UV of vertices
00613     TopExp_Explorer vExp( face, TopAbs_VERTEX );
00614     set<int> foundIndices;
00615     for ( ; vExp.More(); vExp.Next() ) {
00616       const TopoDS_Vertex v = TopoDS::Vertex( vExp.Current() );
00617       gp_Pnt2d uv = BRep_Tool::Parameters( v, face );
00618       double minDist = DBL_MAX;
00619       int index;
00620       vector< TPoint >::const_iterator pVecIt = myPoints.begin();
00621       for ( iPoint = 0; pVecIt != myPoints.end(); pVecIt++, iPoint++ ) {
00622         double dist = uv.SquareDistance( (*pVecIt).myInitUV );
00623         if ( dist < minDist ) {
00624           minDist = dist;
00625           index = iPoint;
00626         }
00627       }
00628       if ( foundIndices.insert( index ).second ) // unique?
00629         myKeyPointIDs.push_back( index );
00630     }
00631     myIsBoundaryPointsFound = false;
00632 
00633   }
00634   else
00635   {
00636     // ---------------------------------------------------------------------
00637     // The case where a pattern is being made from the mesh built by mesher
00638     // ---------------------------------------------------------------------
00639 
00640     // Load shapes in the consequent order and count nb of points
00641 
00642     // vertices
00643     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ ) {
00644       int nbV = myShapeIDMap.Extent();
00645       myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
00646       bool added = ( nbV < myShapeIDMap.Extent() );
00647       if ( !added ) { // vertex encountered twice
00648         // a seam vertex have two corresponding key points
00649         myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ).Reversed());
00650         ++nbNodes;
00651       }
00652       if ( SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( *elIt ))
00653         nbNodes += eSubMesh->NbNodes() + 1;
00654     }
00655     // edges
00656     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
00657       myShapeIDMap.Add( *elIt );
00658     // the face
00659     myShapeIDMap.Add( face );
00660 
00661     myPoints.resize( nbNodes );
00662 
00663     // Load U of points on edges
00664 
00665     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
00666     {
00667       TopoDS_Edge & edge = *elIt;
00668       list< TPoint* > & ePoints = getShapePoints( edge );
00669       double f, l;
00670       Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( edge, face, f, l );
00671       bool isForward = ( edge.Orientation() == TopAbs_FORWARD );
00672 
00673       TopoDS_Shape v1 = TopExp::FirstVertex( edge, true ); // always FORWARD
00674       TopoDS_Shape v2 = TopExp::LastVertex( edge, true ); // always REVERSED
00675       // to make adjacent edges share key-point, we make v2 FORWARD too
00676       // (as we have different points for same shape with different orienation)
00677       v2.Reverse();
00678 
00679       // on closed face we must have REVERSED some of seam vertices
00680       if ( isClosed ) {
00681         if ( helper.IsSeamShape( edge ) ) {
00682           if ( helper.IsRealSeam( edge ) && !isForward ) {
00683             // reverse on reversed SEAM edge
00684             v1.Reverse();
00685             v2.Reverse();
00686           }
00687         }
00688         else { // on CLOSED edge (i.e. having one vertex with different orienations)
00689           for ( int is2 = 0; is2 < 2; ++is2 ) {
00690             TopoDS_Shape & v = is2 ? v2 : v1;
00691             if ( helper.IsRealSeam( v ) ) {
00692               // reverse or not depending on orientation of adjacent seam
00693               TopoDS_Edge seam;
00694               list<TopoDS_Edge>::iterator eIt2 = elIt;
00695               if ( is2 )
00696                 seam = ( ++eIt2 == eList.end() ? eList.front() : *eIt2 );
00697               else
00698                 seam = ( eIt2 == eList.begin() ? eList.back() : *(--eIt2) );
00699               if ( seam.Orientation() == TopAbs_REVERSED )
00700                 v.Reverse();
00701             }
00702           }
00703         }
00704       }
00705 
00706       // the forward key-point
00707       list< TPoint* > * vPoint = & getShapePoints( v1 );
00708       if ( vPoint->empty() )
00709       {
00710         SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v1 );
00711         if ( vSubMesh && vSubMesh->NbNodes() ) {
00712           myKeyPointIDs.push_back( iPoint );
00713           SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
00714           const SMDS_MeshNode* node = nIt->next();
00715           if ( v1.Orientation() == TopAbs_REVERSED )
00716             closeNodePointIDMap.insert( make_pair( node, iPoint ));
00717           else
00718             nodePointIDMap.insert( make_pair( node, iPoint ));
00719 
00720           TPoint* keyPoint = &myPoints[ iPoint++ ];
00721           vPoint->push_back( keyPoint );
00722           if ( theProject )
00723             keyPoint->myInitUV = project( node, projector );
00724           else
00725             keyPoint->myInitUV = C2d->Value( isForward ? f : l ).XY();
00726           keyPoint->myInitXYZ.SetCoord (keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0);
00727         }
00728       }
00729       if ( !vPoint->empty() )
00730         ePoints.push_back( vPoint->front() );
00731 
00732       // on-edge points
00733       SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edge );
00734       if ( eSubMesh && eSubMesh->NbNodes() )
00735       {
00736         // loop on nodes of an edge: sort them by param on edge
00737         typedef map < double, const SMDS_MeshNode* > TParamNodeMap;
00738         TParamNodeMap paramNodeMap;
00739         int nbMeduimNodes = 0;
00740         SMDS_NodeIteratorPtr nIt = eSubMesh->GetNodes();
00741         while ( nIt->more() )
00742         {
00743           const SMDS_MeshNode* node = nIt->next();
00744           if ( isQuadMesh && helper.IsMedium( node, SMDSAbs_Face )) {
00745             ++nbMeduimNodes;
00746             continue;
00747           }
00748           const SMDS_EdgePosition* epos =
00749             static_cast<const SMDS_EdgePosition*>(node->GetPosition());
00750           double u = epos->GetUParameter();
00751           paramNodeMap.insert( make_pair( u, node ));
00752         }
00753         if ( paramNodeMap.size() != eSubMesh->NbNodes() ) {
00754           // wrong U on edge, project
00755           Extrema_ExtPC proj;
00756           BRepAdaptor_Curve aCurve( edge );
00757           proj.Initialize( aCurve, f, l );
00758           paramNodeMap.clear();
00759           nIt = eSubMesh->GetNodes();
00760           for ( int iNode = 0; nIt->more(); ++iNode ) {
00761             const SMDS_MeshNode* node = nIt->next();
00762             if ( isQuadMesh && helper.IsMedium( node, SMDSAbs_Face ))
00763               continue;
00764             proj.Perform( gp_Pnt( node->X(), node->Y(), node->Z()));
00765             double u = 0;
00766             if ( proj.IsDone() ) {
00767               for ( int i = 1, nb = proj.NbExt(); i <= nb; ++i )
00768                 if ( proj.IsMin( i )) {
00769                   u = proj.Point( i ).Parameter();
00770                   break;
00771                 }
00772             } else {
00773               u = isForward ? iNode : eSubMesh->NbNodes() - iNode;
00774             }
00775             paramNodeMap.insert( make_pair( u, node ));
00776           }
00777 
00778           //rnv : To fix the bug IPAL21999 Pattern Mapping - New - collapse of pattern mesh
00779           if ( paramNodeMap.size() != eSubMesh->NbNodes() - nbMeduimNodes )
00780             return setErrorCode(ERR_UNEXPECTED);
00781         }
00782 
00783         // put U in [0,1] so that the first key-point has U==0
00784         bool isSeam = helper.IsRealSeam( edge );
00785         double du = l - f;
00786         TParamNodeMap::iterator         unIt  = paramNodeMap.begin();
00787         TParamNodeMap::reverse_iterator unRIt = paramNodeMap.rbegin();
00788         while ( unIt != paramNodeMap.end() )
00789         {
00790           TPoint* p = & myPoints[ iPoint ];
00791           ePoints.push_back( p );
00792           const SMDS_MeshNode* node = isForward ? (*unIt).second : (*unRIt).second;
00793           if ( isSeam && !isForward )
00794             closeNodePointIDMap.insert( make_pair( node, iPoint ));
00795           else
00796             nodePointIDMap.insert ( make_pair( node, iPoint ));
00797 
00798           if ( theProject )
00799             p->myInitUV = project( node, projector );
00800           else {
00801             double u = isForward ? (*unIt).first : (*unRIt).first;
00802             p->myInitU = isForward ? (( u - f ) / du ) : ( 1.0 - ( u - f ) / du );
00803             p->myInitUV = C2d->Value( u ).XY();
00804           }
00805           p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
00806           unIt++; unRIt++;
00807           iPoint++;
00808         }
00809       }
00810       // the reverse key-point
00811       vPoint = & getShapePoints( v2 );
00812       if ( vPoint->empty() )
00813       {
00814         SMESHDS_SubMesh * vSubMesh = aMeshDS->MeshElements( v2 );
00815         if ( vSubMesh && vSubMesh->NbNodes() ) {
00816           myKeyPointIDs.push_back( iPoint );
00817           SMDS_NodeIteratorPtr nIt = vSubMesh->GetNodes();
00818           const SMDS_MeshNode* node = nIt->next();
00819           if ( v2.Orientation() == TopAbs_REVERSED )
00820             closeNodePointIDMap.insert( make_pair( node, iPoint ));
00821           else
00822             nodePointIDMap.insert( make_pair( node, iPoint ));
00823 
00824           TPoint* keyPoint = &myPoints[ iPoint++ ];
00825           vPoint->push_back( keyPoint );
00826           if ( theProject )
00827             keyPoint->myInitUV = project( node, projector );
00828           else
00829             keyPoint->myInitUV = C2d->Value( isForward ? l : f ).XY();
00830           keyPoint->myInitXYZ.SetCoord( keyPoint->myInitUV.X(), keyPoint->myInitUV.Y(), 0 );
00831         }
00832       }
00833       if ( !vPoint->empty() )
00834         ePoints.push_back( vPoint->front() );
00835 
00836       // compute U of edge-points
00837       if ( theProject )
00838       {
00839         double totalDist = 0;
00840         list< TPoint* >::iterator pIt = ePoints.begin();
00841         TPoint* prevP = *pIt;
00842         prevP->myInitU = totalDist;
00843         for ( pIt++; pIt != ePoints.end(); pIt++ ) {
00844           TPoint* p = *pIt;
00845           totalDist += ( p->myInitUV - prevP->myInitUV ).Modulus();
00846           p->myInitU = totalDist;
00847           prevP = p;
00848         }
00849         if ( totalDist > DBL_MIN)
00850           for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
00851             TPoint* p = *pIt;
00852             p->myInitU /= totalDist;
00853           }
00854       }
00855     } // loop on edges of a wire
00856 
00857     // Load in-face points and elements
00858 
00859     if ( fSubMesh && fSubMesh->NbElements() )
00860     {
00861       list< TPoint* > & fPoints = getShapePoints( face );
00862       SMDS_NodeIteratorPtr nIt = fSubMesh->GetNodes();
00863       while ( nIt->more() )
00864       {
00865         const SMDS_MeshNode* node = nIt->next();
00866         if ( isQuadMesh && helper.IsMedium( node, SMDSAbs_Face ))
00867           continue;
00868         nodePointIDMap.insert( make_pair( node, iPoint ));
00869         TPoint* p = &myPoints[ iPoint++ ];
00870         fPoints.push_back( p );
00871         if ( theProject )
00872           p->myInitUV = project( node, projector );
00873         else {
00874           const SMDS_FacePosition* pos =
00875             static_cast<const SMDS_FacePosition*>(node->GetPosition());
00876           p->myInitUV.SetCoord( pos->GetUParameter(), pos->GetVParameter() );
00877         }
00878         p->myInitXYZ.SetCoord( p->myInitUV.X(), p->myInitUV.Y(), 0 );
00879       }
00880       // load elements
00881       TNodePointIDMap::iterator n_id, not_found = closeNodePointIDMap.end();
00882       SMDS_ElemIteratorPtr elemIt = fSubMesh->GetElements();
00883       while ( elemIt->more() )
00884       {
00885         const SMDS_MeshElement* elem = elemIt->next();
00886         SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
00887         myElemPointIDs.push_back( TElemDef() );
00888         TElemDef& elemPoints = myElemPointIDs.back();
00889         // find point indices corresponding to element nodes
00890         while ( nIt->more() )
00891         {
00892           const SMDS_MeshNode* node = smdsNode( nIt->next() );
00893           n_id = nodePointIDMap.find( node );
00894           if ( n_id == nodePointIDMap.end() )
00895             continue; // medium node
00896           iPoint = n_id->second; // point index of interest
00897           // for a node on a seam edge there are two points
00898           if ( helper.IsRealSeam( node->getshapeId() ) &&
00899                ( n_id = closeNodePointIDMap.find( node )) != not_found )
00900           {
00901             TPoint & p1 = myPoints[ iPoint ];
00902             TPoint & p2 = myPoints[ n_id->second ];
00903             // Select point closest to the rest nodes of element in UV space
00904             SMDS_ElemIteratorPtr nIt2 = elem->nodesIterator();
00905             const SMDS_MeshNode* notSeamNode = 0;
00906             // find node not on a seam edge
00907             while ( nIt2->more() && !notSeamNode ) {
00908               const SMDS_MeshNode* n = smdsNode( nIt2->next() );
00909               if ( !helper.IsSeamShape( n->getshapeId() ))
00910                 notSeamNode = n;
00911             }
00912             gp_Pnt2d uv = helper.GetNodeUV( theFace, node, notSeamNode );
00913             double dist1 = uv.SquareDistance( p1.myInitUV );
00914             double dist2 = uv.SquareDistance( p2.myInitUV );
00915             if ( dist2 < dist1 )
00916               iPoint = n_id->second;
00917           }
00918           elemPoints.push_back( iPoint );
00919         }
00920       }
00921     }
00922     myPoints.resize( nodePointIDMap.size() + closeNodePointIDMap.size() );
00923 
00924     myIsBoundaryPointsFound = true;
00925   }
00926 
00927   // Assure that U range is proportional to V range
00928 
00929   Bnd_Box2d bndBox;
00930   vector< TPoint >::iterator pVecIt = myPoints.begin();
00931   for ( ; pVecIt != myPoints.end(); pVecIt++ )
00932     bndBox.Add( gp_Pnt2d( (*pVecIt).myInitUV ));
00933   double minU, minV, maxU, maxV;
00934   bndBox.Get( minU, minV, maxU, maxV );
00935   double dU = maxU - minU, dV = maxV - minV;
00936   if ( dU <= DBL_MIN || dV <= DBL_MIN ) {
00937     Clear();
00938     bndBox.SetVoid();
00939     // define where is the problem, in the face or in the mesh
00940     TopExp_Explorer vExp( face, TopAbs_VERTEX );
00941     for ( ; vExp.More(); vExp.Next() ) {
00942       gp_Pnt2d uv = BRep_Tool::Parameters( TopoDS::Vertex( vExp.Current() ), face );
00943       bndBox.Add( uv );
00944     }
00945     bndBox.Get( minU, minV, maxU, maxV );
00946     dU = maxU - minU, dV = maxV - minV;
00947     if ( dU <= DBL_MIN || dV <= DBL_MIN )
00948       // face problem
00949       return setErrorCode( ERR_LOADF_NARROW_FACE );
00950     else
00951       // mesh is projected onto a line, e.g.
00952       return setErrorCode( ERR_LOADF_CANT_PROJECT );
00953   }
00954   double ratio = dU / dV, maxratio = 3, scale;
00955   int iCoord = 0;
00956   if ( ratio > maxratio ) {
00957     scale = ratio / maxratio;
00958     iCoord = 2;
00959   }
00960   else if ( ratio < 1./maxratio ) {
00961     scale = maxratio / ratio;
00962     iCoord = 1;
00963   }
00964   if ( iCoord ) {
00965     SCRUTE( scale );
00966     for ( pVecIt = myPoints.begin(); pVecIt != myPoints.end(); pVecIt++ ) {
00967       TPoint & p = *pVecIt;
00968       p.myInitUV.SetCoord( iCoord, p.myInitUV.Coord( iCoord ) * scale );
00969       p.myInitXYZ.SetCoord( p.myInitUV.X(), p.myInitUV.Y(), 0 );
00970     }
00971   }
00972   if ( myElemPointIDs.empty() ) {
00973     MESSAGE( "No elements bound to the face");
00974     return setErrorCode( ERR_LOAD_EMPTY_SUBMESH );
00975   }
00976 
00977   return setErrorCode( ERR_OK );
00978 }
00979 
00980 //=======================================================================
00981 //function : computeUVOnEdge
00982 //purpose  : compute coordinates of points on theEdge
00983 //=======================================================================
00984 
00985 void SMESH_Pattern::computeUVOnEdge (const TopoDS_Edge&      theEdge,
00986                                      const list< TPoint* > & ePoints )
00987 {
00988   bool isForward = ( theEdge.Orientation() == TopAbs_FORWARD );
00989   double f, l;
00990   Handle(Geom2d_Curve) C2d =
00991     BRep_Tool::CurveOnSurface( theEdge, TopoDS::Face( myShape ), f, l );
00992 
00993   ePoints.back()->myInitU = 1.0;
00994   list< TPoint* >::const_iterator pIt = ePoints.begin();
00995   for ( pIt++; pIt != ePoints.end(); pIt++ )
00996   {
00997     TPoint* point = *pIt;
00998     // U
00999     double du = ( isForward ? point->myInitU : 1 - point->myInitU );
01000     point->myU = ( f * ( 1 - du ) + l * du );
01001     // UV
01002     point->myUV = C2d->Value( point->myU ).XY();
01003   }
01004 }
01005 
01006 //=======================================================================
01007 //function : intersectIsolines
01008 //purpose  : 
01009 //=======================================================================
01010 
01011 static bool intersectIsolines(const gp_XY& uv11, const gp_XY& uv12, const double r1,
01012                               const gp_XY& uv21, const gp_XY& uv22, const double r2,
01013                               gp_XY& resUV,
01014                               bool& isDeformed)
01015 {
01016   gp_XY loc1 = uv11 * ( 1 - r1 ) + uv12 * r1;
01017   gp_XY loc2 = uv21 * ( 1 - r2 ) + uv22 * r2;
01018   resUV = 0.5 * ( loc1 + loc2 );
01019   //isDeformed = ( loc1 - loc2 ).SquareModulus() > 1e-8;
01020   // SKL 26.07.2007 for NPAL16567
01021   double d1 = (uv11-uv12).Modulus();
01022   double d2 = (uv21-uv22).Modulus();
01023   // double delta = d1*d2*1e-6; PAL17233
01024   double delta = min( d1, d2 ) / 10.;
01025   isDeformed = ( loc1 - loc2 ).SquareModulus() > delta * delta;
01026 
01027 //   double len1 = ( uv11 - uv12 ).Modulus();
01028 //   double len2 = ( uv21 - uv22 ).Modulus();
01029 //   resUV = loc1 * len2 / ( len1 + len2 ) + loc2 * len1 / ( len1 + len2 );
01030 //  return true;
01031 
01032 
01033 //   gp_Lin2d line1( uv11, uv12 - uv11 );
01034 //   gp_Lin2d line2( uv21, uv22 - uv21 );
01035 //   double angle = Abs( line1.Angle( line2 ) );
01036 
01037 //     IntAna2d_AnaIntersection inter;
01038 //     inter.Perform( line1.Normal( loc1 ), line2.Normal( loc2 ) );
01039 //     if ( inter.IsDone() && inter.NbPoints() == 1 )
01040 //     {
01041 //       gp_Pnt2d interUV = inter.Point(1).Value();
01042 //       resUV += interUV.XY();
01043 //   inter.Perform( line1, line2 );
01044 //   interUV = inter.Point(1).Value();
01045 //   resUV += interUV.XY();
01046 
01047 //   resUV /= 2.;
01048 //     }
01049   if ( isDeformed ) {
01050     MESSAGE("intersectIsolines(), d1 = " << d1 << ", d2 = " << d2 << ", delta = " << delta <<
01051             ", " << (loc1 - loc2).SquareModulus() << " > " << delta * delta);
01052   }
01053   return true;
01054 }
01055 
01056 //=======================================================================
01057 //function : compUVByIsoIntersection
01058 //purpose  : 
01059 //=======================================================================
01060 
01061 bool SMESH_Pattern::compUVByIsoIntersection (const list< list< TPoint* > >& theBndPoints,
01062                                              const gp_XY&                   theInitUV,
01063                                              gp_XY&                         theUV,
01064                                              bool &                         theIsDeformed )
01065 {
01066   // compute UV by intersection of 2 iso lines
01067   //gp_Lin2d isoLine[2];
01068   gp_XY uv1[2], uv2[2];
01069   double ratio[2];
01070   const double zero = DBL_MIN;
01071   for ( int iIso = 0; iIso < 2; iIso++ )
01072   {
01073     // to build an iso line:
01074     // find 2 pairs of consequent edge-points such that the range of their
01075     // initial parameters encloses the in-face point initial parameter
01076     gp_XY UV[2], initUV[2];
01077     int nbUV = 0, iCoord = iIso + 1;
01078     double initParam = theInitUV.Coord( iCoord );
01079 
01080     list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
01081     for ( ; bndIt != theBndPoints.end(); bndIt++ )
01082     {
01083       const list< TPoint* > & bndPoints = * bndIt;
01084       TPoint* prevP = bndPoints.back(); // this is the first point
01085       list< TPoint* >::const_iterator pIt = bndPoints.begin();
01086       bool coincPrev = false;
01087       // loop on the edge-points
01088       for ( ; pIt != bndPoints.end(); pIt++ )
01089       {
01090         double paramDiff     = initParam - (*pIt)->myInitUV.Coord( iCoord );
01091         double prevParamDiff = initParam - prevP->myInitUV.Coord( iCoord );
01092         double sumOfDiff = Abs(prevParamDiff) + Abs(paramDiff);
01093         if (!coincPrev && // ignore if initParam coincides with prev point param
01094             sumOfDiff > zero && // ignore if both points coincide with initParam
01095             prevParamDiff * paramDiff <= zero )
01096         {
01097           // find UV in parametric space of theFace
01098           double r = Abs(prevParamDiff) / sumOfDiff;
01099           gp_XY uvInit = (*pIt)->myInitUV * r + prevP->myInitUV * ( 1 - r );
01100           int i = nbUV++;
01101           if ( i >= 2 ) {
01102             // throw away uv most distant from <theInitUV>
01103             gp_XY vec0 = initUV[0] - theInitUV;
01104             gp_XY vec1 = initUV[1] - theInitUV;
01105             gp_XY vec  = uvInit    - theInitUV;
01106             bool isBetween = ( vec0 * vec1 < 0 ); // is theInitUV between initUV[0] and initUV[1]
01107             double dist0 = vec0.SquareModulus();
01108             double dist1 = vec1.SquareModulus();
01109             double dist  = vec .SquareModulus();
01110             if ( !isBetween || dist < dist0 || dist < dist1 ) {
01111               i = ( dist0 < dist1 ? 1 : 0 );
01112               if ( isBetween && vec.Dot( i ? vec1 : vec0 ) < 0 )
01113                 i = 3; // theInitUV must remain between
01114             }
01115           }
01116           if ( i < 2 ) {
01117             initUV[ i ] = uvInit;
01118             UV[ i ]     = (*pIt)->myUV * r + prevP->myUV * ( 1 - r );
01119           }
01120           coincPrev = ( Abs(paramDiff) <= zero );
01121         }
01122         else
01123           coincPrev = false;
01124         prevP = *pIt;
01125       }
01126     }
01127     if ( nbUV < 2 || (UV[0]-UV[1]).SquareModulus() <= DBL_MIN*DBL_MIN ) {
01128       MESSAGE(" consequent edge-points not found, nb UV found: " << nbUV <<
01129               ", for point: " << theInitUV.X() <<" " << theInitUV.Y() );
01130       return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
01131     }
01132     // an iso line should be normal to UV[0] - UV[1] direction
01133     // and be located at the same relative distance as from initial ends
01134     //gp_Lin2d iso( UV[0], UV[0] - UV[1] );
01135     double r =
01136       (initUV[0]-theInitUV).Modulus() / (initUV[0]-initUV[1]).Modulus();
01137     //gp_Pnt2d isoLoc = UV[0] * ( 1 - r ) + UV[1] * r;
01138     //isoLine[ iIso ] = iso.Normal( isoLoc );
01139     uv1[ iIso ] = UV[0];
01140     uv2[ iIso ] = UV[1];
01141     ratio[ iIso ] = r;
01142   }
01143   if ( !intersectIsolines( uv1[0], uv2[0], ratio[0],
01144                           uv1[1], uv2[1], ratio[1], theUV, theIsDeformed )) {
01145     MESSAGE(" Cant intersect isolines for a point "<<theInitUV.X()<<", "<<theInitUV.Y());
01146     return setErrorCode( ERR_APPLF_BAD_TOPOLOGY );
01147   }
01148 
01149   return true;
01150 }
01151 
01152 
01153 // ==========================================================
01154 // structure representing a node of a grid of iso-poly-lines
01155 // ==========================================================
01156 
01157 struct TIsoNode {
01158   bool   myIsMovable;
01159   gp_XY  myInitUV;
01160   gp_XY  myUV;
01161   double myRatio[2];
01162   gp_Dir2d  myDir[2]; // boundary tangent dir for boundary nodes, iso dir for internal ones
01163   TIsoNode* myNext[4]; // order: (iDir=0,isForward=0), (1,0), (0,1), (1,1)
01164   TIsoNode* myBndNodes[4];     // order: (iDir=0,i=0), (1,0), (0,1), (1,1)
01165   TIsoNode(double initU, double initV):
01166     myInitUV( initU, initV ), myUV( 1e100, 1e100 ), myIsMovable(true)
01167   { myNext[0] = myNext[1] = myNext[2] = myNext[3] = 0; }
01168   bool IsUVComputed() const
01169   { return myUV.X() != 1e100; }
01170   bool IsMovable() const
01171   { return myIsMovable && myNext[0] && myNext[1] && myNext[2] && myNext[3]; }
01172   void SetNotMovable()
01173   { myIsMovable = false; }
01174   void SetBoundaryNode(TIsoNode* node, int iDir, int i)
01175   { myBndNodes[ iDir + i * 2 ] = node; }
01176   TIsoNode* GetBoundaryNode(int iDir, int i)
01177   { return myBndNodes[ iDir + i * 2 ]; }
01178   void SetNext(TIsoNode* node, int iDir, int isForward)
01179   { myNext[ iDir + isForward  * 2 ] = node; }
01180   TIsoNode* GetNext(int iDir, int isForward)
01181   { return myNext[ iDir + isForward * 2 ]; }
01182 };
01183 
01184 //=======================================================================
01185 //function : getNextNode
01186 //purpose  : 
01187 //=======================================================================
01188 
01189 static inline TIsoNode* getNextNode(const TIsoNode* node, int dir )
01190 {
01191   TIsoNode* n = node->myNext[ dir ];
01192   if ( n && !n->IsUVComputed()/* && node->IsMovable()*/ ) {
01193     n = 0;//node->myBndNodes[ dir ];
01194 //     MESSAGE("getNextNode: use bnd for node "<<
01195 //             node->myInitUV.X()<<" "<<node->myInitUV.Y());
01196   }
01197   return n;
01198 }
01199 //=======================================================================
01200 //function : checkQuads
01201 //purpose  : check if newUV destortes quadrangles around node,
01202 //           and if ( crit == FIX_OLD ) fix newUV in this case
01203 //=======================================================================
01204 
01205 enum { CHECK_NEW_IN, CHECK_NEW_OK, FIX_OLD };
01206 
01207 static bool checkQuads (const TIsoNode* node,
01208                         gp_XY&          newUV,
01209                         const bool      reversed,
01210                         const int       crit = FIX_OLD,
01211                         double          fixSize = 0.)
01212 {
01213   gp_XY oldUV = node->myUV, oldUVFixed[4], oldUVImpr[4];
01214   int nbOldFix = 0, nbOldImpr = 0;
01215   double newBadRate = 0, oldBadRate = 0;
01216   bool newIsOk = true, newIsIn = true, oldIsIn = true, oldIsOk = true;
01217   int i, dir1 = 0, dir2 = 3;
01218   for ( ; dir1 < 4; dir1++, dir2++ )  // loop on 4 quadrangles around <node>
01219   {
01220     if ( dir2 > 3 ) dir2 = 0;
01221     TIsoNode* n[3];
01222     // walking counterclockwise around a quad,
01223     // nodes are in the order: node, n[0], n[1], n[2]
01224     n[0] = getNextNode( node, dir1 );
01225     n[2] = getNextNode( node, dir2 );
01226     if ( !n[0] || !n[2] ) continue;
01227     n[1] = getNextNode( n[0], dir2 );
01228     if ( !n[1] ) n[1] = getNextNode( n[2], dir1 );
01229     bool isTriangle = ( !n[1] );
01230     if ( reversed ) {
01231       TIsoNode* tmp = n[0]; n[0] = n[2]; n[2] = tmp;
01232     }
01233 //     if ( fixSize != 0 ) {
01234 // cout<<"NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
01235 // cout<<"\t0: "<<n[0]->myInitUV.X()<<" "<<n[0]->myInitUV.Y()<<" UV: "<<n[0]->myUV.X()<<" "<<n[0]->myUV.Y()<<endl;
01236 // cout<<"\t1: "<<n[1]->myInitUV.X()<<" "<<n[1]->myInitUV.Y()<<" UV: "<<n[1]->myUV.X()<<" "<<n[1]->myUV.Y()<<endl;
01237 // cout<<"\t2: "<<n[2]->myInitUV.X()<<" "<<n[2]->myInitUV.Y()<<" UV: "<<n[2]->myUV.X()<<" "<<n[2]->myUV.Y()<<endl;
01238 // }
01239     // check if a quadrangle is degenerated
01240     if ( !isTriangle &&
01241         ((( n[0]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN ) ||
01242          (( n[2]->myUV - n[1]->myUV ).SquareModulus() <= DBL_MIN )))
01243       isTriangle = true;
01244     if ( isTriangle &&
01245         ( n[0]->myUV - n[2]->myUV ).SquareModulus() <= DBL_MIN )
01246       continue;
01247 
01248     // find min size of the diagonal node-n[1]
01249     double minDiag = fixSize;
01250     if ( minDiag == 0. ) {
01251       double maxLen2 = ( node->myUV - n[0]->myUV ).SquareModulus();
01252       if ( !isTriangle ) {
01253         maxLen2 = Max( maxLen2, ( n[0]->myUV - n[1]->myUV ).SquareModulus() );
01254         maxLen2 = Max( maxLen2, ( n[1]->myUV - n[2]->myUV ).SquareModulus() );
01255       }
01256       maxLen2 = Max( maxLen2, ( n[2]->myUV - node->myUV ).SquareModulus() );
01257       minDiag = sqrt( maxLen2 ) * PI / 60.; // ~ maxLen * Sin( 3 deg )
01258     }
01259 
01260     // check if newUV is behind 3 dirs: n[0]-n[1], n[1]-n[2] and n[0]-n[2]
01261     // ( behind means "to the right of")
01262     // it is OK if
01263     // 1. newUV is not behind 01 and 12 dirs
01264     // 2. or newUV is not behind 02 dir and n[2] is convex
01265     bool newIn[3] = { true, true, true }, newOk[3] = { true, true, true };
01266     bool wasIn[3] = { true, true, true }, wasOk[3] = { true, true, true };
01267     gp_Vec2d moveVec[3], outVec[3];
01268     for ( i = isTriangle ? 2 : 0; i < 3; i++ )
01269     {
01270       bool isDiag = ( i == 2 );
01271       if ( isDiag && newOk[0] && newOk[1] && !isTriangle )
01272         break;
01273       gp_Vec2d sideDir;
01274       if ( isDiag )
01275         sideDir = gp_Vec2d( n[0]->myUV, n[2]->myUV );
01276       else
01277         sideDir = gp_Vec2d( n[i]->myUV, n[i+1]->myUV );
01278 
01279       gp_Vec2d outDir( sideDir.Y(), -sideDir.X() ); // to the right
01280       outDir.Normalize();
01281       gp_Vec2d newDir( n[i]->myUV, newUV );
01282       gp_Vec2d oldDir( n[i]->myUV, oldUV );
01283       outVec[i] = outDir;
01284       if ( newIsOk ) newOk[i] = ( outDir * newDir < -minDiag );
01285       if ( newIsIn ) newIn[i] = ( outDir * newDir < 0 );
01286       if ( crit == FIX_OLD ) {
01287         wasIn[i] = ( outDir * oldDir < 0 );
01288         wasOk[i] = ( outDir * oldDir < -minDiag );
01289         if ( !newOk[i] )
01290           newBadRate += outDir * newDir;
01291         if ( !wasOk[i] )
01292           oldBadRate += outDir * oldDir;
01293         // push node inside
01294         if ( !wasOk[i] ) {
01295           double oldDist = - outDir * oldDir;//, l2 = outDir * newDir;
01296           //               double r = ( l1 - minDiag ) / ( l1 + l2 );
01297           //               moveVec[i] = r * gp_Vec2d( node->myUV, newUV );
01298           moveVec[i] = ( oldDist - minDiag ) * outDir;
01299         }
01300       }
01301     }
01302 
01303     // check if n[2] is convex
01304     bool convex = true;
01305     if ( !isTriangle )
01306       convex = ( outVec[0] * gp_Vec2d( n[1]->myUV, n[2]->myUV ) < 0 );
01307 
01308     bool isNewOk = ( newOk[0] && newOk[1] ) || ( newOk[2] && convex );
01309     bool isNewIn = ( newIn[0] && newIn[1] ) || ( newIn[2] && convex );
01310     newIsOk = ( newIsOk && isNewOk );
01311     newIsIn = ( newIsIn && isNewIn );
01312 
01313     if ( crit != FIX_OLD ) {
01314       if ( crit == CHECK_NEW_OK && !newIsOk ) break;
01315       if ( crit == CHECK_NEW_IN && !newIsIn ) break;
01316       continue;
01317     }
01318 
01319     bool isOldIn = ( wasIn[0] && wasIn[1] ) || ( wasIn[2] && convex );
01320     bool isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
01321     oldIsIn = ( oldIsIn && isOldIn );
01322     oldIsOk = ( oldIsOk && isOldIn );
01323 
01324 
01325     if ( !isOldIn ) { // node is outside a quadrangle
01326       // move newUV inside a quadrangle
01327 //MESSAGE("Quad "<< dir1 << "  WAS IN " << wasIn[0]<<" "<<wasIn[1]<<" "<<wasIn[2]);
01328       // node and newUV are outside: push newUV inside
01329       gp_XY uv;
01330       if ( convex || isTriangle ) {
01331         uv = 0.5 * ( n[0]->myUV + n[2]->myUV ) - minDiag * outVec[2].XY();
01332       }
01333       else {
01334         gp_Vec2d out = outVec[0].Normalized() + outVec[1].Normalized();
01335         double outSize = out.Magnitude();
01336         if ( outSize > DBL_MIN )
01337           out /= outSize;
01338         else
01339           out.SetCoord( -outVec[1].Y(), outVec[1].X() );
01340         uv = n[1]->myUV - minDiag * out.XY();
01341       }
01342       oldUVFixed[ nbOldFix++ ] = uv;
01343       //node->myUV = newUV;
01344     }
01345     else if ( !isOldOk )  {
01346       // try to fix old UV: move node inside as less as possible
01347 //MESSAGE("Quad "<< dir1 << "  old is BAD, try to fix old, minDiag: "<< minDiag);
01348       gp_XY uv1, uv2 = node->myUV;
01349       for ( i = isTriangle ? 2 : 0; i < 3; i++ ) // mark not computed vectors
01350         if ( wasOk[i] )
01351           moveVec[ i ].SetCoord( 1, 2e100); // not use this vector
01352       while ( !isOldOk ) {
01353         // find the least moveVec
01354         int i, iMin = 4;
01355         double minMove2 = 1e100;
01356         for ( i = isTriangle ? 2 : 0; i < 3; i++ )
01357         {
01358           if ( moveVec[i].Coord(1) < 1e100 ) {
01359             double move2 = moveVec[i].SquareMagnitude();
01360             if ( move2 < minMove2 ) {
01361               minMove2 = move2;
01362               iMin = i;
01363             }
01364           }
01365         }
01366         if ( iMin == 4 ) {
01367           break;
01368         }
01369         // move node to newUV
01370         uv1 = node->myUV + moveVec[ iMin ].XY();
01371         uv2 += moveVec[ iMin ].XY();
01372         moveVec[ iMin ].SetCoord( 1, 2e100); // not use this vector more
01373         // check if uv1 is ok
01374         for ( i = isTriangle ? 2 : 0; i < 3; i++ )
01375           wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv1 ) < -minDiag );
01376         isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
01377         if ( isOldOk )
01378           oldUVImpr[ nbOldImpr++ ] = uv1;
01379         else {
01380           // check if uv2 is ok
01381           for ( i = isTriangle ? 2 : 0; i < 3; i++ )
01382             wasOk[i] = ( outVec[i] * gp_Vec2d( n[i]->myUV, uv2 ) < -minDiag );
01383           isOldOk = ( wasOk[0] && wasOk[1] ) || ( wasOk[2] && convex );
01384           if ( isOldOk )
01385             oldUVImpr[ nbOldImpr++ ] = uv2;
01386         }
01387       }
01388     }
01389 
01390   } // loop on 4 quadrangles around <node>
01391 
01392   if ( crit == CHECK_NEW_OK  )
01393     return newIsOk;
01394   if ( crit == CHECK_NEW_IN  )
01395     return newIsIn;
01396 
01397   if ( newIsOk )
01398     return true;
01399 
01400   if ( oldIsOk )
01401     newUV = oldUV;
01402   else {
01403     if ( oldIsIn && nbOldImpr ) {
01404 //       MESSAGE(" Try to improve UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
01405 //               " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
01406       gp_XY uv = oldUVImpr[ 0 ];
01407       for ( int i = 1; i < nbOldImpr; i++ )
01408         uv += oldUVImpr[ i ];
01409       uv /= nbOldImpr;
01410       if ( checkQuads( node, uv, reversed, CHECK_NEW_OK )) {
01411         newUV = uv;
01412         return false;
01413       }
01414       else {
01415         //MESSAGE(" Cant improve UV, uv: "<<uv.X()<<" "<<uv.Y());
01416       }
01417     }
01418     if ( !oldIsIn && nbOldFix ) {
01419 //       MESSAGE(" Try to fix UV, init: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<
01420 //               " uv: "<<oldUV.X()<<" "<<oldUV.Y() );
01421       gp_XY uv = oldUVFixed[ 0 ];
01422       for ( int i = 1; i < nbOldFix; i++ )
01423         uv += oldUVFixed[ i ];
01424       uv /= nbOldFix;
01425       if ( checkQuads( node, uv, reversed, CHECK_NEW_IN )) {
01426         newUV = uv;
01427         return false;
01428       }
01429       else {
01430         //MESSAGE(" Cant fix UV, uv: "<<uv.X()<<" "<<uv.Y());
01431       }
01432     }
01433     if ( newIsIn && oldIsIn )
01434       newUV = ( newBadRate < oldBadRate ) ? newUV : oldUV;
01435     else if ( !newIsIn )
01436       newUV = oldUV;
01437   }
01438 
01439   return false;
01440 }
01441 
01442 //=======================================================================
01443 //function : compUVByElasticIsolines
01444 //purpose  : compute UV as nodes of iso-poly-lines consisting of
01445 //           segments keeping relative size as in the pattern
01446 //=======================================================================
01447 //#define DEB_COMPUVBYELASTICISOLINES
01448 bool SMESH_Pattern::
01449   compUVByElasticIsolines(const list< list< TPoint* > >& theBndPoints,
01450                           const list< TPoint* >&         thePntToCompute)
01451 {
01452   return false; // PAL17233
01453 //cout << "============================== KEY POINTS =============================="<<endl;
01454 //   list< int >::iterator kpIt = myKeyPointIDs.begin();
01455 //   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ ) {
01456 //     TPoint& p = myPoints[ *kpIt ];
01457 //     cout << "INIT: " << p.myInitUV.X() << " " << p.myInitUV.Y() <<
01458 //       " UV: " << p.myUV.X() << " " << p.myUV.Y() << endl;
01459 //  }
01460 //cout << "=============================="<<endl;
01461 
01462   // Define parameters of iso-grid nodes in U and V dir
01463 
01464   set< double > paramSet[ 2 ];
01465   list< list< TPoint* > >::const_iterator pListIt;
01466   list< TPoint* >::const_iterator pIt;
01467   for ( pListIt = theBndPoints.begin(); pListIt != theBndPoints.end(); pListIt++ ) {
01468     const list< TPoint* > & pList = * pListIt;
01469     for ( pIt = pList.begin(); pIt != pList.end(); pIt++ ) {
01470       paramSet[0].insert( (*pIt)->myInitUV.X() );
01471       paramSet[1].insert( (*pIt)->myInitUV.Y() );
01472     }
01473   }
01474   for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
01475     paramSet[0].insert( (*pIt)->myInitUV.X() );
01476     paramSet[1].insert( (*pIt)->myInitUV.Y() );
01477   }
01478   // unite close parameters and split too long segments
01479   int iDir;
01480   double tol[ 2 ];
01481   for ( iDir = 0; iDir < 2; iDir++ )
01482   {
01483     set< double > & params = paramSet[ iDir ];
01484     double range = ( *params.rbegin() - *params.begin() );
01485     double toler = range / 1e6;
01486     tol[ iDir ] = toler;
01487 //    double maxSegment = range / params.size() / 2.;
01488 //
01489 //     set< double >::iterator parIt = params.begin();
01490 //     double prevPar = *parIt;
01491 //     for ( parIt++; parIt != params.end(); parIt++ )
01492 //     {
01493 //       double segLen = (*parIt) - prevPar;
01494 //       if ( segLen < toler )
01495 //         ;//params.erase( prevPar ); // unite
01496 //       else if ( segLen > maxSegment )
01497 //         params.insert( prevPar + 0.5 * segLen ); // split
01498 //       prevPar = (*parIt);
01499 //     }
01500   }
01501 
01502   // Make nodes of a grid of iso-poly-lines
01503 
01504   list < TIsoNode > nodes;
01505   typedef list < TIsoNode *> TIsoLine;
01506   map < double, TIsoLine > isoMap[ 2 ];
01507 
01508   set< double > & params0 = paramSet[ 0 ];
01509   set< double >::iterator par0It = params0.begin();
01510   for ( ; par0It != params0.end(); par0It++ )
01511   {
01512     TIsoLine & isoLine0 = isoMap[0][ *par0It ]; // vertical isoline with const U
01513     set< double > & params1 = paramSet[ 1 ];
01514     set< double >::iterator par1It = params1.begin();
01515     for ( ; par1It != params1.end(); par1It++ )
01516     {
01517       nodes.push_back( TIsoNode( *par0It, *par1It ) );
01518       isoLine0.push_back( & nodes.back() );
01519       isoMap[1][ *par1It ].push_back( & nodes.back() );
01520     }
01521   }
01522 
01523   // Compute intersections of boundaries with iso-lines:
01524   // only boundary nodes will have computed UV so far
01525 
01526   Bnd_Box2d uvBnd;
01527   list< list< TPoint* > >::const_iterator bndIt = theBndPoints.begin();
01528   list< TIsoNode* > bndNodes; // nodes corresponding to outer theBndPoints
01529   for ( ; bndIt != theBndPoints.end(); bndIt++ )
01530   {
01531     const list< TPoint* > & bndPoints = * bndIt;
01532     TPoint* prevP = bndPoints.back(); // this is the first point
01533     list< TPoint* >::const_iterator pIt = bndPoints.begin();
01534     // loop on the edge-points
01535     for ( ; pIt != bndPoints.end(); pIt++ )
01536     {
01537       TPoint* point = *pIt;
01538       for ( iDir = 0; iDir < 2; iDir++ )
01539       {
01540         const int iCoord = iDir + 1;
01541         const int iOtherCoord = 2 - iDir;
01542         double par1 = prevP->myInitUV.Coord( iCoord );
01543         double par2 = point->myInitUV.Coord( iCoord );
01544         double parDif = par2 - par1;
01545         if ( Abs( parDif ) <= DBL_MIN )
01546           continue;
01547         // find iso-lines intersecting a bounadry
01548         double toler = tol[ 1 - iDir ];
01549         double minPar = Min ( par1, par2 );
01550         double maxPar = Max ( par1, par2 );
01551         map < double, TIsoLine >& isos = isoMap[ iDir ];
01552         map < double, TIsoLine >::iterator isoIt = isos.begin();
01553         for ( ; isoIt != isos.end(); isoIt++ )
01554         {
01555           double isoParam = (*isoIt).first;
01556           if ( isoParam < minPar || isoParam > maxPar )
01557             continue;
01558           double r = ( isoParam - par1 ) / parDif;
01559           gp_XY uv = ( 1 - r ) * prevP->myUV + r * point->myUV;
01560           gp_XY initUV = ( 1 - r ) * prevP->myInitUV + r * point->myInitUV;
01561           double otherPar = initUV.Coord( iOtherCoord ); // along isoline
01562           // find existing node with otherPar or insert a new one
01563           TIsoLine & isoLine = (*isoIt).second;
01564           double nodePar;
01565           TIsoLine::iterator nIt = isoLine.begin();
01566           for ( ; nIt != isoLine.end(); nIt++ ) {
01567             nodePar = (*nIt)->myInitUV.Coord( iOtherCoord );
01568             if ( nodePar >= otherPar )
01569               break;
01570           }
01571           TIsoNode * node;
01572           if ( Abs( nodePar - otherPar ) <= toler )
01573             node = ( nIt == isoLine.end() ) ? isoLine.back() : (*nIt);
01574           else {
01575             nodes.push_back( TIsoNode( initUV.X(), initUV.Y() ) );
01576             node = & nodes.back();
01577             isoLine.insert( nIt, node );
01578           }
01579           node->SetNotMovable();
01580           node->myUV = uv;
01581           uvBnd.Add( gp_Pnt2d( uv ));
01582 //  cout << "bnd: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<node->myUV.X()<<" "<<node->myUV.Y()<<endl;
01583           // tangent dir
01584           gp_XY tgt( point->myUV - prevP->myUV );
01585           if ( ::IsEqual( r, 1. ))
01586             node->myDir[ 0 ] = tgt;
01587           else if ( ::IsEqual( r, 0. ))
01588             node->myDir[ 1 ] = tgt;
01589           else
01590             node->myDir[ 1 ] = node->myDir[ 0 ] = tgt;
01591           // keep boundary nodes corresponding to boundary points
01592           if ( bndIt == theBndPoints.begin() && ::IsEqual( r, 1. ))
01593             if ( bndNodes.empty() || bndNodes.back() != node )
01594               bndNodes.push_back( node );
01595         } // loop on isolines
01596       } // loop on 2 directions
01597       prevP = point;
01598     } // loop on boundary points
01599   } // loop on boundaries
01600 
01601   // Define orientation
01602 
01603   // find the point with the least X
01604   double leastX = DBL_MAX;
01605   TIsoNode * leftNode;
01606   list < TIsoNode >::iterator nodeIt = nodes.begin();
01607   for ( ; nodeIt != nodes.end(); nodeIt++  ) {
01608     TIsoNode & node = *nodeIt;
01609     if ( node.IsUVComputed() && node.myUV.X() < leastX ) {
01610       leastX = node.myUV.X();
01611       leftNode = &node;
01612     }
01613 // if ( node.IsUVComputed() ) {
01614 // cout << "bndNode INIT: " << node.myInitUV.X()<<" "<<node.myInitUV.Y()<<" UV: "<<
01615 //   node.myUV.X()<<" "<<node.myUV.Y()<<endl<<
01616 //    " dir0: "<<node.myDir[0].X()<<" "<<node.myDir[0].Y() <<
01617 //      " dir1: "<<node.myDir[1].X()<<" "<<node.myDir[1].Y() << endl;
01618 // }
01619   }
01620   bool reversed = ( leftNode->myDir[0].Y() + leftNode->myDir[1].Y() > 0 );
01621   //SCRUTE( reversed );
01622 
01623   // Prepare internal nodes:
01624   // 1. connect nodes
01625   // 2. compute ratios
01626   // 3. find boundary nodes for each node
01627   // 4. remove nodes out of the boundary
01628   for ( iDir = 0; iDir < 2; iDir++ )
01629   {
01630     const int iCoord = 2 - iDir; // coord changing along an isoline
01631     map < double, TIsoLine >& isos = isoMap[ iDir ];
01632     map < double, TIsoLine >::iterator isoIt = isos.begin();
01633     for ( ; isoIt != isos.end(); isoIt++ )
01634     {
01635       TIsoLine & isoLine = (*isoIt).second;
01636       bool firstCompNodeFound = false;
01637       TIsoLine::iterator lastCompNodePos, nPrevIt, nIt, nNextIt, nIt2;
01638       nPrevIt = nIt = nNextIt = isoLine.begin();
01639       nIt++;
01640       nNextIt++; nNextIt++;
01641       while ( nIt != isoLine.end() )
01642       {
01643         // 1. connect prev - cur
01644         TIsoNode* node = *nIt, * prevNode = *nPrevIt;
01645         if ( !firstCompNodeFound && prevNode->IsUVComputed() ) {
01646           firstCompNodeFound = true;
01647           lastCompNodePos = nPrevIt;
01648         }
01649         if ( firstCompNodeFound ) {
01650           node->SetNext( prevNode, iDir, 0 );
01651           prevNode->SetNext( node, iDir, 1 );
01652         }
01653         // 2. compute ratio
01654         if ( nNextIt != isoLine.end() ) {
01655           double par1 = prevNode->myInitUV.Coord( iCoord );
01656           double par2 = node->myInitUV.Coord( iCoord );
01657           double par3 = (*nNextIt)->myInitUV.Coord( iCoord );
01658           node->myRatio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
01659         }
01660         // 3. find boundary nodes
01661         if ( node->IsUVComputed() )
01662           lastCompNodePos = nIt;
01663         else if ( firstCompNodeFound && nNextIt != isoLine.end() ) {
01664           TIsoNode* bndNode1 = *lastCompNodePos, *bndNode2 = 0;
01665           for ( nIt2 = nNextIt; nIt2 != isoLine.end(); nIt2++ )
01666             if ( (*nIt2)->IsUVComputed() )
01667               break;
01668           if ( nIt2 != isoLine.end() ) {
01669             bndNode2 = *nIt2;
01670             node->SetBoundaryNode( bndNode1, iDir, 0 );
01671             node->SetBoundaryNode( bndNode2, iDir, 1 );
01672 // cout << "--------------------------------------------------"<<endl;
01673 //  cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<<endl<<
01674 //   " dir0: "<<bndNode1->myDir[0].X()<<" "<<bndNode1->myDir[0].Y() <<
01675 //     " dir1: "<<bndNode1->myDir[1].X()<<" "<<bndNode1->myDir[1].Y() << endl;
01676 //  cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl<<
01677 //   " dir0: "<<bndNode2->myDir[0].X()<<" "<<bndNode2->myDir[0].Y() <<
01678 //     " dir1: "<<bndNode2->myDir[1].X()<<" "<<bndNode2->myDir[1].Y() << endl;
01679           }
01680           else {
01682             node->SetBoundaryNode( 0, iDir, 0 );
01683             node->SetBoundaryNode( 0, iDir, 1 );
01684           }
01685         }
01686         nIt++; nPrevIt++;
01687         if ( nNextIt != isoLine.end() ) nNextIt++;
01688         // 4. remove nodes out of the boundary
01689         if ( !firstCompNodeFound )
01690           isoLine.pop_front();
01691       } // loop on isoLine nodes
01692 
01693       // remove nodes after the boundary
01694 //       for ( nIt = ++lastCompNodePos; nIt != isoLine.end(); nIt++ )
01695 //         (*nIt)->SetNotMovable();
01696       isoLine.erase( ++lastCompNodePos, isoLine.end() );
01697     } // loop on isolines
01698   } // loop on 2 directions
01699 
01700   // Compute local isoline direction for internal nodes
01701 
01702   /*
01703   map < double, TIsoLine >& isos = isoMap[ 0 ]; // vertical isolines with const U
01704   map < double, TIsoLine >::iterator isoIt = isos.begin();
01705   for ( ; isoIt != isos.end(); isoIt++ )
01706   {
01707     TIsoLine & isoLine = (*isoIt).second;
01708     TIsoLine::iterator nIt = isoLine.begin();
01709     for ( ; nIt != isoLine.end(); nIt++ )
01710     {
01711       TIsoNode* node = *nIt;
01712       if ( node->IsUVComputed() || !node->IsMovable() )
01713         continue;
01714       gp_Vec2d aTgt[2], aNorm[2];
01715       double ratio[2];
01716       bool OK = true;
01717       for ( iDir = 0; iDir < 2; iDir++ )
01718       {
01719         TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
01720         TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
01721         if ( !bndNode1 || !bndNode2 ) {
01722           OK = false;
01723           break;
01724         }
01725         const int iCoord = 2 - iDir; // coord changing along an isoline
01726         double par1 = bndNode1->myInitUV.Coord( iCoord );
01727         double par2 = node->myInitUV.Coord( iCoord );
01728         double par3 = bndNode2->myInitUV.Coord( iCoord );
01729         ratio[ iDir ] = ( par2 - par1 ) / ( par3 - par1 );
01730 
01731         gp_Vec2d tgt1( bndNode1->myDir[0].XY() + bndNode1->myDir[1].XY() );
01732         gp_Vec2d tgt2( bndNode2->myDir[0].XY() + bndNode2->myDir[1].XY() );
01733         if ( bool( iDir ) == reversed ) tgt2.Reverse(); // along perpend. isoline
01734         else                            tgt1.Reverse();
01735 //cout<<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" | "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
01736 
01737         if ( ratio[ iDir ] < 0.5 )
01738           aNorm[ iDir ] = gp_Vec2d( -tgt1.Y(), tgt1.X() ); // rotate tgt to the left
01739         else
01740           aNorm[ iDir ] = gp_Vec2d( -tgt2.Y(), tgt2.X() );
01741         if ( iDir == 1 )
01742           aNorm[ iDir ].Reverse();  // along iDir isoline
01743 
01744         double angle = tgt1.Angle( tgt2 ); //  [-PI, PI]
01745         // maybe angle is more than |PI|
01746         if ( Abs( angle ) > PI / 2. ) {
01747           // check direction of the last but one perpendicular isoline
01748           TIsoNode* prevNode = bndNode2->GetNext( iDir, 0 );
01749           bndNode1 = prevNode->GetBoundaryNode( 1 - iDir, 0 );
01750           bndNode2 = prevNode->GetBoundaryNode( 1 - iDir, 1 );
01751           gp_Vec2d isoDir( bndNode1->myUV, bndNode2->myUV );
01752           if ( isoDir * tgt2 < 0 )
01753             isoDir.Reverse();
01754           double angle2 = tgt1.Angle( isoDir );
01755           //cout << " isoDir: "<< isoDir.X() <<" "<<isoDir.Y() << " ANGLE: "<< angle << " "<<angle2<<endl;
01756           if (angle2 * angle < 0 && // check the sign of an angle close to PI
01757               Abs ( Abs ( angle ) - PI ) <= PI / 180. ) {
01758             //MESSAGE("REVERSE ANGLE");
01759             angle = -angle;
01760           }
01761           if ( Abs( angle2 ) > Abs( angle ) ||
01762               ( angle2 * angle < 0 && Abs( angle2 ) > Abs( angle - angle2 ))) {
01763             //MESSAGE("Add PI");
01764             // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
01765             // cout <<"ISO: " << isoParam << " " << (*iso2It).first << endl;
01766             // cout << "bndNode1: " << bndNode1->myUV.X()<<" "<<bndNode1->myUV.Y()<< endl;
01767             // cout << "bndNode2: " << bndNode2->myUV.X()<<" "<<bndNode2->myUV.Y()<<endl;
01768             // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<"  "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
01769             angle += ( angle < 0 ) ? 2. * PI : -2. * PI;
01770           }
01771         }
01772         aTgt[ iDir ] = tgt1.Rotated( angle * ratio[ iDir ] ).XY();
01773       } // loop on 2 dir
01774 
01775       if ( OK ) {
01776         for ( iDir = 0; iDir < 2; iDir++ )
01777         {
01778           aTgt[iDir].Normalize();
01779           aNorm[1-iDir].Normalize();
01780           double r = Abs ( ratio[iDir] - 0.5 ) * 2.0; // [0,1] - distance from the middle
01781           r *= r;
01782 
01783           node->myDir[iDir] = //aTgt[iDir];
01784             aNorm[1-iDir] * r + aTgt[iDir] * ( 1. - r );
01785         }
01786 // cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
01787 // cout <<" tgt: " << tgt1.X()<<" "<<tgt1.Y()<<" - "<< tgt2.X()<<" "<<tgt2.Y()<<endl;
01788 //  cout << " isoDir: "<< node->myDir[0].X() <<" "<<node->myDir[0].Y()<<"  |  "
01789 //    << node->myDir[1].X() <<" "<<node->myDir[1].Y()<<endl;
01790       }
01791     } // loop on iso nodes
01792   } // loop on isolines
01793 */
01794   // Find nodes to start computing UV from
01795 
01796   list< TIsoNode* > startNodes;
01797   list< TIsoNode* >::iterator nIt = bndNodes.end();
01798   TIsoNode* node = *(--nIt);
01799   TIsoNode* prevNode = *(--nIt);
01800   for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
01801   {
01802     TIsoNode* nextNode = *nIt;
01803     gp_Vec2d initTgt1( prevNode->myInitUV, node->myInitUV );
01804     gp_Vec2d initTgt2( node->myInitUV, nextNode->myInitUV );
01805     double initAngle = initTgt1.Angle( initTgt2 );
01806     double angle = node->myDir[0].Angle( node->myDir[1] );
01807     if ( reversed ) angle = -angle;
01808     if ( initAngle > angle && initAngle - angle > PI / 2.1 ) {
01809       // find a close internal node
01810       TIsoNode* nClose = 0;
01811       list< TIsoNode* > testNodes;
01812       testNodes.push_back( node );
01813       list< TIsoNode* >::iterator it = testNodes.begin();
01814       for ( ; !nClose && it != testNodes.end(); it++ )
01815       {
01816         for (int i = 0; i < 4; i++ )
01817         {
01818           nClose = (*it)->myNext[ i ];
01819           if ( nClose ) {
01820             if ( !nClose->IsUVComputed() )
01821               break;
01822             else {
01823               testNodes.push_back( nClose );
01824               nClose = 0;
01825             }
01826           }
01827         }
01828       }
01829       startNodes.push_back( nClose );
01830 // cout << "START: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<" UV: "<<
01831 //   node->myUV.X()<<" "<<node->myUV.Y()<<endl<<
01832 //   "initAngle: " << initAngle << " angle: " << angle << endl;
01833 // cout <<" init tgt: " << initTgt1.X()<<" "<<initTgt1.Y()<<" | "<< initTgt2.X()<<" "<<initTgt2.Y()<<endl;
01834 // cout << " tgt: "<< node->myDir[ 0 ].X() <<" "<<node->myDir[ 0 ].Y()<<" | "<<
01835 //    node->myDir[ 1 ].X() <<" "<<node->myDir[ 1 ].Y()<<endl;
01836 // cout << "CLOSE: "<<nClose->myInitUV.X()<<" "<<nClose->myInitUV.Y()<<endl;
01837     }
01838     prevNode = node;
01839     node = nextNode;
01840   }
01841 
01842   // Compute starting UV of internal nodes
01843 
01844   list < TIsoNode* > internNodes;
01845   bool needIteration = true;
01846   if ( startNodes.empty() ) {
01847     MESSAGE( " Starting UV by compUVByIsoIntersection()");
01848     needIteration = false;
01849     map < double, TIsoLine >& isos = isoMap[ 0 ];
01850     map < double, TIsoLine >::iterator isoIt = isos.begin();
01851     for ( ; isoIt != isos.end(); isoIt++ )
01852     {
01853       TIsoLine & isoLine = (*isoIt).second;
01854       TIsoLine::iterator nIt = isoLine.begin();
01855       for ( ; !needIteration && nIt != isoLine.end(); nIt++ )
01856       {
01857         TIsoNode* node = *nIt;
01858         if ( !node->IsUVComputed() && node->IsMovable() ) {
01859           internNodes.push_back( node );
01860           //bool isDeformed;
01861           if ( !compUVByIsoIntersection(theBndPoints, node->myInitUV,
01862                                         node->myUV, needIteration ))
01863             node->myUV = node->myInitUV;
01864         }
01865       }
01866     }
01867     if ( needIteration )
01868       for ( nIt = bndNodes.begin(); nIt != bndNodes.end(); nIt++ )
01869       {
01870         TIsoNode* node = *nIt, *nClose = 0;
01871         list< TIsoNode* > testNodes;
01872         testNodes.push_back( node );
01873         list< TIsoNode* >::iterator it = testNodes.begin();
01874         for ( ; !nClose && it != testNodes.end(); it++ )
01875         {
01876           for (int i = 0; i < 4; i++ )
01877           {
01878             nClose = (*it)->myNext[ i ];
01879             if ( nClose ) {
01880               if ( !nClose->IsUVComputed() && nClose->IsMovable() )
01881                 break;
01882               else {
01883                 testNodes.push_back( nClose );
01884                 nClose = 0;
01885               }
01886             }
01887           }
01888         }
01889         startNodes.push_back( nClose );
01890       }
01891   }
01892 
01893   double aMin[2], aMax[2], step[2];
01894   uvBnd.Get( aMin[0], aMin[1], aMax[0], aMax[1] );
01895   double minUvSize = Min ( aMax[0]-aMin[0], aMax[1]-aMin[1] );
01896   step[0] = minUvSize / paramSet[ 0 ].size() / 10;
01897   step[1] = minUvSize / paramSet[ 1 ].size() / 10;
01898 //cout << "STEPS: " << step[0] << " " << step[1]<< endl;
01899 
01900   for ( nIt = startNodes.begin(); nIt != startNodes.end(); nIt++ )
01901   {
01902     TIsoNode *node = *nIt;
01903     if ( node->IsUVComputed() || !node->IsMovable() )
01904       continue;
01905     gp_XY newUV( 0, 0 ), sumDir( 0, 0 );
01906     int nbComp = 0, nbPrev = 0;
01907     for ( iDir = 0; iDir < 2; iDir++ )
01908     {
01909       TIsoNode* prevNode1 = 0, *prevNode2 = 0;
01910       TIsoNode* n = node->GetNext( iDir, 0 );
01911       if ( n->IsUVComputed() )
01912         prevNode1 = n;
01913       else
01914         startNodes.push_back( n );
01915       n = node->GetNext( iDir, 1 );
01916       if ( n->IsUVComputed() )
01917         prevNode2 = n;
01918       else
01919         startNodes.push_back( n );
01920       if ( !prevNode1 ) {
01921         prevNode1 = prevNode2;
01922         prevNode2 = 0;
01923       }
01924       if ( prevNode1 ) nbPrev++;
01925       if ( prevNode2 ) nbPrev++;
01926       if ( prevNode1 ) {
01927         gp_XY dir;
01928           double prevPar = prevNode1->myInitUV.Coord( 2 - iDir );
01929           double par = node->myInitUV.Coord( 2 - iDir );
01930           bool isEnd = ( prevPar > par );
01931 //          dir = node->myDir[ 1 - iDir ].XY() * ( isEnd ? -1. : 1. );
01932         //cout << "__________"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
01933           TIsoNode* bndNode = node->GetBoundaryNode( iDir, isEnd );
01934           if ( !bndNode ) {
01935             MESSAGE("Why we are here?");
01936             continue;
01937           }
01938           gp_XY tgt( bndNode->myDir[0].XY() + bndNode->myDir[1].XY() );
01939           dir.SetCoord( 1, tgt.Y() * ( reversed ? 1 : -1 ));
01940           dir.SetCoord( 2, tgt.X() * ( reversed ? -1 : 1 ));
01941         //cout << "bndNode UV: " << bndNode->myUV.X()<<" "<<bndNode->myUV.Y()<< endl;
01942           //  cout << " tgt: "<< bndNode->myDir[ 0 ].X() <<" "<<bndNode->myDir[ 0 ].Y()<<" | "<<
01943           //     bndNode->myDir[ 1 ].X() <<" "<<bndNode->myDir[ 1 ].Y()<<endl;
01944           //cout << "prevNode UV: " << prevNode1->myUV.X()<<" "<<prevNode1->myUV.Y()<<
01945             //" par: " << prevPar << endl;
01946           //           cout <<" tgt: " << tgt.X()<<" "<<tgt.Y()<<endl;
01947         //cout << " DIR: "<< dir.X() <<" "<<dir.Y()<<endl;
01948         if ( prevNode2 ) {
01949           //cout << "____2next______"<<endl<< "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
01950           gp_XY & uv1 = prevNode1->myUV;
01951           gp_XY & uv2 = prevNode2->myUV;
01952 //           dir = ( uv2 - uv1 );
01953 //           double len = dir.Modulus();
01954 //           if ( len > DBL_MIN )
01955 //             dir /= len * 0.5;
01956           double r = node->myRatio[ iDir ];
01957           newUV += uv1 * ( 1 - r ) + uv2 * r;
01958         }
01959         else {
01960           newUV += prevNode1->myUV + dir * step[ iDir ];
01961         }
01962         sumDir += dir;
01963         nbComp++;
01964       }
01965     }
01966     if ( !nbComp ) continue;
01967     newUV /= nbComp;
01968     node->myUV = newUV;
01969     //cout << "NODE: "<<node->myInitUV.X()<<" "<<node->myInitUV.Y()<<endl;
01970 
01971     // check if a quadrangle is not distorted
01972     if ( nbPrev > 1 ) {
01973       //int crit = ( nbPrev == 4 ) ? FIX_OLD : CHECK_NEW_IN;
01974       if ( !checkQuads( node, newUV, reversed, FIX_OLD, step[0] + step[1] )) {
01975       //cout <<" newUV: " << node->myUV.X() << " "<<node->myUV.Y() << " nbPrev: "<<nbPrev<< endl;
01976       //  cout << "_FIX_INIT_ fixedUV: " << newUV.X() << " "<<newUV.Y() << endl;
01977         node->myUV = newUV;
01978       }
01979     }
01980     internNodes.push_back( node );
01981   }
01982 
01983   // Move nodes
01984 
01985   static int maxNbIter = 100;
01986 #ifdef DEB_COMPUVBYELASTICISOLINES
01987 //   maxNbIter++;
01988   bool useNbMoveNode = 0;
01989   static int maxNbNodeMove = 100;
01990   maxNbNodeMove++;
01991   int nbNodeMove = 0;
01992   if ( !useNbMoveNode )
01993     maxNbIter = ( maxNbIter < 0 ) ? 100 : -1;
01994 #endif
01995   double maxMove;
01996   int nbIter = 0;
01997   do {
01998     if ( !needIteration) break;
01999 #ifdef DEB_COMPUVBYELASTICISOLINES
02000     if ( nbIter >= maxNbIter ) break;
02001 #endif
02002     maxMove = 0.0;
02003     list < TIsoNode* >::iterator nIt = internNodes.begin();
02004     for ( ; nIt != internNodes.end(); nIt++  ) {
02005 #ifdef DEB_COMPUVBYELASTICISOLINES
02006       if (useNbMoveNode )
02007         cout << nbNodeMove <<" =================================================="<<endl;
02008 #endif
02009       TIsoNode * node = *nIt;
02010       // make lines
02011       //gp_Lin2d line[2];
02012       gp_XY loc[2];
02013       for ( iDir = 0; iDir < 2; iDir++ )
02014       {
02015         gp_XY & uv1 = node->GetNext( iDir, 0 )->myUV;
02016         gp_XY & uv2 = node->GetNext( iDir, 1 )->myUV;
02017         double r = node->myRatio[ iDir ];
02018         loc[ iDir ] = uv1 * ( 1 - r ) + uv2 * r;
02019 //         line[ iDir ].SetLocation( loc[ iDir ] );
02020 //         line[ iDir ].SetDirection( node->myDir[ iDir ] );
02021       }
02022       // define ratio
02023       bool ok = true; // <- stupid fix TO AVOID PB OF NODES WITH NULL BND NODES
02024 //      double locR[2] = { 0, 0 };
02025       for ( iDir = 0; iDir < 2; iDir++ )
02026       {
02027         const int iCoord = 2 - iDir; // coord changing along an isoline
02028         TIsoNode* bndNode1 = node->GetBoundaryNode( iDir, 0 );
02029         TIsoNode* bndNode2 = node->GetBoundaryNode( iDir, 1 );
02030         if ( !bndNode1 || !bndNode2 ) {
02031           ok = false; break;
02032         }
02033         double par1 = bndNode1->myInitUV.Coord( iCoord );
02034         double par2 = node->myInitUV.Coord( iCoord );
02035         double par3 = bndNode2->myInitUV.Coord( iCoord );
02036         double r = ( par2 - par1 ) / ( par3 - par1 );
02037         r = Abs ( r - 0.5 ) * 2.0;  // [0,1] - distance from the middle
02038 //        locR[ iDir ] = ( 1 - r * r ) * 0.25;
02039       }
02040       //locR[0] = locR[1] = 0.25;
02041       // intersect the 2 lines and move a node
02042       //IntAna2d_AnaIntersection inter( line[0], line[1] );
02043       if ( ok /*inter.IsDone() && inter.NbPoints() ==*/ )
02044       {
02045 //         double intR = 1 - locR[0] - locR[1];
02046 //         gp_XY newUV = inter.Point(1).Value().XY();
02047 //         if ( !checkQuads( node, newUV, reversed, CHECK_NEW_IN ))
02048 //           newUV = ( locR[0] * loc[0] + locR[1] * loc[1] ) / ( 1 - intR );
02049 //         else
02050 //           newUV = intR * newUV + locR[0] * loc[0] + locR[1] * loc[1];
02051         gp_XY newUV = 0.5 * ( loc[0] +  loc[1] );
02052         // avoid parallel isolines intersection
02053         checkQuads( node, newUV, reversed );
02054 
02055         maxMove = Max( maxMove, ( newUV - node->myUV ).SquareModulus());
02056         node->myUV = newUV;
02057       } // intersection found
02058 #ifdef DEB_COMPUVBYELASTICISOLINES
02059       if (useNbMoveNode && ++nbNodeMove >= maxNbNodeMove ) break;
02060 #endif
02061     } // loop on internal nodes
02062 #ifdef DEB_COMPUVBYELASTICISOLINES
02063     if (useNbMoveNode && nbNodeMove >= maxNbNodeMove ) break;
02064 #endif
02065   } while ( maxMove > 1e-8 && nbIter++ < maxNbIter );
02066 
02067   MESSAGE( "compUVByElasticIsolines(): Nb iterations " << nbIter << " dist: " << sqrt( maxMove ));
02068 
02069   if ( nbIter >= maxNbIter && sqrt(maxMove) > minUvSize * 0.05 ) {
02070     MESSAGE( "compUVByElasticIsolines() failed: "<<sqrt(maxMove)<<">"<<minUvSize * 0.05);
02071 #ifndef DEB_COMPUVBYELASTICISOLINES
02072     return false;
02073 #endif
02074   }
02075 
02076   // Set computed UV to points
02077 
02078   for ( pIt = thePntToCompute.begin(); pIt != thePntToCompute.end(); pIt++ ) {
02079     TPoint* point = *pIt;
02080     //gp_XY oldUV = point->myUV;
02081     double minDist = DBL_MAX;
02082     list < TIsoNode >::iterator nIt = nodes.begin();
02083     for ( ; nIt != nodes.end(); nIt++ ) {
02084       double dist = ( (*nIt).myInitUV - point->myInitUV ).SquareModulus();
02085       if ( dist < minDist ) {
02086         minDist = dist;
02087         point->myUV = (*nIt).myUV;
02088       }
02089     }
02090   }
02091 
02092   return true;
02093 }
02094 
02095 
02096 //=======================================================================
02097 //function : setFirstEdge
02098 //purpose  : choose the best first edge of theWire; return the summary distance
02099 //           between point UV computed by isolines intersection and
02100 //           eventual UV got from edge p-curves
02101 //=======================================================================
02102 
02103 //#define DBG_SETFIRSTEDGE
02104 double SMESH_Pattern::setFirstEdge (list< TopoDS_Edge > & theWire, int theFirstEdgeID)
02105 {
02106   int iE, nbEdges = theWire.size();
02107   if ( nbEdges == 1 )
02108     return 0;
02109 
02110   // Transform UVs computed by iso to fit bnd box of a wire
02111 
02112   // max nb of points on an edge
02113   int maxNbPnt = 0;
02114   int eID = theFirstEdgeID;
02115   for ( iE = 0; iE < nbEdges; iE++ )
02116     maxNbPnt = Max ( maxNbPnt, getShapePoints( eID++ ).size() );
02117 
02118   // compute bnd boxes
02119   TopoDS_Face face = TopoDS::Face( myShape );
02120   Bnd_Box2d bndBox, eBndBox;
02121   eID = theFirstEdgeID;
02122   list< TopoDS_Edge >::iterator eIt;
02123   list< TPoint* >::iterator pIt;
02124   for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
02125   {
02126     // UV by isos stored in TPoint.myXYZ
02127     list< TPoint* > & ePoints = getShapePoints( eID++ );
02128     for ( pIt = ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
02129       TPoint* p = (*pIt);
02130       bndBox.Add( gp_Pnt2d( p->myXYZ.X(), p->myXYZ.Y() ));
02131     }
02132     // UV by an edge p-curve
02133     double f, l;
02134     Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface( *eIt, face, f, l );
02135     double dU = ( l - f ) / ( maxNbPnt - 1 );
02136     for ( int i = 0; i < maxNbPnt; i++ )
02137       eBndBox.Add( C2d->Value( f + i * dU ));
02138   }
02139 
02140   // transform UVs by isos
02141   double minPar[2], maxPar[2], eMinPar[2], eMaxPar[2];
02142   bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
02143   eBndBox.Get( eMinPar[0], eMinPar[1], eMaxPar[0], eMaxPar[1] );
02144 #ifdef DBG_SETFIRSTEDGE
02145   MESSAGE ( "EDGES: X: " << eMinPar[0] << " - " << eMaxPar[0] << " Y: "
02146          << eMinPar[1] << " - " << eMaxPar[1] );
02147 #endif
02148   for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
02149   {
02150     double dMin = eMinPar[i] - minPar[i];
02151     double dMax = eMaxPar[i] - maxPar[i];
02152     double dPar = maxPar[i] - minPar[i];
02153     eID = theFirstEdgeID;
02154     for ( iE = 0; iE < nbEdges; iE++ ) // loop on edges of a boundary
02155     {
02156       list< TPoint* > & ePoints = getShapePoints( eID++ );
02157       for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) // loop on edge points
02158       {
02159         double par = (*pIt)->myXYZ.Coord( iC );
02160         double r = ( par - minPar[i] ) / dPar;
02161         par += ( 1 - r ) * dMin + r * dMax;
02162         (*pIt)->myXYZ.SetCoord( iC, par );
02163       }
02164     }
02165   }
02166 
02167   TopoDS_Edge eBest;
02168   double minDist = DBL_MAX;
02169   for ( iE = 0 ; iE < nbEdges; iE++ )
02170   {
02171 #ifdef DBG_SETFIRSTEDGE
02172     MESSAGE ( " VARIANT " << iE );
02173 #endif
02174     // evaluate the distance between UV computed by the 2 methods:
02175     // by isos intersection ( myXYZ ) and by edge p-curves ( myUV )
02176     double dist = 0;
02177     int eID = theFirstEdgeID;
02178     for ( eIt = theWire.begin(); eIt != theWire.end(); eIt++ )
02179     {
02180       list< TPoint* > & ePoints = getShapePoints( eID++ );
02181       computeUVOnEdge( *eIt, ePoints );
02182       for ( pIt = ++ePoints.begin(); pIt != ePoints.end(); pIt++ ) {
02183         TPoint* p = (*pIt);
02184         dist += ( p->myUV - gp_XY( p->myXYZ.X(), p->myXYZ.Y() )).SquareModulus();
02185 #ifdef DBG_SETFIRSTEDGE
02186         MESSAGE ( " ISO : ( " << p->myXYZ.X() << ", "<< p->myXYZ.Y() << " ) PCURVE : ( " <<
02187                   p->myUV.X() << ", " << p->myUV.Y() << ") " );
02188 #endif
02189       }
02190     }
02191 #ifdef DBG_SETFIRSTEDGE
02192     MESSAGE ( "dist -- " << dist );
02193 #endif
02194     if ( dist < minDist ) {
02195       minDist = dist;
02196       eBest = theWire.front();
02197     }
02198     // check variant with another first edge
02199     theWire.splice( theWire.begin(), theWire, --theWire.end(), theWire.end() );
02200   }
02201   // put the best first edge to the theWire front
02202   if ( eBest != theWire.front() ) {
02203     eIt = find ( theWire.begin(), theWire.end(), eBest );
02204     theWire.splice( theWire.begin(), theWire, eIt, theWire.end() );
02205   }
02206 
02207   return minDist;
02208 }
02209 
02210 //=======================================================================
02211 //function : sortSameSizeWires
02212 //purpose  : sort wires in theWireList from theFromWire until theToWire,
02213 //           the wires are set in the order to correspond to the order
02214 //           of boundaries; after sorting, edges in the wires are put
02215 //           in a good order, point UVs on edges are computed and points
02216 //           are appended to theEdgesPointsList
02217 //=======================================================================
02218 
02219 bool SMESH_Pattern::sortSameSizeWires (TListOfEdgesList &                theWireList,
02220                                        const TListOfEdgesList::iterator& theFromWire,
02221                                        const TListOfEdgesList::iterator& theToWire,
02222                                        const int                         theFirstEdgeID,
02223                                        list< list< TPoint* > >&          theEdgesPointsList )
02224 {
02225   TopoDS_Face F = TopoDS::Face( myShape );
02226   int iW, nbWires = 0;
02227   TListOfEdgesList::iterator wlIt = theFromWire;
02228   while ( wlIt++ != theToWire )
02229     nbWires++;
02230 
02231   // Recompute key-point UVs by isolines intersection,
02232   // compute CG of key-points for each wire and bnd boxes of GCs
02233 
02234   bool aBool;
02235   gp_XY orig( gp::Origin2d().XY() );
02236   vector< gp_XY > vGcVec( nbWires, orig ), gcVec( nbWires, orig );
02237   Bnd_Box2d bndBox, vBndBox;
02238   int eID = theFirstEdgeID;
02239   list< TopoDS_Edge >::iterator eIt;
02240   for ( iW = 0, wlIt = theFromWire; wlIt != theToWire; wlIt++, iW++ )
02241   {
02242     list< TopoDS_Edge > & wire = *wlIt;
02243     for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
02244     {
02245       list< TPoint* > & ePoints = getShapePoints( eID++ );
02246       TPoint* p = ePoints.front();
02247       if ( !compUVByIsoIntersection( theEdgesPointsList, p->myInitUV, p->myUV, aBool )) {
02248         MESSAGE("cant sortSameSizeWires()");
02249         return false;
02250       }
02251       gcVec[iW] += p->myUV;
02252       bndBox.Add( gp_Pnt2d( p->myUV ));
02253       TopoDS_Vertex V = TopExp::FirstVertex( *eIt, true );
02254       gp_Pnt2d vXY = BRep_Tool::Parameters( V, F );
02255       vGcVec[iW] += vXY.XY();
02256       vBndBox.Add( vXY );
02257       // keep the computed UV to compare against by setFirstEdge()
02258       p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
02259     }
02260     gcVec[iW] /= nbWires;
02261     vGcVec[iW] /= nbWires;
02262 // cout << " Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
02263 //   " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
02264   }
02265 
02266   // Transform GCs computed by isos to fit in bnd box of GCs by vertices
02267 
02268   double minPar[2], maxPar[2], vMinPar[2], vMaxPar[2];
02269   bndBox.Get( minPar[0], minPar[1], maxPar[0], maxPar[1] );
02270   vBndBox.Get( vMinPar[0], vMinPar[1], vMaxPar[0], vMaxPar[1] );
02271   for ( int iC = 1, i = 0; i < 2; iC++, i++ ) // loop on 2 coordinates
02272   {
02273     double dMin = vMinPar[i] - minPar[i];
02274     double dMax = vMaxPar[i] - maxPar[i];
02275     double dPar = maxPar[i] - minPar[i];
02276     if ( Abs( dPar ) <= DBL_MIN )
02277       continue;
02278     for ( iW = 0; iW < nbWires; iW++ ) { // loop on GCs of wires
02279       double par = gcVec[iW].Coord( iC );
02280       double r = ( par - minPar[i] ) / dPar;
02281       par += ( 1 - r ) * dMin + r * dMax;
02282       gcVec[iW].SetCoord( iC, par );
02283     }
02284   }
02285 
02286   // Define boundary - wire correspondence by GC closeness
02287 
02288   TListOfEdgesList tmpWList;
02289   tmpWList.splice( tmpWList.end(), theWireList, theFromWire, theToWire );
02290   typedef map< int, TListOfEdgesList::iterator > TIntWirePosMap;
02291   TIntWirePosMap bndIndWirePosMap;
02292   vector< bool > bndFound( nbWires, false );
02293   for ( iW = 0, wlIt = tmpWList.begin(); iW < nbWires; iW++, wlIt++ )
02294   {
02295 // cout << " TRSF Wire " << iW << " iso: " << gcVec[iW].X() << " " << gcVec[iW].Y() << endl <<
02296 //   " \t vertex: " << vGcVec[iW].X() << " " << vGcVec[iW].Y() << endl;
02297     double minDist = DBL_MAX;
02298     gp_XY & wGc = vGcVec[ iW ];
02299     int bIndex;
02300     for ( int iB = 0; iB < nbWires; iB++ ) {
02301       if ( bndFound[ iB ] ) continue;
02302       double dist = ( wGc - gcVec[ iB ] ).SquareModulus();
02303       if ( dist < minDist ) {
02304         minDist = dist;
02305         bIndex = iB;
02306       }
02307     }
02308     bndFound[ bIndex ] = true;
02309     bndIndWirePosMap.insert( TIntWirePosMap::value_type( bIndex, wlIt ));
02310   }
02311 
02312   // Treat each wire
02313 
02314   TIntWirePosMap::iterator bIndWPosIt = bndIndWirePosMap.begin();
02315   eID = theFirstEdgeID;
02316   for ( ; bIndWPosIt != bndIndWirePosMap.end(); bIndWPosIt++ )
02317   {
02318     TListOfEdgesList::iterator wirePos = (*bIndWPosIt).second;
02319     list < TopoDS_Edge > & wire = ( *wirePos );
02320 
02321     // choose the best first edge of a wire
02322     setFirstEdge( wire, eID );
02323 
02324     // compute eventual UV and fill theEdgesPointsList
02325     theEdgesPointsList.push_back( list< TPoint* >() );
02326     list< TPoint* > & edgesPoints = theEdgesPointsList.back();
02327     for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
02328     {
02329       list< TPoint* > & ePoints = getShapePoints( eID++ );
02330       computeUVOnEdge( *eIt, ePoints );
02331       edgesPoints.insert( edgesPoints.end(), ePoints.begin(), (--ePoints.end()));
02332     }
02333     // put wire back to theWireList
02334     wlIt = wirePos++;
02335     theWireList.splice( theToWire, tmpWList, wlIt, wirePos );
02336   }
02337 
02338   return true;
02339 }
02340 
02341 //=======================================================================
02342 //function : Apply
02343 //purpose  : Compute  nodes coordinates applying
02344 //           the loaded pattern to <theFace>. The first key-point
02345 //           will be mapped into <theVertexOnKeyPoint1>
02346 //=======================================================================
02347 
02348 bool SMESH_Pattern::Apply (const TopoDS_Face&   theFace,
02349                            const TopoDS_Vertex& theVertexOnKeyPoint1,
02350                            const bool           theReverse)
02351 {
02352   MESSAGE(" ::Apply(face) " );
02353   TopoDS_Face face  = theReverse ? TopoDS::Face( theFace.Reversed() ) : theFace;
02354   if ( !setShapeToMesh( face ))
02355     return false;
02356 
02357   // find points on edges, it fills myNbKeyPntInBoundary
02358   if ( !findBoundaryPoints() )
02359     return false;
02360 
02361   // Define the edges order so that the first edge starts at
02362   // theVertexOnKeyPoint1
02363 
02364   list< TopoDS_Edge > eList;
02365   list< int >         nbVertexInWires;
02366   int nbWires = SMESH_Block::GetOrderedEdges( face, theVertexOnKeyPoint1, eList, nbVertexInWires);
02367   if ( !theVertexOnKeyPoint1.IsSame( TopExp::FirstVertex( eList.front(), true )))
02368   {
02369     MESSAGE( " theVertexOnKeyPoint1 not found in the outer wire ");
02370     return setErrorCode( ERR_APPLF_BAD_VERTEX );
02371   }
02372   // check nb wires and edges
02373   list< int > l1 = myNbKeyPntInBoundary, l2 = nbVertexInWires;
02374   l1.sort(); l2.sort();
02375   if ( l1 != l2 )
02376   {
02377     MESSAGE( "Wrong nb vertices in wires" );
02378     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
02379   }
02380 
02381   // here shapes get IDs, for the outer wire IDs are OK
02382   list<TopoDS_Edge>::iterator elIt = eList.begin();
02383   for ( ; elIt != eList.end(); elIt++ ) {
02384     myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
02385     bool isClosed1 = BRep_Tool::IsClosed( *elIt, theFace );
02386     // BEGIN: jfa for bug 0019943
02387     if (isClosed1) {
02388       isClosed1 = false;
02389       for (TopExp_Explorer expw (theFace, TopAbs_WIRE); expw.More() && !isClosed1; expw.Next()) {
02390         const TopoDS_Wire& wire = TopoDS::Wire(expw.Current());
02391         int nbe = 0;
02392         for (BRepTools_WireExplorer we (wire, theFace); we.More() && !isClosed1; we.Next()) {
02393           if (we.Current().IsSame(*elIt)) {
02394             nbe++;
02395             if (nbe == 2) isClosed1 = true;
02396           }
02397         }
02398       }
02399     }
02400     // END: jfa for bug 0019943
02401     if (isClosed1)
02402       myShapeIDMap.Add( TopExp::LastVertex( *elIt, true ));// vertex orienation is REVERSED
02403   }
02404   int nbVertices = myShapeIDMap.Extent();
02405 
02406   for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
02407     myShapeIDMap.Add( *elIt );
02408 
02409   myShapeIDMap.Add( face );
02410 
02411   if ( myShapeIDToPointsMap.size() != myShapeIDMap.Extent() ) {
02412     MESSAGE( myShapeIDToPointsMap.size() <<" != " << myShapeIDMap.Extent());
02413     return setErrorCode( ERR_APPLF_INTERNAL_EEROR );
02414   }
02415 
02416   // points on edges to be used for UV computation of in-face points
02417   list< list< TPoint* > > edgesPointsList;
02418   edgesPointsList.push_back( list< TPoint* >() );
02419   list< TPoint* > * edgesPoints = & edgesPointsList.back();
02420   list< TPoint* >::iterator pIt;
02421 
02422   // compute UV of points on the outer wire
02423   int iE, nbEdgesInOuterWire = nbVertexInWires.front();
02424   for (iE = 0, elIt = eList.begin();
02425        iE < nbEdgesInOuterWire && elIt != eList.end();
02426        iE++, elIt++ )
02427   {
02428     list< TPoint* > & ePoints = getShapePoints( *elIt );
02429     // compute UV
02430     computeUVOnEdge( *elIt, ePoints );
02431     // collect on-edge points (excluding the last one)
02432     edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
02433   }
02434 
02435   // If there are several wires, define the order of edges of inner wires:
02436   // compute UV of inner edge-points using 2 methods: the one for in-face points
02437   // and the one for on-edge points and then choose the best edge order
02438   // by the best correspondance of the 2 results
02439   if ( nbWires > 1 )
02440   {
02441     // compute UV of inner edge-points using the method for in-face points
02442     // and devide eList into a list of separate wires
02443     bool aBool;
02444     list< list< TopoDS_Edge > > wireList;
02445     list<TopoDS_Edge>::iterator eIt = elIt;
02446     list<int>::iterator nbEIt = nbVertexInWires.begin();
02447     for ( nbEIt++; nbEIt != nbVertexInWires.end(); nbEIt++ )
02448     {
02449       int nbEdges = *nbEIt;
02450       wireList.push_back( list< TopoDS_Edge >() );
02451       list< TopoDS_Edge > & wire = wireList.back();
02452       for ( iE = 0 ; iE < nbEdges; eIt++, iE++ )
02453       {
02454         list< TPoint* > & ePoints = getShapePoints( *eIt );
02455         pIt = ePoints.begin();
02456         for (  pIt++; pIt != ePoints.end(); pIt++ ) {
02457           TPoint* p = (*pIt);
02458           if ( !compUVByIsoIntersection( edgesPointsList, p->myInitUV, p->myUV, aBool )) {
02459             MESSAGE("cant Apply(face)");
02460             return false;
02461           }
02462           // keep the computed UV to compare against by setFirstEdge()
02463           p->myXYZ.SetCoord( p->myUV.X(), p->myUV.Y(), 0. );
02464         }
02465         wire.push_back( *eIt );
02466       }
02467     }
02468     // remove inner edges from eList
02469     eList.erase( elIt, eList.end() );
02470 
02471     // sort wireList by nb edges in a wire
02472     sortBySize< TopoDS_Edge > ( wireList );
02473 
02474     // an ID of the first edge of a boundary
02475     int id1 = nbVertices + nbEdgesInOuterWire + 1;
02476 //     if ( nbSeamShapes > 0 )
02477 //       id1 += 2; // 2 vertices more
02478 
02479     // find points - edge correspondence for wires of unique size,
02480     // edge order within a wire should be defined only
02481 
02482     list< list< TopoDS_Edge > >::iterator wlIt = wireList.begin();
02483     while ( wlIt != wireList.end() )
02484     {
02485       list< TopoDS_Edge >& wire = (*wlIt);
02486       int nbEdges = wire.size();
02487       wlIt++;
02488       if ( wlIt == wireList.end() || (*wlIt).size() != nbEdges ) // a unique size wire
02489       {
02490         // choose the best first edge of a wire
02491         setFirstEdge( wire, id1 );
02492 
02493         // compute eventual UV and collect on-edge points
02494         edgesPointsList.push_back( list< TPoint* >() );
02495         edgesPoints = & edgesPointsList.back();
02496         int eID = id1;
02497         for ( eIt = wire.begin(); eIt != wire.end(); eIt++ )
02498         {
02499           list< TPoint* > & ePoints = getShapePoints( eID++ );
02500           computeUVOnEdge( *eIt, ePoints );
02501           edgesPoints->insert( edgesPoints->end(), ePoints.begin(), (--ePoints.end()));
02502         }
02503       }
02504       id1 += nbEdges;
02505     }
02506 
02507     // find boundary - wire correspondence for several wires of same size
02508 
02509     id1 = nbVertices + nbEdgesInOuterWire + 1;
02510     wlIt = wireList.begin();
02511     while ( wlIt != wireList.end() )
02512     {
02513       int nbSameSize = 0, nbEdges = (*wlIt).size();
02514       list< list< TopoDS_Edge > >::iterator wlIt2 = wlIt;
02515       wlIt2++;
02516       while ( wlIt2 != wireList.end() && (*wlIt2).size() == nbEdges ) { // a same size wire
02517         nbSameSize++;
02518         wlIt2++;
02519       }
02520       if ( nbSameSize > 0 )
02521         if (!sortSameSizeWires(wireList, wlIt, wlIt2, id1, edgesPointsList))
02522           return false;
02523       wlIt = wlIt2;
02524       id1 += nbEdges * ( nbSameSize + 1 );
02525     }
02526 
02527     // add well-ordered edges to eList
02528 
02529     for ( wlIt = wireList.begin(); wlIt != wireList.end(); wlIt++ )
02530     {
02531       list< TopoDS_Edge >& wire = (*wlIt);
02532       eList.splice( eList.end(), wire, wire.begin(), wire.end() );
02533     }
02534 
02535     // re-fill myShapeIDMap - all shapes get good IDs
02536 
02537     myShapeIDMap.Clear();
02538     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
02539       myShapeIDMap.Add( TopExp::FirstVertex( *elIt, true ));
02540     for ( elIt = eList.begin(); elIt != eList.end(); elIt++ )
02541       myShapeIDMap.Add( *elIt );
02542     myShapeIDMap.Add( face );
02543 
02544   } // there are inner wires
02545 
02546   // Compute XYZ of on-edge points
02547 
02548   TopLoc_Location loc;
02549   for ( iE = nbVertices + 1, elIt = eList.begin(); elIt != eList.end(); elIt++ )
02550   {
02551     BRepAdaptor_Curve C3d( *elIt );
02552     list< TPoint* > & ePoints = getShapePoints( iE++ );
02553     pIt = ePoints.begin();
02554     for ( pIt++; pIt != ePoints.end(); pIt++ )
02555     {
02556       TPoint* point = *pIt;
02557       point->myXYZ = C3d.Value( point->myU );
02558     }
02559   }
02560 
02561   // Compute UV and XYZ of in-face points
02562 
02563   // try to use a simple algo
02564   list< TPoint* > & fPoints = getShapePoints( face );
02565   bool isDeformed = false;
02566   for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
02567     if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
02568                                   (*pIt)->myUV, isDeformed )) {
02569       MESSAGE("cant Apply(face)");
02570       return false;
02571     }
02572   // try to use a complex algo if it is a difficult case
02573   if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
02574   {
02575     for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
02576       if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
02577                                     (*pIt)->myUV, isDeformed )) {
02578         MESSAGE("cant Apply(face)");
02579         return false;
02580       }
02581   }
02582 
02583   Handle(Geom_Surface) aSurface = BRep_Tool::Surface( face, loc );
02584   const gp_Trsf & aTrsf = loc.Transformation();
02585   for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
02586   {
02587     TPoint * point = *pIt;
02588     point->myXYZ = aSurface->Value( point->myUV.X(), point->myUV.Y() );
02589     if ( !loc.IsIdentity() )
02590       aTrsf.Transforms( point->myXYZ.ChangeCoord() );
02591   }
02592 
02593   myIsComputed = true;
02594 
02595   return setErrorCode( ERR_OK );
02596 }
02597 
02598 //=======================================================================
02599 //function : Apply
02600 //purpose  : Compute nodes coordinates applying
02601 //           the loaded pattern to <theFace>. The first key-point
02602 //           will be mapped into <theNodeIndexOnKeyPoint1>-th node
02603 //=======================================================================
02604 
02605 bool SMESH_Pattern::Apply (const SMDS_MeshFace* theFace,
02606                            const int            theNodeIndexOnKeyPoint1,
02607                            const bool           theReverse)
02608 {
02609 //  MESSAGE(" ::Apply(MeshFace) " );
02610 
02611   if ( !IsLoaded() ) {
02612     MESSAGE( "Pattern not loaded" );
02613     return setErrorCode( ERR_APPL_NOT_LOADED );
02614   }
02615 
02616   // check nb of nodes
02617   const int nbFaceNodes = theFace->NbCornerNodes();
02618   if ( nbFaceNodes != myNbKeyPntInBoundary.front() ) {
02619     MESSAGE( myKeyPointIDs.size() << " != " << nbFaceNodes );
02620     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
02621   }
02622 
02623   // find points on edges, it fills myNbKeyPntInBoundary
02624   if ( !findBoundaryPoints() )
02625     return false;
02626 
02627   // check that there are no holes in a pattern
02628   if (myNbKeyPntInBoundary.size() > 1 ) {
02629     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
02630   }
02631 
02632   // Define the nodes order
02633 
02634   list< const SMDS_MeshNode* > nodes;
02635   list< const SMDS_MeshNode* >::iterator n = nodes.end();
02636   SMDS_ElemIteratorPtr noIt = theFace->nodesIterator();
02637   int iSub = 0;
02638   while ( noIt->more() && iSub < nbFaceNodes ) {
02639     const SMDS_MeshNode* node = smdsNode( noIt->next() );
02640     nodes.push_back( node );
02641     if ( iSub++ == theNodeIndexOnKeyPoint1 )
02642       n = --nodes.end();
02643   }
02644   if ( n != nodes.end() ) {
02645     if ( theReverse ) {
02646       if ( n != --nodes.end() )
02647         nodes.splice( nodes.begin(), nodes, ++n, nodes.end() );
02648       nodes.reverse();
02649     }
02650     else if ( n != nodes.begin() )
02651       nodes.splice( nodes.end(), nodes, nodes.begin(), n );
02652   }
02653   list< gp_XYZ > xyzList;
02654   myOrderedNodes.resize( nbFaceNodes );
02655   for ( iSub = 0, n = nodes.begin(); n != nodes.end(); ++n ) {
02656     xyzList.push_back( gp_XYZ( (*n)->X(), (*n)->Y(), (*n)->Z() ));
02657     myOrderedNodes[ iSub++] = *n;
02658   }
02659 
02660   // Define a face plane
02661 
02662   list< gp_XYZ >::iterator xyzIt = xyzList.begin();
02663   gp_Pnt P ( *xyzIt++ );
02664   gp_Vec Vx( P, *xyzIt++ ), N;
02665   do {
02666     N = Vx ^ gp_Vec( P, *xyzIt++ );
02667   } while ( N.SquareMagnitude() <= DBL_MIN && xyzIt != xyzList.end() );
02668   if ( N.SquareMagnitude() <= DBL_MIN )
02669     return setErrorCode( ERR_APPLF_BAD_FACE_GEOM );
02670   gp_Ax2 pos( P, N, Vx );
02671 
02672   // Compute UV of key-points on a plane
02673   for ( xyzIt = xyzList.begin(), iSub = 1; xyzIt != xyzList.end(); xyzIt++, iSub++ )
02674   {
02675     gp_Vec vec ( pos.Location(), *xyzIt );
02676     TPoint* p = getShapePoints( iSub ).front();
02677     p->myUV.SetX( vec * pos.XDirection() );
02678     p->myUV.SetY( vec * pos.YDirection() );
02679     p->myXYZ = *xyzIt;
02680   }
02681 
02682   // points on edges to be used for UV computation of in-face points
02683   list< list< TPoint* > > edgesPointsList;
02684   edgesPointsList.push_back( list< TPoint* >() );
02685   list< TPoint* > * edgesPoints = & edgesPointsList.back();
02686   list< TPoint* >::iterator pIt;
02687 
02688   // compute UV and XYZ of points on edges
02689 
02690   for ( xyzIt = xyzList.begin(); xyzIt != xyzList.end(); iSub++ )
02691   {
02692     gp_XYZ& xyz1 = *xyzIt++;
02693     gp_XYZ& xyz2 = ( xyzIt != xyzList.end() ) ? *xyzIt : xyzList.front();
02694 
02695     list< TPoint* > & ePoints = getShapePoints( iSub );
02696     ePoints.back()->myInitU = 1.0;
02697     list< TPoint* >::const_iterator pIt = ++ePoints.begin();
02698     while ( *pIt != ePoints.back() )
02699     {
02700       TPoint* p = *pIt++;
02701       p->myXYZ = xyz1 * ( 1 - p->myInitU ) + xyz2 * p->myInitU;
02702       gp_Vec vec ( pos.Location(), p->myXYZ );
02703       p->myUV.SetX( vec * pos.XDirection() );
02704       p->myUV.SetY( vec * pos.YDirection() );
02705     }
02706     // collect on-edge points (excluding the last one)
02707     edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
02708   }
02709 
02710   // Compute UV and XYZ of in-face points
02711 
02712   // try to use a simple algo to compute UV
02713   list< TPoint* > & fPoints = getShapePoints( iSub );
02714   bool isDeformed = false;
02715   for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
02716     if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
02717                                   (*pIt)->myUV, isDeformed )) {
02718       MESSAGE("cant Apply(face)");
02719       return false;
02720     }
02721   // try to use a complex algo if it is a difficult case
02722   if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
02723   {
02724     for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
02725       if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
02726                                     (*pIt)->myUV, isDeformed )) {
02727         MESSAGE("cant Apply(face)");
02728         return false;
02729       }
02730   }
02731 
02732   for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
02733   {
02734     (*pIt)->myXYZ = ElSLib::PlaneValue( (*pIt)->myUV.X(), (*pIt)->myUV.Y(), pos );
02735   }
02736 
02737   myIsComputed = true;
02738 
02739   return setErrorCode( ERR_OK );
02740 }
02741 
02742 //=======================================================================
02743 //function : Apply
02744 //purpose  : Compute nodes coordinates applying
02745 //           the loaded pattern to <theFace>. The first key-point
02746 //           will be mapped into <theNodeIndexOnKeyPoint1>-th node
02747 //=======================================================================
02748 
02749 bool SMESH_Pattern::Apply (SMESH_Mesh*          theMesh,
02750                            const SMDS_MeshFace* theFace,
02751                            const TopoDS_Shape&  theSurface,
02752                            const int            theNodeIndexOnKeyPoint1,
02753                            const bool           theReverse)
02754 {
02755 //  MESSAGE(" ::Apply(MeshFace) " );
02756   if ( theSurface.IsNull() || theSurface.ShapeType() != TopAbs_FACE ) {
02757     return Apply( theFace, theNodeIndexOnKeyPoint1, theReverse);
02758   }
02759   const TopoDS_Face& face = TopoDS::Face( theSurface );
02760   TopLoc_Location loc;
02761   Handle(Geom_Surface) surface = BRep_Tool::Surface( face, loc );
02762   const gp_Trsf & aTrsf = loc.Transformation();
02763 
02764   if ( !IsLoaded() ) {
02765     MESSAGE( "Pattern not loaded" );
02766     return setErrorCode( ERR_APPL_NOT_LOADED );
02767   }
02768 
02769   // check nb of nodes
02770   if (theFace->NbNodes() != myNbKeyPntInBoundary.front() ) {
02771     MESSAGE( myKeyPointIDs.size() << " != " << theFace->NbNodes() );
02772     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
02773   }
02774 
02775   // find points on edges, it fills myNbKeyPntInBoundary
02776   if ( !findBoundaryPoints() )
02777     return false;
02778 
02779   // check that there are no holes in a pattern
02780   if (myNbKeyPntInBoundary.size() > 1 ) {
02781     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
02782   }
02783 
02784   // Define the nodes order
02785 
02786   list< const SMDS_MeshNode* > nodes;
02787   list< const SMDS_MeshNode* >::iterator n = nodes.end();
02788   SMDS_ElemIteratorPtr noIt = theFace->nodesIterator();
02789   int iSub = 0;
02790   while ( noIt->more() ) {
02791     const SMDS_MeshNode* node = smdsNode( noIt->next() );
02792     nodes.push_back( node );
02793     if ( iSub++ == theNodeIndexOnKeyPoint1 )
02794       n = --nodes.end();
02795   }
02796   if ( n != nodes.end() ) {
02797     if ( theReverse ) {
02798       if ( n != --nodes.end() )
02799         nodes.splice( nodes.begin(), nodes, ++n, nodes.end() );
02800       nodes.reverse();
02801     }
02802     else if ( n != nodes.begin() )
02803       nodes.splice( nodes.end(), nodes, nodes.begin(), n );
02804   }
02805 
02806   // find a node not on a seam edge, if necessary
02807   SMESH_MesherHelper helper( *theMesh );
02808   helper.SetSubShape( theSurface );
02809   const SMDS_MeshNode* inFaceNode = 0;
02810   if ( helper.GetNodeUVneedInFaceNode() )
02811   {
02812     SMESH_MeshEditor editor( theMesh );
02813     for ( n = nodes.begin(); ( !inFaceNode && n != nodes.end()); ++n ) {
02814       int shapeID = editor.FindShape( *n );
02815       if ( !shapeID )
02816         return Apply( theFace, theNodeIndexOnKeyPoint1, theReverse);
02817       if ( !helper.IsSeamShape( shapeID ))
02818         inFaceNode = *n;
02819     }
02820   }
02821 
02822   // Set UV of key-points (i.e. of nodes of theFace )
02823   vector< gp_XY > keyUV( theFace->NbNodes() );
02824   myOrderedNodes.resize( theFace->NbNodes() );
02825   for ( iSub = 1, n = nodes.begin(); n != nodes.end(); ++n, ++iSub )
02826   {
02827     TPoint* p = getShapePoints( iSub ).front();
02828     p->myUV  = helper.GetNodeUV( face, *n, inFaceNode );
02829     p->myXYZ = gp_XYZ( (*n)->X(), (*n)->Y(), (*n)->Z() );
02830 
02831     keyUV[ iSub-1 ] = p->myUV;
02832     myOrderedNodes[ iSub-1 ] = *n;
02833   }
02834 
02835   // points on edges to be used for UV computation of in-face points
02836   list< list< TPoint* > > edgesPointsList;
02837   edgesPointsList.push_back( list< TPoint* >() );
02838   list< TPoint* > * edgesPoints = & edgesPointsList.back();
02839   list< TPoint* >::iterator pIt;
02840 
02841   // compute UV and XYZ of points on edges
02842 
02843   for ( int i = 0; i < myOrderedNodes.size(); ++i, ++iSub )
02844   {
02845     gp_XY& uv1 = keyUV[ i ];
02846     gp_XY& uv2 = ( i+1 < keyUV.size() ) ? keyUV[ i+1 ] : keyUV[ 0 ];
02847 
02848     list< TPoint* > & ePoints = getShapePoints( iSub );
02849     ePoints.back()->myInitU = 1.0;
02850     list< TPoint* >::const_iterator pIt = ++ePoints.begin();
02851     while ( *pIt != ePoints.back() )
02852     {
02853       TPoint* p = *pIt++;
02854       p->myUV = uv1 * ( 1 - p->myInitU ) + uv2 * p->myInitU;
02855       p->myXYZ = surface->Value( p->myUV.X(), p->myUV.Y() );
02856       if ( !loc.IsIdentity() )
02857         aTrsf.Transforms( p->myXYZ.ChangeCoord() );
02858     }
02859     // collect on-edge points (excluding the last one)
02860     edgesPoints->insert( edgesPoints->end(), ePoints.begin(), --ePoints.end());
02861   }
02862 
02863   // Compute UV and XYZ of in-face points
02864 
02865   // try to use a simple algo to compute UV
02866   list< TPoint* > & fPoints = getShapePoints( iSub );
02867   bool isDeformed = false;
02868   for ( pIt = fPoints.begin(); !isDeformed && pIt != fPoints.end(); pIt++ )
02869     if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
02870                                   (*pIt)->myUV, isDeformed )) {
02871       MESSAGE("cant Apply(face)");
02872       return false;
02873     }
02874   // try to use a complex algo if it is a difficult case
02875   if ( isDeformed && !compUVByElasticIsolines( edgesPointsList, fPoints ))
02876   {
02877     for ( ; pIt != fPoints.end(); pIt++ ) // continue with the simple algo
02878       if ( !compUVByIsoIntersection( edgesPointsList, (*pIt)->myInitUV,
02879                                     (*pIt)->myUV, isDeformed )) {
02880         MESSAGE("cant Apply(face)");
02881         return false;
02882       }
02883   }
02884 
02885   for ( pIt = fPoints.begin(); pIt != fPoints.end(); pIt++ )
02886   {
02887     TPoint * point = *pIt;
02888     point->myXYZ = surface->Value( point->myUV.X(), point->myUV.Y() );
02889     if ( !loc.IsIdentity() )
02890       aTrsf.Transforms( point->myXYZ.ChangeCoord() );
02891   }
02892 
02893   myIsComputed = true;
02894 
02895   return setErrorCode( ERR_OK );
02896 }
02897 
02898 //=======================================================================
02899 //function : undefinedXYZ
02900 //purpose  : 
02901 //=======================================================================
02902 
02903 static const gp_XYZ& undefinedXYZ()
02904 {
02905   static gp_XYZ xyz( 1.e100, 0., 0. );
02906   return xyz;
02907 }
02908 
02909 //=======================================================================
02910 //function : isDefined
02911 //purpose  : 
02912 //=======================================================================
02913 
02914 inline static bool isDefined(const gp_XYZ& theXYZ)
02915 {
02916   return theXYZ.X() < 1.e100;
02917 }
02918 
02919 //=======================================================================
02920 //function : Apply
02921 //purpose  : Compute nodes coordinates applying
02922 //           the loaded pattern to <theFaces>. The first key-point
02923 //           will be mapped into <theNodeIndexOnKeyPoint1>-th node
02924 //=======================================================================
02925 
02926 bool SMESH_Pattern::Apply (SMESH_Mesh*                     theMesh,
02927                            std::set<const SMDS_MeshFace*>& theFaces,
02928                            const int                       theNodeIndexOnKeyPoint1,
02929                            const bool                      theReverse)
02930 {
02931   MESSAGE(" ::Apply(set<MeshFace>) " );
02932 
02933   if ( !IsLoaded() ) {
02934     MESSAGE( "Pattern not loaded" );
02935     return setErrorCode( ERR_APPL_NOT_LOADED );
02936   }
02937 
02938   // find points on edges, it fills myNbKeyPntInBoundary
02939   if ( !findBoundaryPoints() )
02940     return false;
02941 
02942   // check that there are no holes in a pattern
02943   if (myNbKeyPntInBoundary.size() > 1 ) {
02944     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
02945   }
02946 
02947   myShape.Nullify();
02948   myXYZ.clear();
02949   myElemXYZIDs.clear();
02950   myXYZIdToNodeMap.clear();
02951   myElements.clear();
02952   myIdsOnBoundary.clear();
02953   myReverseConnectivity.clear();
02954 
02955   myXYZ.resize( myPoints.size() * theFaces.size(), undefinedXYZ() );
02956   myElements.reserve( theFaces.size() );
02957 
02958   // to find point index
02959   map< TPoint*, int > pointIndex;
02960   for ( int i = 0; i < myPoints.size(); i++ )
02961     pointIndex.insert( make_pair( & myPoints[ i ], i ));
02962 
02963   int ind1 = 0; // lowest point index for a face
02964 
02965   // meshed geometry
02966   TopoDS_Shape shape;
02967 //   int          shapeID = 0;
02968 //   SMESH_MeshEditor editor( theMesh );
02969 
02970   // apply to each face in theFaces set
02971   set<const SMDS_MeshFace*>::iterator face = theFaces.begin();
02972   for ( ; face != theFaces.end(); ++face )
02973   {
02974 //     int curShapeId = editor.FindShape( *face );
02975 //     if ( curShapeId != shapeID ) {
02976 //       if ( curShapeId )
02977 //         shape = theMesh->GetMeshDS()->IndexToShape( curShapeId );
02978 //       else
02979 //         shape.Nullify();
02980 //       shapeID = curShapeId;
02981 //     }
02982     bool ok;
02983     if ( shape.IsNull() )
02984       ok = Apply( *face, theNodeIndexOnKeyPoint1, theReverse );
02985     else
02986       ok = Apply( theMesh, *face, shape, theNodeIndexOnKeyPoint1, theReverse );
02987     if ( !ok ) {
02988       MESSAGE( "Failed on " << *face );
02989       continue;
02990     }
02991     myElements.push_back( *face );
02992 
02993     // store computed points belonging to elements
02994     list< TElemDef >::iterator ll = myElemPointIDs.begin();
02995     for ( ; ll != myElemPointIDs.end(); ++ll )
02996     {
02997       myElemXYZIDs.push_back(TElemDef());
02998       TElemDef& xyzIds = myElemXYZIDs.back();
02999       TElemDef& pIds = *ll;
03000       for ( TElemDef::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
03001         int pIndex = *id + ind1;
03002         xyzIds.push_back( pIndex );
03003         myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
03004         myReverseConnectivity[ pIndex ].push_back( & xyzIds );
03005       }
03006     }
03007     // put points on links to myIdsOnBoundary,
03008     // they will be used to sew new elements on adjacent refined elements
03009     int nbNodes = (*face)->NbCornerNodes(), eID = nbNodes + 1;
03010     for ( int i = 0; i < nbNodes; i++ )
03011     {
03012       list< TPoint* > & linkPoints = getShapePoints( eID++ );
03013       const SMDS_MeshNode* n1 = myOrderedNodes[ i ];
03014       const SMDS_MeshNode* n2 = myOrderedNodes[ i + 1 == nbNodes ? 0 : i + 1 ];
03015       // make a link and a node set
03016       TNodeSet linkSet, node1Set;
03017       linkSet.insert( n1 );
03018       linkSet.insert( n2 );
03019       node1Set.insert( n1 );
03020       list< TPoint* >::iterator p = linkPoints.begin();
03021       {
03022         // map the first link point to n1
03023         int nId = pointIndex[ *p ] + ind1;
03024         myXYZIdToNodeMap[ nId ] = n1;
03025         list< list< int > >& groups = myIdsOnBoundary[ node1Set ];
03026         groups.push_back(list< int > ());
03027         groups.back().push_back( nId );
03028       }
03029       // add the linkSet to the map
03030       list< list< int > >& groups = myIdsOnBoundary[ linkSet ];
03031       groups.push_back(list< int > ());
03032       list< int >& indList = groups.back();
03033       // add points to the map excluding the end points
03034       for ( p++; *p != linkPoints.back(); p++ )
03035         indList.push_back( pointIndex[ *p ] + ind1 );
03036     }
03037     ind1 += myPoints.size();
03038   }
03039 
03040   return !myElemXYZIDs.empty();
03041 }
03042 
03043 //=======================================================================
03044 //function : Apply
03045 //purpose  : Compute nodes coordinates applying
03046 //           the loaded pattern to <theVolumes>. The (0,0,0) key-point
03047 //           will be mapped into <theNode000Index>-th node. The
03048 //           (0,0,1) key-point will be mapped into <theNode000Index>-th
03049 //           node.
03050 //=======================================================================
03051 
03052 bool SMESH_Pattern::Apply (std::set<const SMDS_MeshVolume*> & theVolumes,
03053                            const int                          theNode000Index,
03054                            const int                          theNode001Index)
03055 {
03056   MESSAGE(" ::Apply(set<MeshVolumes>) " );
03057 
03058   if ( !IsLoaded() ) {
03059     MESSAGE( "Pattern not loaded" );
03060     return setErrorCode( ERR_APPL_NOT_LOADED );
03061   }
03062 
03063    // bind ID to points
03064   if ( !findBoundaryPoints() )
03065     return false;
03066 
03067   // check that there are no holes in a pattern
03068   if (myNbKeyPntInBoundary.size() > 1 ) {
03069     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
03070   }
03071 
03072   myShape.Nullify();
03073   myXYZ.clear();
03074   myElemXYZIDs.clear();
03075   myXYZIdToNodeMap.clear();
03076   myElements.clear();
03077   myIdsOnBoundary.clear();
03078   myReverseConnectivity.clear();
03079 
03080   myXYZ.resize( myPoints.size() * theVolumes.size(), undefinedXYZ() );
03081   myElements.reserve( theVolumes.size() );
03082 
03083   // to find point index
03084   map< TPoint*, int > pointIndex;
03085   for ( int i = 0; i < myPoints.size(); i++ )
03086     pointIndex.insert( make_pair( & myPoints[ i ], i ));
03087 
03088   int ind1 = 0; // lowest point index for an element
03089 
03090   // apply to each element in theVolumes set
03091   set<const SMDS_MeshVolume*>::iterator vol = theVolumes.begin();
03092   for ( ; vol != theVolumes.end(); ++vol )
03093   {
03094     if ( !Apply( *vol, theNode000Index, theNode001Index )) {
03095       MESSAGE( "Failed on " << *vol );
03096       continue;
03097     }
03098     myElements.push_back( *vol );
03099 
03100     // store computed points belonging to elements
03101     list< TElemDef >::iterator ll = myElemPointIDs.begin();
03102     for ( ; ll != myElemPointIDs.end(); ++ll )
03103     {
03104       myElemXYZIDs.push_back(TElemDef());
03105       TElemDef& xyzIds = myElemXYZIDs.back();
03106       TElemDef& pIds = *ll;
03107       for ( TElemDef::iterator id = pIds.begin(); id != pIds.end(); id++ ) {
03108         int pIndex = *id + ind1;
03109         xyzIds.push_back( pIndex );
03110         myXYZ[ pIndex ] = myPoints[ *id ].myXYZ.XYZ();
03111         myReverseConnectivity[ pIndex ].push_back( & xyzIds );
03112       }
03113     }
03114     // put points on edges and faces to myIdsOnBoundary,
03115     // they will be used to sew new elements on adjacent refined elements
03116     for ( int Id = SMESH_Block::ID_V000; Id <= SMESH_Block::ID_F1yz; Id++ )
03117     {
03118       // make a set of sub-points
03119       TNodeSet subNodes;
03120       vector< int > subIDs;
03121       if ( SMESH_Block::IsVertexID( Id )) {
03122         subNodes.insert( myOrderedNodes[ Id - 1 ]);
03123       }
03124       else if ( SMESH_Block::IsEdgeID( Id )) {
03125         SMESH_Block::GetEdgeVertexIDs( Id, subIDs );
03126         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
03127         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
03128       }
03129       else {
03130         SMESH_Block::GetFaceEdgesIDs( Id, subIDs );
03131         int e1 = subIDs[ 0 ], e2 = subIDs[ 1 ];
03132         SMESH_Block::GetEdgeVertexIDs( e1, subIDs );
03133         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
03134         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
03135         SMESH_Block::GetEdgeVertexIDs( e2, subIDs );
03136         subNodes.insert( myOrderedNodes[ subIDs.front() - 1 ]);
03137         subNodes.insert( myOrderedNodes[ subIDs.back() - 1 ]);
03138       }
03139       // add points
03140       list< TPoint* > & points = getShapePoints( Id );
03141       list< TPoint* >::iterator p = points.begin();
03142       list< list< int > >& groups = myIdsOnBoundary[ subNodes ];
03143       groups.push_back(list< int > ());
03144       list< int >& indList = groups.back();
03145       for ( ; p != points.end(); p++ )
03146         indList.push_back( pointIndex[ *p ] + ind1 );
03147       if ( subNodes.size() == 1 ) // vertex case
03148         myXYZIdToNodeMap[ indList.back() ] = myOrderedNodes[ Id - 1 ];
03149     }
03150     ind1 += myPoints.size();
03151   }
03152 
03153   return !myElemXYZIDs.empty();
03154 }
03155 
03156 //=======================================================================
03157 //function : Load
03158 //purpose  : Create a pattern from the mesh built on <theBlock>
03159 //=======================================================================
03160 
03161 bool SMESH_Pattern::Load (SMESH_Mesh*         theMesh,
03162                           const TopoDS_Shell& theBlock)
03163 {
03164   MESSAGE(" ::Load(volume) " );
03165   Clear();
03166   myIs2D = false;
03167   SMESHDS_SubMesh * aSubMesh;
03168 
03169   const bool isQuadMesh = theMesh->NbVolumes( ORDER_QUADRATIC );
03170 
03171   // load shapes in myShapeIDMap
03172   SMESH_Block block;
03173   TopoDS_Vertex v1, v2;
03174   if ( !block.LoadBlockShapes( theBlock, v1, v2, myShapeIDMap ))
03175     return setErrorCode( ERR_LOADV_BAD_SHAPE );
03176 
03177   // count nodes
03178   int nbNodes = 0, shapeID;
03179   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
03180   {
03181     const TopoDS_Shape& S = myShapeIDMap( shapeID );
03182     aSubMesh = getSubmeshWithElements( theMesh, S );
03183     if ( aSubMesh )
03184       nbNodes += aSubMesh->NbNodes();
03185   }
03186   myPoints.resize( nbNodes );
03187 
03188   // load U of points on edges
03189   TNodePointIDMap nodePointIDMap;
03190   int iPoint = 0;
03191   for ( shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
03192   {
03193     const TopoDS_Shape& S = myShapeIDMap( shapeID );
03194     list< TPoint* > & shapePoints = getShapePoints( shapeID );
03195     aSubMesh = getSubmeshWithElements( theMesh, S );
03196     if ( ! aSubMesh ) continue;
03197     SMDS_NodeIteratorPtr nIt = aSubMesh->GetNodes();
03198     if ( !nIt->more() ) continue;
03199 
03200       // store a node and a point
03201     while ( nIt->more() ) {
03202       const SMDS_MeshNode* node = smdsNode( nIt->next() );
03203       if ( isQuadMesh && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Volume ))
03204         continue;
03205       nodePointIDMap.insert( make_pair( node, iPoint ));
03206       if ( block.IsVertexID( shapeID ))
03207         myKeyPointIDs.push_back( iPoint );
03208       TPoint* p = & myPoints[ iPoint++ ];
03209       shapePoints.push_back( p );
03210       p->myXYZ.SetCoord( node->X(), node->Y(), node->Z() );
03211       p->myInitXYZ.SetCoord( 0,0,0 );
03212     }
03213     list< TPoint* >::iterator pIt = shapePoints.begin();
03214 
03215     // compute init XYZ
03216     switch ( S.ShapeType() )
03217     {
03218     case TopAbs_VERTEX:
03219     case TopAbs_EDGE: {
03220 
03221       for ( ; pIt != shapePoints.end(); pIt++ ) {
03222         double * coef = block.GetShapeCoef( shapeID );
03223         for ( int iCoord = 1; iCoord <= 3; iCoord++ )
03224           if ( coef[ iCoord - 1] > 0 )
03225             (*pIt)->myInitXYZ.SetCoord( iCoord, 1. );
03226       }
03227       if ( S.ShapeType() == TopAbs_VERTEX )
03228         break;
03229 
03230       const TopoDS_Edge& edge = TopoDS::Edge( S );
03231       double f,l;
03232       BRep_Tool::Range( edge, f, l );
03233       int iCoord     = SMESH_Block::GetCoordIndOnEdge( shapeID );
03234       bool isForward = SMESH_Block::IsForwardEdge( edge, myShapeIDMap );
03235       pIt = shapePoints.begin();
03236       nIt = aSubMesh->GetNodes();
03237       for ( ; nIt->more(); pIt++ )
03238       {
03239         const SMDS_MeshNode* node = nIt->next();
03240         if ( isQuadMesh && SMESH_MeshEditor::IsMedium( node, SMDSAbs_Edge ))
03241           continue;
03242         const SMDS_EdgePosition* epos =
03243           static_cast<const SMDS_EdgePosition*>(node->GetPosition());
03244         double u = ( epos->GetUParameter() - f ) / ( l - f );
03245         (*pIt)->myInitXYZ.SetCoord( iCoord, isForward ? u : 1 - u );
03246       }
03247       break;
03248     }
03249     default:
03250       for ( ; pIt != shapePoints.end(); pIt++ )
03251       {
03252         if ( !block.ComputeParameters( (*pIt)->myXYZ, (*pIt)->myInitXYZ, shapeID )) {
03253           MESSAGE( "!block.ComputeParameters()" );
03254           return setErrorCode( ERR_LOADV_COMPUTE_PARAMS );
03255         }
03256       }
03257     }
03258   } // loop on block sub-shapes
03259 
03260   // load elements
03261 
03262   aSubMesh = getSubmeshWithElements( theMesh, theBlock );
03263   if ( aSubMesh )
03264   {
03265     SMDS_ElemIteratorPtr elemIt = aSubMesh->GetElements();
03266     while ( elemIt->more() ) {
03267       const SMDS_MeshElement* elem = elemIt->next();
03268       myElemPointIDs.push_back( TElemDef() );
03269       TElemDef& elemPoints = myElemPointIDs.back();
03270       int nbNodes = elem->NbCornerNodes();
03271       for ( int i = 0;i < nbNodes; ++i )
03272         elemPoints.push_back( nodePointIDMap[ elem->GetNode( i )]);
03273     }
03274   }
03275 
03276   myIsBoundaryPointsFound = true;
03277 
03278   return setErrorCode( ERR_OK );
03279 }
03280 
03281 //=======================================================================
03282 //function : getSubmeshWithElements
03283 //purpose  : return submesh containing elements bound to theBlock in theMesh
03284 //=======================================================================
03285 
03286 SMESHDS_SubMesh * SMESH_Pattern::getSubmeshWithElements(SMESH_Mesh*         theMesh,
03287                                                         const TopoDS_Shape& theShape)
03288 {
03289   SMESHDS_SubMesh * aSubMesh = theMesh->GetMeshDS()->MeshElements( theShape );
03290   if ( aSubMesh && ( aSubMesh->GetElements()->more() || aSubMesh->GetNodes()->more() ))
03291     return aSubMesh;
03292 
03293   if ( theShape.ShapeType() == TopAbs_SHELL )
03294   {
03295     // look for submesh of VOLUME
03296     TopTools_ListIteratorOfListOfShape it( theMesh->GetAncestors( theShape ));
03297     for (; it.More(); it.Next()) {
03298       aSubMesh = theMesh->GetMeshDS()->MeshElements( it.Value() );
03299       if ( aSubMesh && ( aSubMesh->GetElements()->more() || aSubMesh->GetNodes()->more() ))
03300         return aSubMesh;
03301     }
03302   }
03303   return 0;
03304 }
03305 
03306 
03307 //=======================================================================
03308 //function : Apply
03309 //purpose  : Compute nodes coordinates applying
03310 //           the loaded pattern to <theBlock>. The (0,0,0) key-point
03311 //           will be mapped into <theVertex000>. The (0,0,1)
03312 //           fifth key-point will be mapped into <theVertex001>.
03313 //=======================================================================
03314 
03315 bool SMESH_Pattern::Apply (const TopoDS_Shell&  theBlock,
03316                            const TopoDS_Vertex& theVertex000,
03317                            const TopoDS_Vertex& theVertex001)
03318 {
03319   MESSAGE(" ::Apply(volume) " );
03320 
03321   if (!findBoundaryPoints()     || // bind ID to points
03322       !setShapeToMesh( theBlock )) // check theBlock is a suitable shape
03323     return false;
03324 
03325   SMESH_Block block;  // bind ID to shape
03326   if (!block.LoadBlockShapes( theBlock, theVertex000, theVertex001, myShapeIDMap ))
03327     return setErrorCode( ERR_APPLV_BAD_SHAPE );
03328 
03329   // compute XYZ of points on shapes
03330 
03331   for ( int shapeID = 1; shapeID <= myShapeIDMap.Extent(); shapeID++ )
03332   {
03333     list< TPoint* > & shapePoints = getShapePoints( shapeID );
03334     list< TPoint* >::iterator pIt = shapePoints.begin();
03335     const TopoDS_Shape& S = myShapeIDMap( shapeID );
03336     switch ( S.ShapeType() )
03337     {
03338     case TopAbs_VERTEX: {
03339 
03340       for ( ; pIt != shapePoints.end(); pIt++ )
03341         block.VertexPoint( shapeID, (*pIt)->myXYZ.ChangeCoord() );
03342       break;
03343     }
03344     case TopAbs_EDGE: {
03345 
03346       for ( ; pIt != shapePoints.end(); pIt++ )
03347         block.EdgePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
03348       break;
03349     }
03350     case TopAbs_FACE: {
03351 
03352       for ( ; pIt != shapePoints.end(); pIt++ )
03353         block.FacePoint( shapeID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
03354       break;
03355     }
03356     default:
03357       for ( ; pIt != shapePoints.end(); pIt++ )
03358         block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
03359     }
03360   } // loop on block sub-shapes
03361 
03362   myIsComputed = true;
03363 
03364   return setErrorCode( ERR_OK );
03365 }
03366 
03367 //=======================================================================
03368 //function : Apply
03369 //purpose  : Compute nodes coordinates applying
03370 //           the loaded pattern to <theVolume>. The (0,0,0) key-point
03371 //           will be mapped into <theNode000Index>-th node. The
03372 //           (0,0,1) key-point will be mapped into <theNode000Index>-th
03373 //           node.
03374 //=======================================================================
03375 
03376 bool SMESH_Pattern::Apply (const SMDS_MeshVolume* theVolume,
03377                            const int              theNode000Index,
03378                            const int              theNode001Index)
03379 {
03380   //MESSAGE(" ::Apply(MeshVolume) " );
03381 
03382   if (!findBoundaryPoints()) // bind ID to points
03383     return false;
03384 
03385   SMESH_Block block;  // bind ID to shape
03386   if (!block.LoadMeshBlock( theVolume, theNode000Index, theNode001Index, myOrderedNodes ))
03387     return setErrorCode( ERR_APPLV_BAD_SHAPE );
03388   // compute XYZ of points on shapes
03389 
03390   for ( int ID = SMESH_Block::ID_V000; ID <= SMESH_Block::ID_Shell; ID++ )
03391   {
03392     list< TPoint* > & shapePoints = getShapePoints( ID );
03393     list< TPoint* >::iterator pIt = shapePoints.begin();
03394 
03395     if ( block.IsVertexID( ID ))
03396       for ( ; pIt != shapePoints.end(); pIt++ ) {
03397         block.VertexPoint( ID, (*pIt)->myXYZ.ChangeCoord() );
03398       }
03399     else if ( block.IsEdgeID( ID ))
03400       for ( ; pIt != shapePoints.end(); pIt++ ) {
03401         block.EdgePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
03402       }
03403     else if ( block.IsFaceID( ID ))
03404       for ( ; pIt != shapePoints.end(); pIt++ ) {
03405         block.FacePoint( ID, (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
03406       }
03407     else
03408       for ( ; pIt != shapePoints.end(); pIt++ )
03409         block.ShellPoint( (*pIt)->myInitXYZ, (*pIt)->myXYZ.ChangeCoord() );
03410   } // loop on block sub-shapes
03411 
03412   myIsComputed = true;
03413 
03414   return setErrorCode( ERR_OK );
03415 }
03416 
03417 //=======================================================================
03418 //function : mergePoints
03419 //purpose  : Merge XYZ on edges and/or faces.
03420 //=======================================================================
03421 
03422 void SMESH_Pattern::mergePoints (const bool uniteGroups)
03423 {
03424   map< TNodeSet, list< list< int > > >::iterator idListIt = myIdsOnBoundary.begin();
03425   for ( ; idListIt != myIdsOnBoundary.end(); idListIt++ )
03426   {
03427     list<list< int > >& groups = idListIt->second;
03428     if ( groups.size() < 2 )
03429       continue;
03430 
03431     // find tolerance
03432     const TNodeSet& nodes = idListIt->first;
03433     double tol2 = 1.e-10;
03434     if ( nodes.size() > 1 ) {
03435       Bnd_Box box;
03436       TNodeSet::const_iterator n = nodes.begin();
03437       for ( ; n != nodes.end(); ++n )
03438         box.Add( gp_Pnt( (*n)->X(), (*n)->Y(), (*n)->Z() ));
03439       double x, y, z, X, Y, Z;
03440       box.Get( x, y, z, X, Y, Z );
03441       gp_Pnt p( x, y, z ), P( X, Y, Z );
03442       tol2 = 1.e-4 * p.SquareDistance( P );
03443     }
03444 
03445     // to unite groups on link
03446     bool unite = ( uniteGroups && nodes.size() == 2 );
03447     map< double, int > distIndMap;
03448     const SMDS_MeshNode* node = *nodes.begin();
03449     gp_Pnt P( node->X(), node->Y(), node->Z() );
03450 
03451     // compare points, replace indices
03452 
03453     list< int >::iterator ind1, ind2;
03454     list< list< int > >::iterator grpIt1, grpIt2;
03455     for ( grpIt1 = groups.begin(); grpIt1 != groups.end(); grpIt1++ )
03456     {
03457       list< int >& indices1 = *grpIt1;
03458       grpIt2 = grpIt1;
03459       for ( grpIt2++; grpIt2 != groups.end(); grpIt2++ )
03460       {
03461         list< int >& indices2 = *grpIt2;
03462         for ( ind1 = indices1.begin(); ind1 != indices1.end(); ind1++ )
03463         {
03464           gp_XYZ& p1 = myXYZ[ *ind1 ];
03465           ind2 = indices2.begin();
03466           while ( ind2 != indices2.end() )
03467           {
03468             gp_XYZ& p2 = myXYZ[ *ind2 ];
03469             //MESSAGE("COMP: " << *ind1 << " " << *ind2 << " X: " << p2.X() << " tol2: " << tol2);
03470             if ( ( p1 - p2 ).SquareModulus() <= tol2 )
03471             {
03472               ASSERT( myReverseConnectivity.find( *ind2 ) != myReverseConnectivity.end() );
03473               list< TElemDef* > & elemXYZIDsList = myReverseConnectivity[ *ind2 ];
03474               list< TElemDef* >::iterator elemXYZIDs = elemXYZIDsList.begin();
03475               for ( ; elemXYZIDs != elemXYZIDsList.end(); elemXYZIDs++ )
03476               {
03477                 //MESSAGE( " Replace " << *ind2 << " with " << *ind1 );
03478                 myXYZ[ *ind2 ] = undefinedXYZ();
03479                 replace( (*elemXYZIDs)->begin(), (*elemXYZIDs)->end(), *ind2, *ind1 );
03480               }
03481               ind2 = indices2.erase( ind2 );
03482             }
03483             else
03484               ind2++;
03485           }
03486         }
03487       }
03488       if ( unite ) { // sort indices using distIndMap
03489         for ( ind1 = indices1.begin(); ind1 != indices1.end(); ind1++ )
03490         {
03491           ASSERT( isDefined( myXYZ[ *ind1 ] ));
03492           double dist = P.SquareDistance( myXYZ[ *ind1 ]);
03493           distIndMap.insert( make_pair( dist, *ind1 ));
03494         }
03495       }
03496     }
03497     if ( unite ) { // put all sorted indices into the first group
03498       list< int >& g = groups.front();
03499       g.clear();
03500       map< double, int >::iterator dist_ind = distIndMap.begin();
03501       for ( ; dist_ind != distIndMap.end(); dist_ind++ )
03502         g.push_back( dist_ind->second );
03503     }
03504   } // loop on myIdsOnBoundary
03505 }
03506 
03507 //=======================================================================
03508 //function : makePolyElements
03509 //purpose  : prepare intermediate data to create Polygons and Polyhedrons
03510 //=======================================================================
03511 
03512 void SMESH_Pattern::
03513   makePolyElements(const vector< const SMDS_MeshNode* >& theNodes,
03514                    const bool                            toCreatePolygons,
03515                    const bool                            toCreatePolyedrs)
03516 {
03517   myPolyElemXYZIDs.clear();
03518   myPolyElems.clear();
03519   myPolyElems.reserve( myIdsOnBoundary.size() );
03520 
03521   // make a set of refined elements
03522   TIDSortedElemSet avoidSet, elemSet;
03523   std::vector<const SMDS_MeshElement*>::iterator itv =  myElements.begin();
03524   for(; itv!=myElements.end(); itv++) {
03525     const SMDS_MeshElement* el = (*itv);
03526     avoidSet.insert( el );
03527   }
03528   //avoidSet.insert( myElements.begin(), myElements.end() );
03529 
03530   map< TNodeSet, list< list< int > > >::iterator indListIt, nn_IdList;
03531 
03532   if ( toCreatePolygons )
03533   {
03534     int lastFreeId = myXYZ.size();
03535 
03536     // loop on links of refined elements
03537     indListIt = myIdsOnBoundary.begin();
03538     for ( ; indListIt != myIdsOnBoundary.end(); indListIt++ )
03539     {
03540       const TNodeSet & linkNodes = indListIt->first;
03541       if ( linkNodes.size() != 2 )
03542         continue; // skip face
03543       const SMDS_MeshNode* n1 = * linkNodes.begin();
03544       const SMDS_MeshNode* n2 = * linkNodes.rbegin();
03545 
03546       list<list< int > >& idGroups = indListIt->second; // ids of nodes to build
03547       if ( idGroups.empty() || idGroups.front().empty() )
03548         continue;
03549 
03550       // find not refined face having n1-n2 link
03551 
03552       while (true)
03553       {
03554         const SMDS_MeshElement* face =
03555           SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
03556         if ( face )
03557         {
03558           avoidSet.insert ( face );
03559           myPolyElems.push_back( face );
03560 
03561           // some links of <face> are split;
03562           // make list of xyz for <face>
03563           myPolyElemXYZIDs.push_back(TElemDef());
03564           TElemDef & faceNodeIds = myPolyElemXYZIDs.back();
03565           // loop on links of a <face>
03566           SMDS_ElemIteratorPtr nIt = face->nodesIterator();
03567           int i = 0, nbNodes = face->NbNodes();
03568           vector<const SMDS_MeshNode*> nodes( nbNodes + 1 );
03569           while ( nIt->more() )
03570             nodes[ i++ ] = smdsNode( nIt->next() );
03571           nodes[ i ] = nodes[ 0 ];
03572           for ( i = 0; i < nbNodes; ++i )
03573           {
03574             // look for point mapped on a link
03575             TNodeSet faceLinkNodes;
03576             faceLinkNodes.insert( nodes[ i ] );
03577             faceLinkNodes.insert( nodes[ i + 1 ] );
03578             if ( faceLinkNodes == linkNodes )
03579               nn_IdList = indListIt;
03580             else
03581               nn_IdList = myIdsOnBoundary.find( faceLinkNodes );
03582             // add face point ids
03583             faceNodeIds.push_back( ++lastFreeId );
03584             myXYZIdToNodeMap.insert( make_pair( lastFreeId, nodes[ i ]));
03585             if ( nn_IdList != myIdsOnBoundary.end() )
03586             {
03587               // there are points mapped on a link
03588               list< int >& mappedIds = nn_IdList->second.front();
03589               if ( isReversed( nodes[ i ], mappedIds ))
03590                 faceNodeIds.insert (faceNodeIds.end(),mappedIds.rbegin(), mappedIds.rend() );
03591               else
03592                 faceNodeIds.insert (faceNodeIds.end(),mappedIds.begin(), mappedIds.end() );
03593             }
03594           } // loop on links of a <face>
03595         } // if ( face )
03596         else
03597           break;
03598       } // while (true)
03599 
03600       if ( myIs2D && idGroups.size() > 1 ) {
03601 
03602         // sew new elements on 2 refined elements sharing n1-n2 link
03603 
03604         list< int >& idsOnLink = idGroups.front();
03605         // temporarily add ids of link nodes to idsOnLink
03606         bool rev = isReversed( n1, idsOnLink );
03607         for ( int i = 0; i < 2; ++i )
03608         {
03609           TNodeSet nodeSet;
03610           nodeSet.insert( i ? n2 : n1 );
03611           ASSERT( myIdsOnBoundary.find( nodeSet ) != myIdsOnBoundary.end() );
03612           list<list< int > >& groups = myIdsOnBoundary[ nodeSet ];
03613           int nodeId = groups.front().front();
03614           bool append = i;
03615           if ( rev ) append = !append;
03616           if ( append )
03617             idsOnLink.push_back( nodeId );
03618           else
03619             idsOnLink.push_front( nodeId );
03620         }
03621         list< int >::iterator id = idsOnLink.begin();
03622         for ( ; id != idsOnLink.end(); ++id ) // loop on XYZ ids on a link
03623         {
03624           list< TElemDef* >& elemDefs = myReverseConnectivity[ *id ]; // elems sharing id
03625           list< TElemDef* >::iterator pElemDef = elemDefs.begin();
03626           for ( ; pElemDef != elemDefs.end(); pElemDef++ ) // loop on elements sharing id
03627           {
03628             TElemDef* pIdList = *pElemDef; // ptr on list of ids making element up
03629             // look for <id> in element definition
03630             TElemDef::iterator idDef = find( pIdList->begin(), pIdList->end(), *id );
03631             ASSERT ( idDef != pIdList->end() );
03632             // look for 2 neighbour ids of <id> in element definition
03633             for ( int prev = 0; prev < 2; ++prev ) {
03634               TElemDef::iterator idDef2 = idDef;
03635               if ( prev )
03636                 idDef2 = ( idDef2 == pIdList->begin() ) ? --pIdList->end() : --idDef2;
03637               else
03638                 idDef2 = ( ++idDef2 == pIdList->end() ) ? pIdList->begin() : idDef2;
03639               // look for idDef2 on a link starting from id
03640               list< int >::iterator id2 = find( id, idsOnLink.end(), *idDef2 );
03641               if ( id2 != idsOnLink.end() && id != --id2 ) { // found not next to id
03642                 // insert ids located on link between <id> and <id2>
03643                 // into the element definition between idDef and idDef2
03644                 if ( prev )
03645                   for ( ; id2 != id; --id2 )
03646                     pIdList->insert( idDef, *id2 );
03647                 else {
03648                   list< int >::iterator id1 = id;
03649                   for ( ++id1, ++id2; id1 != id2; ++id1 )
03650                     pIdList->insert( idDef2, *id1 );
03651                 }
03652               }
03653             }
03654           }
03655         }
03656         // remove ids of link nodes
03657         idsOnLink.pop_front();
03658         idsOnLink.pop_back();
03659       }
03660     } // loop on myIdsOnBoundary
03661   } // if ( toCreatePolygons )
03662 
03663   if ( toCreatePolyedrs )
03664   {
03665     // check volumes adjacent to the refined elements
03666     SMDS_VolumeTool volTool;
03667     vector<const SMDS_MeshElement*>::iterator refinedElem = myElements.begin();
03668     for ( ; refinedElem != myElements.end(); ++refinedElem )
03669     {
03670       // loop on nodes of refinedElem
03671       SMDS_ElemIteratorPtr nIt = (*refinedElem)->nodesIterator();
03672       while ( nIt->more() ) {
03673         const SMDS_MeshNode* node = smdsNode( nIt->next() );
03674         // loop on inverse elements of node
03675         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
03676         while ( eIt->more() )
03677         {
03678           const SMDS_MeshElement* elem = eIt->next();
03679           if ( !volTool.Set( elem ) || !avoidSet.insert( elem ).second )
03680             continue; // skip faces or refined elements
03681           // add polyhedron definition
03682           myPolyhedronQuantities.push_back(vector<int> ());
03683           myPolyElemXYZIDs.push_back(TElemDef());
03684           vector<int>& quantity = myPolyhedronQuantities.back();
03685           TElemDef &   elemDef  = myPolyElemXYZIDs.back();
03686           // get definitions of new elements on volume faces
03687           bool makePoly = false;
03688           for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
03689           {
03690             if ( getFacesDefinition(volTool.GetFaceNodes( iF ),
03691                                     volTool.NbFaceNodes( iF ),
03692                                     theNodes, elemDef, quantity))
03693               makePoly = true;
03694           }
03695           if ( makePoly )
03696             myPolyElems.push_back( elem );
03697           else {
03698             myPolyhedronQuantities.pop_back();
03699             myPolyElemXYZIDs.pop_back();
03700           }
03701         }
03702       }
03703     }
03704   }
03705 }
03706 
03707 //=======================================================================
03708 //function : getFacesDefinition
03709 //purpose  : return faces definition for a volume face defined by theBndNodes
03710 //=======================================================================
03711 
03712 bool SMESH_Pattern::
03713   getFacesDefinition(const SMDS_MeshNode**                 theBndNodes,
03714                      const int                             theNbBndNodes,
03715                      const vector< const SMDS_MeshNode* >& theNodes,
03716                      list< int >&                          theFaceDefs,
03717                      vector<int>&                          theQuantity)
03718 {
03719   bool makePoly = false;
03720 
03721   set< const SMDS_MeshNode* > bndNodeSet( theBndNodes, theBndNodes + theNbBndNodes);
03722 
03723   map< TNodeSet, list< list< int > > >::iterator nn_IdList;
03724 
03725   // make a set of all nodes on a face
03726   set< int > ids;
03727   if ( !myIs2D ) { // for 2D, merge only edges
03728     nn_IdList = myIdsOnBoundary.find( bndNodeSet );
03729     if ( nn_IdList != myIdsOnBoundary.end() ) {
03730       list< int > & faceIds = nn_IdList->second.front();
03731       if ( !faceIds.empty() ) {
03732         makePoly = true;
03733         ids.insert( faceIds.begin(), faceIds.end() );
03734       }
03735     }
03736   }
03737 
03738   // add ids on links and bnd nodes
03739   int lastFreeId = Max( myXYZIdToNodeMap.rbegin()->first, theNodes.size() );
03740   TElemDef faceDef; // definition for the case if there is no new adjacent volumes
03741   for ( int iN = 0; iN < theNbBndNodes; ++iN )
03742   {
03743     // add id of iN-th bnd node
03744     TNodeSet nSet;
03745     nSet.insert( theBndNodes[ iN ] );
03746     nn_IdList = myIdsOnBoundary.find( nSet );
03747     int bndId = ++lastFreeId;
03748     if ( nn_IdList != myIdsOnBoundary.end() ) {
03749       bndId = nn_IdList->second.front().front();
03750       ids.insert( bndId );
03751     }
03752     else {
03753       myXYZIdToNodeMap.insert( make_pair( bndId, theBndNodes[ iN ] ));
03754     }
03755     faceDef.push_back( bndId );
03756     // add ids on a link
03757     TNodeSet linkNodes;
03758     linkNodes.insert( theBndNodes[ iN ]);
03759     linkNodes.insert( theBndNodes[ (iN + 1) % theNbBndNodes] );
03760     nn_IdList = myIdsOnBoundary.find( linkNodes );
03761     if ( nn_IdList != myIdsOnBoundary.end() ) {
03762       list< int > & linkIds = nn_IdList->second.front();
03763       if ( !linkIds.empty() )
03764       {
03765         makePoly = true;
03766         ids.insert( linkIds.begin(), linkIds.end() );
03767         if ( isReversed( theBndNodes[ iN ], linkIds ))
03768           faceDef.insert( faceDef.end(), linkIds.begin(), linkIds.end() );
03769         else
03770           faceDef.insert( faceDef.end(), linkIds.rbegin(), linkIds.rend() );
03771       }
03772     }
03773   }
03774 
03775   // find faces definition of new volumes
03776 
03777   bool defsAdded = false;
03778   if ( !myIs2D ) { // for 2D, merge only edges
03779     SMDS_VolumeTool vol;
03780     set< TElemDef* > checkedVolDefs;
03781     set< int >::iterator id = ids.begin();
03782     for ( ; id != ids.end(); ++id )
03783     {
03784       // definitions of volumes sharing id
03785       list< TElemDef* >& defList = myReverseConnectivity[ *id ];
03786       ASSERT( !defList.empty() );
03787       // loop on volume definitions
03788       list< TElemDef* >::iterator pIdList = defList.begin();
03789       for ( ; pIdList != defList.end(); ++pIdList)
03790       {
03791         if ( !checkedVolDefs.insert( *pIdList ).second )
03792           continue; // skip already checked volume definition
03793         vector< int > idVec( (*pIdList)->begin(), (*pIdList)->end() );
03794         // loop on face defs of a volume
03795         SMDS_VolumeTool::VolumeType volType = vol.GetType( idVec.size() );
03796         if ( volType == SMDS_VolumeTool::UNKNOWN )
03797           continue;
03798         int nbFaces = vol.NbFaces( volType );
03799         for ( int iF = 0; iF < nbFaces; ++iF )
03800         {
03801           const int* nodeInds = vol.GetFaceNodesIndices( volType, iF, true );
03802           int iN, nbN = vol.NbFaceNodes( volType, iF );
03803           // check if all nodes of a faces are in <ids>
03804           bool all = true;
03805           for ( iN = 0; iN < nbN && all; ++iN ) {
03806             int nodeId = idVec[ nodeInds[ iN ]];
03807             all = ( ids.find( nodeId ) != ids.end() );
03808           }
03809           if ( all ) {
03810             // store a face definition
03811             for ( iN = 0; iN < nbN; ++iN ) {
03812               theFaceDefs.push_back( idVec[ nodeInds[ iN ]]);
03813             }
03814             theQuantity.push_back( nbN );
03815             defsAdded = true;
03816           }
03817         }
03818       }
03819     }
03820   }
03821   if ( !defsAdded ) {
03822     theQuantity.push_back( faceDef.size() );
03823     theFaceDefs.splice( theFaceDefs.end(), faceDef );
03824   }
03825 
03826   return makePoly;
03827 }
03828 
03829 //=======================================================================
03830 //function : clearSubMesh
03831 //purpose  : 
03832 //=======================================================================
03833 
03834 static bool clearSubMesh( SMESH_Mesh*         theMesh,
03835                           const TopoDS_Shape& theShape)
03836 {
03837   bool removed = false;
03838   if ( SMESH_subMesh * aSubMesh = theMesh->GetSubMeshContaining( theShape ))
03839   {
03840     removed = !aSubMesh->IsEmpty();
03841     if ( removed )
03842       aSubMesh->ComputeStateEngine( SMESH_subMesh::CLEAN );
03843   }
03844   else {
03845     SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
03846     if ( SMESHDS_SubMesh* aSubMeshDS = aMeshDS->MeshElements( theShape ))
03847     {
03848       SMDS_ElemIteratorPtr eIt = aSubMeshDS->GetElements();
03849       removed = eIt->more();
03850       while ( eIt->more() )
03851         aMeshDS->RemoveElement( eIt->next() );
03852       SMDS_NodeIteratorPtr nIt = aSubMeshDS->GetNodes();
03853       removed = removed || nIt->more();
03854       while ( nIt->more() )
03855         aMeshDS->RemoveNode( smdsNode( nIt->next() ));
03856     }
03857   }
03858   return removed;
03859 }
03860 
03861 //=======================================================================
03862 //function : clearMesh
03863 //purpose  : clear mesh elements existing on myShape in theMesh
03864 //=======================================================================
03865 
03866 void SMESH_Pattern::clearMesh(SMESH_Mesh* theMesh) const
03867 {
03868 
03869   if ( !myShape.IsNull() )
03870   {
03871     if ( !clearSubMesh( theMesh, myShape ) && !myIs2D ) { // myShape is SHELL but volumes may be bound to SOLID
03872       TopTools_ListIteratorOfListOfShape it( theMesh->GetAncestors( myShape ));
03873       for (; it.More() && it.Value().ShapeType() == TopAbs_SOLID; it.Next())
03874       {
03875         clearSubMesh( theMesh, it.Value() );
03876       }
03877     }
03878   }
03879 }
03880 
03881 //=======================================================================
03882 //function : MakeMesh
03883 //purpose  : Create nodes and elements in <theMesh> using nodes
03884 //           coordinates computed by either of Apply...() methods
03885 // WARNING : StdMeshers_Projection_... relies on MakeMesh() behavior: that
03886 //           it does not care of nodes and elements already existing on
03887 //           subshapes. DO NOT MERGE them or modify also StdMeshers_Projection_..
03888 //=======================================================================
03889 
03890 bool SMESH_Pattern::MakeMesh(SMESH_Mesh* theMesh,
03891                              const bool  toCreatePolygons,
03892                              const bool  toCreatePolyedrs)
03893 {
03894   MESSAGE(" ::MakeMesh() " );
03895   if ( !myIsComputed )
03896     return setErrorCode( ERR_MAKEM_NOT_COMPUTED );
03897 
03898   mergePoints( toCreatePolygons );
03899 
03900   SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
03901 
03902   // clear elements and nodes existing on myShape
03903   clearMesh(theMesh);
03904 
03905   bool onMeshElements = ( !myElements.empty() );
03906 
03907   // Create missing nodes
03908 
03909   vector< const SMDS_MeshNode* > nodesVector; // i-th point/xyz -> node
03910   if ( onMeshElements )
03911   {
03912     nodesVector.resize( Max( myXYZ.size(), myXYZIdToNodeMap.rbegin()->first ), 0 );
03913     map< int, const SMDS_MeshNode*>::iterator i_node = myXYZIdToNodeMap.begin();
03914     for ( ; i_node != myXYZIdToNodeMap.end(); i_node++ ) {
03915       nodesVector[ i_node->first ] = i_node->second;
03916     }
03917     for ( int i = 0; i < myXYZ.size(); ++i ) {
03918       if ( !nodesVector[ i ] && isDefined( myXYZ[ i ] ) )
03919         nodesVector[ i ] = aMeshDS->AddNode (myXYZ[ i ].X(),
03920                                              myXYZ[ i ].Y(),
03921                                              myXYZ[ i ].Z());
03922     }
03923   }
03924   else
03925   {
03926     nodesVector.resize( myPoints.size(), 0 );
03927 
03928     // to find point index
03929     map< TPoint*, int > pointIndex;
03930     for ( int i = 0; i < myPoints.size(); i++ )
03931       pointIndex.insert( make_pair( & myPoints[ i ], i ));
03932 
03933     // loop on sub-shapes of myShape: create nodes
03934     map< int, list< TPoint* > >::iterator idPointIt = myShapeIDToPointsMap.begin();
03935     for ( ; idPointIt != myShapeIDToPointsMap.end(); idPointIt++ )
03936     {
03937       TopoDS_Shape S;
03938       //SMESHDS_SubMesh * subMeshDS = 0;
03939       if ( !myShapeIDMap.IsEmpty() ) {
03940         S = myShapeIDMap( idPointIt->first );
03941         //subMeshDS = aMeshDS->MeshElements( S );
03942       }
03943       list< TPoint* > & points = idPointIt->second;
03944       list< TPoint* >::iterator pIt = points.begin();
03945       for ( ; pIt != points.end(); pIt++ )
03946       {
03947         TPoint* point = *pIt;
03948         int pIndex = pointIndex[ point ];
03949         if ( nodesVector [ pIndex ] )
03950           continue;
03951         SMDS_MeshNode* node = aMeshDS->AddNode (point->myXYZ.X(),
03952                                                 point->myXYZ.Y(),
03953                                                 point->myXYZ.Z());
03954         nodesVector [ pIndex ] = node;
03955 
03956         if ( !S.IsNull() /*subMeshDS*/ ) {
03957           // !!!!! do not merge new nodes with ones existing on submeshes (see method comment)
03958           switch ( S.ShapeType() ) {
03959           case TopAbs_VERTEX: {
03960             aMeshDS->SetNodeOnVertex( node, TopoDS::Vertex( S )); break;
03961           }
03962           case TopAbs_EDGE: {
03963             aMeshDS->SetNodeOnEdge( node, TopoDS::Edge( S ), point->myU ); break;
03964           }
03965           case TopAbs_FACE: {
03966             aMeshDS->SetNodeOnFace( node, TopoDS::Face( S ),
03967                                     point->myUV.X(), point->myUV.Y() ); break;
03968           }
03969           default:
03970             aMeshDS->SetNodeInVolume( node, TopoDS::Shell( S ));
03971           }
03972         }
03973       }
03974     }
03975   }
03976 
03977   // create elements
03978 
03979   if ( onMeshElements )
03980   {
03981     // prepare data to create poly elements
03982     makePolyElements( nodesVector, toCreatePolygons, toCreatePolyedrs );
03983 
03984     // refine elements
03985     createElements( theMesh, nodesVector, myElemXYZIDs, myElements );
03986     // sew old and new elements
03987     createElements( theMesh, nodesVector, myPolyElemXYZIDs, myPolyElems );
03988   }
03989   else
03990   {
03991     createElements( theMesh, nodesVector, myElemPointIDs, myElements );
03992   }
03993 
03994   aMeshDS->compactMesh();
03995 
03996 //   const map<int,SMESHDS_SubMesh*>& sm = aMeshDS->SubMeshes();
03997 //   map<int,SMESHDS_SubMesh*>::const_iterator i_sm = sm.begin();
03998 //   for ( ; i_sm != sm.end(); i_sm++ )
03999 //   {
04000 //     cout << " SM " << i_sm->first << " ";
04001 //     TopAbs::Print( aMeshDS->IndexToShape( i_sm->first ).ShapeType(), cout)<< " ";
04002 //     //SMDS_ElemIteratorPtr GetElements();
04003 //     SMDS_NodeIteratorPtr nit = i_sm->second->GetNodes();
04004 //     while ( nit->more() )
04005 //       cout << nit->next()->GetID() << " ";
04006 //     cout << endl;
04007 //   }
04008   return setErrorCode( ERR_OK );
04009 }
04010 
04011 //=======================================================================
04012 //function : createElements
04013 //purpose  : add elements to the mesh
04014 //=======================================================================
04015 
04016 void SMESH_Pattern::createElements(SMESH_Mesh*                            theMesh,
04017                                    const vector<const SMDS_MeshNode* >&   theNodesVector,
04018                                    const list< TElemDef > &               theElemNodeIDs,
04019                                    const vector<const SMDS_MeshElement*>& theElements)
04020 {
04021   SMESHDS_Mesh* aMeshDS = theMesh->GetMeshDS();
04022   SMESH_MeshEditor editor( theMesh );
04023 
04024   bool onMeshElements = !theElements.empty();
04025 
04026   // shapes and groups theElements are on
04027   vector< int > shapeIDs;
04028   vector< list< SMESHDS_Group* > > groups;
04029   set< const SMDS_MeshNode* > shellNodes;
04030   if ( onMeshElements )
04031   {
04032     shapeIDs.resize( theElements.size() );
04033     groups.resize( theElements.size() );
04034     const set<SMESHDS_GroupBase*>& allGroups = aMeshDS->GetGroups();
04035     set<SMESHDS_GroupBase*>::const_iterator grIt;
04036     for ( int i = 0; i < theElements.size(); i++ )
04037     {
04038       shapeIDs[ i ] = editor.FindShape( theElements[ i ] );
04039       for ( grIt = allGroups.begin(); grIt != allGroups.end(); grIt++ ) {
04040         SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
04041         if ( group && group->SMDSGroup().Contains( theElements[ i ] ))
04042           groups[ i ].push_back( group );
04043       }
04044     }
04045     // get all nodes bound to shells because their SpacePosition is not set
04046     // by SMESHDS_Mesh::SetNodeInVolume()
04047     TopoDS_Shape aMainShape = aMeshDS->ShapeToMesh();
04048     if ( !aMainShape.IsNull() ) {
04049       TopExp_Explorer shellExp( aMainShape, TopAbs_SHELL );
04050       for ( ; shellExp.More(); shellExp.Next() )
04051       {
04052         SMESHDS_SubMesh * sm = aMeshDS->MeshElements( shellExp.Current() );
04053         if ( sm ) {
04054           SMDS_NodeIteratorPtr nIt = sm->GetNodes();
04055           while ( nIt->more() )
04056             shellNodes.insert( nIt->next() );
04057         }
04058       }
04059     }
04060   }
04061    // nb new elements per a refined element
04062   int nbNewElemsPerOld = 1;
04063   if ( onMeshElements )
04064     nbNewElemsPerOld = theElemNodeIDs.size() / theElements.size();
04065 
04066   bool is2d = myIs2D;
04067 
04068   list< TElemDef >::const_iterator enIt = theElemNodeIDs.begin();
04069   list< vector<int> >::iterator quantity = myPolyhedronQuantities.begin();
04070   for ( int iElem = 0; enIt != theElemNodeIDs.end(); enIt++, iElem++ )
04071   {
04072     const TElemDef & elemNodeInd = *enIt;
04073     // retrieve nodes
04074     vector< const SMDS_MeshNode* > nodes( elemNodeInd.size() );
04075     TElemDef::const_iterator id = elemNodeInd.begin();
04076     int nbNodes;
04077     for ( nbNodes = 0; id != elemNodeInd.end(); id++ ) {
04078       if ( *id < theNodesVector.size() )
04079         nodes[ nbNodes++ ] = theNodesVector[ *id ];
04080       else
04081         nodes[ nbNodes++ ] = myXYZIdToNodeMap[ *id ];
04082     }
04083     // dim of refined elem
04084     int elemIndex = iElem / nbNewElemsPerOld; // refined element index
04085     if ( onMeshElements ) {
04086       is2d = ( theElements[ elemIndex ]->GetType() == SMDSAbs_Face );
04087     }
04088     // add an element
04089     const SMDS_MeshElement* elem = 0;
04090     if ( is2d ) {
04091       switch ( nbNodes ) {
04092       case 3:
04093         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2] ); break;
04094       case 4:
04095         elem = aMeshDS->AddFace( nodes[0], nodes[1], nodes[2], nodes[3] ); break;
04096       case 6:
04097         if ( !onMeshElements ) {// create a quadratic face
04098           elem = aMeshDS->AddFace (nodes[0], nodes[1], nodes[2], nodes[3],
04099                                    nodes[4], nodes[5] ); break;
04100         } // else do not break but create a polygon
04101       case 8:
04102         if ( !onMeshElements ) {// create a quadratic face
04103           elem = aMeshDS->AddFace (nodes[0], nodes[1], nodes[2], nodes[3],
04104                                    nodes[4], nodes[5], nodes[6], nodes[7] ); break;
04105         } // else do not break but create a polygon
04106       default:
04107         elem = aMeshDS->AddPolygonalFace( nodes );
04108       }
04109     }
04110     else {
04111       switch ( nbNodes ) {
04112       case 4:
04113         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3] ); break;
04114       case 5:
04115         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
04116                                    nodes[4] ); break;
04117       case 6:
04118         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
04119                                    nodes[4], nodes[5] ); break;
04120       case 8:
04121         elem = aMeshDS->AddVolume (nodes[0], nodes[1], nodes[2], nodes[3],
04122                                    nodes[4], nodes[5], nodes[6], nodes[7] ); break;
04123       default:
04124         elem = aMeshDS->AddPolyhedralVolume( nodes, *quantity++ );
04125       }
04126     }
04127     // set element on a shape
04128     if ( elem && onMeshElements ) // applied to mesh elements
04129     {
04130       int shapeID = shapeIDs[ elemIndex ];
04131       if ( shapeID > 0 ) {
04132         aMeshDS->SetMeshElementOnShape( elem, shapeID );
04133         // set nodes on a shape
04134         TopoDS_Shape S = aMeshDS->IndexToShape( shapeID );
04135         if ( S.ShapeType() == TopAbs_SOLID ) {
04136           TopoDS_Iterator shellIt( S );
04137           if ( shellIt.More() )
04138             shapeID = aMeshDS->ShapeToIndex( shellIt.Value() );
04139         }
04140         SMDS_ElemIteratorPtr noIt = elem->nodesIterator();
04141         while ( noIt->more() ) {
04142           SMDS_MeshNode* node = const_cast<SMDS_MeshNode*>(smdsNode( noIt->next() ));
04143           if (!node->getshapeId() &&
04144               shellNodes.find( node ) == shellNodes.end() ) {
04145             if ( S.ShapeType() == TopAbs_FACE )
04146               aMeshDS->SetNodeOnFace( node, shapeID,
04147                                       Precision::Infinite(),// <- it's a sign that UV is not set
04148                                       Precision::Infinite());
04149             else {
04150               aMeshDS->SetNodeInVolume( node, shapeID );
04151               shellNodes.insert( node );
04152             }
04153           }
04154         }
04155       }
04156       // add elem in groups
04157       list< SMESHDS_Group* >::iterator g = groups[ elemIndex ].begin();
04158       for ( ; g != groups[ elemIndex ].end(); ++g )
04159         (*g)->SMDSGroup().Add( elem );
04160     }
04161     if ( elem && !myShape.IsNull() ) // applied to shape
04162       aMeshDS->SetMeshElementOnShape( elem, myShape );
04163   }
04164 
04165   // make that SMESH_subMesh::_computeState == COMPUTE_OK
04166   // so that operations with hypotheses will erase the mesh being built
04167 
04168   SMESH_subMesh * subMesh;
04169   if ( !myShape.IsNull() ) {
04170     subMesh = theMesh->GetSubMesh( myShape );
04171     if ( subMesh )
04172       subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
04173   }
04174   if ( onMeshElements ) {
04175     list< int > elemIDs;
04176     for ( int i = 0; i < theElements.size(); i++ )
04177     {
04178       subMesh = theMesh->GetSubMeshContaining( shapeIDs[ i ] );
04179       if ( subMesh )
04180         subMesh->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
04181 
04182       elemIDs.push_back( theElements[ i ]->GetID() );
04183     }
04184     // remove refined elements
04185     editor.Remove( elemIDs, false );
04186   }
04187 }
04188 
04189 //=======================================================================
04190 //function : isReversed
04191 //purpose  : check xyz ids order in theIdsList taking into account
04192 //           theFirstNode on a link
04193 //=======================================================================
04194 
04195 bool SMESH_Pattern::isReversed(const SMDS_MeshNode* theFirstNode,
04196                                const list< int >&   theIdsList) const
04197 {
04198   if ( theIdsList.size() < 2 )
04199     return false;
04200 
04201   gp_Pnt Pf ( theFirstNode->X(), theFirstNode->Y(), theFirstNode->Z() );
04202   gp_Pnt P[2];
04203   list<int>::const_iterator id = theIdsList.begin();
04204   for ( int i = 0; i < 2; ++i, ++id ) {
04205     if ( *id < myXYZ.size() )
04206       P[ i ] = myXYZ[ *id ];
04207     else {
04208       map< int, const SMDS_MeshNode*>::const_iterator i_n;
04209       i_n = myXYZIdToNodeMap.find( *id );
04210       ASSERT( i_n != myXYZIdToNodeMap.end() );
04211       const SMDS_MeshNode* n = i_n->second;
04212       P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
04213     }
04214   }
04215   return Pf.SquareDistance( P[ 1 ] ) < Pf.SquareDistance( P[ 0 ] );
04216 }
04217 
04218 
04219 //=======================================================================
04220 //function : arrangeBoundaries
04221 //purpose  : if there are several wires, arrange boundaryPoints so that
04222 //           the outer wire goes first and fix inner wires orientation
04223 //           update myKeyPointIDs to correspond to the order of key-points
04224 //           in boundaries; sort internal boundaries by the nb of key-points
04225 //=======================================================================
04226 
04227 void SMESH_Pattern::arrangeBoundaries (list< list< TPoint* > >& boundaryList)
04228 {
04229   typedef list< list< TPoint* > >::iterator TListOfListIt;
04230   TListOfListIt bndIt;
04231   list< TPoint* >::iterator pIt;
04232 
04233   int nbBoundaries = boundaryList.size();
04234   if ( nbBoundaries > 1 )
04235   {
04236     // sort boundaries by nb of key-points
04237     if ( nbBoundaries > 2 )
04238     {
04239       // move boundaries in tmp list
04240       list< list< TPoint* > > tmpList;
04241       tmpList.splice( tmpList.begin(), boundaryList, boundaryList.begin(), boundaryList.end());
04242       // make a map nb-key-points to boundary-position-in-tmpList,
04243       // boundary-positions get ordered in it
04244       typedef map< int, TListOfListIt > TNbKpBndPosMap;
04245       TNbKpBndPosMap nbKpBndPosMap;
04246       bndIt = tmpList.begin();
04247       list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
04248       for ( ; nbKpIt != myNbKeyPntInBoundary.end(); nbKpIt++, bndIt++ ) {
04249         int nb = *nbKpIt * nbBoundaries;
04250         while ( nbKpBndPosMap.find ( nb ) != nbKpBndPosMap.end() )
04251           nb++;
04252         nbKpBndPosMap.insert( TNbKpBndPosMap::value_type( nb, bndIt ));
04253       }
04254       // move boundaries back to boundaryList
04255       TNbKpBndPosMap::iterator nbKpBndPosIt = nbKpBndPosMap.begin();
04256       for ( ; nbKpBndPosIt != nbKpBndPosMap.end(); nbKpBndPosIt++ ) {
04257         TListOfListIt & bndPos2 = (*nbKpBndPosIt).second;
04258         TListOfListIt bndPos1 = bndPos2++;
04259         boundaryList.splice( boundaryList.end(), tmpList, bndPos1, bndPos2 );
04260       }
04261     }
04262 
04263     // Look for the outer boundary: the one with the point with the least X
04264     double leastX = DBL_MAX;
04265     TListOfListIt outerBndPos;
04266     for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++ )
04267     {
04268       list< TPoint* >& boundary = (*bndIt);
04269       for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
04270       {
04271         TPoint* point = *pIt;
04272         if ( point->myInitXYZ.X() < leastX ) {
04273           leastX = point->myInitXYZ.X();
04274           outerBndPos = bndIt;
04275         }
04276       }
04277     }
04278 
04279     if ( outerBndPos != boundaryList.begin() )
04280       boundaryList.splice( boundaryList.begin(), boundaryList, outerBndPos, ++outerBndPos );
04281 
04282   } // if nbBoundaries > 1
04283 
04284   // Check boundaries orientation and re-fill myKeyPointIDs
04285 
04286   set< TPoint* > keyPointSet;
04287   list< int >::iterator kpIt = myKeyPointIDs.begin();
04288   for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
04289     keyPointSet.insert( & myPoints[ *kpIt ]);
04290   myKeyPointIDs.clear();
04291 
04292   // update myNbKeyPntInBoundary also
04293   list< int >::iterator nbKpIt = myNbKeyPntInBoundary.begin();
04294 
04295   for ( bndIt = boundaryList.begin(); bndIt != boundaryList.end(); bndIt++, nbKpIt++ )
04296   {
04297     // find the point with the least X
04298     double leastX = DBL_MAX;
04299     list< TPoint* >::iterator xpIt;
04300     list< TPoint* >& boundary = (*bndIt);
04301     for ( pIt = boundary.begin(); pIt != boundary.end(); pIt++)
04302     {
04303       TPoint* point = *pIt;
04304       if ( point->myInitXYZ.X() < leastX ) {
04305         leastX = point->myInitXYZ.X();
04306         xpIt = pIt;
04307       }
04308     }
04309     // find points next to the point with the least X
04310     TPoint* p = *xpIt, *pPrev, *pNext;
04311     if ( p == boundary.front() )
04312       pPrev = *(++boundary.rbegin());
04313     else {
04314       xpIt--;
04315       pPrev = *xpIt;
04316       xpIt++;
04317     }
04318     if ( p == boundary.back() )
04319       pNext = *(++boundary.begin());
04320     else {
04321       xpIt++;
04322       pNext = *xpIt;
04323     }
04324     // vectors of boundary direction near <p>
04325     gp_Vec2d v1( pPrev->myInitUV, p->myInitUV ), v2( p->myInitUV, pNext->myInitUV );
04326     double sqMag1 = v1.SquareMagnitude(), sqMag2 = v2.SquareMagnitude();
04327     if ( sqMag1 > DBL_MIN && sqMag2 > DBL_MIN ) {
04328       double yPrev = v1.Y() / sqrt( sqMag1 );
04329       double yNext = v2.Y() / sqrt( sqMag2 );
04330       double sumY = yPrev + yNext;
04331       bool reverse;
04332       if ( bndIt == boundaryList.begin() ) // outer boundary
04333         reverse = sumY > 0;
04334       else
04335         reverse = sumY < 0;
04336       if ( reverse )
04337         boundary.reverse();
04338     }
04339 
04340     // Put key-point IDs of a well-oriented boundary in myKeyPointIDs
04341     (*nbKpIt) = 0; // count nb of key-points again
04342     pIt = boundary.begin();
04343     for ( ; pIt != boundary.end(); pIt++)
04344     {
04345       TPoint* point = *pIt;
04346       if ( keyPointSet.find( point ) == keyPointSet.end() )
04347         continue;
04348       // find an index of a keypoint
04349       int index = 0;
04350       vector< TPoint >::const_iterator pVecIt = myPoints.begin();
04351       for ( ; pVecIt != myPoints.end(); pVecIt++, index++ )
04352         if ( &(*pVecIt) == point )
04353           break;
04354       myKeyPointIDs.push_back( index );
04355       (*nbKpIt)++;
04356     }
04357     myKeyPointIDs.pop_back(); // remove the first key-point from the back
04358     (*nbKpIt)--;
04359 
04360   } // loop on a list of boundaries
04361 
04362   ASSERT( myKeyPointIDs.size() == keyPointSet.size() );
04363 }
04364 
04365 //=======================================================================
04366 //function : findBoundaryPoints
04367 //purpose  : if loaded from file, find points to map on edges and faces and
04368 //           compute their parameters
04369 //=======================================================================
04370 
04371 bool SMESH_Pattern::findBoundaryPoints()
04372 {
04373   if ( myIsBoundaryPointsFound ) return true;
04374 
04375   MESSAGE(" findBoundaryPoints() ");
04376 
04377   myNbKeyPntInBoundary.clear();
04378 
04379   if ( myIs2D )
04380   {
04381     set< TPoint* > pointsInElems;
04382 
04383     // Find free links of elements:
04384     // put links of all elements in a set and remove links encountered twice
04385 
04386     typedef pair< TPoint*, TPoint*> TLink;
04387     set< TLink > linkSet;
04388     list<TElemDef >::iterator epIt = myElemPointIDs.begin();
04389     for ( ; epIt != myElemPointIDs.end(); epIt++ )
04390     {
04391       TElemDef & elemPoints = *epIt;
04392       TElemDef::iterator pIt = elemPoints.begin();
04393       int prevP = elemPoints.back();
04394       for ( ; pIt != elemPoints.end(); pIt++ ) {
04395         TPoint* p1 = & myPoints[ prevP ];
04396         TPoint* p2 = & myPoints[ *pIt ];
04397         TLink link(( p1 < p2 ? p1 : p2 ), ( p1 < p2 ? p2 : p1 ));
04398         ASSERT( link.first != link.second );
04399         pair<set< TLink >::iterator,bool> itUniq = linkSet.insert( link );
04400         if ( !itUniq.second )
04401           linkSet.erase( itUniq.first );
04402         prevP = *pIt;
04403 
04404         pointsInElems.insert( p1 );
04405       }
04406     }
04407     // Now linkSet contains only free links,
04408     // find the points order that they have in boundaries
04409 
04410     // 1. make a map of key-points
04411     set< TPoint* > keyPointSet;
04412     list< int >::iterator kpIt = myKeyPointIDs.begin();
04413     for ( ; kpIt != myKeyPointIDs.end(); kpIt++ )
04414       keyPointSet.insert( & myPoints[ *kpIt ]);
04415 
04416     // 2. chain up boundary points
04417     list< list< TPoint* > > boundaryList;
04418     boundaryList.push_back( list< TPoint* >() );
04419     list< TPoint* > * boundary = & boundaryList.back();
04420 
04421     TPoint *point1, *point2, *keypoint1;
04422     kpIt = myKeyPointIDs.begin();
04423     point1 = keypoint1 = & myPoints[ *kpIt++ ];
04424     // loop on free links: look for the next point
04425     int iKeyPoint = 0;
04426     set< TLink >::iterator lIt = linkSet.begin();
04427     while ( lIt != linkSet.end() )
04428     {
04429       if ( (*lIt).first == point1 )
04430         point2 = (*lIt).second;
04431       else if ( (*lIt).second == point1 )
04432         point2 = (*lIt).first;
04433       else {
04434         lIt++;
04435         continue;
04436       }
04437       linkSet.erase( lIt );
04438       lIt = linkSet.begin();
04439 
04440       if ( keyPointSet.find( point2 ) == keyPointSet.end() ) // not a key-point
04441       {
04442         boundary->push_back( point2 );
04443       }
04444       else // a key-point found
04445       {
04446         keyPointSet.erase( point2 ); // keyPointSet contains not found key-points only
04447         iKeyPoint++;
04448         if ( point2 != keypoint1 ) // its not the boundary end
04449         {
04450           boundary->push_back( point2 );
04451         }
04452         else  // the boundary end reached
04453         {
04454           boundary->push_front( keypoint1 );
04455           boundary->push_back( keypoint1 );
04456           myNbKeyPntInBoundary.push_back( iKeyPoint );
04457           if ( keyPointSet.empty() )
04458             break; // all boundaries containing key-points are found
04459 
04460           // prepare to search for the next boundary
04461           boundaryList.push_back( list< TPoint* >() );
04462           boundary = & boundaryList.back();
04463           point2 = keypoint1 = (*keyPointSet.begin());
04464         }
04465       }
04466       point1 = point2;
04467     } // loop on the free links set
04468 
04469     if ( boundary->empty() ) {
04470       MESSAGE(" a separate key-point");
04471       return setErrorCode( ERR_READ_BAD_KEY_POINT );
04472     }
04473 
04474     // if there are several wires, arrange boundaryPoints so that
04475     // the outer wire goes first and fix inner wires orientation;
04476     // sort myKeyPointIDs to correspond to the order of key-points
04477     // in boundaries
04478     arrangeBoundaries( boundaryList );
04479 
04480     // Find correspondence shape ID - points,
04481     // compute points parameter on edge
04482 
04483     keyPointSet.clear();
04484     for ( kpIt = myKeyPointIDs.begin(); kpIt != myKeyPointIDs.end(); kpIt++ )
04485       keyPointSet.insert( & myPoints[ *kpIt ]);
04486 
04487     set< TPoint* > edgePointSet; // to find in-face points
04488     int vertexID = 1; // the first index in TopTools_IndexedMapOfShape
04489     int edgeID = myKeyPointIDs.size() + 1;
04490 
04491     list< list< TPoint* > >::iterator bndIt = boundaryList.begin();
04492     for ( ; bndIt != boundaryList.end(); bndIt++ )
04493     {
04494       boundary = & (*bndIt);
04495       double edgeLength = 0;
04496       list< TPoint* >::iterator pIt = boundary->begin();
04497       getShapePoints( edgeID ).push_back( *pIt );
04498       getShapePoints( vertexID++ ).push_back( *pIt );
04499       for ( pIt++; pIt != boundary->end(); pIt++)
04500       {
04501         list< TPoint* > & edgePoints = getShapePoints( edgeID );
04502         TPoint* prevP = edgePoints.empty() ? 0 : edgePoints.back();
04503         TPoint* point = *pIt;
04504         edgePointSet.insert( point );
04505         if ( keyPointSet.find( point ) == keyPointSet.end() ) // inside-edge point
04506         {
04507           edgePoints.push_back( point );
04508           edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
04509           point->myInitU = edgeLength;
04510         }
04511         else // a key-point
04512         {
04513           // treat points on the edge which ends up: compute U [0,1]
04514           edgePoints.push_back( point );
04515           if ( edgePoints.size() > 2 ) {
04516             edgeLength += ( point->myInitUV - prevP->myInitUV ).Modulus();
04517             list< TPoint* >::iterator epIt = edgePoints.begin();
04518             for ( ; epIt != edgePoints.end(); epIt++ )
04519               (*epIt)->myInitU /= edgeLength;
04520           }
04521           // begin the next edge treatment
04522           edgeLength = 0;
04523           edgeID++;
04524           if ( point != boundary->front() ) { // not the first key-point again
04525             getShapePoints( edgeID ).push_back( point );
04526             getShapePoints( vertexID++ ).push_back( point );
04527           }
04528         }
04529       }
04530     }
04531 
04532     // find in-face points
04533     list< TPoint* > & facePoints = getShapePoints( edgeID );
04534     vector< TPoint >::iterator pVecIt = myPoints.begin();
04535     for ( ; pVecIt != myPoints.end(); pVecIt++ ) {
04536       TPoint* point = &(*pVecIt);
04537       if ( edgePointSet.find( point ) == edgePointSet.end() &&
04538           pointsInElems.find( point ) != pointsInElems.end())
04539         facePoints.push_back( point );
04540     }
04541 
04542   } // 2D case
04543 
04544   else // 3D case
04545   {
04546     // bind points to shapes according to point parameters
04547     vector< TPoint >::iterator pVecIt = myPoints.begin();
04548     for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ ) {
04549       TPoint* point = &(*pVecIt);
04550       int shapeID = SMESH_Block::GetShapeIDByParams( point->myInitXYZ );
04551       getShapePoints( shapeID ).push_back( point );
04552       // detect key-points
04553       if ( SMESH_Block::IsVertexID( shapeID ))
04554         myKeyPointIDs.push_back( i );
04555     }
04556   }
04557 
04558   myIsBoundaryPointsFound = true;
04559   return myIsBoundaryPointsFound;
04560 }
04561 
04562 //=======================================================================
04563 //function : Clear
04564 //purpose  : clear fields
04565 //=======================================================================
04566 
04567 void SMESH_Pattern::Clear()
04568 {
04569   myIsComputed = myIsBoundaryPointsFound = false;
04570 
04571   myPoints.clear();
04572   myKeyPointIDs.clear();
04573   myElemPointIDs.clear();
04574   myShapeIDToPointsMap.clear();
04575   myShapeIDMap.Clear();
04576   myShape.Nullify();
04577   myNbKeyPntInBoundary.clear();
04578 
04579   myXYZ.clear();
04580   myElemXYZIDs.clear();
04581   myXYZIdToNodeMap.clear();
04582   myElements.clear();
04583   myOrderedNodes.clear();
04584   myPolyElems.clear();
04585   myPolyElemXYZIDs.clear();
04586   myPolyhedronQuantities.clear();
04587   myIdsOnBoundary.clear();
04588   myReverseConnectivity.clear();
04589 }
04590 
04591 //================================================================================
04595 //================================================================================
04596 
04597 bool SMESH_Pattern::setErrorCode( const ErrorCode theErrorCode )
04598 {
04599   myErrorCode = theErrorCode;
04600   return myErrorCode == ERR_OK;
04601 }
04602 
04603 //=======================================================================
04604 //function : setShapeToMesh
04605 //purpose  : set a shape to be meshed. Return True if meshing is possible
04606 //=======================================================================
04607 
04608 bool SMESH_Pattern::setShapeToMesh(const TopoDS_Shape& theShape)
04609 {
04610   if ( !IsLoaded() ) {
04611     MESSAGE( "Pattern not loaded" );
04612     return setErrorCode( ERR_APPL_NOT_LOADED );
04613   }
04614 
04615   TopAbs_ShapeEnum aType = theShape.ShapeType();
04616   bool dimOk = ( myIs2D ? aType == TopAbs_FACE : aType == TopAbs_SHELL );
04617   if ( !dimOk ) {
04618     MESSAGE( "Pattern dimention mismatch" );
04619     return setErrorCode( ERR_APPL_BAD_DIMENTION );
04620   }
04621 
04622   // check if a face is closed
04623   int nbNodeOnSeamEdge = 0;
04624   if ( myIs2D ) {
04625     TopTools_MapOfShape seamVertices;
04626     TopoDS_Face face = TopoDS::Face( theShape );
04627     TopExp_Explorer eExp( theShape, TopAbs_EDGE );
04628     for ( ; eExp.More() && nbNodeOnSeamEdge == 0; eExp.Next() ) {
04629       const TopoDS_Edge& ee = TopoDS::Edge(eExp.Current());
04630       if ( BRep_Tool::IsClosed(ee, face) ) {
04631         // seam edge and vertices encounter twice in theFace
04632         if ( !seamVertices.Add( TopExp::FirstVertex( ee ))) nbNodeOnSeamEdge++;
04633         if ( !seamVertices.Add( TopExp::LastVertex( ee ))) nbNodeOnSeamEdge++;
04634       }
04635     }
04636   }
04637 
04638   // check nb of vertices
04639   TopTools_IndexedMapOfShape vMap;
04640   TopExp::MapShapes( theShape, TopAbs_VERTEX, vMap );
04641   if ( vMap.Extent() + nbNodeOnSeamEdge != myKeyPointIDs.size() ) {
04642     MESSAGE( myKeyPointIDs.size() + nbNodeOnSeamEdge << " != " << vMap.Extent() );
04643     return setErrorCode( ERR_APPL_BAD_NB_VERTICES );
04644   }
04645 
04646   myElements.clear(); // not refine elements
04647   myElemXYZIDs.clear();
04648 
04649   myShapeIDMap.Clear();
04650   myShape = theShape;
04651   return true;
04652 }
04653 
04654 //=======================================================================
04655 //function : GetMappedPoints
04656 //purpose  : Return nodes coordinates computed by Apply() method
04657 //=======================================================================
04658 
04659 bool SMESH_Pattern::GetMappedPoints ( list< const gp_XYZ * > & thePoints ) const
04660 {
04661   thePoints.clear();
04662   if ( !myIsComputed )
04663     return false;
04664 
04665   if ( myElements.empty() ) { // applied to shape
04666     vector< TPoint >::const_iterator pVecIt = myPoints.begin();
04667     for ( ; pVecIt != myPoints.end(); pVecIt++ )
04668       thePoints.push_back( & (*pVecIt).myXYZ.XYZ() );
04669   }
04670   else { // applied to mesh elements
04671     const gp_XYZ * definedXYZ = & myPoints[ myKeyPointIDs.front() ].myXYZ.XYZ();
04672     vector<gp_XYZ>::const_iterator xyz = myXYZ.begin();
04673     for ( ; xyz != myXYZ.end(); ++xyz )
04674       if ( !isDefined( *xyz ))
04675         thePoints.push_back( definedXYZ );
04676       else
04677         thePoints.push_back( & (*xyz) );
04678   }
04679   return !thePoints.empty();
04680 }
04681 
04682 
04683 //=======================================================================
04684 //function : GetPoints
04685 //purpose  : Return nodes coordinates of the pattern
04686 //=======================================================================
04687 
04688 bool SMESH_Pattern::GetPoints ( list< const gp_XYZ * > & thePoints ) const
04689 {
04690   thePoints.clear();
04691 
04692   if ( !IsLoaded() )
04693     return false;
04694 
04695   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
04696   for ( ; pVecIt != myPoints.end(); pVecIt++ )
04697     thePoints.push_back( & (*pVecIt).myInitXYZ );
04698 
04699   return ( thePoints.size() > 0 );
04700 }
04701 
04702 //=======================================================================
04703 //function : getShapePoints
04704 //purpose  : return list of points located on theShape
04705 //=======================================================================
04706 
04707 list< SMESH_Pattern::TPoint* > &
04708   SMESH_Pattern::getShapePoints(const TopoDS_Shape& theShape)
04709 {
04710   int aShapeID;
04711   if ( !myShapeIDMap.Contains( theShape ))
04712     aShapeID = myShapeIDMap.Add( theShape );
04713   else
04714     aShapeID = myShapeIDMap.FindIndex( theShape );
04715 
04716   return myShapeIDToPointsMap[ aShapeID ];
04717 }
04718 
04719 //=======================================================================
04720 //function : getShapePoints
04721 //purpose  : return list of points located on the shape
04722 //=======================================================================
04723 
04724 list< SMESH_Pattern::TPoint* > & SMESH_Pattern::getShapePoints(const int theShapeID)
04725 {
04726   return myShapeIDToPointsMap[ theShapeID ];
04727 }
04728 
04729 //=======================================================================
04730 //function : DumpPoints
04731 //purpose  : Debug
04732 //=======================================================================
04733 
04734 void SMESH_Pattern::DumpPoints() const
04735 {
04736 #ifdef _DEBUG_
04737   vector< TPoint >::const_iterator pVecIt = myPoints.begin();
04738   for ( int i = 0; pVecIt != myPoints.end(); pVecIt++, i++ )
04739     MESSAGE_ADD ( std::endl << i << ": " << *pVecIt );
04740 #endif
04741 }
04742 
04743 //=======================================================================
04744 //function : TPoint()
04745 //purpose  : 
04746 //=======================================================================
04747 
04748 SMESH_Pattern::TPoint::TPoint()
04749 {
04750 #ifdef _DEBUG_
04751   myInitXYZ.SetCoord(0,0,0);
04752   myInitUV.SetCoord(0.,0.);
04753   myInitU = 0;
04754   myXYZ.SetCoord(0,0,0);
04755   myUV.SetCoord(0.,0.);
04756   myU = 0;
04757 #endif
04758 }
04759 
04760 //=======================================================================
04761 //function : operator <<
04762 //purpose  : 
04763 //=======================================================================
04764 
04765 ostream & operator <<(ostream & OS, const SMESH_Pattern::TPoint& p)
04766 {
04767   gp_XYZ xyz = p.myInitXYZ;
04768   OS << "\tinit( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
04769   gp_XY xy = p.myInitUV;
04770   OS << " uv( " <<  xy.X() << " " << xy.Y() << " )";
04771   double u = p.myInitU;
04772   OS << " u( " <<  u << " )) " << &p << endl;
04773   xyz = p.myXYZ.XYZ();
04774   OS << "\t    ( xyz( " << xyz.X() << " " << xyz.Y() << " " << xyz.Z() << " )";
04775   xy = p.myUV;
04776   OS << " uv( " <<  xy.X() << " " << xy.Y() << " )";
04777   u = p.myU;
04778   OS << " u( " <<  u << " ))" << endl;
04779 
04780   return OS;
04781 }
Copyright © 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE
Copyright © 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS