Version: 6.3.1

src/SMESH/SMESH_MeshEditor.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 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
00024 // File      : SMESH_MeshEditor.cxx
00025 // Created   : Mon Apr 12 16:10:22 2004
00026 // Author    : Edward AGAPOV (eap)
00027 //
00028 #define CHRONODEF
00029 #include "SMESH_MeshEditor.hxx"
00030 
00031 #include "SMDS_FaceOfNodes.hxx"
00032 #include "SMDS_VolumeTool.hxx"
00033 #include "SMDS_EdgePosition.hxx"
00034 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
00035 #include "SMDS_FacePosition.hxx"
00036 #include "SMDS_SpacePosition.hxx"
00037 //#include "SMDS_QuadraticFaceOfNodes.hxx"
00038 #include "SMDS_MeshGroup.hxx"
00039 #include "SMDS_LinearEdge.hxx"
00040 #include "SMDS_Downward.hxx"
00041 #include "SMDS_SetIterator.hxx"
00042 
00043 #include "SMESHDS_Group.hxx"
00044 #include "SMESHDS_Mesh.hxx"
00045 
00046 #include "SMESH_Algo.hxx"
00047 #include "SMESH_ControlsDef.hxx"
00048 #include "SMESH_Group.hxx"
00049 #include "SMESH_MesherHelper.hxx"
00050 #include "SMESH_OctreeNode.hxx"
00051 #include "SMESH_subMesh.hxx"
00052 
00053 #include "utilities.h"
00054 
00055 #include <BRepAdaptor_Surface.hxx>
00056 #include <BRepClass3d_SolidClassifier.hxx>
00057 #include <BRep_Tool.hxx>
00058 #include <ElCLib.hxx>
00059 #include <Extrema_GenExtPS.hxx>
00060 #include <Extrema_POnCurv.hxx>
00061 #include <Extrema_POnSurf.hxx>
00062 #include <GC_MakeSegment.hxx>
00063 #include <Geom2d_Curve.hxx>
00064 #include <GeomAPI_ExtremaCurveCurve.hxx>
00065 #include <GeomAdaptor_Surface.hxx>
00066 #include <Geom_Curve.hxx>
00067 #include <Geom_Line.hxx>
00068 #include <Geom_Surface.hxx>
00069 #include <IntAna_IntConicQuad.hxx>
00070 #include <IntAna_Quadric.hxx>
00071 #include <Precision.hxx>
00072 #include <TColStd_ListOfInteger.hxx>
00073 #include <TopAbs_State.hxx>
00074 #include <TopExp.hxx>
00075 #include <TopExp_Explorer.hxx>
00076 #include <TopTools_ListIteratorOfListOfShape.hxx>
00077 #include <TopTools_ListOfShape.hxx>
00078 #include <TopTools_SequenceOfShape.hxx>
00079 #include <TopoDS.hxx>
00080 #include <TopoDS_Face.hxx>
00081 #include <gp.hxx>
00082 #include <gp_Ax1.hxx>
00083 #include <gp_Dir.hxx>
00084 #include <gp_Lin.hxx>
00085 #include <gp_Pln.hxx>
00086 #include <gp_Trsf.hxx>
00087 #include <gp_Vec.hxx>
00088 #include <gp_XY.hxx>
00089 #include <gp_XYZ.hxx>
00090 
00091 #include <math.h>
00092 
00093 #include <map>
00094 #include <set>
00095 #include <numeric>
00096 #include <limits>
00097 #include <algorithm>
00098 #include <sstream>
00099 
00100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
00101 
00102 using namespace std;
00103 using namespace SMESH::Controls;
00104 
00105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
00106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
00107 
00108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
00109 
00110 //=======================================================================
00111 //function : SMESH_MeshEditor
00112 //purpose  :
00113 //=======================================================================
00114 
00115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
00116   :myMesh( theMesh ) // theMesh may be NULL
00117 {
00118 }
00119 
00120 //=======================================================================
00124 //=======================================================================
00125 
00126 SMDS_MeshElement*
00127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
00128                              const SMDSAbs_ElementType            type,
00129                              const bool                           isPoly,
00130                              const int                            ID)
00131 {
00132   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
00133   SMDS_MeshElement* e = 0;
00134   int nbnode = node.size();
00135   SMESHDS_Mesh* mesh = GetMeshDS();
00136   switch ( type ) {
00137   case SMDSAbs_Face:
00138     if ( !isPoly ) {
00139       if      (nbnode == 3) {
00140         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
00141         else           e = mesh->AddFace      (node[0], node[1], node[2] );
00142       }
00143       else if (nbnode == 4) {
00144         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
00145         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
00146       }
00147       else if (nbnode == 6) {
00148         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
00149                                                node[4], node[5], ID);
00150         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
00151                                                node[4], node[5] );
00152       }
00153       else if (nbnode == 8) {
00154         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
00155                                                node[4], node[5], node[6], node[7], ID);
00156         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
00157                                                node[4], node[5], node[6], node[7] );
00158       }
00159     } else {
00160       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
00161       else           e = mesh->AddPolygonalFace      (node    );
00162     }
00163     break;
00164 
00165   case SMDSAbs_Volume:
00166     if ( !isPoly ) {
00167       if      (nbnode == 4) {
00168         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
00169         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
00170       }
00171       else if (nbnode == 5) {
00172         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00173                                                  node[4], ID);
00174         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00175                                                  node[4] );
00176       }
00177       else if (nbnode == 6) {
00178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00179                                                  node[4], node[5], ID);
00180         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00181                                                  node[4], node[5] );
00182       }
00183       else if (nbnode == 8) {
00184         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00185                                                  node[4], node[5], node[6], node[7], ID);
00186         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00187                                                  node[4], node[5], node[6], node[7] );
00188       }
00189       else if (nbnode == 10) {
00190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00191                                                  node[4], node[5], node[6], node[7],
00192                                                  node[8], node[9], ID);
00193         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00194                                                  node[4], node[5], node[6], node[7],
00195                                                  node[8], node[9] );
00196       }
00197       else if (nbnode == 13) {
00198         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00199                                                  node[4], node[5], node[6], node[7],
00200                                                  node[8], node[9], node[10],node[11],
00201                                                  node[12],ID);
00202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00203                                                  node[4], node[5], node[6], node[7],
00204                                                  node[8], node[9], node[10],node[11],
00205                                                  node[12] );
00206       }
00207       else if (nbnode == 15) {
00208         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00209                                                  node[4], node[5], node[6], node[7],
00210                                                  node[8], node[9], node[10],node[11],
00211                                                  node[12],node[13],node[14],ID);
00212         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00213                                                  node[4], node[5], node[6], node[7],
00214                                                  node[8], node[9], node[10],node[11],
00215                                                  node[12],node[13],node[14] );
00216       }
00217       else if (nbnode == 20) {
00218         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00219                                                  node[4], node[5], node[6], node[7],
00220                                                  node[8], node[9], node[10],node[11],
00221                                                  node[12],node[13],node[14],node[15],
00222                                                  node[16],node[17],node[18],node[19],ID);
00223         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00224                                                  node[4], node[5], node[6], node[7],
00225                                                  node[8], node[9], node[10],node[11],
00226                                                  node[12],node[13],node[14],node[15],
00227                                                  node[16],node[17],node[18],node[19] );
00228       }
00229     }
00230     break;
00231 
00232   case SMDSAbs_Edge:
00233     if ( nbnode == 2 ) {
00234       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
00235       else           e = mesh->AddEdge      (node[0], node[1] );
00236     }
00237     else if ( nbnode == 3 ) {
00238       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
00239       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
00240     }
00241     break;
00242 
00243   case SMDSAbs_0DElement:
00244     if ( nbnode == 1 ) {
00245       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
00246       else           e = mesh->Add0DElement      (node[0] );
00247     }
00248     break;
00249 
00250   case SMDSAbs_Node:
00251     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
00252     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
00253     break;
00254 
00255   default:;
00256   }
00257   if ( e ) myLastCreatedElems.Append( e );
00258   return e;
00259 }
00260 
00261 //=======================================================================
00265 //=======================================================================
00266 
00267 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
00268                                                const SMDSAbs_ElementType type,
00269                                                const bool                isPoly,
00270                                                const int                 ID)
00271 {
00272   vector<const SMDS_MeshNode*> nodes;
00273   nodes.reserve( nodeIDs.size() );
00274   vector<int>::const_iterator id = nodeIDs.begin();
00275   while ( id != nodeIDs.end() ) {
00276     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
00277       nodes.push_back( node );
00278     else
00279       return 0;
00280   }
00281   return AddElement( nodes, type, isPoly, ID );
00282 }
00283 
00284 //=======================================================================
00285 //function : Remove
00286 //purpose  : Remove a node or an element.
00287 //           Modify a compute state of sub-meshes which become empty
00288 //=======================================================================
00289 
00290 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
00291                               const bool         isNodes )
00292 {
00293   myLastCreatedElems.Clear();
00294   myLastCreatedNodes.Clear();
00295 
00296   SMESHDS_Mesh* aMesh = GetMeshDS();
00297   set< SMESH_subMesh *> smmap;
00298 
00299   int removed = 0;
00300   list<int>::const_iterator it = theIDs.begin();
00301   for ( ; it != theIDs.end(); it++ ) {
00302     const SMDS_MeshElement * elem;
00303     if ( isNodes )
00304       elem = aMesh->FindNode( *it );
00305     else
00306       elem = aMesh->FindElement( *it );
00307     if ( !elem )
00308       continue;
00309 
00310     // Notify VERTEX sub-meshes about modification
00311     if ( isNodes ) {
00312       const SMDS_MeshNode* node = cast2Node( elem );
00313       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
00314         if ( int aShapeID = node->getshapeId() )
00315           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
00316             smmap.insert( sm );
00317     }
00318     // Find sub-meshes to notify about modification
00319     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
00320     //     while ( nodeIt->more() ) {
00321     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
00322     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
00323     //       if ( aPosition.get() ) {
00324     //         if ( int aShapeID = aPosition->GetShapeId() ) {
00325     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
00326     //             smmap.insert( sm );
00327     //         }
00328     //       }
00329     //     }
00330 
00331     // Do remove
00332     if ( isNodes )
00333       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
00334     else
00335       aMesh->RemoveElement( elem );
00336     removed++;
00337   }
00338 
00339   // Notify sub-meshes about modification
00340   if ( !smmap.empty() ) {
00341     set< SMESH_subMesh *>::iterator smIt;
00342     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
00343       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
00344   }
00345 
00346   //   // Check if the whole mesh becomes empty
00347   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
00348   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
00349 
00350   return removed;
00351 }
00352 
00353 //=======================================================================
00354 //function : FindShape
00355 //purpose  : Return an index of the shape theElem is on
00356 //           or zero if a shape not found
00357 //=======================================================================
00358 
00359 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
00360 {
00361   myLastCreatedElems.Clear();
00362   myLastCreatedNodes.Clear();
00363 
00364   SMESHDS_Mesh * aMesh = GetMeshDS();
00365   if ( aMesh->ShapeToMesh().IsNull() )
00366     return 0;
00367 
00368   int aShapeID = theElem->getshapeId();
00369   if ( aShapeID < 1 )
00370     return 0;
00371 
00372   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
00373     if ( sm->Contains( theElem ))
00374       return aShapeID;
00375 
00376   if ( theElem->GetType() == SMDSAbs_Node ) {
00377     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
00378   }
00379   else {
00380     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
00381   }
00382 
00383   TopoDS_Shape aShape; // the shape a node of theElem is on
00384   if ( theElem->GetType() != SMDSAbs_Node )
00385   {
00386     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
00387     while ( nodeIt->more() ) {
00388       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
00389       if ((aShapeID = node->getshapeId()) > 0) {
00390         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
00391           if ( sm->Contains( theElem ))
00392             return aShapeID;
00393           if ( aShape.IsNull() )
00394             aShape = aMesh->IndexToShape( aShapeID );
00395         }
00396       }
00397     }
00398   }
00399 
00400   // None of nodes is on a proper shape,
00401   // find the shape among ancestors of aShape on which a node is
00402   if ( !aShape.IsNull() ) {
00403     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
00404     for ( ; ancIt.More(); ancIt.Next() ) {
00405       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
00406       if ( sm && sm->Contains( theElem ))
00407         return aMesh->ShapeToIndex( ancIt.Value() );
00408     }
00409   }
00410   else
00411   {
00412     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
00413     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
00414     for ( ; id_sm != id2sm.end(); ++id_sm )
00415       if ( id_sm->second->Contains( theElem ))
00416         return id_sm->first;
00417   }
00418 
00419   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
00420   return 0;
00421 }
00422 
00423 //=======================================================================
00424 //function : IsMedium
00425 //purpose  :
00426 //=======================================================================
00427 
00428 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
00429                                 const SMDSAbs_ElementType typeToCheck)
00430 {
00431   bool isMedium = false;
00432   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
00433   while (it->more() && !isMedium ) {
00434     const SMDS_MeshElement* elem = it->next();
00435     isMedium = elem->IsMediumNode(node);
00436   }
00437   return isMedium;
00438 }
00439 
00440 //=======================================================================
00441 //function : ShiftNodesQuadTria
00442 //purpose  : auxilary
00443 //           Shift nodes in the array corresponded to quadratic triangle
00444 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
00445 //=======================================================================
00446 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
00447 {
00448   const SMDS_MeshNode* nd1 = aNodes[0];
00449   aNodes[0] = aNodes[1];
00450   aNodes[1] = aNodes[2];
00451   aNodes[2] = nd1;
00452   const SMDS_MeshNode* nd2 = aNodes[3];
00453   aNodes[3] = aNodes[4];
00454   aNodes[4] = aNodes[5];
00455   aNodes[5] = nd2;
00456 }
00457 
00458 //=======================================================================
00459 //function : GetNodesFromTwoTria
00460 //purpose  : auxilary
00461 //           Shift nodes in the array corresponded to quadratic triangle
00462 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
00463 //=======================================================================
00464 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
00465                                 const SMDS_MeshElement * theTria2,
00466                                 const SMDS_MeshNode* N1[],
00467                                 const SMDS_MeshNode* N2[])
00468 {
00469   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
00470   int i=0;
00471   while(i<6) {
00472     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
00473     i++;
00474   }
00475   if(it->more()) return false;
00476   it = theTria2->nodesIterator();
00477   i=0;
00478   while(i<6) {
00479     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
00480     i++;
00481   }
00482   if(it->more()) return false;
00483 
00484   int sames[3] = {-1,-1,-1};
00485   int nbsames = 0;
00486   int j;
00487   for(i=0; i<3; i++) {
00488     for(j=0; j<3; j++) {
00489       if(N1[i]==N2[j]) {
00490         sames[i] = j;
00491         nbsames++;
00492         break;
00493       }
00494     }
00495   }
00496   if(nbsames!=2) return false;
00497   if(sames[0]>-1) {
00498     ShiftNodesQuadTria(N1);
00499     if(sames[1]>-1) {
00500       ShiftNodesQuadTria(N1);
00501     }
00502   }
00503   i = sames[0] + sames[1] + sames[2];
00504   for(; i<2; i++) {
00505     ShiftNodesQuadTria(N2);
00506   }
00507   // now we receive following N1 and N2 (using numeration as above image)
00508   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
00509   // i.e. first nodes from both arrays determ new diagonal
00510   return true;
00511 }
00512 
00513 //=======================================================================
00514 //function : InverseDiag
00515 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
00516 //           but having other common link.
00517 //           Return False if args are improper
00518 //=======================================================================
00519 
00520 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
00521                                     const SMDS_MeshElement * theTria2 )
00522 {
00523   MESSAGE("InverseDiag");
00524   myLastCreatedElems.Clear();
00525   myLastCreatedNodes.Clear();
00526 
00527   if (!theTria1 || !theTria2)
00528     return false;
00529 
00530   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
00531   if (!F1) return false;
00532   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
00533   if (!F2) return false;
00534   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
00535       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
00536 
00537     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
00538     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
00539     //    |/ |                                         | \|
00540     //  B +--+ 2                                     B +--+ 2
00541 
00542     // put nodes in array and find out indices of the same ones
00543     const SMDS_MeshNode* aNodes [6];
00544     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
00545     int i = 0;
00546     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
00547     while ( it->more() ) {
00548       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
00549 
00550       if ( i > 2 ) // theTria2
00551         // find same node of theTria1
00552         for ( int j = 0; j < 3; j++ )
00553           if ( aNodes[ i ] == aNodes[ j ]) {
00554             sameInd[ j ] = i;
00555             sameInd[ i ] = j;
00556             break;
00557           }
00558       // next
00559       i++;
00560       if ( i == 3 ) {
00561         if ( it->more() )
00562           return false; // theTria1 is not a triangle
00563         it = theTria2->nodesIterator();
00564       }
00565       if ( i == 6 && it->more() )
00566         return false; // theTria2 is not a triangle
00567     }
00568 
00569     // find indices of 1,2 and of A,B in theTria1
00570     int iA = 0, iB = 0, i1 = 0, i2 = 0;
00571     for ( i = 0; i < 6; i++ ) {
00572       if ( sameInd [ i ] == 0 ) {
00573         if ( i < 3 ) i1 = i;
00574         else         i2 = i;
00575       }
00576       else if (i < 3) {
00577         if ( iA ) iB = i;
00578         else      iA = i;
00579       }
00580     }
00581     // nodes 1 and 2 should not be the same
00582     if ( aNodes[ i1 ] == aNodes[ i2 ] )
00583       return false;
00584 
00585     // theTria1: A->2
00586     aNodes[ iA ] = aNodes[ i2 ];
00587     // theTria2: B->1
00588     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
00589 
00590     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
00591     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
00592 
00593     return true;
00594 
00595   } // end if(F1 && F2)
00596 
00597   // check case of quadratic faces
00598   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
00599     return false;
00600   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
00601     return false;
00602 
00603   //       5
00604   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
00605   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
00606   //    |   / |
00607   //  7 +  +  + 6
00608   //    | /9  |
00609   //    |/    |
00610   //  4 +--+--+ 3
00611   //       8
00612 
00613   const SMDS_MeshNode* N1 [6];
00614   const SMDS_MeshNode* N2 [6];
00615   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
00616     return false;
00617   // now we receive following N1 and N2 (using numeration as above image)
00618   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
00619   // i.e. first nodes from both arrays determ new diagonal
00620 
00621   const SMDS_MeshNode* N1new [6];
00622   const SMDS_MeshNode* N2new [6];
00623   N1new[0] = N1[0];
00624   N1new[1] = N2[0];
00625   N1new[2] = N2[1];
00626   N1new[3] = N1[4];
00627   N1new[4] = N2[3];
00628   N1new[5] = N1[5];
00629   N2new[0] = N1[0];
00630   N2new[1] = N1[1];
00631   N2new[2] = N2[0];
00632   N2new[3] = N1[3];
00633   N2new[4] = N2[5];
00634   N2new[5] = N1[4];
00635   // replaces nodes in faces
00636   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
00637   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
00638 
00639   return true;
00640 }
00641 
00642 //=======================================================================
00643 //function : findTriangles
00644 //purpose  : find triangles sharing theNode1-theNode2 link
00645 //=======================================================================
00646 
00647 static bool findTriangles(const SMDS_MeshNode *    theNode1,
00648                           const SMDS_MeshNode *    theNode2,
00649                           const SMDS_MeshElement*& theTria1,
00650                           const SMDS_MeshElement*& theTria2)
00651 {
00652   if ( !theNode1 || !theNode2 ) return false;
00653 
00654   theTria1 = theTria2 = 0;
00655 
00656   set< const SMDS_MeshElement* > emap;
00657   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
00658   while (it->more()) {
00659     const SMDS_MeshElement* elem = it->next();
00660     if ( elem->NbNodes() == 3 )
00661       emap.insert( elem );
00662   }
00663   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
00664   while (it->more()) {
00665     const SMDS_MeshElement* elem = it->next();
00666     if ( emap.find( elem ) != emap.end() ) {
00667       if ( theTria1 ) {
00668         // theTria1 must be element with minimum ID
00669         if( theTria1->GetID() < elem->GetID() ) {
00670           theTria2 = elem;
00671         }
00672         else {
00673           theTria2 = theTria1;
00674           theTria1 = elem;
00675         }
00676         break;
00677       }
00678       else {
00679         theTria1 = elem;
00680       }
00681     }
00682   }
00683   return ( theTria1 && theTria2 );
00684 }
00685 
00686 //=======================================================================
00687 //function : InverseDiag
00688 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
00689 //           with ones built on the same 4 nodes but having other common link.
00690 //           Return false if proper faces not found
00691 //=======================================================================
00692 
00693 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
00694                                     const SMDS_MeshNode * theNode2)
00695 {
00696   myLastCreatedElems.Clear();
00697   myLastCreatedNodes.Clear();
00698 
00699   MESSAGE( "::InverseDiag()" );
00700 
00701   const SMDS_MeshElement *tr1, *tr2;
00702   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
00703     return false;
00704 
00705   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
00706   if (!F1) return false;
00707   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
00708   if (!F2) return false;
00709   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
00710       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
00711 
00712     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
00713     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
00714     //    |/ |                                    | \|
00715     //  B +--+ 2                                B +--+ 2
00716 
00717     // put nodes in array
00718     // and find indices of 1,2 and of A in tr1 and of B in tr2
00719     int i, iA1 = 0, i1 = 0;
00720     const SMDS_MeshNode* aNodes1 [3];
00721     SMDS_ElemIteratorPtr it;
00722     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
00723       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
00724       if ( aNodes1[ i ] == theNode1 )
00725         iA1 = i; // node A in tr1
00726       else if ( aNodes1[ i ] != theNode2 )
00727         i1 = i;  // node 1
00728     }
00729     int iB2 = 0, i2 = 0;
00730     const SMDS_MeshNode* aNodes2 [3];
00731     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
00732       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
00733       if ( aNodes2[ i ] == theNode2 )
00734         iB2 = i; // node B in tr2
00735       else if ( aNodes2[ i ] != theNode1 )
00736         i2 = i;  // node 2
00737     }
00738 
00739     // nodes 1 and 2 should not be the same
00740     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
00741       return false;
00742 
00743     // tr1: A->2
00744     aNodes1[ iA1 ] = aNodes2[ i2 ];
00745     // tr2: B->1
00746     aNodes2[ iB2 ] = aNodes1[ i1 ];
00747 
00748     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
00749     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
00750 
00751     return true;
00752   }
00753 
00754   // check case of quadratic faces
00755   return InverseDiag(tr1,tr2);
00756 }
00757 
00758 //=======================================================================
00759 //function : getQuadrangleNodes
00760 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
00761 //           fusion of triangles tr1 and tr2 having shared link on
00762 //           theNode1 and theNode2
00763 //=======================================================================
00764 
00765 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
00766                         const SMDS_MeshNode *    theNode1,
00767                         const SMDS_MeshNode *    theNode2,
00768                         const SMDS_MeshElement * tr1,
00769                         const SMDS_MeshElement * tr2 )
00770 {
00771   if( tr1->NbNodes() != tr2->NbNodes() )
00772     return false;
00773   // find the 4-th node to insert into tr1
00774   const SMDS_MeshNode* n4 = 0;
00775   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
00776   int i=0;
00777   while ( !n4 && i<3 ) {
00778     const SMDS_MeshNode * n = cast2Node( it->next() );
00779     i++;
00780     bool isDiag = ( n == theNode1 || n == theNode2 );
00781     if ( !isDiag )
00782       n4 = n;
00783   }
00784   // Make an array of nodes to be in a quadrangle
00785   int iNode = 0, iFirstDiag = -1;
00786   it = tr1->nodesIterator();
00787   i=0;
00788   while ( i<3 ) {
00789     const SMDS_MeshNode * n = cast2Node( it->next() );
00790     i++;
00791     bool isDiag = ( n == theNode1 || n == theNode2 );
00792     if ( isDiag ) {
00793       if ( iFirstDiag < 0 )
00794         iFirstDiag = iNode;
00795       else if ( iNode - iFirstDiag == 1 )
00796         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
00797     }
00798     else if ( n == n4 ) {
00799       return false; // tr1 and tr2 should not have all the same nodes
00800     }
00801     theQuadNodes[ iNode++ ] = n;
00802   }
00803   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
00804     theQuadNodes[ iNode ] = n4;
00805 
00806   return true;
00807 }
00808 
00809 //=======================================================================
00810 //function : DeleteDiag
00811 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
00812 //           with a quadrangle built on the same 4 nodes.
00813 //           Return false if proper faces not found
00814 //=======================================================================
00815 
00816 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
00817                                    const SMDS_MeshNode * theNode2)
00818 {
00819   myLastCreatedElems.Clear();
00820   myLastCreatedNodes.Clear();
00821 
00822   MESSAGE( "::DeleteDiag()" );
00823 
00824   const SMDS_MeshElement *tr1, *tr2;
00825   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
00826     return false;
00827 
00828   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
00829   if (!F1) return false;
00830   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
00831   if (!F2) return false;
00832   SMESHDS_Mesh * aMesh = GetMeshDS();
00833 
00834   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
00835       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
00836 
00837     const SMDS_MeshNode* aNodes [ 4 ];
00838     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
00839       return false;
00840 
00841     const SMDS_MeshElement* newElem = 0;
00842     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
00843     myLastCreatedElems.Append(newElem);
00844     AddToSameGroups( newElem, tr1, aMesh );
00845     int aShapeId = tr1->getshapeId();
00846     if ( aShapeId )
00847       {
00848         aMesh->SetMeshElementOnShape( newElem, aShapeId );
00849       }
00850     aMesh->RemoveElement( tr1 );
00851     aMesh->RemoveElement( tr2 );
00852 
00853     return true;
00854   }
00855 
00856   // check case of quadratic faces
00857   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
00858     return false;
00859   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
00860     return false;
00861 
00862   //       5
00863   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
00864   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
00865   //    |   / |
00866   //  7 +  +  + 6
00867   //    | /9  |
00868   //    |/    |
00869   //  4 +--+--+ 3
00870   //       8
00871 
00872   const SMDS_MeshNode* N1 [6];
00873   const SMDS_MeshNode* N2 [6];
00874   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
00875     return false;
00876   // now we receive following N1 and N2 (using numeration as above image)
00877   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
00878   // i.e. first nodes from both arrays determ new diagonal
00879 
00880   const SMDS_MeshNode* aNodes[8];
00881   aNodes[0] = N1[0];
00882   aNodes[1] = N1[1];
00883   aNodes[2] = N2[0];
00884   aNodes[3] = N2[1];
00885   aNodes[4] = N1[3];
00886   aNodes[5] = N2[5];
00887   aNodes[6] = N2[3];
00888   aNodes[7] = N1[5];
00889 
00890   const SMDS_MeshElement* newElem = 0;
00891   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
00892                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
00893   myLastCreatedElems.Append(newElem);
00894   AddToSameGroups( newElem, tr1, aMesh );
00895   int aShapeId = tr1->getshapeId();
00896   if ( aShapeId )
00897     {
00898       aMesh->SetMeshElementOnShape( newElem, aShapeId );
00899     }
00900   aMesh->RemoveElement( tr1 );
00901   aMesh->RemoveElement( tr2 );
00902 
00903   // remove middle node (9)
00904   GetMeshDS()->RemoveNode( N1[4] );
00905 
00906   return true;
00907 }
00908 
00909 //=======================================================================
00910 //function : Reorient
00911 //purpose  : Reverse theElement orientation
00912 //=======================================================================
00913 
00914 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
00915 {
00916   MESSAGE("Reorient");
00917   myLastCreatedElems.Clear();
00918   myLastCreatedNodes.Clear();
00919 
00920   if (!theElem)
00921     return false;
00922   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
00923   if ( !it || !it->more() )
00924     return false;
00925 
00926   switch ( theElem->GetType() ) {
00927 
00928   case SMDSAbs_Edge:
00929   case SMDSAbs_Face: {
00930     if(!theElem->IsQuadratic()) {
00931       int i = theElem->NbNodes();
00932       vector<const SMDS_MeshNode*> aNodes( i );
00933       while ( it->more() )
00934         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
00935       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
00936     }
00937     else {
00938       // quadratic elements
00939       if(theElem->GetType()==SMDSAbs_Edge) {
00940         vector<const SMDS_MeshNode*> aNodes(3);
00941         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
00942         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
00943         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
00944         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
00945       }
00946       else {
00947         int nbn = theElem->NbNodes();
00948         vector<const SMDS_MeshNode*> aNodes(nbn);
00949         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
00950         int i=1;
00951         for(; i<nbn/2; i++) {
00952           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
00953         }
00954         for(i=0; i<nbn/2; i++) {
00955           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
00956         }
00957         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
00958       }
00959     }
00960   }
00961   case SMDSAbs_Volume: {
00962     if (theElem->IsPoly()) {
00963       // TODO reorient vtk polyhedron
00964       MESSAGE("reorient vtk polyhedron ?");
00965       const SMDS_VtkVolume* aPolyedre =
00966         dynamic_cast<const SMDS_VtkVolume*>( theElem );
00967       if (!aPolyedre) {
00968         MESSAGE("Warning: bad volumic element");
00969         return false;
00970       }
00971 
00972       int nbFaces = aPolyedre->NbFaces();
00973       vector<const SMDS_MeshNode *> poly_nodes;
00974       vector<int> quantities (nbFaces);
00975 
00976       // reverse each face of the polyedre
00977       for (int iface = 1; iface <= nbFaces; iface++) {
00978         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
00979         quantities[iface - 1] = nbFaceNodes;
00980 
00981         for (inode = nbFaceNodes; inode >= 1; inode--) {
00982           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
00983           poly_nodes.push_back(curNode);
00984         }
00985       }
00986 
00987       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
00988 
00989     }
00990     else {
00991       SMDS_VolumeTool vTool;
00992       if ( !vTool.Set( theElem ))
00993         return false;
00994       vTool.Inverse();
00995       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
00996       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
00997     }
00998   }
00999   default:;
01000   }
01001 
01002   return false;
01003 }
01004 
01005 //=======================================================================
01006 //function : getBadRate
01007 //purpose  :
01008 //=======================================================================
01009 
01010 static double getBadRate (const SMDS_MeshElement*               theElem,
01011                           SMESH::Controls::NumericalFunctorPtr& theCrit)
01012 {
01013   SMESH::Controls::TSequenceOfXYZ P;
01014   if ( !theElem || !theCrit->GetPoints( theElem, P ))
01015     return 1e100;
01016   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
01017   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
01018 }
01019 
01020 //=======================================================================
01021 //function : QuadToTri
01022 //purpose  : Cut quadrangles into triangles.
01023 //           theCrit is used to select a diagonal to cut
01024 //=======================================================================
01025 
01026 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
01027                                   SMESH::Controls::NumericalFunctorPtr theCrit)
01028 {
01029   myLastCreatedElems.Clear();
01030   myLastCreatedNodes.Clear();
01031 
01032   MESSAGE( "::QuadToTri()" );
01033 
01034   if ( !theCrit.get() )
01035     return false;
01036 
01037   SMESHDS_Mesh * aMesh = GetMeshDS();
01038 
01039   Handle(Geom_Surface) surface;
01040   SMESH_MesherHelper   helper( *GetMesh() );
01041 
01042   TIDSortedElemSet::iterator itElem;
01043   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
01044     const SMDS_MeshElement* elem = *itElem;
01045     if ( !elem || elem->GetType() != SMDSAbs_Face )
01046       continue;
01047     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
01048       continue;
01049 
01050     // retrieve element nodes
01051     const SMDS_MeshNode* aNodes [8];
01052     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
01053     int i = 0;
01054     while ( itN->more() )
01055       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
01056 
01057     // compare two sets of possible triangles
01058     double aBadRate1, aBadRate2; // to what extent a set is bad
01059     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
01060     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
01061     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
01062 
01063     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
01064     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
01065     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
01066 
01067     int aShapeId = FindShape( elem );
01068     const SMDS_MeshElement* newElem1 = 0;
01069     const SMDS_MeshElement* newElem2 = 0;
01070 
01071     if( !elem->IsQuadratic() ) {
01072 
01073       // split liner quadrangle
01074       if ( aBadRate1 <= aBadRate2 ) {
01075         // tr1 + tr2 is better
01076         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
01077         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
01078       }
01079       else {
01080         // tr3 + tr4 is better
01081         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
01082         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
01083       }
01084     }
01085     else {
01086 
01087       // split quadratic quadrangle
01088 
01089       // get surface elem is on
01090       if ( aShapeId != helper.GetSubShapeID() ) {
01091         surface.Nullify();
01092         TopoDS_Shape shape;
01093         if ( aShapeId > 0 )
01094           shape = aMesh->IndexToShape( aShapeId );
01095         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
01096           TopoDS_Face face = TopoDS::Face( shape );
01097           surface = BRep_Tool::Surface( face );
01098           if ( !surface.IsNull() )
01099             helper.SetSubShape( shape );
01100         }
01101       }
01102       // get elem nodes
01103       const SMDS_MeshNode* aNodes [8];
01104       const SMDS_MeshNode* inFaceNode = 0;
01105       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
01106       int i = 0;
01107       while ( itN->more() ) {
01108         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
01109         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
01110              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
01111         {
01112           inFaceNode = aNodes[ i-1 ];
01113         }
01114       }
01115       // find middle point for (0,1,2,3)
01116       // and create a node in this point;
01117       gp_XYZ p( 0,0,0 );
01118       if ( surface.IsNull() ) {
01119         for(i=0; i<4; i++)
01120           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
01121         p /= 4;
01122       }
01123       else {
01124         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
01125         gp_XY uv( 0,0 );
01126         for(i=0; i<4; i++)
01127           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
01128         uv /= 4.;
01129         p = surface->Value( uv.X(), uv.Y() ).XYZ();
01130       }
01131       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
01132       myLastCreatedNodes.Append(newN);
01133 
01134       // create a new element
01135       if ( aBadRate1 <= aBadRate2 ) {
01136         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
01137                                   aNodes[6], aNodes[7], newN );
01138         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
01139                                   newN,      aNodes[4], aNodes[5] );
01140       }
01141       else {
01142         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
01143                                   aNodes[7], aNodes[4], newN );
01144         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
01145                                   newN,      aNodes[5], aNodes[6] );
01146       }
01147     } // quadratic case
01148 
01149     // care of a new element
01150 
01151     myLastCreatedElems.Append(newElem1);
01152     myLastCreatedElems.Append(newElem2);
01153     AddToSameGroups( newElem1, elem, aMesh );
01154     AddToSameGroups( newElem2, elem, aMesh );
01155 
01156     // put a new triangle on the same shape
01157     if ( aShapeId )
01158       {
01159         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
01160         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
01161       }
01162     aMesh->RemoveElement( elem );
01163   }
01164   return true;
01165 }
01166 
01167 //=======================================================================
01168 //function : BestSplit
01169 //purpose  : Find better diagonal for cutting.
01170 //=======================================================================
01171 
01172 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
01173                                  SMESH::Controls::NumericalFunctorPtr theCrit)
01174 {
01175   myLastCreatedElems.Clear();
01176   myLastCreatedNodes.Clear();
01177 
01178   if (!theCrit.get())
01179     return -1;
01180 
01181   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
01182     return -1;
01183 
01184   if( theQuad->NbNodes()==4 ||
01185       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
01186 
01187     // retrieve element nodes
01188     const SMDS_MeshNode* aNodes [4];
01189     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
01190     int i = 0;
01191     //while (itN->more())
01192     while (i<4) {
01193       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
01194     }
01195     // compare two sets of possible triangles
01196     double aBadRate1, aBadRate2; // to what extent a set is bad
01197     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
01198     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
01199     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
01200 
01201     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
01202     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
01203     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
01204 
01205     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
01206       return 1; // diagonal 1-3
01207 
01208     return 2; // diagonal 2-4
01209   }
01210   return -1;
01211 }
01212 
01213 namespace
01214 {
01215   // Methods of splitting volumes into tetra
01216 
01217   const int theHexTo5_1[5*4+1] =
01218     {
01219       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
01220     };
01221   const int theHexTo5_2[5*4+1] =
01222     {
01223       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
01224     };
01225   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
01226 
01227   const int theHexTo6_1[6*4+1] =
01228     {
01229       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
01230     };
01231   const int theHexTo6_2[6*4+1] =
01232     {
01233       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
01234     };
01235   const int theHexTo6_3[6*4+1] =
01236     {
01237       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
01238     };
01239   const int theHexTo6_4[6*4+1] =
01240     {
01241       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
01242     };
01243   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
01244 
01245   const int thePyraTo2_1[2*4+1] =
01246     {
01247       0, 1, 2, 4,    0, 2, 3, 4,   -1
01248     };
01249   const int thePyraTo2_2[2*4+1] =
01250     {
01251       1, 2, 3, 4,    1, 3, 0, 4,   -1
01252     };
01253   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
01254 
01255   const int thePentaTo3_1[3*4+1] =
01256     {
01257       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
01258     };
01259   const int thePentaTo3_2[3*4+1] =
01260     {
01261       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
01262     };
01263   const int thePentaTo3_3[3*4+1] =
01264     {
01265       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
01266     };
01267   const int thePentaTo3_4[3*4+1] =
01268     {
01269       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
01270     };
01271   const int thePentaTo3_5[3*4+1] =
01272     {
01273       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
01274     };
01275   const int thePentaTo3_6[3*4+1] =
01276     {
01277       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
01278     };
01279   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
01280                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
01281 
01282   struct TTriangleFacet 
01283   {
01284     int _n1, _n2, _n3;
01285     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
01286     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
01287     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
01288   };
01289   struct TSplitMethod
01290   {
01291     int        _nbTetra;
01292     const int* _connectivity; 
01293     bool       _baryNode;     
01294     bool       _ownConn;      
01295     map<int, const SMDS_MeshNode*> _faceBaryNode; 
01296 
01297     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
01298       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
01299     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
01300     bool hasFacet( const TTriangleFacet& facet ) const
01301     {
01302       const int* tetConn = _connectivity;
01303       for ( ; tetConn[0] >= 0; tetConn += 4 )
01304         if (( facet.contains( tetConn[0] ) +
01305               facet.contains( tetConn[1] ) +
01306               facet.contains( tetConn[2] ) +
01307               facet.contains( tetConn[3] )) == 3 )
01308           return true;
01309       return false;
01310     }
01311   };
01312 
01313   //=======================================================================
01317   //=======================================================================
01318 
01319   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
01320   {
01321     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
01322 
01323     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
01324     // an edge and a face barycenter; tertaherdons are based on triangles and
01325     // a volume barycenter
01326     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
01327 
01328     // Find out how adjacent volumes are split
01329 
01330     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
01331     int hasAdjacentSplits = 0, maxTetConnSize = 0;
01332     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
01333     {
01334       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
01335       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
01336       if ( nbNodes < 4 ) continue;
01337 
01338       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
01339       const int* nInd = vol.GetFaceNodesIndices( iF );
01340       if ( nbNodes == 4 )
01341       {
01342         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
01343         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
01344         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
01345         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
01346       }
01347       else
01348       {
01349         int iCom = 0; // common node of triangle faces to split into
01350         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
01351         {
01352           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
01353                                nInd[ iQ * ( (iCom+1)%nbNodes )],
01354                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
01355           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
01356                                nInd[ iQ * ( (iCom+2)%nbNodes )],
01357                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
01358           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
01359           {
01360             triaSplits.push_back( t012 );
01361             triaSplits.push_back( t023 );
01362             break;
01363           }
01364         }
01365       }
01366       if ( !triaSplits.empty() )
01367         hasAdjacentSplits = true;
01368     }
01369 
01370     // Among variants of split method select one compliant with adjacent volumes
01371 
01372     TSplitMethod method;
01373     if ( !vol.Element()->IsPoly() && !is24TetMode )
01374     {
01375       int nbVariants = 2, nbTet = 0;
01376       const int** connVariants = 0;
01377       switch ( vol.Element()->GetEntityType() )
01378       {
01379       case SMDSEntity_Hexa:
01380       case SMDSEntity_Quad_Hexa:
01381         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
01382           connVariants = theHexTo5, nbTet = 5;
01383         else
01384           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
01385         break;
01386       case SMDSEntity_Pyramid:
01387       case SMDSEntity_Quad_Pyramid:
01388         connVariants = thePyraTo2;  nbTet = 2;
01389         break;
01390       case SMDSEntity_Penta:
01391       case SMDSEntity_Quad_Penta:
01392         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
01393         break;
01394       default:
01395         nbVariants = 0;
01396       }
01397       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
01398       {
01399         // check method compliancy with adjacent tetras,
01400         // all found splits must be among facets of tetras described by this method
01401         method = TSplitMethod( nbTet, connVariants[variant] );
01402         if ( hasAdjacentSplits && method._nbTetra > 0 )
01403         {
01404           bool facetCreated = true;
01405           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
01406           {
01407             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
01408             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
01409               facetCreated = method.hasFacet( *facet );
01410           }
01411           if ( !facetCreated )
01412             method = TSplitMethod(0); // incompatible method
01413         }
01414       }
01415     }
01416     if ( method._nbTetra < 1 )
01417     {
01418       // No standard method is applicable, use a generic solution:
01419       // each facet of a volume is split into triangles and
01420       // each of triangles and a volume barycenter form a tetrahedron.
01421 
01422       int* connectivity = new int[ maxTetConnSize + 1 ];
01423       method._connectivity = connectivity;
01424       method._ownConn = true;
01425       method._baryNode = true;
01426 
01427       int connSize = 0;
01428       int baryCenInd = vol.NbNodes();
01429       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
01430       {
01431         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
01432         const int*   nInd = vol.GetFaceNodesIndices( iF );
01433         // find common node of triangle facets of tetra to create
01434         int iCommon = 0; // index in linear numeration
01435         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
01436         if ( !triaSplits.empty() )
01437         {
01438           // by found facets
01439           const TTriangleFacet* facet = &triaSplits.front();
01440           for ( ; iCommon < nbNodes-1 ; ++iCommon )
01441             if ( facet->contains( nInd[ iQ * iCommon ]) &&
01442                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
01443               break;
01444         }
01445         else if ( nbNodes > 3 && !is24TetMode )
01446         {
01447           // find the best method of splitting into triangles by aspect ratio
01448           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
01449           map< double, int > badness2iCommon;
01450           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
01451           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
01452           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
01453             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
01454             {
01455               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
01456                                       nodes[ iQ*((iLast-1)%nbNodes)],
01457                                       nodes[ iQ*((iLast  )%nbNodes)]);
01458               double badness = getBadRate( &tria, aspectRatio );
01459               badness2iCommon.insert( make_pair( badness, iCommon ));
01460             }
01461           // use iCommon with lowest badness
01462           iCommon = badness2iCommon.begin()->second;
01463         }
01464         if ( iCommon >= nbNodes )
01465           iCommon = 0; // something wrong
01466 
01467         // fill connectivity of tetrahedra based on a current face
01468         int nbTet = nbNodes - 2;
01469         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
01470         {
01471           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
01472           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
01473           nbTet = nbNodes;
01474           for ( int i = 0; i < nbTet; ++i )
01475           {
01476             int i1 = i, i2 = (i+1) % nbNodes;
01477             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
01478             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
01479             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
01480             connectivity[ connSize++ ] = faceBaryCenInd;
01481             connectivity[ connSize++ ] = baryCenInd;
01482           }
01483         }
01484         else
01485         {
01486           for ( int i = 0; i < nbTet; ++i )
01487           {
01488             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
01489             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
01490             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
01491             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
01492             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
01493             connectivity[ connSize++ ] = baryCenInd;
01494           }
01495         }
01496         method._nbTetra += nbTet;
01497       }
01498       connectivity[ connSize++ ] = -1;
01499     }
01500     return method;
01501   }
01502   //================================================================================
01506   //================================================================================
01507 
01508   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
01509   {
01510     // find the tetrahedron including the three nodes of facet
01511     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
01512     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
01513     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
01514     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
01515     while ( volIt1->more() )
01516     {
01517       const SMDS_MeshElement* v = volIt1->next();
01518       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
01519         continue;
01520       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
01521       while ( volIt2->more() )
01522         if ( v != volIt2->next() )
01523           continue;
01524       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
01525       while ( volIt3->more() )
01526         if ( v == volIt3->next() )
01527           return true;
01528     }
01529     return false;
01530   }
01531 
01532   //=======================================================================
01536   //=======================================================================
01537 
01538   struct TVolumeFaceKey: pair< int, pair< int, int> >
01539   {
01540     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
01541     {
01542       TIDSortedNodeSet sortedNodes;
01543       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
01544       int nbNodes = vol.NbFaceNodes( iF );
01545       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
01546       for ( int i = 0; i < nbNodes; i += iQ )
01547         sortedNodes.insert( fNodes[i] );
01548       TIDSortedNodeSet::iterator n = sortedNodes.begin();
01549       first = (*(n++))->GetID();
01550       second.first = (*(n++))->GetID();
01551       second.second = (*(n++))->GetID();
01552     }
01553   };
01554 } // namespace
01555 
01556 //=======================================================================
01557 //function : SplitVolumesIntoTetra
01558 //purpose  : Split volumic elements into tetrahedra.
01559 //=======================================================================
01560 
01561 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
01562                                               const int                theMethodFlags)
01563 {
01564   // std-like iterator on coordinates of nodes of mesh element
01565   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
01566   NXyzIterator xyzEnd;
01567 
01568   SMDS_VolumeTool    volTool;
01569   SMESH_MesherHelper helper( *GetMesh());
01570 
01571   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
01572   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
01573   
01574   SMESH_SequenceOfElemPtr newNodes, newElems;
01575 
01576   // map face of volume to it's baricenrtic node
01577   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
01578   double bc[3];
01579 
01580   TIDSortedElemSet::const_iterator elem = theElems.begin();
01581   for ( ; elem != theElems.end(); ++elem )
01582   {
01583     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
01584     if ( geomType <= SMDSEntity_Quad_Tetra )
01585       continue; // tetra or face or ...
01586 
01587     if ( !volTool.Set( *elem )) continue; // not volume? strange...
01588 
01589     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
01590     if ( splitMethod._nbTetra < 1 ) continue;
01591 
01592     // find submesh to add new tetras to
01593     if ( !subMesh || !subMesh->Contains( *elem ))
01594     {
01595       int shapeID = FindShape( *elem );
01596       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
01597       subMesh = GetMeshDS()->MeshElements( shapeID );
01598     }
01599     int iQ;
01600     if ( (*elem)->IsQuadratic() )
01601     {
01602       iQ = 2;
01603       // add quadratic links to the helper
01604       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
01605       {
01606         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
01607         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
01608           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
01609       }
01610       helper.SetIsQuadratic( true );
01611     }
01612     else
01613     {
01614       iQ = 1;
01615       helper.SetIsQuadratic( false );
01616     }
01617     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
01618     helper.SetElementsOnShape( true );
01619     if ( splitMethod._baryNode )
01620     {
01621       // make a node at barycenter
01622       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
01623       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
01624       nodes.push_back( gcNode );
01625       newNodes.Append( gcNode );
01626     }
01627     if ( !splitMethod._faceBaryNode.empty() )
01628     {
01629       // make or find baricentric nodes of faces
01630       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
01631       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
01632       {
01633         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
01634           volFace2BaryNode.insert
01635           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
01636         if ( !f_n->second )
01637         {
01638           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
01639           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
01640         }
01641         nodes.push_back( iF_n->second = f_n->second );
01642       }
01643     }
01644 
01645     // make tetras
01646     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
01647     const int* tetConn = splitMethod._connectivity;
01648     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
01649       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
01650                                                        nodes[ tetConn[1] ],
01651                                                        nodes[ tetConn[2] ],
01652                                                        nodes[ tetConn[3] ]));
01653 
01654     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
01655 
01656     // Split faces on sides of the split volume
01657 
01658     const SMDS_MeshNode** volNodes = volTool.GetNodes();
01659     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
01660     {
01661       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
01662       if ( nbNodes < 4 ) continue;
01663 
01664       // find an existing face
01665       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
01666                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
01667       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
01668       {
01669         // make triangles
01670         helper.SetElementsOnShape( false );
01671         vector< const SMDS_MeshElement* > triangles;
01672 
01673         // find submesh to add new triangles in
01674         if ( !fSubMesh || !fSubMesh->Contains( face ))
01675         {
01676           int shapeID = FindShape( face );
01677           fSubMesh = GetMeshDS()->MeshElements( shapeID );
01678         }
01679         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
01680         if ( iF_n != splitMethod._faceBaryNode.end() )
01681         {
01682           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
01683           {
01684             const SMDS_MeshNode* n1 = fNodes[iN];
01685             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
01686             const SMDS_MeshNode *n3 = iF_n->second;
01687             if ( !volTool.IsFaceExternal( iF ))
01688               swap( n2, n3 );
01689             triangles.push_back( helper.AddFace( n1,n2,n3 ));
01690 
01691             if ( fSubMesh && n3->getshapeId() < 1 )
01692               fSubMesh->AddNode( n3 );
01693           }
01694         }
01695         else
01696         {
01697           // among possible triangles create ones discribed by split method
01698           const int* nInd = volTool.GetFaceNodesIndices( iF );
01699           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
01700           int iCom = 0; // common node of triangle faces to split into
01701           list< TTriangleFacet > facets;
01702           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
01703           {
01704             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
01705                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
01706                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
01707             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
01708                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
01709                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
01710             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
01711             {
01712               facets.push_back( t012 );
01713               facets.push_back( t023 );
01714               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
01715                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
01716                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
01717                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
01718               break;
01719             }
01720           }
01721           list< TTriangleFacet >::iterator facet = facets.begin();
01722           for ( ; facet != facets.end(); ++facet )
01723           {
01724             if ( !volTool.IsFaceExternal( iF ))
01725               swap( facet->_n2, facet->_n3 );
01726             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
01727                                                  volNodes[ facet->_n2 ],
01728                                                  volNodes[ facet->_n3 ]));
01729           }
01730         }
01731         for ( int i = 0; i < triangles.size(); ++i )
01732         {
01733           if ( !triangles[i] ) continue;
01734           if ( fSubMesh )
01735             fSubMesh->AddElement( triangles[i]);
01736           newElems.Append( triangles[i] );
01737         }
01738         ReplaceElemInGroups( face, triangles, GetMeshDS() );
01739         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
01740       }
01741 
01742     } // loop on volume faces to split them into triangles
01743 
01744     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
01745 
01746   } // loop on volumes to split
01747 
01748   myLastCreatedNodes = newNodes;
01749   myLastCreatedElems = newElems;
01750 }
01751 
01752 //=======================================================================
01753 //function : AddToSameGroups
01754 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
01755 //=======================================================================
01756 
01757 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
01758                                         const SMDS_MeshElement* elemInGroups,
01759                                         SMESHDS_Mesh *          aMesh)
01760 {
01761   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
01762   if (!groups.empty()) {
01763     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
01764     for ( ; grIt != groups.end(); grIt++ ) {
01765       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
01766       if ( group && group->Contains( elemInGroups ))
01767         group->SMDSGroup().Add( elemToAdd );
01768     }
01769   }
01770 }
01771 
01772 
01773 //=======================================================================
01774 //function : RemoveElemFromGroups
01775 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
01776 //=======================================================================
01777 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
01778                                              SMESHDS_Mesh *          aMesh)
01779 {
01780   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
01781   if (!groups.empty())
01782   {
01783     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
01784     for (; GrIt != groups.end(); GrIt++)
01785     {
01786       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
01787       if (!grp || grp->IsEmpty()) continue;
01788       grp->SMDSGroup().Remove(removeelem);
01789     }
01790   }
01791 }
01792 
01793 //================================================================================
01797 //================================================================================
01798 
01799 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
01800                                             const SMDS_MeshElement* elemToAdd,
01801                                             SMESHDS_Mesh *          aMesh)
01802 {
01803   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
01804   if (!groups.empty()) {
01805     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
01806     for ( ; grIt != groups.end(); grIt++ ) {
01807       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
01808       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
01809         group->SMDSGroup().Add( elemToAdd );
01810     }
01811   }
01812 }
01813 
01814 //================================================================================
01818 //================================================================================
01819 
01820 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
01821                                             const vector<const SMDS_MeshElement*>& elemToAdd,
01822                                             SMESHDS_Mesh *                         aMesh)
01823 {
01824   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
01825   if (!groups.empty())
01826   {
01827     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
01828     for ( ; grIt != groups.end(); grIt++ ) {
01829       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
01830       if ( group && group->SMDSGroup().Remove( elemToRm ) )
01831         for ( int i = 0; i < elemToAdd.size(); ++i )
01832           group->SMDSGroup().Add( elemToAdd[ i ] );
01833     }
01834   }
01835 }
01836 
01837 //=======================================================================
01838 //function : QuadToTri
01839 //purpose  : Cut quadrangles into triangles.
01840 //           theCrit is used to select a diagonal to cut
01841 //=======================================================================
01842 
01843 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
01844                                   const bool         the13Diag)
01845 {
01846   myLastCreatedElems.Clear();
01847   myLastCreatedNodes.Clear();
01848 
01849   MESSAGE( "::QuadToTri()" );
01850 
01851   SMESHDS_Mesh * aMesh = GetMeshDS();
01852 
01853   Handle(Geom_Surface) surface;
01854   SMESH_MesherHelper   helper( *GetMesh() );
01855 
01856   TIDSortedElemSet::iterator itElem;
01857   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
01858     const SMDS_MeshElement* elem = *itElem;
01859     if ( !elem || elem->GetType() != SMDSAbs_Face )
01860       continue;
01861     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
01862     if(!isquad) continue;
01863 
01864     if(elem->NbNodes()==4) {
01865       // retrieve element nodes
01866       const SMDS_MeshNode* aNodes [4];
01867       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
01868       int i = 0;
01869       while ( itN->more() )
01870         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
01871 
01872       int aShapeId = FindShape( elem );
01873       const SMDS_MeshElement* newElem1 = 0;
01874       const SMDS_MeshElement* newElem2 = 0;
01875       if ( the13Diag ) {
01876         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
01877         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
01878       }
01879       else {
01880         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
01881         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
01882       }
01883       myLastCreatedElems.Append(newElem1);
01884       myLastCreatedElems.Append(newElem2);
01885       // put a new triangle on the same shape and add to the same groups
01886       if ( aShapeId )
01887         {
01888           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
01889           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
01890         }
01891       AddToSameGroups( newElem1, elem, aMesh );
01892       AddToSameGroups( newElem2, elem, aMesh );
01893       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
01894       aMesh->RemoveElement( elem );
01895     }
01896 
01897     // Quadratic quadrangle
01898 
01899     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
01900 
01901       // get surface elem is on
01902       int aShapeId = FindShape( elem );
01903       if ( aShapeId != helper.GetSubShapeID() ) {
01904         surface.Nullify();
01905         TopoDS_Shape shape;
01906         if ( aShapeId > 0 )
01907           shape = aMesh->IndexToShape( aShapeId );
01908         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
01909           TopoDS_Face face = TopoDS::Face( shape );
01910           surface = BRep_Tool::Surface( face );
01911           if ( !surface.IsNull() )
01912             helper.SetSubShape( shape );
01913         }
01914       }
01915 
01916       const SMDS_MeshNode* aNodes [8];
01917       const SMDS_MeshNode* inFaceNode = 0;
01918       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
01919       int i = 0;
01920       while ( itN->more() ) {
01921         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
01922         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
01923              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
01924         {
01925           inFaceNode = aNodes[ i-1 ];
01926         }
01927       }
01928 
01929       // find middle point for (0,1,2,3)
01930       // and create a node in this point;
01931       gp_XYZ p( 0,0,0 );
01932       if ( surface.IsNull() ) {
01933         for(i=0; i<4; i++)
01934           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
01935         p /= 4;
01936       }
01937       else {
01938         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
01939         gp_XY uv( 0,0 );
01940         for(i=0; i<4; i++)
01941           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
01942         uv /= 4.;
01943         p = surface->Value( uv.X(), uv.Y() ).XYZ();
01944       }
01945       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
01946       myLastCreatedNodes.Append(newN);
01947 
01948       // create a new element
01949       const SMDS_MeshElement* newElem1 = 0;
01950       const SMDS_MeshElement* newElem2 = 0;
01951       if ( the13Diag ) {
01952         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
01953                                   aNodes[6], aNodes[7], newN );
01954         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
01955                                   newN,      aNodes[4], aNodes[5] );
01956       }
01957       else {
01958         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
01959                                   aNodes[7], aNodes[4], newN );
01960         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
01961                                   newN,      aNodes[5], aNodes[6] );
01962       }
01963       myLastCreatedElems.Append(newElem1);
01964       myLastCreatedElems.Append(newElem2);
01965       // put a new triangle on the same shape and add to the same groups
01966       if ( aShapeId )
01967         {
01968           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
01969           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
01970         }
01971       AddToSameGroups( newElem1, elem, aMesh );
01972       AddToSameGroups( newElem2, elem, aMesh );
01973       aMesh->RemoveElement( elem );
01974     }
01975   }
01976 
01977   return true;
01978 }
01979 
01980 //=======================================================================
01981 //function : getAngle
01982 //purpose  :
01983 //=======================================================================
01984 
01985 double getAngle(const SMDS_MeshElement * tr1,
01986                 const SMDS_MeshElement * tr2,
01987                 const SMDS_MeshNode *    n1,
01988                 const SMDS_MeshNode *    n2)
01989 {
01990   double angle = 2*PI; // bad angle
01991 
01992   // get normals
01993   SMESH::Controls::TSequenceOfXYZ P1, P2;
01994   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
01995        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
01996     return angle;
01997   gp_Vec N1,N2;
01998   if(!tr1->IsQuadratic())
01999     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
02000   else
02001     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
02002   if ( N1.SquareMagnitude() <= gp::Resolution() )
02003     return angle;
02004   if(!tr2->IsQuadratic())
02005     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
02006   else
02007     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
02008   if ( N2.SquareMagnitude() <= gp::Resolution() )
02009     return angle;
02010 
02011   // find the first diagonal node n1 in the triangles:
02012   // take in account a diagonal link orientation
02013   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
02014   for ( int t = 0; t < 2; t++ ) {
02015     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
02016     int i = 0, iDiag = -1;
02017     while ( it->more()) {
02018       const SMDS_MeshElement *n = it->next();
02019       if ( n == n1 || n == n2 ) {
02020         if ( iDiag < 0)
02021           iDiag = i;
02022         else {
02023           if ( i - iDiag == 1 )
02024             nFirst[ t ] = ( n == n1 ? n2 : n1 );
02025           else
02026             nFirst[ t ] = n;
02027           break;
02028         }
02029       }
02030       i++;
02031     }
02032   }
02033   if ( nFirst[ 0 ] == nFirst[ 1 ] )
02034     N2.Reverse();
02035 
02036   angle = N1.Angle( N2 );
02037   //SCRUTE( angle );
02038   return angle;
02039 }
02040 
02041 // =================================================
02042 // class generating a unique ID for a pair of nodes
02043 // and able to return nodes by that ID
02044 // =================================================
02045 class LinkID_Gen {
02046 public:
02047 
02048   LinkID_Gen( const SMESHDS_Mesh* theMesh )
02049     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
02050   {}
02051 
02052   long GetLinkID (const SMDS_MeshNode * n1,
02053                   const SMDS_MeshNode * n2) const
02054   {
02055     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
02056   }
02057 
02058   bool GetNodes (const long             theLinkID,
02059                  const SMDS_MeshNode* & theNode1,
02060                  const SMDS_MeshNode* & theNode2) const
02061   {
02062     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
02063     if ( !theNode1 ) return false;
02064     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
02065     if ( !theNode2 ) return false;
02066     return true;
02067   }
02068 
02069 private:
02070   LinkID_Gen();
02071   const SMESHDS_Mesh* myMesh;
02072   long                myMaxID;
02073 };
02074 
02075 
02076 //=======================================================================
02077 //function : TriToQuad
02078 //purpose  : Fuse neighbour triangles into quadrangles.
02079 //           theCrit is used to select a neighbour to fuse with.
02080 //           theMaxAngle is a max angle between element normals at which
02081 //           fusion is still performed.
02082 //=======================================================================
02083 
02084 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
02085                                   SMESH::Controls::NumericalFunctorPtr theCrit,
02086                                   const double                         theMaxAngle)
02087 {
02088   myLastCreatedElems.Clear();
02089   myLastCreatedNodes.Clear();
02090 
02091   MESSAGE( "::TriToQuad()" );
02092 
02093   if ( !theCrit.get() )
02094     return false;
02095 
02096   SMESHDS_Mesh * aMesh = GetMeshDS();
02097 
02098   // Prepare data for algo: build
02099   // 1. map of elements with their linkIDs
02100   // 2. map of linkIDs with their elements
02101 
02102   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
02103   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
02104   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
02105   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
02106 
02107   TIDSortedElemSet::iterator itElem;
02108   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
02109     const SMDS_MeshElement* elem = *itElem;
02110     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
02111     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
02112     if(!IsTria) continue;
02113 
02114     // retrieve element nodes
02115     const SMDS_MeshNode* aNodes [4];
02116     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
02117     int i = 0;
02118     while ( i<3 )
02119       aNodes[ i++ ] = cast2Node( itN->next() );
02120     aNodes[ 3 ] = aNodes[ 0 ];
02121 
02122     // fill maps
02123     for ( i = 0; i < 3; i++ ) {
02124       SMESH_TLink link( aNodes[i], aNodes[i+1] );
02125       // check if elements sharing a link can be fused
02126       itLE = mapLi_listEl.find( link );
02127       if ( itLE != mapLi_listEl.end() ) {
02128         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
02129           continue;
02130         const SMDS_MeshElement* elem2 = (*itLE).second.front();
02131         //if ( FindShape( elem ) != FindShape( elem2 ))
02132         //  continue; // do not fuse triangles laying on different shapes
02133         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
02134           continue; // avoid making badly shaped quads
02135         (*itLE).second.push_back( elem );
02136       }
02137       else {
02138         mapLi_listEl[ link ].push_back( elem );
02139       }
02140       mapEl_setLi [ elem ].insert( link );
02141     }
02142   }
02143   // Clean the maps from the links shared by a sole element, ie
02144   // links to which only one element is bound in mapLi_listEl
02145 
02146   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
02147     int nbElems = (*itLE).second.size();
02148     if ( nbElems < 2  ) {
02149       const SMDS_MeshElement* elem = (*itLE).second.front();
02150       SMESH_TLink link = (*itLE).first;
02151       mapEl_setLi[ elem ].erase( link );
02152       if ( mapEl_setLi[ elem ].empty() )
02153         mapEl_setLi.erase( elem );
02154     }
02155   }
02156 
02157   // Algo: fuse triangles into quadrangles
02158 
02159   while ( ! mapEl_setLi.empty() ) {
02160     // Look for the start element:
02161     // the element having the least nb of shared links
02162     const SMDS_MeshElement* startElem = 0;
02163     int minNbLinks = 4;
02164     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
02165       int nbLinks = (*itEL).second.size();
02166       if ( nbLinks < minNbLinks ) {
02167         startElem = (*itEL).first;
02168         minNbLinks = nbLinks;
02169         if ( minNbLinks == 1 )
02170           break;
02171       }
02172     }
02173 
02174     // search elements to fuse starting from startElem or links of elements
02175     // fused earlyer - startLinks
02176     list< SMESH_TLink > startLinks;
02177     while ( startElem || !startLinks.empty() ) {
02178       while ( !startElem && !startLinks.empty() ) {
02179         // Get an element to start, by a link
02180         SMESH_TLink linkId = startLinks.front();
02181         startLinks.pop_front();
02182         itLE = mapLi_listEl.find( linkId );
02183         if ( itLE != mapLi_listEl.end() ) {
02184           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
02185           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
02186           for ( ; itE != listElem.end() ; itE++ )
02187             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
02188               startElem = (*itE);
02189           mapLi_listEl.erase( itLE );
02190         }
02191       }
02192 
02193       if ( startElem ) {
02194         // Get candidates to be fused
02195         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
02196         const SMESH_TLink *link12, *link13;
02197         startElem = 0;
02198         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
02199         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
02200         ASSERT( !setLi.empty() );
02201         set< SMESH_TLink >::iterator itLi;
02202         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
02203         {
02204           const SMESH_TLink & link = (*itLi);
02205           itLE = mapLi_listEl.find( link );
02206           if ( itLE == mapLi_listEl.end() )
02207             continue;
02208 
02209           const SMDS_MeshElement* elem = (*itLE).second.front();
02210           if ( elem == tr1 )
02211             elem = (*itLE).second.back();
02212           mapLi_listEl.erase( itLE );
02213           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
02214             continue;
02215           if ( tr2 ) {
02216             tr3 = elem;
02217             link13 = &link;
02218           }
02219           else {
02220             tr2 = elem;
02221             link12 = &link;
02222           }
02223 
02224           // add other links of elem to list of links to re-start from
02225           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
02226           set< SMESH_TLink >::iterator it;
02227           for ( it = links.begin(); it != links.end(); it++ ) {
02228             const SMESH_TLink& link2 = (*it);
02229             if ( link2 != link )
02230               startLinks.push_back( link2 );
02231           }
02232         }
02233 
02234         // Get nodes of possible quadrangles
02235         const SMDS_MeshNode *n12 [4], *n13 [4];
02236         bool Ok12 = false, Ok13 = false;
02237         const SMDS_MeshNode *linkNode1, *linkNode2;
02238         if(tr2) {
02239           linkNode1 = link12->first;
02240           linkNode2 = link12->second;
02241           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
02242             Ok12 = true;
02243         }
02244         if(tr3) {
02245           linkNode1 = link13->first;
02246           linkNode2 = link13->second;
02247           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
02248             Ok13 = true;
02249         }
02250 
02251         // Choose a pair to fuse
02252         if ( Ok12 && Ok13 ) {
02253           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
02254           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
02255           double aBadRate12 = getBadRate( &quad12, theCrit );
02256           double aBadRate13 = getBadRate( &quad13, theCrit );
02257           if (  aBadRate13 < aBadRate12 )
02258             Ok12 = false;
02259           else
02260             Ok13 = false;
02261         }
02262 
02263         // Make quadrangles
02264         // and remove fused elems and removed links from the maps
02265         mapEl_setLi.erase( tr1 );
02266         if ( Ok12 ) {
02267           mapEl_setLi.erase( tr2 );
02268           mapLi_listEl.erase( *link12 );
02269           if(tr1->NbNodes()==3) {
02270             const SMDS_MeshElement* newElem = 0;
02271             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
02272             myLastCreatedElems.Append(newElem);
02273             AddToSameGroups( newElem, tr1, aMesh );
02274             int aShapeId = tr1->getshapeId();
02275             if ( aShapeId )
02276               {
02277                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
02278               }
02279             aMesh->RemoveElement( tr1 );
02280             aMesh->RemoveElement( tr2 );
02281           }
02282           else {
02283             const SMDS_MeshNode* N1 [6];
02284             const SMDS_MeshNode* N2 [6];
02285             GetNodesFromTwoTria(tr1,tr2,N1,N2);
02286             // now we receive following N1 and N2 (using numeration as above image)
02287             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
02288             // i.e. first nodes from both arrays determ new diagonal
02289             const SMDS_MeshNode* aNodes[8];
02290             aNodes[0] = N1[0];
02291             aNodes[1] = N1[1];
02292             aNodes[2] = N2[0];
02293             aNodes[3] = N2[1];
02294             aNodes[4] = N1[3];
02295             aNodes[5] = N2[5];
02296             aNodes[6] = N2[3];
02297             aNodes[7] = N1[5];
02298             const SMDS_MeshElement* newElem = 0;
02299             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
02300                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
02301             myLastCreatedElems.Append(newElem);
02302             AddToSameGroups( newElem, tr1, aMesh );
02303             int aShapeId = tr1->getshapeId();
02304             if ( aShapeId )
02305               {
02306                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
02307               }
02308             aMesh->RemoveElement( tr1 );
02309             aMesh->RemoveElement( tr2 );
02310             // remove middle node (9)
02311             GetMeshDS()->RemoveNode( N1[4] );
02312           }
02313         }
02314         else if ( Ok13 ) {
02315           mapEl_setLi.erase( tr3 );
02316           mapLi_listEl.erase( *link13 );
02317           if(tr1->NbNodes()==3) {
02318             const SMDS_MeshElement* newElem = 0;
02319             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
02320             myLastCreatedElems.Append(newElem);
02321             AddToSameGroups( newElem, tr1, aMesh );
02322             int aShapeId = tr1->getshapeId();
02323             if ( aShapeId )
02324               {
02325                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
02326               }
02327             aMesh->RemoveElement( tr1 );
02328             aMesh->RemoveElement( tr3 );
02329           }
02330           else {
02331             const SMDS_MeshNode* N1 [6];
02332             const SMDS_MeshNode* N2 [6];
02333             GetNodesFromTwoTria(tr1,tr3,N1,N2);
02334             // now we receive following N1 and N2 (using numeration as above image)
02335             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
02336             // i.e. first nodes from both arrays determ new diagonal
02337             const SMDS_MeshNode* aNodes[8];
02338             aNodes[0] = N1[0];
02339             aNodes[1] = N1[1];
02340             aNodes[2] = N2[0];
02341             aNodes[3] = N2[1];
02342             aNodes[4] = N1[3];
02343             aNodes[5] = N2[5];
02344             aNodes[6] = N2[3];
02345             aNodes[7] = N1[5];
02346             const SMDS_MeshElement* newElem = 0;
02347             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
02348                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
02349             myLastCreatedElems.Append(newElem);
02350             AddToSameGroups( newElem, tr1, aMesh );
02351             int aShapeId = tr1->getshapeId();
02352             if ( aShapeId )
02353               {
02354                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
02355               }
02356             aMesh->RemoveElement( tr1 );
02357             aMesh->RemoveElement( tr3 );
02358             // remove middle node (9)
02359             GetMeshDS()->RemoveNode( N1[4] );
02360           }
02361         }
02362 
02363         // Next element to fuse: the rejected one
02364         if ( tr3 )
02365           startElem = Ok12 ? tr3 : tr2;
02366 
02367       } // if ( startElem )
02368     } // while ( startElem || !startLinks.empty() )
02369   } // while ( ! mapEl_setLi.empty() )
02370 
02371   return true;
02372 }
02373 
02374 
02375 /*#define DUMPSO(txt) \
02376 //  cout << txt << endl;
02377 //=============================================================================
02378 //
02379 //
02380 //
02381 //=============================================================================
02382 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
02383 {
02384 if ( i1 == i2 )
02385 return;
02386 int tmp = idNodes[ i1 ];
02387 idNodes[ i1 ] = idNodes[ i2 ];
02388 idNodes[ i2 ] = tmp;
02389 gp_Pnt Ptmp = P[ i1 ];
02390 P[ i1 ] = P[ i2 ];
02391 P[ i2 ] = Ptmp;
02392 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
02393 }
02394 
02395 //=======================================================================
02396 //function : SortQuadNodes
02397 //purpose  : Set 4 nodes of a quadrangle face in a good order.
02398 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
02399 //           1 or 2 else 0.
02400 //=======================================================================
02401 
02402 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
02403 int               idNodes[] )
02404 {
02405   gp_Pnt P[4];
02406   int i;
02407   for ( i = 0; i < 4; i++ ) {
02408     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
02409     if ( !n ) return 0;
02410     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
02411   }
02412 
02413   gp_Vec V1(P[0], P[1]);
02414   gp_Vec V2(P[0], P[2]);
02415   gp_Vec V3(P[0], P[3]);
02416 
02417   gp_Vec Cross1 = V1 ^ V2;
02418   gp_Vec Cross2 = V2 ^ V3;
02419 
02420   i = 0;
02421   if (Cross1.Dot(Cross2) < 0)
02422   {
02423     Cross1 = V2 ^ V1;
02424     Cross2 = V1 ^ V3;
02425 
02426     if (Cross1.Dot(Cross2) < 0)
02427       i = 2;
02428     else
02429       i = 1;
02430     swap ( i, i + 1, idNodes, P );
02431 
02432     //     for ( int ii = 0; ii < 4; ii++ ) {
02433     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
02434     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
02435     //     }
02436   }
02437   return i;
02438 }
02439 
02440 //=======================================================================
02441 //function : SortHexaNodes
02442 //purpose  : Set 8 nodes of a hexahedron in a good order.
02443 //           Return success status
02444 //=======================================================================
02445 
02446 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
02447                                       int               idNodes[] )
02448 {
02449   gp_Pnt P[8];
02450   int i;
02451   DUMPSO( "INPUT: ========================================");
02452   for ( i = 0; i < 8; i++ ) {
02453     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
02454     if ( !n ) return false;
02455     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
02456     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
02457   }
02458   DUMPSO( "========================================");
02459 
02460 
02461   set<int> faceNodes;  // ids of bottom face nodes, to be found
02462   set<int> checkedId1; // ids of tried 2-nd nodes
02463   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
02464   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
02465   int iMin, iLoop1 = 0;
02466 
02467   // Loop to try the 2-nd nodes
02468 
02469   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
02470   {
02471     // Find not checked 2-nd node
02472     for ( i = 1; i < 8; i++ )
02473       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
02474         int id1 = idNodes[i];
02475         swap ( 1, i, idNodes, P );
02476         checkedId1.insert ( id1 );
02477         break;
02478       }
02479 
02480     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
02481     // ie that all but meybe one (id3 which is on the same face) nodes
02482     // lay on the same side from the triangle plane.
02483 
02484     bool manyInPlane = false; // more than 4 nodes lay in plane
02485     int iLoop2 = 0;
02486     while ( ++iLoop2 < 6 ) {
02487 
02488       // get 1-2-3 plane coeffs
02489       Standard_Real A, B, C, D;
02490       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
02491       if ( N.SquareMagnitude() > gp::Resolution() )
02492       {
02493         gp_Pln pln ( P[0], N );
02494         pln.Coefficients( A, B, C, D );
02495 
02496         // find the node (iMin) closest to pln
02497         Standard_Real dist[ 8 ], minDist = DBL_MAX;
02498         set<int> idInPln;
02499         for ( i = 3; i < 8; i++ ) {
02500           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
02501           if ( fabs( dist[i] ) < minDist ) {
02502             minDist = fabs( dist[i] );
02503             iMin = i;
02504           }
02505           if ( fabs( dist[i] ) <= tol )
02506             idInPln.insert( idNodes[i] );
02507         }
02508 
02509         // there should not be more than 4 nodes in bottom plane
02510         if ( idInPln.size() > 1 )
02511         {
02512           DUMPSO( "### idInPln.size() = " << idInPln.size());
02513           // idInPlane does not contain the first 3 nodes
02514           if ( manyInPlane || idInPln.size() == 5)
02515             return false; // all nodes in one plane
02516           manyInPlane = true;
02517 
02518           // set the 1-st node to be not in plane
02519           for ( i = 3; i < 8; i++ ) {
02520             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
02521               DUMPSO( "### Reset 0-th node");
02522               swap( 0, i, idNodes, P );
02523               break;
02524             }
02525           }
02526 
02527           // reset to re-check second nodes
02528           leastDist = DBL_MAX;
02529           faceNodes.clear();
02530           checkedId1.clear();
02531           iLoop1 = 0;
02532           break; // from iLoop2;
02533         }
02534 
02535         // check that the other 4 nodes are on the same side
02536         bool sameSide = true;
02537         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
02538         for ( i = 3; sameSide && i < 8; i++ ) {
02539           if ( i != iMin )
02540             sameSide = ( isNeg == dist[i] <= 0.);
02541         }
02542 
02543         // keep best solution
02544         if ( sameSide && minDist < leastDist ) {
02545           leastDist = minDist;
02546           faceNodes.clear();
02547           faceNodes.insert( idNodes[ 1 ] );
02548           faceNodes.insert( idNodes[ 2 ] );
02549           faceNodes.insert( idNodes[ iMin ] );
02550           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
02551                   << " leastDist = " << leastDist);
02552           if ( leastDist <= DBL_MIN )
02553             break;
02554         }
02555       }
02556 
02557       // set next 3-d node to check
02558       int iNext = 2 + iLoop2;
02559       if ( iNext < 8 ) {
02560         DUMPSO( "Try 2-nd");
02561         swap ( 2, iNext, idNodes, P );
02562       }
02563     } // while ( iLoop2 < 6 )
02564   } // iLoop1
02565 
02566   if ( faceNodes.empty() ) return false;
02567 
02568   // Put the faceNodes in proper places
02569   for ( i = 4; i < 8; i++ ) {
02570     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
02571       // find a place to put
02572       int iTo = 1;
02573       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
02574         iTo++;
02575       DUMPSO( "Set faceNodes");
02576       swap ( iTo, i, idNodes, P );
02577     }
02578   }
02579 
02580 
02581   // Set nodes of the found bottom face in good order
02582   DUMPSO( " Found bottom face: ");
02583   i = SortQuadNodes( theMesh, idNodes );
02584   if ( i ) {
02585     gp_Pnt Ptmp = P[ i ];
02586     P[ i ] = P[ i+1 ];
02587     P[ i+1 ] = Ptmp;
02588   }
02589   //   else
02590   //     for ( int ii = 0; ii < 4; ii++ ) {
02591   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
02592   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
02593   //    }
02594 
02595   // Gravity center of the top and bottom faces
02596   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
02597   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
02598 
02599   // Get direction from the bottom to the top face
02600   gp_Vec upDir ( aGCb, aGCt );
02601   Standard_Real upDirSize = upDir.Magnitude();
02602   if ( upDirSize <= gp::Resolution() ) return false;
02603   upDir / upDirSize;
02604 
02605   // Assure that the bottom face normal points up
02606   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
02607   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
02608   if ( Nb.Dot( upDir ) < 0 ) {
02609     DUMPSO( "Reverse bottom face");
02610     swap( 1, 3, idNodes, P );
02611   }
02612 
02613   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
02614   Standard_Real minDist = DBL_MAX;
02615   for ( i = 4; i < 8; i++ ) {
02616     // projection of P[i] to the plane defined by P[0] and upDir
02617     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
02618     Standard_Real sqDist = P[0].SquareDistance( Pp );
02619     if ( sqDist < minDist ) {
02620       minDist = sqDist;
02621       iMin = i;
02622     }
02623   }
02624   DUMPSO( "Set 4-th");
02625   swap ( 4, iMin, idNodes, P );
02626 
02627   // Set nodes of the top face in good order
02628   DUMPSO( "Sort top face");
02629   i = SortQuadNodes( theMesh, &idNodes[4] );
02630   if ( i ) {
02631     i += 4;
02632     gp_Pnt Ptmp = P[ i ];
02633     P[ i ] = P[ i+1 ];
02634     P[ i+1 ] = Ptmp;
02635   }
02636 
02637   // Assure that direction of the top face normal is from the bottom face
02638   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
02639   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
02640   if ( Nt.Dot( upDir ) < 0 ) {
02641     DUMPSO( "Reverse top face");
02642     swap( 5, 7, idNodes, P );
02643   }
02644 
02645   //   DUMPSO( "OUTPUT: ========================================");
02646   //   for ( i = 0; i < 8; i++ ) {
02647   //     float *p = ugrid->GetPoint(idNodes[i]);
02648   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
02649   //   }
02650 
02651   return true;
02652 }*/
02653 
02654 //================================================================================
02663 //================================================================================
02664 
02665 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
02666                                        TIDSortedElemSet &   linkedNodes,
02667                                        SMDSAbs_ElementType  type )
02668 {
02669   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
02670   while ( elemIt->more() )
02671   {
02672     const SMDS_MeshElement* elem = elemIt->next();
02673     if(elem->GetType() == SMDSAbs_0DElement)
02674       continue;
02675     
02676     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
02677     if ( elem->GetType() == SMDSAbs_Volume )
02678     {
02679       SMDS_VolumeTool vol( elem );
02680       while ( nodeIt->more() ) {
02681         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
02682         if ( theNode != n && vol.IsLinked( theNode, n ))
02683           linkedNodes.insert( n );
02684       }
02685     }
02686     else
02687     {
02688       for ( int i = 0; nodeIt->more(); ++i ) {
02689         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
02690         if ( n == theNode ) {
02691           int iBefore = i - 1;
02692           int iAfter  = i + 1;
02693           if ( elem->IsQuadratic() ) {
02694             int nb = elem->NbNodes() / 2;
02695             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
02696             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
02697           }
02698           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
02699           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
02700         }
02701       }
02702     }
02703   }
02704 }
02705 
02706 //=======================================================================
02707 //function : laplacianSmooth
02708 //purpose  : pulls theNode toward the center of surrounding nodes directly
02709 //           connected to that node along an element edge
02710 //=======================================================================
02711 
02712 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
02713                      const Handle(Geom_Surface)&          theSurface,
02714                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
02715 {
02716   // find surrounding nodes
02717 
02718   TIDSortedElemSet nodeSet;
02719   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
02720 
02721   // compute new coodrs
02722 
02723   double coord[] = { 0., 0., 0. };
02724   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
02725   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
02726     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
02727     if ( theSurface.IsNull() ) { // smooth in 3D
02728       coord[0] += node->X();
02729       coord[1] += node->Y();
02730       coord[2] += node->Z();
02731     }
02732     else { // smooth in 2D
02733       ASSERT( theUVMap.find( node ) != theUVMap.end() );
02734       gp_XY* uv = theUVMap[ node ];
02735       coord[0] += uv->X();
02736       coord[1] += uv->Y();
02737     }
02738   }
02739   int nbNodes = nodeSet.size();
02740   if ( !nbNodes )
02741     return;
02742   coord[0] /= nbNodes;
02743   coord[1] /= nbNodes;
02744 
02745   if ( !theSurface.IsNull() ) {
02746     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
02747     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
02748     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
02749     coord[0] = p3d.X();
02750     coord[1] = p3d.Y();
02751     coord[2] = p3d.Z();
02752   }
02753   else
02754     coord[2] /= nbNodes;
02755 
02756   // move node
02757 
02758   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
02759 }
02760 
02761 //=======================================================================
02762 //function : centroidalSmooth
02763 //purpose  : pulls theNode toward the element-area-weighted centroid of the
02764 //           surrounding elements
02765 //=======================================================================
02766 
02767 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
02768                       const Handle(Geom_Surface)&          theSurface,
02769                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
02770 {
02771   gp_XYZ aNewXYZ(0.,0.,0.);
02772   SMESH::Controls::Area anAreaFunc;
02773   double totalArea = 0.;
02774   int nbElems = 0;
02775 
02776   // compute new XYZ
02777 
02778   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
02779   while ( elemIt->more() )
02780   {
02781     const SMDS_MeshElement* elem = elemIt->next();
02782     nbElems++;
02783 
02784     gp_XYZ elemCenter(0.,0.,0.);
02785     SMESH::Controls::TSequenceOfXYZ aNodePoints;
02786     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
02787     int nn = elem->NbNodes();
02788     if(elem->IsQuadratic()) nn = nn/2;
02789     int i=0;
02790     //while ( itN->more() ) {
02791     while ( i<nn ) {
02792       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
02793       i++;
02794       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
02795       aNodePoints.push_back( aP );
02796       if ( !theSurface.IsNull() ) { // smooth in 2D
02797         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
02798         gp_XY* uv = theUVMap[ aNode ];
02799         aP.SetCoord( uv->X(), uv->Y(), 0. );
02800       }
02801       elemCenter += aP;
02802     }
02803     double elemArea = anAreaFunc.GetValue( aNodePoints );
02804     totalArea += elemArea;
02805     elemCenter /= nn;
02806     aNewXYZ += elemCenter * elemArea;
02807   }
02808   aNewXYZ /= totalArea;
02809   if ( !theSurface.IsNull() ) {
02810     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
02811     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
02812   }
02813 
02814   // move node
02815 
02816   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
02817 }
02818 
02819 //=======================================================================
02820 //function : getClosestUV
02821 //purpose  : return UV of closest projection
02822 //=======================================================================
02823 
02824 static bool getClosestUV (Extrema_GenExtPS& projector,
02825                           const gp_Pnt&     point,
02826                           gp_XY &           result)
02827 {
02828   projector.Perform( point );
02829   if ( projector.IsDone() ) {
02830     double u, v, minVal = DBL_MAX;
02831     for ( int i = projector.NbExt(); i > 0; i-- )
02832       if ( projector.Value( i ) < minVal ) {
02833         minVal = projector.Value( i );
02834         projector.Point( i ).Parameter( u, v );
02835       }
02836     result.SetCoord( u, v );
02837     return true;
02838   }
02839   return false;
02840 }
02841 
02842 //=======================================================================
02843 //function : Smooth
02844 //purpose  : Smooth theElements during theNbIterations or until a worst
02845 //           element has aspect ratio <= theTgtAspectRatio.
02846 //           Aspect Ratio varies in range [1.0, inf].
02847 //           If theElements is empty, the whole mesh is smoothed.
02848 //           theFixedNodes contains additionally fixed nodes. Nodes built
02849 //           on edges and boundary nodes are always fixed.
02850 //=======================================================================
02851 
02852 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
02853                                set<const SMDS_MeshNode*> & theFixedNodes,
02854                                const SmoothMethod          theSmoothMethod,
02855                                const int                   theNbIterations,
02856                                double                      theTgtAspectRatio,
02857                                const bool                  the2D)
02858 {
02859   myLastCreatedElems.Clear();
02860   myLastCreatedNodes.Clear();
02861 
02862   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
02863 
02864   if ( theTgtAspectRatio < 1.0 )
02865     theTgtAspectRatio = 1.0;
02866 
02867   const double disttol = 1.e-16;
02868 
02869   SMESH::Controls::AspectRatio aQualityFunc;
02870 
02871   SMESHDS_Mesh* aMesh = GetMeshDS();
02872 
02873   if ( theElems.empty() ) {
02874     // add all faces to theElems
02875     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
02876     while ( fIt->more() ) {
02877       const SMDS_MeshElement* face = fIt->next();
02878       theElems.insert( face );
02879     }
02880   }
02881   // get all face ids theElems are on
02882   set< int > faceIdSet;
02883   TIDSortedElemSet::iterator itElem;
02884   if ( the2D )
02885     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
02886       int fId = FindShape( *itElem );
02887       // check that corresponding submesh exists and a shape is face
02888       if (fId &&
02889           faceIdSet.find( fId ) == faceIdSet.end() &&
02890           aMesh->MeshElements( fId )) {
02891         TopoDS_Shape F = aMesh->IndexToShape( fId );
02892         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
02893           faceIdSet.insert( fId );
02894       }
02895     }
02896   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
02897 
02898   // ===============================================
02899   // smooth elements on each TopoDS_Face separately
02900   // ===============================================
02901 
02902   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
02903   for ( ; fId != faceIdSet.rend(); ++fId ) {
02904     // get face surface and submesh
02905     Handle(Geom_Surface) surface;
02906     SMESHDS_SubMesh* faceSubMesh = 0;
02907     TopoDS_Face face;
02908     double fToler2 = 0, f,l;
02909     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
02910     bool isUPeriodic = false, isVPeriodic = false;
02911     if ( *fId ) {
02912       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
02913       surface = BRep_Tool::Surface( face );
02914       faceSubMesh = aMesh->MeshElements( *fId );
02915       fToler2 = BRep_Tool::Tolerance( face );
02916       fToler2 *= fToler2 * 10.;
02917       isUPeriodic = surface->IsUPeriodic();
02918       if ( isUPeriodic )
02919         surface->UPeriod();
02920       isVPeriodic = surface->IsVPeriodic();
02921       if ( isVPeriodic )
02922         surface->VPeriod();
02923       surface->Bounds( u1, u2, v1, v2 );
02924     }
02925     // ---------------------------------------------------------
02926     // for elements on a face, find movable and fixed nodes and
02927     // compute UV for them
02928     // ---------------------------------------------------------
02929     bool checkBoundaryNodes = false;
02930     bool isQuadratic = false;
02931     set<const SMDS_MeshNode*> setMovableNodes;
02932     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
02933     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
02934     list< const SMDS_MeshElement* > elemsOnFace;
02935 
02936     Extrema_GenExtPS projector;
02937     GeomAdaptor_Surface surfAdaptor;
02938     if ( !surface.IsNull() ) {
02939       surfAdaptor.Load( surface );
02940       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
02941     }
02942     int nbElemOnFace = 0;
02943     itElem = theElems.begin();
02944     // loop on not yet smoothed elements: look for elems on a face
02945     while ( itElem != theElems.end() ) {
02946       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
02947         break; // all elements found
02948 
02949       const SMDS_MeshElement* elem = *itElem;
02950       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
02951            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
02952         ++itElem;
02953         continue;
02954       }
02955       elemsOnFace.push_back( elem );
02956       theElems.erase( itElem++ );
02957       nbElemOnFace++;
02958 
02959       if ( !isQuadratic )
02960         isQuadratic = elem->IsQuadratic();
02961 
02962       // get movable nodes of elem
02963       const SMDS_MeshNode* node;
02964       SMDS_TypeOfPosition posType;
02965       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
02966       int nn = 0, nbn =  elem->NbNodes();
02967       if(elem->IsQuadratic())
02968         nbn = nbn/2;
02969       while ( nn++ < nbn ) {
02970         node = static_cast<const SMDS_MeshNode*>( itN->next() );
02971         const SMDS_PositionPtr& pos = node->GetPosition();
02972         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
02973         if (posType != SMDS_TOP_EDGE &&
02974             posType != SMDS_TOP_VERTEX &&
02975             theFixedNodes.find( node ) == theFixedNodes.end())
02976         {
02977           // check if all faces around the node are on faceSubMesh
02978           // because a node on edge may be bound to face
02979           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
02980           bool all = true;
02981           if ( faceSubMesh ) {
02982             while ( eIt->more() && all ) {
02983               const SMDS_MeshElement* e = eIt->next();
02984               all = faceSubMesh->Contains( e );
02985             }
02986           }
02987           if ( all )
02988             setMovableNodes.insert( node );
02989           else
02990             checkBoundaryNodes = true;
02991         }
02992         if ( posType == SMDS_TOP_3DSPACE )
02993           checkBoundaryNodes = true;
02994       }
02995 
02996       if ( surface.IsNull() )
02997         continue;
02998 
02999       // get nodes to check UV
03000       list< const SMDS_MeshNode* > uvCheckNodes;
03001       itN = elem->nodesIterator();
03002       nn = 0; nbn =  elem->NbNodes();
03003       if(elem->IsQuadratic())
03004         nbn = nbn/2;
03005       while ( nn++ < nbn ) {
03006         node = static_cast<const SMDS_MeshNode*>( itN->next() );
03007         if ( uvMap.find( node ) == uvMap.end() )
03008           uvCheckNodes.push_back( node );
03009         // add nodes of elems sharing node
03010         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
03011         //         while ( eIt->more() ) {
03012         //           const SMDS_MeshElement* e = eIt->next();
03013         //           if ( e != elem ) {
03014         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
03015         //             while ( nIt->more() ) {
03016         //               const SMDS_MeshNode* n =
03017         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
03018         //               if ( uvMap.find( n ) == uvMap.end() )
03019         //                 uvCheckNodes.push_back( n );
03020         //             }
03021         //           }
03022         //         }
03023       }
03024       // check UV on face
03025       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
03026       for ( ; n != uvCheckNodes.end(); ++n ) {
03027         node = *n;
03028         gp_XY uv( 0, 0 );
03029         const SMDS_PositionPtr& pos = node->GetPosition();
03030         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
03031         // get existing UV
03032         switch ( posType ) {
03033         case SMDS_TOP_FACE: {
03034           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
03035           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
03036           break;
03037         }
03038         case SMDS_TOP_EDGE: {
03039           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
03040           Handle(Geom2d_Curve) pcurve;
03041           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
03042             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
03043           if ( !pcurve.IsNull() ) {
03044             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
03045             uv = pcurve->Value( u ).XY();
03046           }
03047           break;
03048         }
03049         case SMDS_TOP_VERTEX: {
03050           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
03051           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
03052             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
03053           break;
03054         }
03055         default:;
03056         }
03057         // check existing UV
03058         bool project = true;
03059         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
03060         double dist1 = DBL_MAX, dist2 = 0;
03061         if ( posType != SMDS_TOP_3DSPACE ) {
03062           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
03063           project = dist1 > fToler2;
03064         }
03065         if ( project ) { // compute new UV
03066           gp_XY newUV;
03067           if ( !getClosestUV( projector, pNode, newUV )) {
03068             MESSAGE("Node Projection Failed " << node);
03069           }
03070           else {
03071             if ( isUPeriodic )
03072               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
03073             if ( isVPeriodic )
03074               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
03075             // check new UV
03076             if ( posType != SMDS_TOP_3DSPACE )
03077               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
03078             if ( dist2 < dist1 )
03079               uv = newUV;
03080           }
03081         }
03082         // store UV in the map
03083         listUV.push_back( uv );
03084         uvMap.insert( make_pair( node, &listUV.back() ));
03085       }
03086     } // loop on not yet smoothed elements
03087 
03088     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
03089       checkBoundaryNodes = true;
03090 
03091     // fix nodes on mesh boundary
03092 
03093     if ( checkBoundaryNodes ) {
03094       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
03095       map< SMESH_TLink, int >::iterator link_nb;
03096       // put all elements links to linkNbMap
03097       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
03098       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
03099         const SMDS_MeshElement* elem = (*elemIt);
03100         int nbn =  elem->NbCornerNodes();
03101         // loop on elem links: insert them in linkNbMap
03102         for ( int iN = 0; iN < nbn; ++iN ) {
03103           const SMDS_MeshNode* n1 = elem->GetNode( iN );
03104           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
03105           SMESH_TLink link( n1, n2 );
03106           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
03107           link_nb->second++;
03108         }
03109       }
03110       // remove nodes that are in links encountered only once from setMovableNodes
03111       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
03112         if ( link_nb->second == 1 ) {
03113           setMovableNodes.erase( link_nb->first.node1() );
03114           setMovableNodes.erase( link_nb->first.node2() );
03115         }
03116       }
03117     }
03118 
03119     // -----------------------------------------------------
03120     // for nodes on seam edge, compute one more UV ( uvMap2 );
03121     // find movable nodes linked to nodes on seam and which
03122     // are to be smoothed using the second UV ( uvMap2 )
03123     // -----------------------------------------------------
03124 
03125     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
03126     if ( !surface.IsNull() ) {
03127       TopExp_Explorer eExp( face, TopAbs_EDGE );
03128       for ( ; eExp.More(); eExp.Next() ) {
03129         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
03130         if ( !BRep_Tool::IsClosed( edge, face ))
03131           continue;
03132         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
03133         if ( !sm ) continue;
03134         // find out which parameter varies for a node on seam
03135         double f,l;
03136         gp_Pnt2d uv1, uv2;
03137         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
03138         if ( pcurve.IsNull() ) continue;
03139         uv1 = pcurve->Value( f );
03140         edge.Reverse();
03141         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
03142         if ( pcurve.IsNull() ) continue;
03143         uv2 = pcurve->Value( f );
03144         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
03145         // assure uv1 < uv2
03146         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
03147           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
03148         }
03149         // get nodes on seam and its vertices
03150         list< const SMDS_MeshNode* > seamNodes;
03151         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
03152         while ( nSeamIt->more() ) {
03153           const SMDS_MeshNode* node = nSeamIt->next();
03154           if ( !isQuadratic || !IsMedium( node ))
03155             seamNodes.push_back( node );
03156         }
03157         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
03158         for ( ; vExp.More(); vExp.Next() ) {
03159           sm = aMesh->MeshElements( vExp.Current() );
03160           if ( sm ) {
03161             nSeamIt = sm->GetNodes();
03162             while ( nSeamIt->more() )
03163               seamNodes.push_back( nSeamIt->next() );
03164           }
03165         }
03166         // loop on nodes on seam
03167         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
03168         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
03169           const SMDS_MeshNode* nSeam = *noSeIt;
03170           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
03171           if ( n_uv == uvMap.end() )
03172             continue;
03173           // set the first UV
03174           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
03175           // set the second UV
03176           listUV.push_back( *n_uv->second );
03177           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
03178           if ( uvMap2.empty() )
03179             uvMap2 = uvMap; // copy the uvMap contents
03180           uvMap2[ nSeam ] = &listUV.back();
03181 
03182           // collect movable nodes linked to ones on seam in nodesNearSeam
03183           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
03184           while ( eIt->more() ) {
03185             const SMDS_MeshElement* e = eIt->next();
03186             int nbUseMap1 = 0, nbUseMap2 = 0;
03187             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
03188             int nn = 0, nbn =  e->NbNodes();
03189             if(e->IsQuadratic()) nbn = nbn/2;
03190             while ( nn++ < nbn )
03191             {
03192               const SMDS_MeshNode* n =
03193                 static_cast<const SMDS_MeshNode*>( nIt->next() );
03194               if (n == nSeam ||
03195                   setMovableNodes.find( n ) == setMovableNodes.end() )
03196                 continue;
03197               // add only nodes being closer to uv2 than to uv1
03198               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
03199                            0.5 * ( n->Y() + nSeam->Y() ),
03200                            0.5 * ( n->Z() + nSeam->Z() ));
03201               gp_XY uv;
03202               getClosestUV( projector, pMid, uv );
03203               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
03204                 nodesNearSeam.insert( n );
03205                 nbUseMap2++;
03206               }
03207               else
03208                 nbUseMap1++;
03209             }
03210             // for centroidalSmooth all element nodes must
03211             // be on one side of a seam
03212             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
03213               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
03214               nn = 0;
03215               while ( nn++ < nbn ) {
03216                 const SMDS_MeshNode* n =
03217                   static_cast<const SMDS_MeshNode*>( nIt->next() );
03218                 setMovableNodes.erase( n );
03219               }
03220             }
03221           }
03222         } // loop on nodes on seam
03223       } // loop on edge of a face
03224     } // if ( !face.IsNull() )
03225 
03226     if ( setMovableNodes.empty() ) {
03227       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
03228       continue; // goto next face
03229     }
03230 
03231     // -------------
03232     // SMOOTHING //
03233     // -------------
03234 
03235     int it = -1;
03236     double maxRatio = -1., maxDisplacement = -1.;
03237     set<const SMDS_MeshNode*>::iterator nodeToMove;
03238     for ( it = 0; it < theNbIterations; it++ ) {
03239       maxDisplacement = 0.;
03240       nodeToMove = setMovableNodes.begin();
03241       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
03242         const SMDS_MeshNode* node = (*nodeToMove);
03243         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
03244 
03245         // smooth
03246         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
03247         if ( theSmoothMethod == LAPLACIAN )
03248           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
03249         else
03250           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
03251 
03252         // node displacement
03253         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
03254         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
03255         if ( aDispl > maxDisplacement )
03256           maxDisplacement = aDispl;
03257       }
03258       // no node movement => exit
03259       //if ( maxDisplacement < 1.e-16 ) {
03260       if ( maxDisplacement < disttol ) {
03261         MESSAGE("-- no node movement --");
03262         break;
03263       }
03264 
03265       // check elements quality
03266       maxRatio  = 0;
03267       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
03268       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
03269         const SMDS_MeshElement* elem = (*elemIt);
03270         if ( !elem || elem->GetType() != SMDSAbs_Face )
03271           continue;
03272         SMESH::Controls::TSequenceOfXYZ aPoints;
03273         if ( aQualityFunc.GetPoints( elem, aPoints )) {
03274           double aValue = aQualityFunc.GetValue( aPoints );
03275           if ( aValue > maxRatio )
03276             maxRatio = aValue;
03277         }
03278       }
03279       if ( maxRatio <= theTgtAspectRatio ) {
03280         MESSAGE("-- quality achived --");
03281         break;
03282       }
03283       if (it+1 == theNbIterations) {
03284         MESSAGE("-- Iteration limit exceeded --");
03285       }
03286     } // smoothing iterations
03287 
03288     MESSAGE(" Face id: " << *fId <<
03289             " Nb iterstions: " << it <<
03290             " Displacement: " << maxDisplacement <<
03291             " Aspect Ratio " << maxRatio);
03292 
03293     // ---------------------------------------
03294     // new nodes positions are computed,
03295     // record movement in DS and set new UV
03296     // ---------------------------------------
03297     nodeToMove = setMovableNodes.begin();
03298     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
03299       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
03300       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
03301       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
03302       if ( node_uv != uvMap.end() ) {
03303         gp_XY* uv = node_uv->second;
03304         node->SetPosition
03305           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
03306       }
03307     }
03308 
03309     // move medium nodes of quadratic elements
03310     if ( isQuadratic )
03311     {
03312       SMESH_MesherHelper helper( *GetMesh() );
03313       if ( !face.IsNull() )
03314         helper.SetSubShape( face );
03315       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
03316       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
03317         const SMDS_VtkFace* QF =
03318           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
03319         if(QF && QF->IsQuadratic()) {
03320           vector<const SMDS_MeshNode*> Ns;
03321           Ns.reserve(QF->NbNodes()+1);
03322           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
03323           while ( anIter->more() )
03324             Ns.push_back( cast2Node(anIter->next()) );
03325           Ns.push_back( Ns[0] );
03326           double x, y, z;
03327           for(int i=0; i<QF->NbNodes(); i=i+2) {
03328             if ( !surface.IsNull() ) {
03329               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
03330               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
03331               gp_XY uv = ( uv1 + uv2 ) / 2.;
03332               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
03333               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
03334             }
03335             else {
03336               x = (Ns[i]->X() + Ns[i+2]->X())/2;
03337               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
03338               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
03339             }
03340             if( fabs( Ns[i+1]->X() - x ) > disttol ||
03341                 fabs( Ns[i+1]->Y() - y ) > disttol ||
03342                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
03343               // we have to move i+1 node
03344               aMesh->MoveNode( Ns[i+1], x, y, z );
03345             }
03346           }
03347         }
03348       }
03349     }
03350 
03351   } // loop on face ids
03352 
03353 }
03354 
03355 //=======================================================================
03356 //function : isReverse
03357 //purpose  : Return true if normal of prevNodes is not co-directied with
03358 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
03359 //           iNotSame is where prevNodes and nextNodes are different
03360 //=======================================================================
03361 
03362 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
03363                       vector<const SMDS_MeshNode*> nextNodes,
03364                       const int            nbNodes,
03365                       const int            iNotSame)
03366 {
03367   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
03368   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
03369 
03370   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
03371   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
03372   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
03373   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
03374 
03375   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
03376   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
03377   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
03378   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
03379 
03380   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
03381 
03382   return (vA ^ vB) * vN < 0.0;
03383 }
03384 
03385 //=======================================================================
03394 //=======================================================================
03395 
03396 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
03397                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
03398                                     list<const SMDS_MeshElement*>&        newElems,
03399                                     const int                             nbSteps,
03400                                     SMESH_SequenceOfElemPtr&              srcElements)
03401 {
03402   //MESSAGE("sweepElement " << nbSteps);
03403   SMESHDS_Mesh* aMesh = GetMeshDS();
03404 
03405   // Loop on elem nodes:
03406   // find new nodes and detect same nodes indices
03407   int nbNodes = elem->NbNodes();
03408   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
03409   vector<const SMDS_MeshNode*> prevNod( nbNodes );
03410   vector<const SMDS_MeshNode*> nextNod( nbNodes );
03411   vector<const SMDS_MeshNode*> midlNod( nbNodes );
03412 
03413   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
03414   vector<int> sames(nbNodes);
03415   vector<bool> issimple(nbNodes);
03416 
03417   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
03418     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
03419     const SMDS_MeshNode*                 node         = nnIt->first;
03420     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
03421     if ( listNewNodes.empty() ) {
03422       return;
03423     }
03424 
03425     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
03426 
03427     itNN[ iNode ] = listNewNodes.begin();
03428     prevNod[ iNode ] = node;
03429     nextNod[ iNode ] = listNewNodes.front();
03430     if( !elem->IsQuadratic() || !issimple[iNode] ) {
03431       if ( prevNod[ iNode ] != nextNod [ iNode ])
03432         iNotSameNode = iNode;
03433       else {
03434         iSameNode = iNode;
03435         //nbSame++;
03436         sames[nbSame++] = iNode;
03437       }
03438     }
03439   }
03440 
03441   //cerr<<"  nbSame = "<<nbSame<<endl;
03442   if ( nbSame == nbNodes || nbSame > 2) {
03443     MESSAGE( " Too many same nodes of element " << elem->GetID() );
03444     //INFOS( " Too many same nodes of element " << elem->GetID() );
03445     return;
03446   }
03447 
03448   //  if( elem->IsQuadratic() && nbSame>0 ) {
03449   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
03450   //    return;
03451   //  }
03452 
03453   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
03454   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
03455   if ( nbSame > 0 ) {
03456     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
03457     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
03458     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
03459   }
03460 
03461   //if(nbNodes==8)
03462   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
03463   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
03464   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
03465   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
03466 
03467   // check element orientation
03468   int i0 = 0, i2 = 2;
03469   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
03470     //MESSAGE("Reversed elem " << elem );
03471     i0 = 2;
03472     i2 = 0;
03473     if ( nbSame > 0 )
03474       std::swap( iBeforeSame, iAfterSame );
03475   }
03476 
03477   // make new elements
03478   const SMDS_MeshElement* lastElem = elem;
03479   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
03480     // get next nodes
03481     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
03482       if(issimple[iNode]) {
03483         nextNod[ iNode ] = *itNN[ iNode ];
03484         itNN[ iNode ]++;
03485       }
03486       else {
03487         if( elem->GetType()==SMDSAbs_Node ) {
03488           // we have to use two nodes
03489           midlNod[ iNode ] = *itNN[ iNode ];
03490           itNN[ iNode ]++;
03491           nextNod[ iNode ] = *itNN[ iNode ];
03492           itNN[ iNode ]++;
03493         }
03494         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
03495           // we have to use each second node
03496           //itNN[ iNode ]++;
03497           nextNod[ iNode ] = *itNN[ iNode ];
03498           itNN[ iNode ]++;
03499         }
03500         else {
03501           // we have to use two nodes
03502           midlNod[ iNode ] = *itNN[ iNode ];
03503           itNN[ iNode ]++;
03504           nextNod[ iNode ] = *itNN[ iNode ];
03505           itNN[ iNode ]++;
03506         }
03507       }
03508     }
03509     SMDS_MeshElement* aNewElem = 0;
03510     if(!elem->IsPoly()) {
03511       switch ( nbNodes ) {
03512       case 0:
03513         return;
03514       case 1: { // NODE
03515         if ( nbSame == 0 ) {
03516           if(issimple[0])
03517             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
03518           else
03519             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
03520         }
03521         break;
03522       }
03523       case 2: { // EDGE
03524         if ( nbSame == 0 )
03525           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
03526                                     nextNod[ 1 ], nextNod[ 0 ] );
03527         else
03528           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
03529                                     nextNod[ iNotSameNode ] );
03530         break;
03531       }
03532 
03533       case 3: { // TRIANGLE or quadratic edge
03534         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
03535 
03536           if ( nbSame == 0 )       // --- pentahedron
03537             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
03538                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
03539 
03540           else if ( nbSame == 1 )  // --- pyramid
03541             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
03542                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
03543                                          nextNod[ iSameNode ]);
03544 
03545           else // 2 same nodes:      --- tetrahedron
03546             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
03547                                          nextNod[ iNotSameNode ]);
03548         }
03549         else { // quadratic edge
03550           if(nbSame==0) {     // quadratic quadrangle
03551             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
03552                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
03553           }
03554           else if(nbSame==1) { // quadratic triangle
03555             if(sames[0]==2) {
03556               return; // medium node on axis
03557             }
03558             else if(sames[0]==0) {
03559               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
03560                                         nextNod[2], midlNod[1], prevNod[2]);
03561             }
03562             else { // sames[0]==1
03563               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
03564                                         midlNod[0], nextNod[2], prevNod[2]);
03565             }
03566           }
03567           else {
03568             return;
03569           }
03570         }
03571         break;
03572       }
03573       case 4: { // QUADRANGLE
03574 
03575         if ( nbSame == 0 )       // --- hexahedron
03576           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
03577                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
03578 
03579         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
03580           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
03581                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
03582                                        nextNod[ iSameNode ]);
03583           newElems.push_back( aNewElem );
03584           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
03585                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
03586                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
03587         }
03588         else if ( nbSame == 2 ) { // pentahedron
03589           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
03590             // iBeforeSame is same too
03591             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
03592                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
03593                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
03594           else
03595             // iAfterSame is same too
03596             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
03597                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
03598                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
03599         }
03600         break;
03601       }
03602       case 6: { // quadratic triangle
03603         // create pentahedron with 15 nodes
03604         if(nbSame==0) {
03605           if(i0>0) { // reversed case
03606             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
03607                                          nextNod[0], nextNod[2], nextNod[1],
03608                                          prevNod[5], prevNod[4], prevNod[3],
03609                                          nextNod[5], nextNod[4], nextNod[3],
03610                                          midlNod[0], midlNod[2], midlNod[1]);
03611           }
03612           else { // not reversed case
03613             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
03614                                          nextNod[0], nextNod[1], nextNod[2],
03615                                          prevNod[3], prevNod[4], prevNod[5],
03616                                          nextNod[3], nextNod[4], nextNod[5],
03617                                          midlNod[0], midlNod[1], midlNod[2]);
03618           }
03619         }
03620         else if(nbSame==1) {
03621           // 2d order pyramid of 13 nodes
03622           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
03623           //                                 int n12,int n23,int n34,int n41,
03624           //                                 int n15,int n25,int n35,int n45, int ID);
03625           int n5 = iSameNode;
03626           int n1,n4,n41,n15,n45;
03627           if(i0>0) { // reversed case
03628             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
03629             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
03630             n41 = n1 + 3;
03631             n15 = n5 + 3;
03632             n45 = n4 + 3;
03633           }
03634           else {
03635             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
03636             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
03637             n41 = n4 + 3;
03638             n15 = n1 + 3;
03639             n45 = n5 + 3;
03640           }
03641           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
03642                                       nextNod[n4], prevNod[n4], prevNod[n5],
03643                                       midlNod[n1], nextNod[n41],
03644                                       midlNod[n4], prevNod[n41],
03645                                       prevNod[n15], nextNod[n15],
03646                                       nextNod[n45], prevNod[n45]);
03647         }
03648         else if(nbSame==2) {
03649           // 2d order tetrahedron of 10 nodes
03650           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
03651           //                                 int n12,int n23,int n31,
03652           //                                 int n14,int n24,int n34, int ID);
03653           int n1 = iNotSameNode;
03654           int n2,n3,n12,n23,n31;
03655           if(i0>0) { // reversed case
03656             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
03657             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
03658             n12 = n2 + 3;
03659             n23 = n3 + 3;
03660             n31 = n1 + 3;
03661           }
03662           else {
03663             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
03664             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
03665             n12 = n1 + 3;
03666             n23 = n2 + 3;
03667             n31 = n3 + 3;
03668           }
03669           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
03670                                        prevNod[n12], prevNod[n23], prevNod[n31],
03671                                        midlNod[n1], nextNod[n12], nextNod[n31]);
03672         }
03673         break;
03674       }
03675       case 8: { // quadratic quadrangle
03676         if(nbSame==0) {
03677           // create hexahedron with 20 nodes
03678           if(i0>0) { // reversed case
03679             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
03680                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
03681                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
03682                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
03683                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
03684           }
03685           else { // not reversed case
03686             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
03687                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
03688                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
03689                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
03690                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
03691           }
03692         }
03693         else if(nbSame==1) { 
03694           // --- pyramid + pentahedron - can not be created since it is needed 
03695           // additional middle node ot the center of face
03696           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
03697           return;
03698         }
03699         else if(nbSame==2) {
03700           // 2d order Pentahedron with 15 nodes
03701           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
03702           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
03703           //                                 int n14,int n25,int n36, int ID);
03704           int n1,n2,n4,n5;
03705           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
03706             // iBeforeSame is same too
03707             n1 = iBeforeSame;
03708             n2 = iOpposSame;
03709             n4 = iSameNode;
03710             n5 = iAfterSame;
03711           }
03712           else {
03713             // iAfterSame is same too
03714             n1 = iSameNode;
03715             n2 = iBeforeSame;
03716             n4 = iAfterSame;
03717             n5 = iOpposSame;
03718           }
03719           int n12,n45,n14,n25;
03720           if(i0>0) { //reversed case
03721             n12 = n1 + 4;
03722             n45 = n5 + 4;
03723             n14 = n4 + 4;
03724             n25 = n2 + 4;
03725           }
03726           else {
03727             n12 = n2 + 4;
03728             n45 = n4 + 4;
03729             n14 = n1 + 4;
03730             n25 = n5 + 4;
03731           }
03732           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
03733                                        prevNod[n4], prevNod[n5], nextNod[n5],
03734                                        prevNod[n12], midlNod[n2], nextNod[n12],
03735                                        prevNod[n45], midlNod[n5], nextNod[n45],
03736                                        prevNod[n14], prevNod[n25], nextNod[n25]);
03737         }
03738         break;
03739       }
03740       default: {
03741         // realized for extrusion only
03742         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
03743         //vector<int> quantities (nbNodes + 2);
03744 
03745         //quantities[0] = nbNodes; // bottom of prism
03746         //for (int inode = 0; inode < nbNodes; inode++) {
03747         //  polyedre_nodes[inode] = prevNod[inode];
03748         //}
03749 
03750         //quantities[1] = nbNodes; // top of prism
03751         //for (int inode = 0; inode < nbNodes; inode++) {
03752         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
03753         //}
03754 
03755         //for (int iface = 0; iface < nbNodes; iface++) {
03756         //  quantities[iface + 2] = 4;
03757         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
03758         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
03759         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
03760         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
03761         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
03762         //}
03763         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
03764         break;
03765       }
03766       }
03767     }
03768 
03769     if(!aNewElem) {
03770       // realized for extrusion only
03771       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
03772       vector<int> quantities (nbNodes + 2);
03773 
03774       quantities[0] = nbNodes; // bottom of prism
03775       for (int inode = 0; inode < nbNodes; inode++) {
03776         polyedre_nodes[inode] = prevNod[inode];
03777       }
03778 
03779       quantities[1] = nbNodes; // top of prism
03780       for (int inode = 0; inode < nbNodes; inode++) {
03781         polyedre_nodes[nbNodes + inode] = nextNod[inode];
03782       }
03783 
03784       for (int iface = 0; iface < nbNodes; iface++) {
03785         quantities[iface + 2] = 4;
03786         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
03787         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
03788         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
03789         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
03790         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
03791       }
03792       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
03793     }
03794 
03795     if ( aNewElem ) {
03796       newElems.push_back( aNewElem );
03797       myLastCreatedElems.Append(aNewElem);
03798       srcElements.Append( elem );
03799       lastElem = aNewElem;
03800     }
03801 
03802     // set new prev nodes
03803     for ( iNode = 0; iNode < nbNodes; iNode++ )
03804       prevNod[ iNode ] = nextNod[ iNode ];
03805 
03806   } // for steps
03807 }
03808 
03809 //=======================================================================
03819 //=======================================================================
03820 
03821 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
03822                                   TElemOfElemListMap &     newElemsMap,
03823                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
03824                                   TIDSortedElemSet&        elemSet,
03825                                   const int                nbSteps,
03826                                   SMESH_SequenceOfElemPtr& srcElements)
03827 {
03828   MESSAGE("makeWalls");
03829   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
03830   SMESHDS_Mesh* aMesh = GetMeshDS();
03831 
03832   // Find nodes belonging to only one initial element - sweep them to get edges.
03833 
03834   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
03835   for ( ; nList != mapNewNodes.end(); nList++ ) {
03836     const SMDS_MeshNode* node =
03837       static_cast<const SMDS_MeshNode*>( nList->first );
03838     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
03839     int nbInitElems = 0;
03840     const SMDS_MeshElement* el = 0;
03841     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
03842     while ( eIt->more() && nbInitElems < 2 ) {
03843       el = eIt->next();
03844       SMDSAbs_ElementType type = el->GetType();
03845       if ( type == SMDSAbs_Volume || type < highType ) continue;
03846       if ( type > highType ) {
03847         nbInitElems = 0;
03848         highType = type;
03849       }
03850       if ( elemSet.find(el) != elemSet.end() )
03851         nbInitElems++;
03852     }
03853     if ( nbInitElems < 2 ) {
03854       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
03855       if(!NotCreateEdge) {
03856         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
03857         list<const SMDS_MeshElement*> newEdges;
03858         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
03859       }
03860     }
03861   }
03862 
03863   // Make a ceiling for each element ie an equal element of last new nodes.
03864   // Find free links of faces - make edges and sweep them into faces.
03865 
03866   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
03867   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
03868   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
03869     const SMDS_MeshElement* elem = itElem->first;
03870     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
03871 
03872     if(itElem->second.size()==0) continue;
03873 
03874     if ( elem->GetType() == SMDSAbs_Edge ) {
03875       // create a ceiling edge
03876       if (!elem->IsQuadratic()) {
03877         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
03878                                vecNewNodes[ 1 ]->second.back())) {
03879           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
03880                                                    vecNewNodes[ 1 ]->second.back()));
03881           srcElements.Append( myLastCreatedElems.Last() );
03882         }
03883       }
03884       else {
03885         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
03886                                vecNewNodes[ 1 ]->second.back(),
03887                                vecNewNodes[ 2 ]->second.back())) {
03888           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
03889                                                    vecNewNodes[ 1 ]->second.back(),
03890                                                    vecNewNodes[ 2 ]->second.back()));
03891           srcElements.Append( myLastCreatedElems.Last() );
03892         }
03893       }
03894     }
03895     if ( elem->GetType() != SMDSAbs_Face )
03896       continue;
03897 
03898     bool hasFreeLinks = false;
03899 
03900     TIDSortedElemSet avoidSet;
03901     avoidSet.insert( elem );
03902 
03903     set<const SMDS_MeshNode*> aFaceLastNodes;
03904     int iNode, nbNodes = vecNewNodes.size();
03905     if(!elem->IsQuadratic()) {
03906       // loop on the face nodes
03907       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
03908         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
03909         // look for free links of the face
03910         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
03911         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
03912         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
03913         // check if a link is free
03914         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
03915           hasFreeLinks = true;
03916           // make an edge and a ceiling for a new edge
03917           if ( !aMesh->FindEdge( n1, n2 )) {
03918             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
03919             srcElements.Append( myLastCreatedElems.Last() );
03920           }
03921           n1 = vecNewNodes[ iNode ]->second.back();
03922           n2 = vecNewNodes[ iNext ]->second.back();
03923           if ( !aMesh->FindEdge( n1, n2 )) {
03924             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
03925             srcElements.Append( myLastCreatedElems.Last() );
03926           }
03927         }
03928       }
03929     }
03930     else { // elem is quadratic face
03931       int nbn = nbNodes/2;
03932       for ( iNode = 0; iNode < nbn; iNode++ ) {
03933         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
03934         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
03935         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
03936         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
03937         // check if a link is free
03938         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
03939           hasFreeLinks = true;
03940           // make an edge and a ceiling for a new edge
03941           // find medium node
03942           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
03943           if ( !aMesh->FindEdge( n1, n2, n3 )) {
03944             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
03945             srcElements.Append( myLastCreatedElems.Last() );
03946           }
03947           n1 = vecNewNodes[ iNode ]->second.back();
03948           n2 = vecNewNodes[ iNext ]->second.back();
03949           n3 = vecNewNodes[ iNode+nbn ]->second.back();
03950           if ( !aMesh->FindEdge( n1, n2, n3 )) {
03951             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
03952             srcElements.Append( myLastCreatedElems.Last() );
03953           }
03954         }
03955       }
03956       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
03957         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
03958       }
03959     }
03960 
03961     // sweep free links into faces
03962 
03963     if ( hasFreeLinks )  {
03964       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
03965       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
03966 
03967       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
03968       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
03969         initNodeSet.insert( vecNewNodes[ iNode ]->first );
03970         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
03971       }
03972       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
03973         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
03974         iVol = 0;
03975         while ( iVol++ < volNb ) v++;
03976         // find indices of free faces of a volume and their source edges
03977         list< int > freeInd;
03978         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
03979         SMDS_VolumeTool vTool( *v );
03980         int iF, nbF = vTool.NbFaces();
03981         for ( iF = 0; iF < nbF; iF ++ ) {
03982           if (vTool.IsFreeFace( iF ) &&
03983               vTool.GetFaceNodes( iF, faceNodeSet ) &&
03984               initNodeSet != faceNodeSet) // except an initial face
03985           {
03986             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
03987               continue;
03988             freeInd.push_back( iF );
03989             // find source edge of a free face iF
03990             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
03991             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
03992             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
03993                                    initNodeSet.begin(), initNodeSet.end(),
03994                                    commonNodes.begin());
03995             if ( (*v)->IsQuadratic() )
03996               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
03997             else
03998               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
03999 #ifdef _DEBUG_
04000             if ( !srcEdges.back() )
04001             {
04002               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
04003                    << iF << " of volume #" << vTool.ID() << endl;
04004             }
04005 #endif
04006           }
04007         }
04008         if ( freeInd.empty() )
04009           continue;
04010 
04011         // create faces for all steps;
04012         // if such a face has been already created by sweep of edge,
04013         // assure that its orientation is OK
04014         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
04015           vTool.Set( *v );
04016           vTool.SetExternalNormal();
04017           const int nextShift = vTool.IsForward() ? +1 : -1;
04018           list< int >::iterator ind = freeInd.begin();
04019           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
04020           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
04021           {
04022             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
04023             int nbn = vTool.NbFaceNodes( *ind );
04024             if ( ! (*v)->IsPoly() )
04025               switch ( nbn ) {
04026               case 3: { 
04027                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
04028                 if ( !f ||
04029                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
04030                 {
04031                   const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
04032                                                        nodes[ 1 ],
04033                                                        nodes[ 1 + nextShift ] };
04034                   if ( f )
04035                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
04036                   else
04037                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
04038                                                               newOrder[ 2 ] ));
04039                 }
04040                 break;
04041               }
04042               case 4: { 
04043                 const SMDS_MeshFace * f =
04044                   aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
04045                 if ( !f ||
04046                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
04047                 {
04048                   const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
04049                                                        nodes[ 2 ], nodes[ 2+nextShift ] };
04050                   if ( f )
04051                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
04052                   else
04053                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
04054                                                               newOrder[ 2 ], newOrder[ 3 ]));
04055                 }
04056                 break;
04057               }
04058               case 6: { 
04059                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
04060                                                            nodes[1], nodes[3], nodes[5] );
04061                 if ( !f ||
04062                      nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
04063                 {
04064                   const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
04065                                                        nodes[2],
04066                                                        nodes[2 + 2*nextShift],
04067                                                        nodes[3 - 2*nextShift],
04068                                                        nodes[3],
04069                                                        nodes[3 + 2*nextShift]};
04070                   if ( f )
04071                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
04072                   else
04073                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
04074                                                               newOrder[ 1 ],
04075                                                               newOrder[ 2 ],
04076                                                               newOrder[ 3 ],
04077                                                               newOrder[ 4 ],
04078                                                               newOrder[ 5 ] ));
04079                 }
04080                 break;
04081               }
04082               default:       
04083                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
04084                                                            nodes[1], nodes[3], nodes[5], nodes[7] );
04085                 if ( !f ||
04086                      nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
04087                 {
04088                   const SMDS_MeshNode* newOrder[8] = { nodes[0],
04089                                                        nodes[4 - 2*nextShift],
04090                                                        nodes[4],
04091                                                        nodes[4 + 2*nextShift],
04092                                                        nodes[1],
04093                                                        nodes[5 - 2*nextShift],
04094                                                        nodes[5],
04095                                                        nodes[5 + 2*nextShift] };
04096                   if ( f )
04097                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
04098                   else
04099                     myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
04100                                                              newOrder[ 2 ], newOrder[ 3 ],
04101                                                              newOrder[ 4 ], newOrder[ 5 ],
04102                                                              newOrder[ 6 ], newOrder[ 7 ]));
04103                 }
04104               } // switch ( nbn )
04105 
04106             else { 
04107 
04108               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
04109               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
04110               if ( !f ||
04111                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
04112               {
04113                 if ( !vTool.IsForward() )
04114                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
04115                 if ( f )
04116                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
04117                 else
04118                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
04119               }
04120             }
04121 
04122             while ( srcElements.Length() < myLastCreatedElems.Length() )
04123               srcElements.Append( *srcEdge );
04124 
04125           }  // loop on free faces
04126 
04127           // go to the next volume
04128           iVol = 0;
04129           while ( iVol++ < nbVolumesByStep ) v++;
04130 
04131         } // loop on steps
04132       } // loop on volumes of one step
04133     } // sweep free links into faces
04134 
04135     // Make a ceiling face with a normal external to a volume
04136 
04137     SMDS_VolumeTool lastVol( itElem->second.back() );
04138 
04139     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
04140     if ( iF >= 0 ) {
04141       lastVol.SetExternalNormal();
04142       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
04143       int nbn = lastVol.NbFaceNodes( iF );
04144       switch ( nbn ) {
04145       case 3:
04146         if (!hasFreeLinks ||
04147             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
04148           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
04149         break;
04150       case 4:
04151         if (!hasFreeLinks ||
04152             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
04153           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
04154         break;
04155       default:
04156         if(itElem->second.back()->IsQuadratic()) {
04157           if(nbn==6) {
04158             if (!hasFreeLinks ||
04159                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
04160                                  nodes[1], nodes[3], nodes[5]) ) {
04161               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
04162                                                        nodes[1], nodes[3], nodes[5]));
04163             }
04164           }
04165           else { // nbn==8
04166             if (!hasFreeLinks ||
04167                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
04168                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
04169               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
04170                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
04171           }
04172         }
04173         else {
04174           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
04175           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
04176             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
04177         }
04178       } // switch
04179 
04180       while ( srcElements.Length() < myLastCreatedElems.Length() )
04181         srcElements.Append( myLastCreatedElems.Last() );
04182     }
04183   } // loop on swept elements
04184 }
04185 
04186 //=======================================================================
04187 //function : RotationSweep
04188 //purpose  :
04189 //=======================================================================
04190 
04191 SMESH_MeshEditor::PGroupIDs
04192 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
04193                                 const gp_Ax1&      theAxis,
04194                                 const double       theAngle,
04195                                 const int          theNbSteps,
04196                                 const double       theTol,
04197                                 const bool         theMakeGroups,
04198                                 const bool         theMakeWalls)
04199 {
04200   myLastCreatedElems.Clear();
04201   myLastCreatedNodes.Clear();
04202 
04203   // source elements for each generated one
04204   SMESH_SequenceOfElemPtr srcElems, srcNodes;
04205 
04206   MESSAGE( "RotationSweep()");
04207   gp_Trsf aTrsf;
04208   aTrsf.SetRotation( theAxis, theAngle );
04209   gp_Trsf aTrsf2;
04210   aTrsf2.SetRotation( theAxis, theAngle/2. );
04211 
04212   gp_Lin aLine( theAxis );
04213   double aSqTol = theTol * theTol;
04214 
04215   SMESHDS_Mesh* aMesh = GetMeshDS();
04216 
04217   TNodeOfNodeListMap mapNewNodes;
04218   TElemOfVecOfNnlmiMap mapElemNewNodes;
04219   TElemOfElemListMap newElemsMap;
04220 
04221   // loop on theElems
04222   TIDSortedElemSet::iterator itElem;
04223   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
04224     const SMDS_MeshElement* elem = *itElem;
04225     if ( !elem || elem->GetType() == SMDSAbs_Volume )
04226       continue;
04227     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
04228     newNodesItVec.reserve( elem->NbNodes() );
04229 
04230     // loop on elem nodes
04231     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
04232     while ( itN->more() ) {
04233       // check if a node has been already sweeped
04234       const SMDS_MeshNode* node = cast2Node( itN->next() );
04235 
04236       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
04237       double coord[3];
04238       aXYZ.Coord( coord[0], coord[1], coord[2] );
04239       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
04240 
04241       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
04242       if ( nIt == mapNewNodes.end() ) {
04243         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
04244         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
04245 
04246         // make new nodes
04247         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
04248         //double coord[3];
04249         //aXYZ.Coord( coord[0], coord[1], coord[2] );
04250         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
04251         const SMDS_MeshNode * newNode = node;
04252         for ( int i = 0; i < theNbSteps; i++ ) {
04253           if ( !isOnAxis ) {
04254             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
04255               // create two nodes
04256               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
04257               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
04258               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
04259               myLastCreatedNodes.Append(newNode);
04260               srcNodes.Append( node );
04261               listNewNodes.push_back( newNode );
04262               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
04263               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
04264             }
04265             else {
04266               aTrsf.Transforms( coord[0], coord[1], coord[2] );
04267             }
04268             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
04269             myLastCreatedNodes.Append(newNode);
04270             srcNodes.Append( node );
04271             listNewNodes.push_back( newNode );
04272           }
04273           else {
04274             listNewNodes.push_back( newNode );
04275             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
04276               listNewNodes.push_back( newNode );
04277             }
04278           }
04279         }
04280       }
04281       /*
04282         else {
04283         // if current elem is quadratic and current node is not medium
04284         // we have to check - may be it is needed to insert additional nodes
04285         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
04286         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
04287         if(listNewNodes.size()==theNbSteps) {
04288         listNewNodes.clear();
04289         // make new nodes
04290         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
04291         //double coord[3];
04292         //aXYZ.Coord( coord[0], coord[1], coord[2] );
04293         const SMDS_MeshNode * newNode = node;
04294         if ( !isOnAxis ) {
04295         for(int i = 0; i<theNbSteps; i++) {
04296         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
04297         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
04298         cout<<"    3 AddNode:  "<<newNode;
04299         myLastCreatedNodes.Append(newNode);
04300         listNewNodes.push_back( newNode );
04301         srcNodes.Append( node );
04302         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
04303         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
04304         cout<<"    4 AddNode:  "<<newNode;
04305         myLastCreatedNodes.Append(newNode);
04306         srcNodes.Append( node );
04307         listNewNodes.push_back( newNode );
04308         }
04309         }
04310         else {
04311         listNewNodes.push_back( newNode );
04312         }
04313         }
04314         }
04315         }
04316       */
04317       newNodesItVec.push_back( nIt );
04318     }
04319     // make new elements
04320     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
04321   }
04322 
04323   if ( theMakeWalls )
04324     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
04325 
04326   PGroupIDs newGroupIDs;
04327   if ( theMakeGroups )
04328     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
04329 
04330   return newGroupIDs;
04331 }
04332 
04333 
04334 //=======================================================================
04335 //function : CreateNode
04336 //purpose  :
04337 //=======================================================================
04338 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
04339                                                   const double y,
04340                                                   const double z,
04341                                                   const double tolnode,
04342                                                   SMESH_SequenceOfNode& aNodes)
04343 {
04344   myLastCreatedElems.Clear();
04345   myLastCreatedNodes.Clear();
04346 
04347   gp_Pnt P1(x,y,z);
04348   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
04349 
04350   // try to search in sequence of existing nodes
04351   // if aNodes.Length()>0 we 'nave to use given sequence
04352   // else - use all nodes of mesh
04353   if(aNodes.Length()>0) {
04354     int i;
04355     for(i=1; i<=aNodes.Length(); i++) {
04356       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
04357       if(P1.Distance(P2)<tolnode)
04358         return aNodes.Value(i);
04359     }
04360   }
04361   else {
04362     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
04363     while(itn->more()) {
04364       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
04365       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
04366       if(P1.Distance(P2)<tolnode)
04367         return aN;
04368     }
04369   }
04370 
04371   // create new node and return it
04372   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
04373   myLastCreatedNodes.Append(NewNode);
04374   return NewNode;
04375 }
04376 
04377 
04378 //=======================================================================
04379 //function : ExtrusionSweep
04380 //purpose  :
04381 //=======================================================================
04382 
04383 SMESH_MeshEditor::PGroupIDs
04384 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
04385                                   const gp_Vec&       theStep,
04386                                   const int           theNbSteps,
04387                                   TElemOfElemListMap& newElemsMap,
04388                                   const bool          theMakeGroups,
04389                                   const int           theFlags,
04390                                   const double        theTolerance)
04391 {
04392   ExtrusParam aParams;
04393   aParams.myDir = gp_Dir(theStep);
04394   aParams.myNodes.Clear();
04395   aParams.mySteps = new TColStd_HSequenceOfReal;
04396   int i;
04397   for(i=1; i<=theNbSteps; i++)
04398     aParams.mySteps->Append(theStep.Magnitude());
04399 
04400   return
04401     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
04402 }
04403 
04404 
04405 //=======================================================================
04406 //function : ExtrusionSweep
04407 //purpose  :
04408 //=======================================================================
04409 
04410 SMESH_MeshEditor::PGroupIDs
04411 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
04412                                   ExtrusParam&        theParams,
04413                                   TElemOfElemListMap& newElemsMap,
04414                                   const bool          theMakeGroups,
04415                                   const int           theFlags,
04416                                   const double        theTolerance)
04417 {
04418   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
04419   myLastCreatedElems.Clear();
04420   myLastCreatedNodes.Clear();
04421 
04422   // source elements for each generated one
04423   SMESH_SequenceOfElemPtr srcElems, srcNodes;
04424 
04425   SMESHDS_Mesh* aMesh = GetMeshDS();
04426 
04427   int nbsteps = theParams.mySteps->Length();
04428 
04429   TNodeOfNodeListMap mapNewNodes;
04430   //TNodeOfNodeVecMap mapNewNodes;
04431   TElemOfVecOfNnlmiMap mapElemNewNodes;
04432   //TElemOfVecOfMapNodesMap mapElemNewNodes;
04433 
04434   // loop on theElems
04435   TIDSortedElemSet::iterator itElem;
04436   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
04437     // check element type
04438     const SMDS_MeshElement* elem = *itElem;
04439     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
04440       continue;
04441 
04442     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
04443     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
04444     newNodesItVec.reserve( elem->NbNodes() );
04445 
04446     // loop on elem nodes
04447     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
04448     while ( itN->more() )
04449     {
04450       // check if a node has been already sweeped
04451       const SMDS_MeshNode* node = cast2Node( itN->next() );
04452       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
04453       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
04454       if ( nIt == mapNewNodes.end() ) {
04455         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
04456         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
04457         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
04458         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
04459         //vecNewNodes.reserve(nbsteps);
04460 
04461         // make new nodes
04462         double coord[] = { node->X(), node->Y(), node->Z() };
04463         //int nbsteps = theParams.mySteps->Length();
04464         for ( int i = 0; i < nbsteps; i++ ) {
04465           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
04466             // create additional node
04467             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
04468             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
04469             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
04470             if( theFlags & EXTRUSION_FLAG_SEW ) {
04471               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
04472                                                          theTolerance, theParams.myNodes);
04473               listNewNodes.push_back( newNode );
04474             }
04475             else {
04476               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
04477               myLastCreatedNodes.Append(newNode);
04478               srcNodes.Append( node );
04479               listNewNodes.push_back( newNode );
04480             }
04481           }
04482           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
04483           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
04484           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
04485           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
04486           if( theFlags & EXTRUSION_FLAG_SEW ) {
04487             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
04488                                                        theTolerance, theParams.myNodes);
04489             listNewNodes.push_back( newNode );
04490             //vecNewNodes[i]=newNode;
04491           }
04492           else {
04493             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
04494             myLastCreatedNodes.Append(newNode);
04495             srcNodes.Append( node );
04496             listNewNodes.push_back( newNode );
04497             //vecNewNodes[i]=newNode;
04498           }
04499         }
04500       }
04501       else {
04502         // if current elem is quadratic and current node is not medium
04503         // we have to check - may be it is needed to insert additional nodes
04504         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
04505           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
04506           if(listNewNodes.size()==nbsteps) {
04507             listNewNodes.clear();
04508             double coord[] = { node->X(), node->Y(), node->Z() };
04509             for ( int i = 0; i < nbsteps; i++ ) {
04510               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
04511               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
04512               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
04513               if( theFlags & EXTRUSION_FLAG_SEW ) {
04514                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
04515                                                            theTolerance, theParams.myNodes);
04516                 listNewNodes.push_back( newNode );
04517               }
04518               else {
04519                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
04520                 myLastCreatedNodes.Append(newNode);
04521                 srcNodes.Append( node );
04522                 listNewNodes.push_back( newNode );
04523               }
04524               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
04525               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
04526               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
04527               if( theFlags & EXTRUSION_FLAG_SEW ) {
04528                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
04529                                                            theTolerance, theParams.myNodes);
04530                 listNewNodes.push_back( newNode );
04531               }
04532               else {
04533                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
04534                 myLastCreatedNodes.Append(newNode);
04535                 srcNodes.Append( node );
04536                 listNewNodes.push_back( newNode );
04537               }
04538             }
04539           }
04540         }
04541       }
04542       newNodesItVec.push_back( nIt );
04543     }
04544     // make new elements
04545     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
04546   }
04547 
04548   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
04549     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
04550   }
04551   PGroupIDs newGroupIDs;
04552   if ( theMakeGroups )
04553     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
04554 
04555   return newGroupIDs;
04556 }
04557 
04558 /*
04559 //=======================================================================
04560 //class    : SMESH_MeshEditor_PathPoint
04561 //purpose  : auxiliary class
04562 //=======================================================================
04563 class SMESH_MeshEditor_PathPoint {
04564 public:
04565 SMESH_MeshEditor_PathPoint() {
04566 myPnt.SetCoord(99., 99., 99.);
04567 myTgt.SetCoord(1.,0.,0.);
04568 myAngle=0.;
04569 myPrm=0.;
04570 }
04571 void SetPnt(const gp_Pnt& aP3D){
04572 myPnt=aP3D;
04573 }
04574 void SetTangent(const gp_Dir& aTgt){
04575 myTgt=aTgt;
04576 }
04577 void SetAngle(const double& aBeta){
04578 myAngle=aBeta;
04579 }
04580 void SetParameter(const double& aPrm){
04581 myPrm=aPrm;
04582 }
04583 const gp_Pnt& Pnt()const{
04584 return myPnt;
04585 }
04586 const gp_Dir& Tangent()const{
04587 return myTgt;
04588 }
04589 double Angle()const{
04590 return myAngle;
04591 }
04592 double Parameter()const{
04593 return myPrm;
04594 }
04595 
04596 protected:
04597 gp_Pnt myPnt;
04598 gp_Dir myTgt;
04599 double myAngle;
04600 double myPrm;
04601 };
04602 */
04603 
04604 //=======================================================================
04605 //function : ExtrusionAlongTrack
04606 //purpose  :
04607 //=======================================================================
04608 SMESH_MeshEditor::Extrusion_Error
04609 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
04610                                        SMESH_subMesh*       theTrack,
04611                                        const SMDS_MeshNode* theN1,
04612                                        const bool           theHasAngles,
04613                                        list<double>&        theAngles,
04614                                        const bool           theLinearVariation,
04615                                        const bool           theHasRefPoint,
04616                                        const gp_Pnt&        theRefPoint,
04617                                        const bool           theMakeGroups)
04618 {
04619   MESSAGE("ExtrusionAlongTrack");
04620   myLastCreatedElems.Clear();
04621   myLastCreatedNodes.Clear();
04622 
04623   int aNbE;
04624   std::list<double> aPrms;
04625   TIDSortedElemSet::iterator itElem;
04626 
04627   gp_XYZ aGC;
04628   TopoDS_Edge aTrackEdge;
04629   TopoDS_Vertex aV1, aV2;
04630 
04631   SMDS_ElemIteratorPtr aItE;
04632   SMDS_NodeIteratorPtr aItN;
04633   SMDSAbs_ElementType aTypeE;
04634 
04635   TNodeOfNodeListMap mapNewNodes;
04636 
04637   // 1. Check data
04638   aNbE = theElements.size();
04639   // nothing to do
04640   if ( !aNbE )
04641     return EXTR_NO_ELEMENTS;
04642 
04643   // 1.1 Track Pattern
04644   ASSERT( theTrack );
04645 
04646   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
04647 
04648   aItE = pSubMeshDS->GetElements();
04649   while ( aItE->more() ) {
04650     const SMDS_MeshElement* pE = aItE->next();
04651     aTypeE = pE->GetType();
04652     // Pattern must contain links only
04653     if ( aTypeE != SMDSAbs_Edge )
04654       return EXTR_PATH_NOT_EDGE;
04655   }
04656 
04657   list<SMESH_MeshEditor_PathPoint> fullList;
04658 
04659   const TopoDS_Shape& aS = theTrack->GetSubShape();
04660   // Sub shape for the Pattern must be an Edge or Wire
04661   if( aS.ShapeType() == TopAbs_EDGE ) {
04662     aTrackEdge = TopoDS::Edge( aS );
04663     // the Edge must not be degenerated
04664     if ( BRep_Tool::Degenerated( aTrackEdge ) )
04665       return EXTR_BAD_PATH_SHAPE;
04666     TopExp::Vertices( aTrackEdge, aV1, aV2 );
04667     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
04668     const SMDS_MeshNode* aN1 = aItN->next();
04669     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
04670     const SMDS_MeshNode* aN2 = aItN->next();
04671     // starting node must be aN1 or aN2
04672     if ( !( aN1 == theN1 || aN2 == theN1 ) )
04673       return EXTR_BAD_STARTING_NODE;
04674     aItN = pSubMeshDS->GetNodes();
04675     while ( aItN->more() ) {
04676       const SMDS_MeshNode* pNode = aItN->next();
04677       const SMDS_EdgePosition* pEPos =
04678         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
04679       double aT = pEPos->GetUParameter();
04680       aPrms.push_back( aT );
04681     }
04682     //Extrusion_Error err =
04683     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
04684   }
04685   else if( aS.ShapeType() == TopAbs_WIRE ) {
04686     list< SMESH_subMesh* > LSM;
04687     TopTools_SequenceOfShape Edges;
04688     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
04689     while(itSM->more()) {
04690       SMESH_subMesh* SM = itSM->next();
04691       LSM.push_back(SM);
04692       const TopoDS_Shape& aS = SM->GetSubShape();
04693       Edges.Append(aS);
04694     }
04695     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
04696     int startNid = theN1->GetID();
04697     TColStd_MapOfInteger UsedNums;
04698     int NbEdges = Edges.Length();
04699     int i = 1;
04700     for(; i<=NbEdges; i++) {
04701       int k = 0;
04702       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
04703       for(; itLSM!=LSM.end(); itLSM++) {
04704         k++;
04705         if(UsedNums.Contains(k)) continue;
04706         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
04707         SMESH_subMesh* locTrack = *itLSM;
04708         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
04709         TopExp::Vertices( aTrackEdge, aV1, aV2 );
04710         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
04711         const SMDS_MeshNode* aN1 = aItN->next();
04712         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
04713         const SMDS_MeshNode* aN2 = aItN->next();
04714         // starting node must be aN1 or aN2
04715         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
04716         // 2. Collect parameters on the track edge
04717         aPrms.clear();
04718         aItN = locMeshDS->GetNodes();
04719         while ( aItN->more() ) {
04720           const SMDS_MeshNode* pNode = aItN->next();
04721           const SMDS_EdgePosition* pEPos =
04722             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
04723           double aT = pEPos->GetUParameter();
04724           aPrms.push_back( aT );
04725         }
04726         list<SMESH_MeshEditor_PathPoint> LPP;
04727         //Extrusion_Error err =
04728         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
04729         LLPPs.push_back(LPP);
04730         UsedNums.Add(k);
04731         // update startN for search following egde
04732         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
04733         else startNid = aN1->GetID();
04734         break;
04735       }
04736     }
04737     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
04738     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
04739     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
04740     for(; itPP!=firstList.end(); itPP++) {
04741       fullList.push_back( *itPP );
04742     }
04743     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
04744     fullList.pop_back();
04745     itLLPP++;
04746     for(; itLLPP!=LLPPs.end(); itLLPP++) {
04747       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
04748       itPP = currList.begin();
04749       SMESH_MeshEditor_PathPoint PP2 = currList.front();
04750       gp_Dir D1 = PP1.Tangent();
04751       gp_Dir D2 = PP2.Tangent();
04752       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
04753                            (D1.Z()+D2.Z())/2 ) );
04754       PP1.SetTangent(Dnew);
04755       fullList.push_back(PP1);
04756       itPP++;
04757       for(; itPP!=firstList.end(); itPP++) {
04758         fullList.push_back( *itPP );
04759       }
04760       PP1 = fullList.back();
04761       fullList.pop_back();
04762     }
04763     // if wire not closed
04764     fullList.push_back(PP1);
04765     // else ???
04766   }
04767   else {
04768     return EXTR_BAD_PATH_SHAPE;
04769   }
04770 
04771   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
04772                           theHasRefPoint, theRefPoint, theMakeGroups);
04773 }
04774 
04775 
04776 //=======================================================================
04777 //function : ExtrusionAlongTrack
04778 //purpose  :
04779 //=======================================================================
04780 SMESH_MeshEditor::Extrusion_Error
04781 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
04782                                        SMESH_Mesh*          theTrack,
04783                                        const SMDS_MeshNode* theN1,
04784                                        const bool           theHasAngles,
04785                                        list<double>&        theAngles,
04786                                        const bool           theLinearVariation,
04787                                        const bool           theHasRefPoint,
04788                                        const gp_Pnt&        theRefPoint,
04789                                        const bool           theMakeGroups)
04790 {
04791   myLastCreatedElems.Clear();
04792   myLastCreatedNodes.Clear();
04793 
04794   int aNbE;
04795   std::list<double> aPrms;
04796   TIDSortedElemSet::iterator itElem;
04797 
04798   gp_XYZ aGC;
04799   TopoDS_Edge aTrackEdge;
04800   TopoDS_Vertex aV1, aV2;
04801 
04802   SMDS_ElemIteratorPtr aItE;
04803   SMDS_NodeIteratorPtr aItN;
04804   SMDSAbs_ElementType aTypeE;
04805 
04806   TNodeOfNodeListMap mapNewNodes;
04807 
04808   // 1. Check data
04809   aNbE = theElements.size();
04810   // nothing to do
04811   if ( !aNbE )
04812     return EXTR_NO_ELEMENTS;
04813 
04814   // 1.1 Track Pattern
04815   ASSERT( theTrack );
04816 
04817   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
04818 
04819   aItE = pMeshDS->elementsIterator();
04820   while ( aItE->more() ) {
04821     const SMDS_MeshElement* pE = aItE->next();
04822     aTypeE = pE->GetType();
04823     // Pattern must contain links only
04824     if ( aTypeE != SMDSAbs_Edge )
04825       return EXTR_PATH_NOT_EDGE;
04826   }
04827 
04828   list<SMESH_MeshEditor_PathPoint> fullList;
04829 
04830   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
04831   // Sub shape for the Pattern must be an Edge or Wire
04832   if( aS.ShapeType() == TopAbs_EDGE ) {
04833     aTrackEdge = TopoDS::Edge( aS );
04834     // the Edge must not be degenerated
04835     if ( BRep_Tool::Degenerated( aTrackEdge ) )
04836       return EXTR_BAD_PATH_SHAPE;
04837     TopExp::Vertices( aTrackEdge, aV1, aV2 );
04838     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
04839     const SMDS_MeshNode* aN1 = aItN->next();
04840     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
04841     const SMDS_MeshNode* aN2 = aItN->next();
04842     // starting node must be aN1 or aN2
04843     if ( !( aN1 == theN1 || aN2 == theN1 ) )
04844       return EXTR_BAD_STARTING_NODE;
04845     aItN = pMeshDS->nodesIterator();
04846     while ( aItN->more() ) {
04847       const SMDS_MeshNode* pNode = aItN->next();
04848       if( pNode==aN1 || pNode==aN2 ) continue;
04849       const SMDS_EdgePosition* pEPos =
04850         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
04851       double aT = pEPos->GetUParameter();
04852       aPrms.push_back( aT );
04853     }
04854     //Extrusion_Error err =
04855     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
04856   }
04857   else if( aS.ShapeType() == TopAbs_WIRE ) {
04858     list< SMESH_subMesh* > LSM;
04859     TopTools_SequenceOfShape Edges;
04860     TopExp_Explorer eExp(aS, TopAbs_EDGE);
04861     for(; eExp.More(); eExp.Next()) {
04862       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
04863       if( BRep_Tool::Degenerated(E) ) continue;
04864       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
04865       if(SM) {
04866         LSM.push_back(SM);
04867         Edges.Append(E);
04868       }
04869     }
04870     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
04871     int startNid = theN1->GetID();
04872     TColStd_MapOfInteger UsedNums;
04873     int NbEdges = Edges.Length();
04874     int i = 1;
04875     for(; i<=NbEdges; i++) {
04876       int k = 0;
04877       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
04878       for(; itLSM!=LSM.end(); itLSM++) {
04879         k++;
04880         if(UsedNums.Contains(k)) continue;
04881         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
04882         SMESH_subMesh* locTrack = *itLSM;
04883         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
04884         TopExp::Vertices( aTrackEdge, aV1, aV2 );
04885         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
04886         const SMDS_MeshNode* aN1 = aItN->next();
04887         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
04888         const SMDS_MeshNode* aN2 = aItN->next();
04889         // starting node must be aN1 or aN2
04890         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
04891         // 2. Collect parameters on the track edge
04892         aPrms.clear();
04893         aItN = locMeshDS->GetNodes();
04894         while ( aItN->more() ) {
04895           const SMDS_MeshNode* pNode = aItN->next();
04896           const SMDS_EdgePosition* pEPos =
04897             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
04898           double aT = pEPos->GetUParameter();
04899           aPrms.push_back( aT );
04900         }
04901         list<SMESH_MeshEditor_PathPoint> LPP;
04902         //Extrusion_Error err =
04903         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
04904         LLPPs.push_back(LPP);
04905         UsedNums.Add(k);
04906         // update startN for search following egde
04907         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
04908         else startNid = aN1->GetID();
04909         break;
04910       }
04911     }
04912     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
04913     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
04914     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
04915     for(; itPP!=firstList.end(); itPP++) {
04916       fullList.push_back( *itPP );
04917     }
04918     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
04919     fullList.pop_back();
04920     itLLPP++;
04921     for(; itLLPP!=LLPPs.end(); itLLPP++) {
04922       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
04923       itPP = currList.begin();
04924       SMESH_MeshEditor_PathPoint PP2 = currList.front();
04925       gp_Dir D1 = PP1.Tangent();
04926       gp_Dir D2 = PP2.Tangent();
04927       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
04928                            (D1.Z()+D2.Z())/2 ) );
04929       PP1.SetTangent(Dnew);
04930       fullList.push_back(PP1);
04931       itPP++;
04932       for(; itPP!=currList.end(); itPP++) {
04933         fullList.push_back( *itPP );
04934       }
04935       PP1 = fullList.back();
04936       fullList.pop_back();
04937     }
04938     // if wire not closed
04939     fullList.push_back(PP1);
04940     // else ???
04941   }
04942   else {
04943     return EXTR_BAD_PATH_SHAPE;
04944   }
04945 
04946   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
04947                           theHasRefPoint, theRefPoint, theMakeGroups);
04948 }
04949 
04950 
04951 //=======================================================================
04952 //function : MakeEdgePathPoints
04953 //purpose  : auxilary for ExtrusionAlongTrack
04954 //=======================================================================
04955 SMESH_MeshEditor::Extrusion_Error
04956 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
04957                                      const TopoDS_Edge& aTrackEdge,
04958                                      bool FirstIsStart,
04959                                      list<SMESH_MeshEditor_PathPoint>& LPP)
04960 {
04961   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
04962   aTolVec=1.e-7;
04963   aTolVec2=aTolVec*aTolVec;
04964   double aT1, aT2;
04965   TopoDS_Vertex aV1, aV2;
04966   TopExp::Vertices( aTrackEdge, aV1, aV2 );
04967   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
04968   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
04969   // 2. Collect parameters on the track edge
04970   aPrms.push_front( aT1 );
04971   aPrms.push_back( aT2 );
04972   // sort parameters
04973   aPrms.sort();
04974   if( FirstIsStart ) {
04975     if ( aT1 > aT2 ) {
04976       aPrms.reverse();
04977     }
04978   }
04979   else {
04980     if ( aT2 > aT1 ) {
04981       aPrms.reverse();
04982     }
04983   }
04984   // 3. Path Points
04985   SMESH_MeshEditor_PathPoint aPP;
04986   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
04987   std::list<double>::iterator aItD = aPrms.begin();
04988   for(; aItD != aPrms.end(); ++aItD) {
04989     double aT = *aItD;
04990     gp_Pnt aP3D;
04991     gp_Vec aVec;
04992     aC3D->D1( aT, aP3D, aVec );
04993     aL2 = aVec.SquareMagnitude();
04994     if ( aL2 < aTolVec2 )
04995       return EXTR_CANT_GET_TANGENT;
04996     gp_Dir aTgt( aVec );
04997     aPP.SetPnt( aP3D );
04998     aPP.SetTangent( aTgt );
04999     aPP.SetParameter( aT );
05000     LPP.push_back(aPP);
05001   }
05002   return EXTR_OK;
05003 }
05004 
05005 
05006 //=======================================================================
05007 //function : MakeExtrElements
05008 //purpose  : auxilary for ExtrusionAlongTrack
05009 //=======================================================================
05010 SMESH_MeshEditor::Extrusion_Error
05011 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
05012                                    list<SMESH_MeshEditor_PathPoint>& fullList,
05013                                    const bool theHasAngles,
05014                                    list<double>& theAngles,
05015                                    const bool theLinearVariation,
05016                                    const bool theHasRefPoint,
05017                                    const gp_Pnt& theRefPoint,
05018                                    const bool theMakeGroups)
05019 {
05020   MESSAGE("MakeExtrElements");
05021   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
05022   int aNbTP = fullList.size();
05023   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
05024   // Angles
05025   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
05026     LinearAngleVariation(aNbTP-1, theAngles);
05027   }
05028   vector<double> aAngles( aNbTP );
05029   int j = 0;
05030   for(; j<aNbTP; ++j) {
05031     aAngles[j] = 0.;
05032   }
05033   if ( theHasAngles ) {
05034     double anAngle;;
05035     std::list<double>::iterator aItD = theAngles.begin();
05036     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
05037       anAngle = *aItD;
05038       aAngles[j] = anAngle;
05039     }
05040   }
05041   // fill vector of path points with angles
05042   //aPPs.resize(fullList.size());
05043   j = -1;
05044   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
05045   for(; itPP!=fullList.end(); itPP++) {
05046     j++;
05047     SMESH_MeshEditor_PathPoint PP = *itPP;
05048     PP.SetAngle(aAngles[j]);
05049     aPPs[j] = PP;
05050   }
05051 
05052   TNodeOfNodeListMap mapNewNodes;
05053   TElemOfVecOfNnlmiMap mapElemNewNodes;
05054   TElemOfElemListMap newElemsMap;
05055   TIDSortedElemSet::iterator itElem;
05056   double aX, aY, aZ;
05057   int aNb;
05058   SMDSAbs_ElementType aTypeE;
05059   // source elements for each generated one
05060   SMESH_SequenceOfElemPtr srcElems, srcNodes;
05061 
05062   // 3. Center of rotation aV0
05063   gp_Pnt aV0 = theRefPoint;
05064   gp_XYZ aGC;
05065   if ( !theHasRefPoint ) {
05066     aNb = 0;
05067     aGC.SetCoord( 0.,0.,0. );
05068 
05069     itElem = theElements.begin();
05070     for ( ; itElem != theElements.end(); itElem++ ) {
05071       const SMDS_MeshElement* elem = *itElem;
05072 
05073       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05074       while ( itN->more() ) {
05075         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
05076         aX = node->X();
05077         aY = node->Y();
05078         aZ = node->Z();
05079 
05080         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
05081           list<const SMDS_MeshNode*> aLNx;
05082           mapNewNodes[node] = aLNx;
05083           //
05084           gp_XYZ aXYZ( aX, aY, aZ );
05085           aGC += aXYZ;
05086           ++aNb;
05087         }
05088       }
05089     }
05090     aGC /= aNb;
05091     aV0.SetXYZ( aGC );
05092   } // if (!theHasRefPoint) {
05093   mapNewNodes.clear();
05094 
05095   // 4. Processing the elements
05096   SMESHDS_Mesh* aMesh = GetMeshDS();
05097 
05098   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
05099     // check element type
05100     const SMDS_MeshElement* elem = *itElem;
05101     aTypeE = elem->GetType();
05102     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
05103       continue;
05104 
05105     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
05106     newNodesItVec.reserve( elem->NbNodes() );
05107 
05108     // loop on elem nodes
05109     int nodeIndex = -1;
05110     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05111     while ( itN->more() )
05112     {
05113       ++nodeIndex;
05114       // check if a node has been already processed
05115       const SMDS_MeshNode* node =
05116         static_cast<const SMDS_MeshNode*>( itN->next() );
05117       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
05118       if ( nIt == mapNewNodes.end() ) {
05119         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
05120         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
05121 
05122         // make new nodes
05123         aX = node->X();  aY = node->Y(); aZ = node->Z();
05124 
05125         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
05126         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
05127         gp_Ax1 anAx1, anAxT1T0;
05128         gp_Dir aDT1x, aDT0x, aDT1T0;
05129 
05130         aTolAng=1.e-4;
05131 
05132         aV0x = aV0;
05133         aPN0.SetCoord(aX, aY, aZ);
05134 
05135         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
05136         aP0x = aPP0.Pnt();
05137         aDT0x= aPP0.Tangent();
05138         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
05139 
05140         for ( j = 1; j < aNbTP; ++j ) {
05141           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
05142           aP1x = aPP1.Pnt();
05143           aDT1x = aPP1.Tangent();
05144           aAngle1x = aPP1.Angle();
05145 
05146           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
05147           // Translation
05148           gp_Vec aV01x( aP0x, aP1x );
05149           aTrsf.SetTranslation( aV01x );
05150 
05151           // traslated point
05152           aV1x = aV0x.Transformed( aTrsf );
05153           aPN1 = aPN0.Transformed( aTrsf );
05154 
05155           // rotation 1 [ T1,T0 ]
05156           aAngleT1T0=-aDT1x.Angle( aDT0x );
05157           if (fabs(aAngleT1T0) > aTolAng) {
05158             aDT1T0=aDT1x^aDT0x;
05159             anAxT1T0.SetLocation( aV1x );
05160             anAxT1T0.SetDirection( aDT1T0 );
05161             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
05162 
05163             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
05164           }
05165 
05166           // rotation 2
05167           if ( theHasAngles ) {
05168             anAx1.SetLocation( aV1x );
05169             anAx1.SetDirection( aDT1x );
05170             aTrsfRot.SetRotation( anAx1, aAngle1x );
05171 
05172             aPN1 = aPN1.Transformed( aTrsfRot );
05173           }
05174 
05175           // make new node
05176           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
05177           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
05178             // create additional node
05179             double x = ( aPN1.X() + aPN0.X() )/2.;
05180             double y = ( aPN1.Y() + aPN0.Y() )/2.;
05181             double z = ( aPN1.Z() + aPN0.Z() )/2.;
05182             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
05183             myLastCreatedNodes.Append(newNode);
05184             srcNodes.Append( node );
05185             listNewNodes.push_back( newNode );
05186           }
05187           aX = aPN1.X();
05188           aY = aPN1.Y();
05189           aZ = aPN1.Z();
05190           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
05191           myLastCreatedNodes.Append(newNode);
05192           srcNodes.Append( node );
05193           listNewNodes.push_back( newNode );
05194 
05195           aPN0 = aPN1;
05196           aP0x = aP1x;
05197           aV0x = aV1x;
05198           aDT0x = aDT1x;
05199         }
05200       }
05201 
05202       else {
05203         // if current elem is quadratic and current node is not medium
05204         // we have to check - may be it is needed to insert additional nodes
05205         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
05206           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
05207           if(listNewNodes.size()==aNbTP-1) {
05208             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
05209             gp_XYZ P(node->X(), node->Y(), node->Z());
05210             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
05211             int i;
05212             for(i=0; i<aNbTP-1; i++) {
05213               const SMDS_MeshNode* N = *it;
05214               double x = ( N->X() + P.X() )/2.;
05215               double y = ( N->Y() + P.Y() )/2.;
05216               double z = ( N->Z() + P.Z() )/2.;
05217               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
05218               srcNodes.Append( node );
05219               myLastCreatedNodes.Append(newN);
05220               aNodes[2*i] = newN;
05221               aNodes[2*i+1] = N;
05222               P = gp_XYZ(N->X(),N->Y(),N->Z());
05223             }
05224             listNewNodes.clear();
05225             for(i=0; i<2*(aNbTP-1); i++) {
05226               listNewNodes.push_back(aNodes[i]);
05227             }
05228           }
05229         }
05230       }
05231 
05232       newNodesItVec.push_back( nIt );
05233     }
05234     // make new elements
05235     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
05236     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
05237     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
05238   }
05239 
05240   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
05241 
05242   if ( theMakeGroups )
05243     generateGroups( srcNodes, srcElems, "extruded");
05244 
05245   return EXTR_OK;
05246 }
05247 
05248 
05249 //=======================================================================
05250 //function : LinearAngleVariation
05251 //purpose  : auxilary for ExtrusionAlongTrack
05252 //=======================================================================
05253 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
05254                                             list<double>& Angles)
05255 {
05256   int nbAngles = Angles.size();
05257   if( nbSteps > nbAngles ) {
05258     vector<double> theAngles(nbAngles);
05259     list<double>::iterator it = Angles.begin();
05260     int i = -1;
05261     for(; it!=Angles.end(); it++) {
05262       i++;
05263       theAngles[i] = (*it);
05264     }
05265     list<double> res;
05266     double rAn2St = double( nbAngles ) / double( nbSteps );
05267     double angPrev = 0, angle;
05268     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
05269       double angCur = rAn2St * ( iSt+1 );
05270       double angCurFloor  = floor( angCur );
05271       double angPrevFloor = floor( angPrev );
05272       if ( angPrevFloor == angCurFloor )
05273         angle = rAn2St * theAngles[ int( angCurFloor ) ];
05274       else {
05275         int iP = int( angPrevFloor );
05276         double angPrevCeil = ceil(angPrev);
05277         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
05278 
05279         int iC = int( angCurFloor );
05280         if ( iC < nbAngles )
05281           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
05282 
05283         iP = int( angPrevCeil );
05284         while ( iC-- > iP )
05285           angle += theAngles[ iC ];
05286       }
05287       res.push_back(angle);
05288       angPrev = angCur;
05289     }
05290     Angles.clear();
05291     it = res.begin();
05292     for(; it!=res.end(); it++)
05293       Angles.push_back( *it );
05294   }
05295 }
05296 
05297 
05298 //================================================================================
05308 //================================================================================
05309 
05310 SMESH_MeshEditor::PGroupIDs
05311 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
05312                              const gp_Trsf&     theTrsf,
05313                              const bool         theCopy,
05314                              const bool         theMakeGroups,
05315                              SMESH_Mesh*        theTargetMesh)
05316 {
05317   myLastCreatedElems.Clear();
05318   myLastCreatedNodes.Clear();
05319 
05320   bool needReverse = false;
05321   string groupPostfix;
05322   switch ( theTrsf.Form() ) {
05323   case gp_PntMirror:
05324     MESSAGE("gp_PntMirror");
05325     needReverse = true;
05326     groupPostfix = "mirrored";
05327     break;
05328   case gp_Ax1Mirror:
05329     MESSAGE("gp_Ax1Mirror");
05330     groupPostfix = "mirrored";
05331     break;
05332   case gp_Ax2Mirror:
05333     MESSAGE("gp_Ax2Mirror");
05334     needReverse = true;
05335     groupPostfix = "mirrored";
05336     break;
05337   case gp_Rotation:
05338     MESSAGE("gp_Rotation");
05339     groupPostfix = "rotated";
05340     break;
05341   case gp_Translation:
05342     MESSAGE("gp_Translation");
05343     groupPostfix = "translated";
05344     break;
05345   case gp_Scale:
05346     MESSAGE("gp_Scale");
05347     groupPostfix = "scaled";
05348     break;
05349   case gp_CompoundTrsf: // different scale by axis
05350     MESSAGE("gp_CompoundTrsf");
05351     groupPostfix = "scaled";
05352     break;
05353   default:
05354     MESSAGE("default");
05355     needReverse = false;
05356     groupPostfix = "transformed";
05357   }
05358 
05359   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
05360   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
05361   SMESHDS_Mesh* aMesh    = GetMeshDS();
05362 
05363 
05364   // map old node to new one
05365   TNodeNodeMap nodeMap;
05366 
05367   // elements sharing moved nodes; those of them which have all
05368   // nodes mirrored but are not in theElems are to be reversed
05369   TIDSortedElemSet inverseElemSet;
05370 
05371   // source elements for each generated one
05372   SMESH_SequenceOfElemPtr srcElems, srcNodes;
05373 
05374   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
05375   TIDSortedElemSet orphanNode;
05376 
05377   if ( theElems.empty() ) // transform the whole mesh
05378   {
05379     // add all elements
05380     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
05381     while ( eIt->more() ) theElems.insert( eIt->next() );
05382     // add orphan nodes
05383     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
05384     while ( nIt->more() )
05385     {
05386       const SMDS_MeshNode* node = nIt->next();
05387       if ( node->NbInverseElements() == 0)
05388         orphanNode.insert( node );
05389     }
05390   }
05391 
05392   // loop on elements to transform nodes : first orphan nodes then elems
05393   TIDSortedElemSet::iterator itElem;
05394   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
05395   for (int i=0; i<2; i++)
05396   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
05397     const SMDS_MeshElement* elem = *itElem;
05398     if ( !elem )
05399       continue;
05400 
05401     // loop on elem nodes
05402     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05403     while ( itN->more() ) {
05404 
05405       const SMDS_MeshNode* node = cast2Node( itN->next() );
05406       // check if a node has been already transformed
05407       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
05408         nodeMap.insert( make_pair ( node, node ));
05409       if ( !n2n_isnew.second )
05410         continue;
05411 
05412       double coord[3];
05413       coord[0] = node->X();
05414       coord[1] = node->Y();
05415       coord[2] = node->Z();
05416       theTrsf.Transforms( coord[0], coord[1], coord[2] );
05417       if ( theTargetMesh ) {
05418         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
05419         n2n_isnew.first->second = newNode;
05420         myLastCreatedNodes.Append(newNode);
05421         srcNodes.Append( node );
05422       }
05423       else if ( theCopy ) {
05424         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
05425         n2n_isnew.first->second = newNode;
05426         myLastCreatedNodes.Append(newNode);
05427         srcNodes.Append( node );
05428       }
05429       else {
05430         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
05431         // node position on shape becomes invalid
05432         const_cast< SMDS_MeshNode* > ( node )->SetPosition
05433           ( SMDS_SpacePosition::originSpacePosition() );
05434       }
05435 
05436       // keep inverse elements
05437       if ( !theCopy && !theTargetMesh && needReverse ) {
05438         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
05439         while ( invElemIt->more() ) {
05440           const SMDS_MeshElement* iel = invElemIt->next();
05441           inverseElemSet.insert( iel );
05442         }
05443       }
05444     }
05445   }
05446 
05447   // either create new elements or reverse mirrored ones
05448   if ( !theCopy && !needReverse && !theTargetMesh )
05449     return PGroupIDs();
05450 
05451   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
05452   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
05453     theElems.insert( *invElemIt );
05454 
05455   // replicate or reverse elements
05456   // TODO revoir ordre reverse vtk
05457   enum {
05458     REV_TETRA   = 0,  //  = nbNodes - 4
05459     REV_PYRAMID = 1,  //  = nbNodes - 4
05460     REV_PENTA   = 2,  //  = nbNodes - 4
05461     REV_FACE    = 3,
05462     REV_HEXA    = 4,  //  = nbNodes - 4
05463     FORWARD     = 5
05464   };
05465   int index[][8] = {
05466     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
05467     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
05468     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
05469     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
05470     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
05471     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
05472   };
05473 
05474   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
05475   {
05476     const SMDS_MeshElement* elem = *itElem;
05477     if ( !elem || elem->GetType() == SMDSAbs_Node )
05478       continue;
05479 
05480     int nbNodes = elem->NbNodes();
05481     int elemType = elem->GetType();
05482 
05483     if (elem->IsPoly()) {
05484       // Polygon or Polyhedral Volume
05485       switch ( elemType ) {
05486       case SMDSAbs_Face:
05487         {
05488           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
05489           int iNode = 0;
05490           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05491           while (itN->more()) {
05492             const SMDS_MeshNode* node =
05493               static_cast<const SMDS_MeshNode*>(itN->next());
05494             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
05495             if (nodeMapIt == nodeMap.end())
05496               break; // not all nodes transformed
05497             if (needReverse) {
05498               // reverse mirrored faces and volumes
05499               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
05500             } else {
05501               poly_nodes[iNode] = (*nodeMapIt).second;
05502             }
05503             iNode++;
05504           }
05505           if ( iNode != nbNodes )
05506             continue; // not all nodes transformed
05507 
05508           if ( theTargetMesh ) {
05509             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
05510             srcElems.Append( elem );
05511           }
05512           else if ( theCopy ) {
05513             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
05514             srcElems.Append( elem );
05515           }
05516           else {
05517             aMesh->ChangePolygonNodes(elem, poly_nodes);
05518           }
05519         }
05520         break;
05521       case SMDSAbs_Volume:
05522         {
05523           // ATTENTION: Reversing is not yet done!!!
05524           const SMDS_VtkVolume* aPolyedre =
05525             dynamic_cast<const SMDS_VtkVolume*>( elem );
05526           if (!aPolyedre) {
05527             MESSAGE("Warning: bad volumic element");
05528             continue;
05529           }
05530 
05531           vector<const SMDS_MeshNode*> poly_nodes;
05532           vector<int> quantities;
05533 
05534           bool allTransformed = true;
05535           int nbFaces = aPolyedre->NbFaces();
05536           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
05537             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
05538             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
05539               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
05540               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
05541               if (nodeMapIt == nodeMap.end()) {
05542                 allTransformed = false; // not all nodes transformed
05543               } else {
05544                 poly_nodes.push_back((*nodeMapIt).second);
05545               }
05546             }
05547             quantities.push_back(nbFaceNodes);
05548           }
05549           if ( !allTransformed )
05550             continue; // not all nodes transformed
05551 
05552           if ( theTargetMesh ) {
05553             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
05554             srcElems.Append( elem );
05555           }
05556           else if ( theCopy ) {
05557             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
05558             srcElems.Append( elem );
05559           }
05560           else {
05561             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
05562           }
05563         }
05564         break;
05565       default:;
05566       }
05567       continue;
05568     }
05569 
05570     // Regular elements
05571     int* i = index[ FORWARD ];
05572     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
05573       if ( elemType == SMDSAbs_Face )
05574         i = index[ REV_FACE ];
05575       else
05576         i = index[ nbNodes - 4 ];
05577     }
05578     if(elem->IsQuadratic()) {
05579       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
05580       i = anIds;
05581       if(needReverse) {
05582         if(nbNodes==3) { // quadratic edge
05583           static int anIds[] = {1,0,2};
05584           i = anIds;
05585         }
05586         else if(nbNodes==6) { // quadratic triangle
05587           static int anIds[] = {0,2,1,5,4,3};
05588           i = anIds;
05589         }
05590         else if(nbNodes==8) { // quadratic quadrangle
05591           static int anIds[] = {0,3,2,1,7,6,5,4};
05592           i = anIds;
05593         }
05594         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
05595           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
05596           i = anIds;
05597         }
05598         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
05599           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
05600           i = anIds;
05601         }
05602         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
05603           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
05604           i = anIds;
05605         }
05606         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
05607           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
05608           i = anIds;
05609         }
05610       }
05611     }
05612 
05613     // find transformed nodes
05614     vector<const SMDS_MeshNode*> nodes(nbNodes);
05615     int iNode = 0;
05616     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05617     while ( itN->more() ) {
05618       const SMDS_MeshNode* node =
05619         static_cast<const SMDS_MeshNode*>( itN->next() );
05620       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
05621       if ( nodeMapIt == nodeMap.end() )
05622         break; // not all nodes transformed
05623       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
05624     }
05625     if ( iNode != nbNodes )
05626       continue; // not all nodes transformed
05627 
05628     if ( theTargetMesh ) {
05629       if ( SMDS_MeshElement* copy =
05630            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
05631         myLastCreatedElems.Append( copy );
05632         srcElems.Append( elem );
05633       }
05634     }
05635     else if ( theCopy ) {
05636       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
05637         srcElems.Append( elem );
05638     }
05639     else {
05640       // reverse element as it was reversed by transformation
05641       if ( nbNodes > 2 )
05642         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
05643     }
05644   }
05645 
05646   PGroupIDs newGroupIDs;
05647 
05648   if ( ( theMakeGroups && theCopy ) ||
05649        ( theMakeGroups && theTargetMesh ) )
05650     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
05651 
05652   return newGroupIDs;
05653 }
05654 
05655 
05660 //
05661 //SMESH_MeshEditor::PGroupIDs
05662 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
05663 //                         const gp_Pnt&            thePoint,
05664 //                         const std::list<double>& theScaleFact,
05665 //                         const bool         theCopy,
05666 //                         const bool         theMakeGroups,
05667 //                         SMESH_Mesh*        theTargetMesh)
05668 //{
05669 //  MESSAGE("Scale");
05670 //  myLastCreatedElems.Clear();
05671 //  myLastCreatedNodes.Clear();
05672 //
05673 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
05674 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
05675 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
05676 //
05677 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
05678 //  std::list<double>::const_iterator itS = theScaleFact.begin();
05679 //  scaleX = (*itS);
05680 //  if(theScaleFact.size()==1) {
05681 //    scaleY = (*itS);
05682 //    scaleZ= (*itS);
05683 //  }
05684 //  if(theScaleFact.size()==2) {
05685 //    itS++;
05686 //    scaleY = (*itS);
05687 //    scaleZ= (*itS);
05688 //  }
05689 //  if(theScaleFact.size()>2) {
05690 //    itS++;
05691 //    scaleY = (*itS);
05692 //    itS++;
05693 //    scaleZ= (*itS);
05694 //  }
05695 //
05696 //  // map old node to new one
05697 //  TNodeNodeMap nodeMap;
05698 //
05699 //  // elements sharing moved nodes; those of them which have all
05700 //  // nodes mirrored but are not in theElems are to be reversed
05701 //  TIDSortedElemSet inverseElemSet;
05702 //
05703 //  // source elements for each generated one
05704 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
05705 //
05706 //  // loop on theElems
05707 //  TIDSortedElemSet::iterator itElem;
05708 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
05709 //    const SMDS_MeshElement* elem = *itElem;
05710 //    if ( !elem )
05711 //      continue;
05712 //
05713 //    // loop on elem nodes
05714 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05715 //    while ( itN->more() ) {
05716 //
05717 //      // check if a node has been already transformed
05718 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
05719 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
05720 //        nodeMap.insert( make_pair ( node, node ));
05721 //      if ( !n2n_isnew.second )
05722 //        continue;
05723 //
05724 //      //double coord[3];
05725 //      //coord[0] = node->X();
05726 //      //coord[1] = node->Y();
05727 //      //coord[2] = node->Z();
05728 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
05729 //      double dx = (node->X() - thePoint.X()) * scaleX;
05730 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
05731 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
05732 //      if ( theTargetMesh ) {
05733 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
05734 //        const SMDS_MeshNode * newNode =
05735 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
05736 //        n2n_isnew.first->second = newNode;
05737 //        myLastCreatedNodes.Append(newNode);
05738 //        srcNodes.Append( node );
05739 //      }
05740 //      else if ( theCopy ) {
05741 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
05742 //        const SMDS_MeshNode * newNode =
05743 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
05744 //        n2n_isnew.first->second = newNode;
05745 //        myLastCreatedNodes.Append(newNode);
05746 //        srcNodes.Append( node );
05747 //      }
05748 //      else {
05749 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
05750 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
05751 //        // node position on shape becomes invalid
05752 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
05753 //          ( SMDS_SpacePosition::originSpacePosition() );
05754 //      }
05755 //
05756 //      // keep inverse elements
05757 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
05758 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
05759 //      //  while ( invElemIt->more() ) {
05760 //      //    const SMDS_MeshElement* iel = invElemIt->next();
05761 //      //    inverseElemSet.insert( iel );
05762 //      //  }
05763 //      //}
05764 //    }
05765 //  }
05766 //
05767 //  // either create new elements or reverse mirrored ones
05768 //  //if ( !theCopy && !needReverse && !theTargetMesh )
05769 //  if ( !theCopy && !theTargetMesh )
05770 //    return PGroupIDs();
05771 //
05772 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
05773 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
05774 //    theElems.insert( *invElemIt );
05775 //
05776 //  // replicate or reverse elements
05777 //
05778 //  enum {
05779 //    REV_TETRA   = 0,  //  = nbNodes - 4
05780 //    REV_PYRAMID = 1,  //  = nbNodes - 4
05781 //    REV_PENTA   = 2,  //  = nbNodes - 4
05782 //    REV_FACE    = 3,
05783 //    REV_HEXA    = 4,  //  = nbNodes - 4
05784 //    FORWARD     = 5
05785 //  };
05786 //  int index[][8] = {
05787 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
05788 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
05789 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
05790 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
05791 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
05792 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
05793 //  };
05794 //
05795 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
05796 //  {
05797 //    const SMDS_MeshElement* elem = *itElem;
05798 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
05799 //      continue;
05800 //
05801 //    int nbNodes = elem->NbNodes();
05802 //    int elemType = elem->GetType();
05803 //
05804 //    if (elem->IsPoly()) {
05805 //      // Polygon or Polyhedral Volume
05806 //      switch ( elemType ) {
05807 //      case SMDSAbs_Face:
05808 //        {
05809 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
05810 //          int iNode = 0;
05811 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05812 //          while (itN->more()) {
05813 //            const SMDS_MeshNode* node =
05814 //              static_cast<const SMDS_MeshNode*>(itN->next());
05815 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
05816 //            if (nodeMapIt == nodeMap.end())
05817 //              break; // not all nodes transformed
05818 //            //if (needReverse) {
05819 //            //  // reverse mirrored faces and volumes
05820 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
05821 //            //} else {
05822 //            poly_nodes[iNode] = (*nodeMapIt).second;
05823 //            //}
05824 //            iNode++;
05825 //          }
05826 //          if ( iNode != nbNodes )
05827 //            continue; // not all nodes transformed
05828 //
05829 //          if ( theTargetMesh ) {
05830 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
05831 //            srcElems.Append( elem );
05832 //          }
05833 //          else if ( theCopy ) {
05834 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
05835 //            srcElems.Append( elem );
05836 //          }
05837 //          else {
05838 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
05839 //          }
05840 //        }
05841 //        break;
05842 //      case SMDSAbs_Volume:
05843 //        {
05844 //          // ATTENTION: Reversing is not yet done!!!
05845 //          const SMDS_VtkVolume* aPolyedre =
05846 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
05847 //          if (!aPolyedre) {
05848 //            MESSAGE("Warning: bad volumic element");
05849 //            continue;
05850 //          }
05851 //
05852 //          vector<const SMDS_MeshNode*> poly_nodes;
05853 //          vector<int> quantities;
05854 //
05855 //          bool allTransformed = true;
05856 //          int nbFaces = aPolyedre->NbFaces();
05857 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
05858 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
05859 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
05860 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
05861 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
05862 //              if (nodeMapIt == nodeMap.end()) {
05863 //                allTransformed = false; // not all nodes transformed
05864 //              } else {
05865 //                poly_nodes.push_back((*nodeMapIt).second);
05866 //              }
05867 //            }
05868 //            quantities.push_back(nbFaceNodes);
05869 //          }
05870 //          if ( !allTransformed )
05871 //            continue; // not all nodes transformed
05872 //
05873 //          if ( theTargetMesh ) {
05874 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
05875 //            srcElems.Append( elem );
05876 //          }
05877 //          else if ( theCopy ) {
05878 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
05879 //            srcElems.Append( elem );
05880 //          }
05881 //          else {
05882 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
05883 //          }
05884 //        }
05885 //        break;
05886 //      default:;
05887 //      }
05888 //      continue;
05889 //    }
05890 //
05891 //    // Regular elements
05892 //    int* i = index[ FORWARD ];
05893 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
05894 //    //  if ( elemType == SMDSAbs_Face )
05895 //    //    i = index[ REV_FACE ];
05896 //    //  else
05897 //    //    i = index[ nbNodes - 4 ];
05898 //
05899 //    if(elem->IsQuadratic()) {
05900 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
05901 //      i = anIds;
05902 //      //if(needReverse) {
05903 //      //  if(nbNodes==3) { // quadratic edge
05904 //      //    static int anIds[] = {1,0,2};
05905 //      //    i = anIds;
05906 //      //  }
05907 //      //  else if(nbNodes==6) { // quadratic triangle
05908 //      //    static int anIds[] = {0,2,1,5,4,3};
05909 //      //    i = anIds;
05910 //      //  }
05911 //      //  else if(nbNodes==8) { // quadratic quadrangle
05912 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
05913 //      //    i = anIds;
05914 //      //  }
05915 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
05916 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
05917 //      //    i = anIds;
05918 //      //  }
05919 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
05920 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
05921 //      //    i = anIds;
05922 //      //  }
05923 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
05924 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
05925 //      //    i = anIds;
05926 //      //  }
05927 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
05928 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
05929 //      //    i = anIds;
05930 //      //  }
05931 //      //}
05932 //    }
05933 //
05934 //    // find transformed nodes
05935 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
05936 //    int iNode = 0;
05937 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05938 //    while ( itN->more() ) {
05939 //      const SMDS_MeshNode* node =
05940 //        static_cast<const SMDS_MeshNode*>( itN->next() );
05941 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
05942 //      if ( nodeMapIt == nodeMap.end() )
05943 //        break; // not all nodes transformed
05944 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
05945 //    }
05946 //    if ( iNode != nbNodes )
05947 //      continue; // not all nodes transformed
05948 //
05949 //    if ( theTargetMesh ) {
05950 //      if ( SMDS_MeshElement* copy =
05951 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
05952 //        myLastCreatedElems.Append( copy );
05953 //        srcElems.Append( elem );
05954 //      }
05955 //    }
05956 //    else if ( theCopy ) {
05957 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
05958 //        myLastCreatedElems.Append( copy );
05959 //        srcElems.Append( elem );
05960 //      }
05961 //    }
05962 //    else {
05963 //      // reverse element as it was reversed by transformation
05964 //      if ( nbNodes > 2 )
05965 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
05966 //    }
05967 //  }
05968 //
05969 //  PGroupIDs newGroupIDs;
05970 //
05971 //  if ( theMakeGroups && theCopy ||
05972 //       theMakeGroups && theTargetMesh ) {
05973 //    string groupPostfix = "scaled";
05974 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
05975 //  }
05976 //
05977 //  return newGroupIDs;
05978 //}
05979 
05980 
05981 //=======================================================================
05988 //=======================================================================
05989 
05990 SMESH_MeshEditor::PGroupIDs
05991 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
05992                                  const SMESH_SequenceOfElemPtr& elemGens,
05993                                  const std::string&             postfix,
05994                                  SMESH_Mesh*                    targetMesh)
05995 {
05996   PGroupIDs newGroupIDs( new list<int> );
05997   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
05998 
05999   // Sort existing groups by types and collect their names
06000 
06001   // to store an old group and a generated new one
06002   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
06003   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
06004   // group names
06005   set< string > groupNames;
06006   //
06007   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
06008   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
06009   while ( groupIt->more() ) {
06010     SMESH_Group * group = groupIt->next();
06011     if ( !group ) continue;
06012     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
06013     if ( !groupDS || groupDS->IsEmpty() ) continue;
06014     groupNames.insert( group->GetName() );
06015     groupDS->SetStoreName( group->GetName() );
06016     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
06017   }
06018 
06019   // Groups creation
06020 
06021   // loop on nodes and elements
06022   for ( int isNodes = 0; isNodes < 2; ++isNodes )
06023   {
06024     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
06025     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
06026     if ( gens.Length() != elems.Length() )
06027       throw SALOME_Exception(LOCALIZED("invalid args"));
06028 
06029     // loop on created elements
06030     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
06031     {
06032       const SMDS_MeshElement* sourceElem = gens( iElem );
06033       if ( !sourceElem ) {
06034         MESSAGE("generateGroups(): NULL source element");
06035         continue;
06036       }
06037       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
06038       if ( groupsOldNew.empty() ) {
06039         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
06040           ++iElem; // skip all elements made by sourceElem
06041         continue;
06042       }
06043       // collect all elements made by sourceElem
06044       list< const SMDS_MeshElement* > resultElems;
06045       if ( const SMDS_MeshElement* resElem = elems( iElem ))
06046         if ( resElem != sourceElem )
06047           resultElems.push_back( resElem );
06048       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
06049         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
06050           if ( resElem != sourceElem )
06051             resultElems.push_back( resElem );
06052       // do not generate element groups from node ones
06053       if ( sourceElem->GetType() == SMDSAbs_Node &&
06054            elems( iElem )->GetType() != SMDSAbs_Node )
06055         continue;
06056 
06057       // add resultElems to groups made by ones the sourceElem belongs to
06058       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
06059       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
06060       {
06061         SMESHDS_GroupBase* oldGroup = gOldNew->first;
06062         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
06063         {
06064           SMDS_MeshGroup* & newGroup = gOldNew->second;
06065           if ( !newGroup )// create a new group
06066           {
06067             // make a name
06068             string name = oldGroup->GetStoreName();
06069             if ( !targetMesh ) {
06070               name += "_";
06071               name += postfix;
06072               int nb = 0;
06073               while ( !groupNames.insert( name ).second ) // name exists
06074               {
06075                 if ( nb == 0 ) {
06076                   name += "_1";
06077                 }
06078                 else {
06079                   TCollection_AsciiString nbStr(nb+1);
06080                   name.resize( name.rfind('_')+1 );
06081                   name += nbStr.ToCString();
06082                 }
06083                 ++nb;
06084               }
06085             }
06086             // make a group
06087             int id;
06088             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
06089                                                  name.c_str(), id );
06090             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
06091             newGroup = & groupDS->SMDSGroup();
06092             newGroupIDs->push_back( id );
06093           }
06094 
06095           // fill in a new group
06096           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
06097           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
06098             newGroup->Add( *resElemIt );
06099         }
06100       }
06101     } // loop on created elements
06102   }// loop on nodes and elements
06103 
06104   return newGroupIDs;
06105 }
06106 
06107 //================================================================================
06113 //================================================================================
06114 
06115 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
06116                                             const double         theTolerance,
06117                                             TListOfListOfNodes & theGroupsOfNodes)
06118 {
06119   myLastCreatedElems.Clear();
06120   myLastCreatedNodes.Clear();
06121 
06122   if ( theNodes.empty() )
06123   { // get all nodes in the mesh
06124     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
06125     while ( nIt->more() )
06126       theNodes.insert( theNodes.end(),nIt->next());
06127   }
06128 
06129   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
06130 }
06131 
06132 
06133 //=======================================================================
06137 //=======================================================================
06138 
06139 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
06140 {
06141   //---------------------------------------------------------------------
06145   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
06146   {
06147     myMesh = ( SMESHDS_Mesh* ) theMesh;
06148 
06149     TIDSortedNodeSet nodes;
06150     if ( theMesh ) {
06151       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
06152       while ( nIt->more() )
06153         nodes.insert( nodes.end(), nIt->next() );
06154     }
06155     myOctreeNode = new SMESH_OctreeNode(nodes) ;
06156 
06157     // get max size of a leaf box
06158     SMESH_OctreeNode* tree = myOctreeNode;
06159     while ( !tree->isLeaf() )
06160     {
06161       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
06162       if ( cIt->more() )
06163         tree = cIt->next();
06164     }
06165     myHalfLeafSize = tree->maxSize() / 2.;
06166   }
06167 
06168   //---------------------------------------------------------------------
06172   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
06173   {
06174     myOctreeNode->UpdateByMoveNode( node, toPnt );
06175     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
06176   }
06177 
06178   //---------------------------------------------------------------------
06182   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
06183   {
06184     map<double, const SMDS_MeshNode*> dist2Nodes;
06185     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
06186     if ( !dist2Nodes.empty() )
06187       return dist2Nodes.begin()->second;
06188     list<const SMDS_MeshNode*> nodes;
06189     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
06190 
06191     double minSqDist = DBL_MAX;
06192     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
06193     {
06194       // sort leafs by their distance from thePnt
06195       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
06196       TDistTreeMap treeMap;
06197       list< SMESH_OctreeNode* > treeList;
06198       list< SMESH_OctreeNode* >::iterator trIt;
06199       treeList.push_back( myOctreeNode );
06200 
06201       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
06202       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
06203       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
06204       {
06205         SMESH_OctreeNode* tree = *trIt;
06206         if ( !tree->isLeaf() ) // put children to the queue
06207         {
06208           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
06209           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
06210           while ( cIt->more() )
06211             treeList.push_back( cIt->next() );
06212         }
06213         else if ( tree->NbNodes() ) // put a tree to the treeMap
06214         {
06215           const Bnd_B3d& box = tree->getBox();
06216           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
06217           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
06218           if ( !it_in.second ) // not unique distance to box center
06219             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
06220         }
06221       }
06222       // find distance after which there is no sense to check tree's
06223       double sqLimit = DBL_MAX;
06224       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
06225       if ( treeMap.size() > 5 ) {
06226         SMESH_OctreeNode* closestTree = sqDist_tree->second;
06227         const Bnd_B3d& box = closestTree->getBox();
06228         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
06229         sqLimit = limit * limit;
06230       }
06231       // get all nodes from trees
06232       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
06233         if ( sqDist_tree->first > sqLimit )
06234           break;
06235         SMESH_OctreeNode* tree = sqDist_tree->second;
06236         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
06237       }
06238     }
06239     // find closest among nodes
06240     minSqDist = DBL_MAX;
06241     const SMDS_MeshNode* closestNode = 0;
06242     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
06243     for ( ; nIt != nodes.end(); ++nIt ) {
06244       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
06245       if ( minSqDist > sqDist ) {
06246         closestNode = *nIt;
06247         minSqDist = sqDist;
06248       }
06249     }
06250     return closestNode;
06251   }
06252 
06253   //---------------------------------------------------------------------
06257   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
06258 
06259   //---------------------------------------------------------------------
06263   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
06264 
06265 private:
06266   SMESH_OctreeNode* myOctreeNode;
06267   SMESHDS_Mesh*     myMesh;
06268   double            myHalfLeafSize; // max size of a leaf box
06269 };
06270 
06271 //=======================================================================
06275 //=======================================================================
06276 
06277 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
06278 {
06279   return new SMESH_NodeSearcherImpl( GetMeshDS() );
06280 }
06281 
06282 // ========================================================================
06283 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
06284 {
06285   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
06286   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
06287   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
06288 
06289   //=======================================================================
06293   //=======================================================================
06294 
06295   class ElementBndBoxTree : public SMESH_Octree
06296   {
06297   public:
06298 
06299     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
06300     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
06301     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
06302     ~ElementBndBoxTree();
06303 
06304   protected:
06305     ElementBndBoxTree() {}
06306     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
06307     void buildChildrenData();
06308     Bnd_B3d* buildRootBox();
06309   private:
06311     struct ElementBox : public Bnd_B3d
06312     {
06313       const SMDS_MeshElement* _element;
06314       int                     _refCount; // an ElementBox can be included in several tree branches
06315       ElementBox(const SMDS_MeshElement* elem, double tolerance);
06316     };
06317     vector< ElementBox* > _elements;
06318   };
06319 
06320   //================================================================================
06324   //================================================================================
06325 
06326   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
06327     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
06328   {
06329     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
06330     _elements.reserve( nbElems );
06331 
06332     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
06333     while ( elemIt->more() )
06334       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
06335 
06336     if ( _elements.size() > MaxNbElemsInLeaf )
06337       compute();
06338     else
06339       myIsLeaf = true;
06340   }
06341 
06342   //================================================================================
06346   //================================================================================
06347 
06348   ElementBndBoxTree::~ElementBndBoxTree()
06349   {
06350     for ( int i = 0; i < _elements.size(); ++i )
06351       if ( --_elements[i]->_refCount <= 0 )
06352         delete _elements[i];
06353   }
06354 
06355   //================================================================================
06359   //================================================================================
06360 
06361   Bnd_B3d* ElementBndBoxTree::buildRootBox()
06362   {
06363     Bnd_B3d* box = new Bnd_B3d;
06364     for ( int i = 0; i < _elements.size(); ++i )
06365       box->Add( *_elements[i] );
06366     return box;
06367   }
06368 
06369   //================================================================================
06373   //================================================================================
06374 
06375   void ElementBndBoxTree::buildChildrenData()
06376   {
06377     for ( int i = 0; i < _elements.size(); ++i )
06378     {
06379       for (int j = 0; j < 8; j++)
06380       {
06381         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
06382         {
06383           _elements[i]->_refCount++;
06384           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
06385         }
06386       }
06387       _elements[i]->_refCount--;
06388     }
06389     _elements.clear();
06390 
06391     for (int j = 0; j < 8; j++)
06392     {
06393       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
06394       if ( child->_elements.size() <= MaxNbElemsInLeaf )
06395         child->myIsLeaf = true;
06396 
06397       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
06398         child->_elements.resize( child->_elements.size() ); // compact
06399     }
06400   }
06401 
06402   //================================================================================
06406   //================================================================================
06407 
06408   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
06409                                                 TIDSortedElemSet& foundElems)
06410   {
06411     if ( level() && getBox().IsOut( point.XYZ() ))
06412       return;
06413 
06414     if ( isLeaf() )
06415     {
06416       for ( int i = 0; i < _elements.size(); ++i )
06417         if ( !_elements[i]->IsOut( point.XYZ() ))
06418           foundElems.insert( _elements[i]->_element );
06419     }
06420     else
06421     {
06422       for (int i = 0; i < 8; i++)
06423         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
06424     }
06425   }
06426 
06427   //================================================================================
06431   //================================================================================
06432 
06433   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
06434                                                TIDSortedElemSet& foundElems)
06435   {
06436     if ( level() && getBox().IsOut( line ))
06437       return;
06438 
06439     if ( isLeaf() )
06440     {
06441       for ( int i = 0; i < _elements.size(); ++i )
06442         if ( !_elements[i]->IsOut( line ))
06443           foundElems.insert( _elements[i]->_element );
06444     }
06445     else
06446     {
06447       for (int i = 0; i < 8; i++)
06448         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
06449     }
06450   }
06451 
06452   //================================================================================
06456   //================================================================================
06457 
06458   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
06459   {
06460     _element  = elem;
06461     _refCount = 1;
06462     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
06463     while ( nIt->more() )
06464       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
06465     Enlarge( tolerance );
06466   }
06467 
06468 } // namespace
06469 
06470 //=======================================================================
06475 //=======================================================================
06476 
06477 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
06478 {
06479   SMESHDS_Mesh*                _mesh;
06480   SMDS_ElemIteratorPtr         _meshPartIt;
06481   ElementBndBoxTree*           _ebbTree;
06482   SMESH_NodeSearcherImpl*      _nodeSearcher;
06483   SMDSAbs_ElementType          _elementType;
06484   double                       _tolerance;
06485   bool                         _outerFacesFound;
06486   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
06487 
06488   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
06489     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
06490   ~SMESH_ElementSearcherImpl()
06491   {
06492     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
06493     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
06494   }
06495   virtual int FindElementsByPoint(const gp_Pnt&                      point,
06496                                   SMDSAbs_ElementType                type,
06497                                   vector< const SMDS_MeshElement* >& foundElements);
06498   virtual TopAbs_State GetPointState(const gp_Pnt& point);
06499 
06500   void GetElementsNearLine( const gp_Ax1&                      line,
06501                             SMDSAbs_ElementType                type,
06502                             vector< const SMDS_MeshElement* >& foundElems);
06503   double getTolerance();
06504   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
06505                             const double tolerance, double & param);
06506   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
06507   bool isOuterBoundary(const SMDS_MeshElement* face) const
06508   {
06509     return _outerFaces.empty() || _outerFaces.count(face);
06510   }
06511   struct TInters 
06512   {
06513     const SMDS_MeshElement* _face;
06514     gp_Vec                  _faceNorm;
06515     bool                    _coincides; 
06516     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
06517       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
06518   };
06519   struct TFaceLink 
06520   {
06521     SMESH_TLink      _link;
06522     TIDSortedElemSet _faces;
06523     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
06524       : _link( n1, n2 ), _faces( &face, &face + 1) {}
06525   };
06526 };
06527 
06528 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
06529 {
06530   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
06531              << ", _coincides="<<i._coincides << ")";
06532 }
06533 
06534 //=======================================================================
06538 //=======================================================================
06539 
06540 double SMESH_ElementSearcherImpl::getTolerance()
06541 {
06542   if ( _tolerance < 0 )
06543   {
06544     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
06545 
06546     _tolerance = 0;
06547     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
06548     {
06549       double boxSize = _nodeSearcher->getTree()->maxSize();
06550       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
06551     }
06552     else if ( _ebbTree && meshInfo.NbElements() > 0 )
06553     {
06554       double boxSize = _ebbTree->maxSize();
06555       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
06556     }
06557     if ( _tolerance == 0 )
06558     {
06559       // define tolerance by size of a most complex element
06560       int complexType = SMDSAbs_Volume;
06561       while ( complexType > SMDSAbs_All &&
06562               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
06563         --complexType;
06564       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
06565       double elemSize;
06566       if ( complexType == int( SMDSAbs_Node ))
06567       {
06568         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
06569         elemSize = 1;
06570         if ( meshInfo.NbNodes() > 2 )
06571           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
06572       }
06573       else
06574       {
06575         SMDS_ElemIteratorPtr elemIt =
06576             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
06577         const SMDS_MeshElement* elem = elemIt->next();
06578         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
06579         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
06580         elemSize = 0;
06581         while ( nodeIt->more() )
06582         {
06583           double dist = n1.Distance( cast2Node( nodeIt->next() ));
06584           elemSize = max( dist, elemSize );
06585         }
06586       }
06587       _tolerance = 1e-4 * elemSize;
06588     }
06589   }
06590   return _tolerance;
06591 }
06592 
06593 //================================================================================
06597 //================================================================================
06598 
06599 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
06600                                                      const SMDS_MeshElement* face,
06601                                                      const double            tol,
06602                                                      double &                param)
06603 {
06604   int nbInts = 0;
06605   param = 0;
06606 
06607   GeomAPI_ExtremaCurveCurve anExtCC;
06608   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
06609   
06610   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
06611   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
06612   {
06613     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
06614                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
06615     anExtCC.Init( lineCurve, edge);
06616     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
06617     {
06618       Quantity_Parameter pl, pe;
06619       anExtCC.LowerDistanceParameters( pl, pe );
06620       param += pl;
06621       if ( ++nbInts == 2 )
06622         break;
06623     }
06624   }
06625   if ( nbInts > 0 ) param /= nbInts;
06626   return nbInts > 0;
06627 }
06628 //================================================================================
06632 //================================================================================
06633 
06634 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
06635 {
06636   if ( _outerFacesFound ) return;
06637 
06638   // Collect all outer faces by passing from one outer face to another via their links
06639   // and BTW find out if there are internal faces at all.
06640 
06641   // checked links and links where outer boundary meets internal one
06642   set< SMESH_TLink > visitedLinks, seamLinks;
06643 
06644   // links to treat with already visited faces sharing them
06645   list < TFaceLink > startLinks;
06646 
06647   // load startLinks with the first outerFace
06648   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
06649   _outerFaces.insert( outerFace );
06650 
06651   TIDSortedElemSet emptySet;
06652   while ( !startLinks.empty() )
06653   {
06654     const SMESH_TLink& link  = startLinks.front()._link;
06655     TIDSortedElemSet&  faces = startLinks.front()._faces;
06656 
06657     outerFace = *faces.begin();
06658     // find other faces sharing the link
06659     const SMDS_MeshElement* f;
06660     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
06661       faces.insert( f );
06662 
06663     // select another outer face among the found 
06664     const SMDS_MeshElement* outerFace2 = 0;
06665     if ( faces.size() == 2 )
06666     {
06667       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
06668     }
06669     else if ( faces.size() > 2 )
06670     {
06671       seamLinks.insert( link );
06672 
06673       // link direction within the outerFace
06674       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
06675                    SMESH_TNodeXYZ( link.node2()));
06676       int i1 = outerFace->GetNodeIndex( link.node1() );
06677       int i2 = outerFace->GetNodeIndex( link.node2() );
06678       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
06679       if ( rev ) n1n2.Reverse();
06680       // outerFace normal
06681       gp_XYZ ofNorm, fNorm;
06682       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
06683       {
06684         // direction from the link inside outerFace
06685         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
06686         // sort all other faces by angle with the dirInOF
06687         map< double, const SMDS_MeshElement* > angle2Face;
06688         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
06689         for ( ; face != faces.end(); ++face )
06690         {
06691           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
06692             continue;
06693           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
06694           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
06695           if ( angle < 0 ) angle += 2*PI;
06696           angle2Face.insert( make_pair( angle, *face ));
06697         }
06698         if ( !angle2Face.empty() )
06699           outerFace2 = angle2Face.begin()->second;
06700       }
06701     }
06702     // store the found outer face and add its links to continue seaching from
06703     if ( outerFace2 )
06704     {
06705       _outerFaces.insert( outerFace );
06706       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
06707       for ( int i = 0; i < nbNodes; ++i )
06708       {
06709         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
06710         if ( visitedLinks.insert( link2 ).second )
06711           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
06712       }
06713     }
06714     startLinks.pop_front();
06715   }
06716   _outerFacesFound = true;
06717 
06718   if ( !seamLinks.empty() )
06719   {
06720     // There are internal boundaries touching the outher one,
06721     // find all faces of internal boundaries in order to find
06722     // faces of boundaries of holes, if any.
06723     
06724   }
06725   else
06726   {
06727     _outerFaces.clear();
06728   }
06729 }
06730 
06731 //=======================================================================
06738 //=======================================================================
06739 
06740 int SMESH_ElementSearcherImpl::
06741 FindElementsByPoint(const gp_Pnt&                      point,
06742                     SMDSAbs_ElementType                type,
06743                     vector< const SMDS_MeshElement* >& foundElements)
06744 {
06745   foundElements.clear();
06746 
06747   double tolerance = getTolerance();
06748 
06749   // =================================================================================
06750   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
06751   {
06752     if ( !_nodeSearcher )
06753       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
06754 
06755     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
06756     if ( !closeNode ) return foundElements.size();
06757 
06758     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
06759       return foundElements.size(); // to far from any node
06760 
06761     if ( type == SMDSAbs_Node )
06762     {
06763       foundElements.push_back( closeNode );
06764     }
06765     else
06766     {
06767       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
06768       while ( elemIt->more() )
06769         foundElements.push_back( elemIt->next() );
06770     }
06771   }
06772   // =================================================================================
06773   else // elements more complex than 0D
06774   {
06775     if ( !_ebbTree || _elementType != type )
06776     {
06777       if ( _ebbTree ) delete _ebbTree;
06778       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
06779     }
06780     TIDSortedElemSet suspectElems;
06781     _ebbTree->getElementsNearPoint( point, suspectElems );
06782     TIDSortedElemSet::iterator elem = suspectElems.begin();
06783     for ( ; elem != suspectElems.end(); ++elem )
06784       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
06785         foundElements.push_back( *elem );
06786   }
06787   return foundElements.size();
06788 }
06789 
06790 //================================================================================
06794 //================================================================================
06795 
06796 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
06797 {
06798   double tolerance = getTolerance();
06799   if ( !_ebbTree || _elementType != SMDSAbs_Face )
06800   {
06801     if ( _ebbTree ) delete _ebbTree;
06802     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
06803   }
06804   // Algo: analyse transition of a line starting at the point through mesh boundary;
06805   // try three lines parallel to axis of the coordinate system and perform rough
06806   // analysis. If solution is not clear perform thorough analysis.
06807 
06808   const int nbAxes = 3;
06809   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
06810   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
06811   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
06812   multimap< int, int > nbInt2Axis; // to find the simplest case
06813   for ( int axis = 0; axis < nbAxes; ++axis )
06814   {
06815     gp_Ax1 lineAxis( point, axisDir[axis]);
06816     gp_Lin line    ( lineAxis );
06817 
06818     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
06819     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
06820 
06821     // Intersect faces with the line
06822 
06823     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
06824     TIDSortedElemSet::iterator face = suspectFaces.begin();
06825     for ( ; face != suspectFaces.end(); ++face )
06826     {
06827       // get face plane
06828       gp_XYZ fNorm;
06829       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
06830       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
06831 
06832       // perform intersection
06833       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
06834       if ( !intersection.IsDone() )
06835         continue;
06836       if ( intersection.IsInQuadric() )
06837       {
06838         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
06839       }
06840       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
06841       {
06842         gp_Pnt intersectionPoint = intersection.Point(1);
06843         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
06844           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
06845       }
06846     }
06847     // Analyse intersections roughly
06848 
06849     int nbInter = u2inters.size();
06850     if ( nbInter == 0 )
06851       return TopAbs_OUT; 
06852 
06853     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
06854     if ( nbInter == 1 ) // not closed mesh
06855       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
06856 
06857     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
06858       return TopAbs_ON;
06859 
06860     if ( (f<0) == (l<0) )
06861       return TopAbs_OUT;
06862 
06863     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
06864     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
06865     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
06866       return TopAbs_IN;
06867 
06868     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
06869 
06870     if ( _outerFacesFound ) break; // pass to thorough analysis
06871 
06872   } // three attempts - loop on CS axes
06873 
06874   // Analyse intersections thoroughly.
06875   // We make two loops maximum, on the first one we only exclude touching intersections,
06876   // on the second, if situation is still unclear, we gather and use information on
06877   // position of faces (internal or outer). If faces position is already gathered,
06878   // we make the second loop right away.
06879 
06880   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
06881   {
06882     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
06883     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
06884     {
06885       int axis = nb_axis->second;
06886       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
06887 
06888       gp_Ax1 lineAxis( point, axisDir[axis]);
06889       gp_Lin line    ( lineAxis );
06890 
06891       // add tangent intersections to u2inters
06892       double param;
06893       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
06894       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
06895         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
06896           u2inters.insert(make_pair( param, *tgtInt ));
06897       tangentInters[ axis ].clear();
06898 
06899       // Count intersections before and after the point excluding touching ones.
06900       // If hasPositionInfo we count intersections of outer boundary only
06901 
06902       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
06903       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
06904       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
06905       bool ok = ! u_int1->second._coincides;
06906       while ( ok && u_int1 != u2inters.end() )
06907       {
06908         double u = u_int1->first;
06909         bool touchingInt = false;
06910         if ( ++u_int2 != u2inters.end() )
06911         {
06912           // skip intersections at the same point (if the line passes through edge or node)
06913           int nbSamePnt = 0;
06914           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
06915           {
06916             ++nbSamePnt;
06917             ++u_int2;
06918           }
06919 
06920           // skip tangent intersections
06921           int nbTgt = 0;
06922           const SMDS_MeshElement* prevFace = u_int1->second._face;
06923           while ( ok && u_int2->second._coincides )
06924           {
06925             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
06926               ok = false;
06927             else
06928             {
06929               nbTgt++;
06930               u_int2++;
06931               ok = ( u_int2 != u2inters.end() );
06932             }
06933           }
06934           if ( !ok ) break;
06935 
06936           // skip intersections at the same point after tangent intersections
06937           if ( nbTgt > 0 )
06938           {
06939             double u2 = u_int2->first;
06940             ++u_int2;
06941             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
06942             {
06943               ++nbSamePnt;
06944               ++u_int2;
06945             }
06946           }
06947           // decide if we skipped a touching intersection
06948           if ( nbSamePnt + nbTgt > 0 )
06949           {
06950             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
06951             map< double, TInters >::iterator u_int = u_int1;
06952             for ( ; u_int != u_int2; ++u_int )
06953             {
06954               if ( u_int->second._coincides ) continue;
06955               double dot = u_int->second._faceNorm * line.Direction();
06956               if ( dot > maxDot ) maxDot = dot;
06957               if ( dot < minDot ) minDot = dot;
06958             }
06959             touchingInt = ( minDot*maxDot < 0 );
06960           }
06961         }
06962         if ( !touchingInt )
06963         {
06964           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
06965           {
06966             if ( u < 0 )
06967               ++nbIntBeforePoint;
06968             else
06969               ++nbIntAfterPoint;
06970           }
06971           if ( u < f ) f = u;
06972           if ( u > l ) l = u;
06973         }
06974 
06975         u_int1 = u_int2; // to next intersection
06976 
06977       } // loop on intersections with one line
06978 
06979       if ( ok )
06980       {
06981         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
06982           return TopAbs_ON;
06983 
06984         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
06985           return TopAbs_OUT; 
06986 
06987         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
06988           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
06989 
06990         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
06991           return TopAbs_IN;
06992 
06993         if ( (f<0) == (l<0) )
06994           return TopAbs_OUT;
06995 
06996         if ( hasPositionInfo )
06997           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
06998       }
06999     } // loop on intersections of the tree lines - thorough analysis
07000 
07001     if ( !hasPositionInfo )
07002     {
07003       // gather info on faces position - is face in the outer boundary or not
07004       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
07005       findOuterBoundary( u2inters.begin()->second._face );
07006     }
07007 
07008   } // two attempts - with and w/o faces position info in the mesh
07009 
07010   return TopAbs_UNKNOWN;
07011 }
07012 
07013 //=======================================================================
07017 //=======================================================================
07018 
07019 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
07020                                                      SMDSAbs_ElementType                type,
07021                                                      vector< const SMDS_MeshElement* >& foundElems)
07022 {
07023   if ( !_ebbTree || _elementType != type )
07024   {
07025     if ( _ebbTree ) delete _ebbTree;
07026     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
07027   }
07028   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
07029   _ebbTree->getElementsNearLine( line, suspectFaces );
07030   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
07031 }
07032 
07033 //=======================================================================
07037 //=======================================================================
07038 
07039 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
07040 {
07041   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
07042 }
07043 
07044 //=======================================================================
07048 //=======================================================================
07049 
07050 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
07051 {
07052   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
07053 }
07054 
07055 //=======================================================================
07059 //=======================================================================
07060 
07061 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
07062 {
07063   if ( element->GetType() == SMDSAbs_Volume)
07064   {
07065     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
07066   }
07067 
07068   // get ordered nodes
07069 
07070   vector< gp_XYZ > xyz;
07071   vector<const SMDS_MeshNode*> nodeList;
07072 
07073   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
07074   if ( element->IsQuadratic() ) {
07075     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
07076       nodeIt = f->interlacedNodesElemIterator();
07077     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
07078       nodeIt = e->interlacedNodesElemIterator();
07079   }
07080   while ( nodeIt->more() )
07081     {
07082       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
07083       xyz.push_back( SMESH_TNodeXYZ(node) );
07084       nodeList.push_back(node);
07085     }
07086 
07087   int i, nbNodes = element->NbNodes();
07088 
07089   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
07090   {
07091     // compute face normal
07092     gp_Vec faceNorm(0,0,0);
07093     xyz.push_back( xyz.front() );
07094     nodeList.push_back( nodeList.front() );
07095     for ( i = 0; i < nbNodes; ++i )
07096     {
07097       gp_Vec edge1( xyz[i+1], xyz[i]);
07098       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
07099       faceNorm += edge1 ^ edge2;
07100     }
07101     double normSize = faceNorm.Magnitude();
07102     if ( normSize <= tol )
07103     {
07104       // degenerated face: point is out if it is out of all face edges
07105       for ( i = 0; i < nbNodes; ++i )
07106       {
07107         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
07108         if ( !isOut( &edge, point, tol ))
07109           return false;
07110       }
07111       return true;
07112     }
07113     faceNorm /= normSize;
07114 
07115     // check if the point lays on face plane
07116     gp_Vec n2p( xyz[0], point );
07117     if ( fabs( n2p * faceNorm ) > tol )
07118       return true; // not on face plane
07119 
07120     // check if point is out of face boundary:
07121     // define it by closest transition of a ray point->infinity through face boundary
07122     // on the face plane.
07123     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
07124     // to find intersections of the ray with the boundary.
07125     gp_Vec ray = n2p;
07126     gp_Vec plnNorm = ray ^ faceNorm;
07127     normSize = plnNorm.Magnitude();
07128     if ( normSize <= tol ) return false; // point coincides with the first node
07129     plnNorm /= normSize;
07130     // for each node of the face, compute its signed distance to the plane
07131     vector<double> dist( nbNodes + 1);
07132     for ( i = 0; i < nbNodes; ++i )
07133     {
07134       gp_Vec n2p( xyz[i], point );
07135       dist[i] = n2p * plnNorm;
07136     }
07137     dist.back() = dist.front();
07138     // find the closest intersection
07139     int    iClosest = -1;
07140     double rClosest, distClosest = 1e100;;
07141     gp_Pnt pClosest;
07142     for ( i = 0; i < nbNodes; ++i )
07143     {
07144       double r;
07145       if ( fabs( dist[i]) < tol )
07146         r = 0.;
07147       else if ( fabs( dist[i+1]) < tol )
07148         r = 1.;
07149       else if ( dist[i] * dist[i+1] < 0 )
07150         r = dist[i] / ( dist[i] - dist[i+1] );
07151       else
07152         continue; // no intersection
07153       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
07154       gp_Vec p2int ( point, pInt);
07155       if ( p2int * ray > -tol ) // right half-space
07156       {
07157         double intDist = p2int.SquareMagnitude();
07158         if ( intDist < distClosest )
07159         {
07160           iClosest = i;
07161           rClosest = r;
07162           pClosest = pInt;
07163           distClosest = intDist;
07164         }
07165       }
07166     }
07167     if ( iClosest < 0 )
07168       return true; // no intesections - out
07169 
07170     // analyse transition
07171     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
07172     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
07173     gp_Vec p2int ( point, pClosest );
07174     bool out = (edgeNorm * p2int) < -tol;
07175     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
07176       return out;
07177 
07178     // ray pass through a face node; analyze transition through an adjacent edge
07179     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
07180     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
07181     gp_Vec edgeAdjacent( p1, p2 );
07182     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
07183     bool out2 = (edgeNorm2 * p2int) < -tol;
07184 
07185     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
07186     return covexCorner ? (out || out2) : (out && out2);
07187   }
07188   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
07189   {
07190     // point is out of edge if it is NOT ON any straight part of edge
07191     // (we consider quadratic edge as being composed of two straight parts)
07192     for ( i = 1; i < nbNodes; ++i )
07193     {
07194       gp_Vec edge( xyz[i-1], xyz[i]);
07195       gp_Vec n1p ( xyz[i-1], point);
07196       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
07197       if ( dist > tol )
07198         continue;
07199       gp_Vec n2p( xyz[i], point );
07200       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
07201         continue;
07202       return false; // point is ON this part
07203     }
07204     return true;
07205   }
07206   // Node or 0D element -------------------------------------------------------------------------
07207   {
07208     gp_Vec n2p ( xyz[0], point );
07209     return n2p.Magnitude() <= tol;
07210   }
07211   return true;
07212 }
07213 
07214 //=======================================================================
07215 //function : SimplifyFace
07216 //purpose  :
07217 //=======================================================================
07218 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
07219                                     vector<const SMDS_MeshNode *>&      poly_nodes,
07220                                     vector<int>&                        quantities) const
07221 {
07222   int nbNodes = faceNodes.size();
07223 
07224   if (nbNodes < 3)
07225     return 0;
07226 
07227   set<const SMDS_MeshNode*> nodeSet;
07228 
07229   // get simple seq of nodes
07230   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
07231   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
07232   int iSimple = 0, nbUnique = 0;
07233 
07234   simpleNodes[iSimple++] = faceNodes[0];
07235   nbUnique++;
07236   for (int iCur = 1; iCur < nbNodes; iCur++) {
07237     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
07238       simpleNodes[iSimple++] = faceNodes[iCur];
07239       if (nodeSet.insert( faceNodes[iCur] ).second)
07240         nbUnique++;
07241     }
07242   }
07243   int nbSimple = iSimple;
07244   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
07245     nbSimple--;
07246     iSimple--;
07247   }
07248 
07249   if (nbUnique < 3)
07250     return 0;
07251 
07252   // separate loops
07253   int nbNew = 0;
07254   bool foundLoop = (nbSimple > nbUnique);
07255   while (foundLoop) {
07256     foundLoop = false;
07257     set<const SMDS_MeshNode*> loopSet;
07258     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
07259       const SMDS_MeshNode* n = simpleNodes[iSimple];
07260       if (!loopSet.insert( n ).second) {
07261         foundLoop = true;
07262 
07263         // separate loop
07264         int iC = 0, curLast = iSimple;
07265         for (; iC < curLast; iC++) {
07266           if (simpleNodes[iC] == n) break;
07267         }
07268         int loopLen = curLast - iC;
07269         if (loopLen > 2) {
07270           // create sub-element
07271           nbNew++;
07272           quantities.push_back(loopLen);
07273           for (; iC < curLast; iC++) {
07274             poly_nodes.push_back(simpleNodes[iC]);
07275           }
07276         }
07277         // shift the rest nodes (place from the first loop position)
07278         for (iC = curLast + 1; iC < nbSimple; iC++) {
07279           simpleNodes[iC - loopLen] = simpleNodes[iC];
07280         }
07281         nbSimple -= loopLen;
07282         iSimple -= loopLen;
07283       }
07284     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
07285   } // while (foundLoop)
07286 
07287   if (iSimple > 2) {
07288     nbNew++;
07289     quantities.push_back(iSimple);
07290     for (int i = 0; i < iSimple; i++)
07291       poly_nodes.push_back(simpleNodes[i]);
07292   }
07293 
07294   return nbNew;
07295 }
07296 
07297 //=======================================================================
07298 //function : MergeNodes
07299 //purpose  : In each group, the cdr of nodes are substituted by the first one
07300 //           in all elements.
07301 //=======================================================================
07302 
07303 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
07304 {
07305   MESSAGE("MergeNodes");
07306   myLastCreatedElems.Clear();
07307   myLastCreatedNodes.Clear();
07308 
07309   SMESHDS_Mesh* aMesh = GetMeshDS();
07310 
07311   TNodeNodeMap nodeNodeMap; // node to replace - new node
07312   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
07313   list< int > rmElemIds, rmNodeIds;
07314 
07315   // Fill nodeNodeMap and elems
07316 
07317   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
07318   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
07319     list<const SMDS_MeshNode*>& nodes = *grIt;
07320     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
07321     const SMDS_MeshNode* nToKeep = *nIt;
07322     //MESSAGE("node to keep " << nToKeep->GetID());
07323     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
07324       const SMDS_MeshNode* nToRemove = *nIt;
07325       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
07326       if ( nToRemove != nToKeep ) {
07327         //MESSAGE("  node to remove " << nToRemove->GetID());
07328         rmNodeIds.push_back( nToRemove->GetID() );
07329         AddToSameGroups( nToKeep, nToRemove, aMesh );
07330       }
07331 
07332       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
07333       while ( invElemIt->more() ) {
07334         const SMDS_MeshElement* elem = invElemIt->next();
07335         elems.insert(elem);
07336       }
07337     }
07338   }
07339   // Change element nodes or remove an element
07340 
07341   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
07342   for ( ; eIt != elems.end(); eIt++ ) {
07343     const SMDS_MeshElement* elem = *eIt;
07344     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
07345     int nbNodes = elem->NbNodes();
07346     int aShapeId = FindShape( elem );
07347 
07348     set<const SMDS_MeshNode*> nodeSet;
07349     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
07350     int iUnique = 0, iCur = 0, nbRepl = 0;
07351     vector<int> iRepl( nbNodes );
07352 
07353     // get new seq of nodes
07354     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
07355     while ( itN->more() ) {
07356       const SMDS_MeshNode* n =
07357         static_cast<const SMDS_MeshNode*>( itN->next() );
07358 
07359       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
07360       if ( nnIt != nodeNodeMap.end() ) { // n sticks
07361         n = (*nnIt).second;
07362         // BUG 0020185: begin
07363         {
07364           bool stopRecur = false;
07365           set<const SMDS_MeshNode*> nodesRecur;
07366           nodesRecur.insert(n);
07367           while (!stopRecur) {
07368             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
07369             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
07370               n = (*nnIt_i).second;
07371               if (!nodesRecur.insert(n).second) {
07372                 // error: recursive dependancy
07373                 stopRecur = true;
07374               }
07375             }
07376             else
07377               stopRecur = true;
07378           }
07379         }
07380         // BUG 0020185: end
07381         iRepl[ nbRepl++ ] = iCur;
07382       }
07383       curNodes[ iCur ] = n;
07384       bool isUnique = nodeSet.insert( n ).second;
07385       if ( isUnique ) {
07386         uniqueNodes[ iUnique++ ] = n;
07387         if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
07388           --nbRepl; // n do not stick to a node of the elem
07389       }
07390       iCur++;
07391     }
07392 
07393     // Analyse element topology after replacement
07394 
07395     bool isOk = true;
07396     int nbUniqueNodes = nodeSet.size();
07397     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
07398     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
07399       // Polygons and Polyhedral volumes
07400       if (elem->IsPoly()) {
07401 
07402         if (elem->GetType() == SMDSAbs_Face) {
07403           // Polygon
07404           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
07405           int inode = 0;
07406           for (; inode < nbNodes; inode++) {
07407             face_nodes[inode] = curNodes[inode];
07408           }
07409 
07410           vector<const SMDS_MeshNode *> polygons_nodes;
07411           vector<int> quantities;
07412           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
07413           if (nbNew > 0) {
07414             inode = 0;
07415             for (int iface = 0; iface < nbNew; iface++) {
07416               int nbNodes = quantities[iface];
07417               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
07418               for (int ii = 0; ii < nbNodes; ii++, inode++) {
07419                 poly_nodes[ii] = polygons_nodes[inode];
07420               }
07421               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
07422               myLastCreatedElems.Append(newElem);
07423               if (aShapeId)
07424                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
07425             }
07426 
07427             MESSAGE("ChangeElementNodes MergeNodes Polygon");
07428             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
07429             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
07430             int quid =0;
07431             if (nbNew > 0) quid = nbNew - 1;
07432             vector<int> newquant(quantities.begin()+quid, quantities.end());
07433             const SMDS_MeshElement* newElem = 0;
07434             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
07435             myLastCreatedElems.Append(newElem);
07436             if ( aShapeId && newElem )
07437               aMesh->SetMeshElementOnShape( newElem, aShapeId );
07438             rmElemIds.push_back(elem->GetID());
07439           }
07440           else {
07441             rmElemIds.push_back(elem->GetID());
07442           }
07443 
07444         }
07445         else if (elem->GetType() == SMDSAbs_Volume) {
07446           // Polyhedral volume
07447           if (nbUniqueNodes < 4) {
07448             rmElemIds.push_back(elem->GetID());
07449           }
07450           else {
07451             // each face has to be analyzed in order to check volume validity
07452             const SMDS_VtkVolume* aPolyedre =
07453               dynamic_cast<const SMDS_VtkVolume*>( elem );
07454             if (aPolyedre) {
07455               int nbFaces = aPolyedre->NbFaces();
07456 
07457               vector<const SMDS_MeshNode *> poly_nodes;
07458               vector<int> quantities;
07459 
07460               for (int iface = 1; iface <= nbFaces; iface++) {
07461                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
07462                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
07463 
07464                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
07465                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
07466                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
07467                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
07468                     faceNode = (*nnIt).second;
07469                   }
07470                   faceNodes[inode - 1] = faceNode;
07471                 }
07472 
07473                 SimplifyFace(faceNodes, poly_nodes, quantities);
07474               }
07475 
07476               if (quantities.size() > 3) {
07477                 // to be done: remove coincident faces
07478               }
07479 
07480               if (quantities.size() > 3)
07481                 {
07482                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
07483                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
07484                   const SMDS_MeshElement* newElem = 0;
07485                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
07486                   myLastCreatedElems.Append(newElem);
07487                   if ( aShapeId && newElem )
07488                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
07489                   rmElemIds.push_back(elem->GetID());
07490                 }
07491             }
07492             else {
07493               rmElemIds.push_back(elem->GetID());
07494             }
07495           }
07496         }
07497         else {
07498         }
07499 
07500         continue;
07501       } // poly element
07502 
07503       // Regular elements
07504       // TODO not all the possible cases are solved. Find something more generic?
07505       switch ( nbNodes ) {
07506       case 2: 
07507         isOk = false; break;
07508       case 3: 
07509         isOk = false; break;
07510       case 4:
07511         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
07512           isOk = false;
07513         else { 
07514           if ( nbUniqueNodes < 3 )
07515             isOk = false;
07516           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
07517             isOk = false; // opposite nodes stick
07518           //MESSAGE("isOk " << isOk);
07519         }
07520         break;
07521       case 6: 
07522         if ( nbUniqueNodes == 4 ) {
07523           // ---------------------------------> tetrahedron
07524           if (nbRepl == 3 &&
07525               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
07526             // all top nodes stick: reverse a bottom
07527             uniqueNodes[ 0 ] = curNodes [ 1 ];
07528             uniqueNodes[ 1 ] = curNodes [ 0 ];
07529           }
07530           else if (nbRepl == 3 &&
07531                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
07532             // all bottom nodes stick: set a top before
07533             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
07534             uniqueNodes[ 0 ] = curNodes [ 3 ];
07535             uniqueNodes[ 1 ] = curNodes [ 4 ];
07536             uniqueNodes[ 2 ] = curNodes [ 5 ];
07537           }
07538           else if (nbRepl == 4 &&
07539                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
07540             // a lateral face turns into a line: reverse a bottom
07541             uniqueNodes[ 0 ] = curNodes [ 1 ];
07542             uniqueNodes[ 1 ] = curNodes [ 0 ];
07543           }
07544           else
07545             isOk = false;
07546         }
07547         else if ( nbUniqueNodes == 5 ) {
07548           // PENTAHEDRON --------------------> 2 tetrahedrons
07549           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
07550             // a bottom node sticks with a linked top one
07551             // 1.
07552             SMDS_MeshElement* newElem =
07553               aMesh->AddVolume(curNodes[ 3 ],
07554                                curNodes[ 4 ],
07555                                curNodes[ 5 ],
07556                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
07557             myLastCreatedElems.Append(newElem);
07558             if ( aShapeId )
07559               aMesh->SetMeshElementOnShape( newElem, aShapeId );
07560             // 2. : reverse a bottom
07561             uniqueNodes[ 0 ] = curNodes [ 1 ];
07562             uniqueNodes[ 1 ] = curNodes [ 0 ];
07563             nbUniqueNodes = 4;
07564           }
07565           else
07566             isOk = false;
07567         }
07568         else
07569           isOk = false;
07570         break;
07571       case 8: {
07572         if(elem->IsQuadratic()) { // Quadratic quadrangle
07573           //   1    5    2
07574           //    +---+---+
07575           //    |       |
07576           //    |       |
07577           //   4+       +6
07578           //    |       |
07579           //    |       |
07580           //    +---+---+
07581           //   0    7    3
07582           isOk = false;
07583           if(nbRepl==2) {
07584             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
07585           }
07586           if(nbRepl==3) {
07587             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
07588             nbUniqueNodes = 6;
07589             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
07590               uniqueNodes[0] = curNodes[0];
07591               uniqueNodes[1] = curNodes[2];
07592               uniqueNodes[2] = curNodes[3];
07593               uniqueNodes[3] = curNodes[5];
07594               uniqueNodes[4] = curNodes[6];
07595               uniqueNodes[5] = curNodes[7];
07596               isOk = true;
07597             }
07598             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
07599               uniqueNodes[0] = curNodes[0];
07600               uniqueNodes[1] = curNodes[1];
07601               uniqueNodes[2] = curNodes[2];
07602               uniqueNodes[3] = curNodes[4];
07603               uniqueNodes[4] = curNodes[5];
07604               uniqueNodes[5] = curNodes[6];
07605               isOk = true;
07606             }
07607             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
07608               uniqueNodes[0] = curNodes[1];
07609               uniqueNodes[1] = curNodes[2];
07610               uniqueNodes[2] = curNodes[3];
07611               uniqueNodes[3] = curNodes[5];
07612               uniqueNodes[4] = curNodes[6];
07613               uniqueNodes[5] = curNodes[0];
07614               isOk = true;
07615             }
07616             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
07617               uniqueNodes[0] = curNodes[0];
07618               uniqueNodes[1] = curNodes[1];
07619               uniqueNodes[2] = curNodes[3];
07620               uniqueNodes[3] = curNodes[4];
07621               uniqueNodes[4] = curNodes[6];
07622               uniqueNodes[5] = curNodes[7];
07623               isOk = true;
07624             }
07625             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
07626               uniqueNodes[0] = curNodes[0];
07627               uniqueNodes[1] = curNodes[2];
07628               uniqueNodes[2] = curNodes[3];
07629               uniqueNodes[3] = curNodes[1];
07630               uniqueNodes[4] = curNodes[6];
07631               uniqueNodes[5] = curNodes[7];
07632               isOk = true;
07633             }
07634             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
07635               uniqueNodes[0] = curNodes[0];
07636               uniqueNodes[1] = curNodes[1];
07637               uniqueNodes[2] = curNodes[2];
07638               uniqueNodes[3] = curNodes[4];
07639               uniqueNodes[4] = curNodes[5];
07640               uniqueNodes[5] = curNodes[7];
07641               isOk = true;
07642             }
07643             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
07644               uniqueNodes[0] = curNodes[0];
07645               uniqueNodes[1] = curNodes[1];
07646               uniqueNodes[2] = curNodes[3];
07647               uniqueNodes[3] = curNodes[4];
07648               uniqueNodes[4] = curNodes[2];
07649               uniqueNodes[5] = curNodes[7];
07650               isOk = true;
07651             }
07652             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
07653               uniqueNodes[0] = curNodes[0];
07654               uniqueNodes[1] = curNodes[1];
07655               uniqueNodes[2] = curNodes[2];
07656               uniqueNodes[3] = curNodes[4];
07657               uniqueNodes[4] = curNodes[5];
07658               uniqueNodes[5] = curNodes[3];
07659               isOk = true;
07660             }
07661           }
07662           if(nbRepl==4) {
07663             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
07664           }
07665           if(nbRepl==5) {
07666             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
07667           }
07668           break;
07669         }
07671         isOk = false;
07672         SMDS_VolumeTool hexa (elem);
07673         hexa.SetExternalNormal();
07674         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
07676           for ( int iFace = 0; iFace < 6; iFace++ ) {
07677             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
07678             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
07679                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
07680                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
07681               // one face turns into a point ...
07682               int iOppFace = hexa.GetOppFaceIndex( iFace );
07683               ind = hexa.GetFaceNodesIndices( iOppFace );
07684               int nbStick = 0;
07685               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
07686                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
07687                   nbStick++;
07688               }
07689               if ( nbStick == 1 ) {
07690                 // ... and the opposite one - into a triangle.
07691                 // set a top node
07692                 ind = hexa.GetFaceNodesIndices( iFace );
07693                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
07694                 isOk = true;
07695               }
07696               break;
07697             }
07698           }
07699         }
07700         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
07702           int nbTria = 0, iTria[3];
07703           const int *ind; // indices of face nodes
07704           // look for triangular faces
07705           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
07706             ind = hexa.GetFaceNodesIndices( iFace );
07707             TIDSortedNodeSet faceNodes;
07708             for ( iCur = 0; iCur < 4; iCur++ )
07709               faceNodes.insert( curNodes[ind[iCur]] );
07710             if ( faceNodes.size() == 3 )
07711               iTria[ nbTria++ ] = iFace;
07712           }
07713           // check if triangles are opposite
07714           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
07715           {
07716             isOk = true;
07717             // set nodes of the bottom triangle
07718             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
07719             vector<int> indB;
07720             for ( iCur = 0; iCur < 4; iCur++ )
07721               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
07722                 indB.push_back( ind[iCur] );
07723             if ( !hexa.IsForward() )
07724               std::swap( indB[0], indB[2] );
07725             for ( iCur = 0; iCur < 3; iCur++ )
07726               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
07727             // set nodes of the top triangle
07728             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
07729             for ( iCur = 0; iCur < 3; ++iCur )
07730               for ( int j = 0; j < 4; ++j )
07731                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
07732                 {
07733                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
07734                   break;
07735                 }
07736           }
07737           break;
07738         }
07739         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
07741           for ( int iFace = 0; iFace < 6; iFace++ ) {
07742             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
07743             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
07744                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
07745                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
07746               // one face turns into a point ...
07747               int iOppFace = hexa.GetOppFaceIndex( iFace );
07748               ind = hexa.GetFaceNodesIndices( iOppFace );
07749               int nbStick = 0;
07750               iUnique = 2;  // reverse a tetrahedron 1 bottom
07751               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
07752                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
07753                   nbStick++;
07754                 else if ( iUnique >= 0 )
07755                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
07756               }
07757               if ( nbStick == 0 ) {
07758                 // ... and the opposite one is a quadrangle
07759                 // set a top node
07760                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
07761                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
07762                 nbUniqueNodes = 4;
07763                 // tetrahedron 2
07764                 SMDS_MeshElement* newElem =
07765                   aMesh->AddVolume(curNodes[ind[ 0 ]],
07766                                    curNodes[ind[ 3 ]],
07767                                    curNodes[ind[ 2 ]],
07768                                    curNodes[indTop[ 0 ]]);
07769                 myLastCreatedElems.Append(newElem);
07770                 if ( aShapeId )
07771                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
07772                 isOk = true;
07773               }
07774               break;
07775             }
07776           }
07777         }
07778         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
07780           // find indices of quad and tri faces
07781           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
07782           for ( iFace = 0; iFace < 6; iFace++ ) {
07783             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
07784             nodeSet.clear();
07785             for ( iCur = 0; iCur < 4; iCur++ )
07786               nodeSet.insert( curNodes[ind[ iCur ]] );
07787             nbUniqueNodes = nodeSet.size();
07788             if ( nbUniqueNodes == 3 )
07789               iTriFace[ nbTri++ ] = iFace;
07790             else if ( nbUniqueNodes == 4 )
07791               iQuadFace[ nbQuad++ ] = iFace;
07792           }
07793           if (nbQuad == 2 && nbTri == 4 &&
07794               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
07795             // 2 opposite quadrangles stuck with a diagonal;
07796             // sample groups of merged indices: (0-4)(2-6)
07797             // --------------------------------------------> 2 tetrahedrons
07798             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
07799             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
07800             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
07801             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
07802                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
07803               // stuck with 0-2 diagonal
07804               i0  = ind1[ 3 ];
07805               i1d = ind1[ 0 ];
07806               i2  = ind1[ 1 ];
07807               i3d = ind1[ 2 ];
07808               i0t = ind2[ 1 ];
07809               i2t = ind2[ 3 ];
07810             }
07811             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
07812                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
07813               // stuck with 1-3 diagonal
07814               i0  = ind1[ 0 ];
07815               i1d = ind1[ 1 ];
07816               i2  = ind1[ 2 ];
07817               i3d = ind1[ 3 ];
07818               i0t = ind2[ 0 ];
07819               i2t = ind2[ 1 ];
07820             }
07821             else {
07822               ASSERT(0);
07823             }
07824             // tetrahedron 1
07825             uniqueNodes[ 0 ] = curNodes [ i0 ];
07826             uniqueNodes[ 1 ] = curNodes [ i1d ];
07827             uniqueNodes[ 2 ] = curNodes [ i3d ];
07828             uniqueNodes[ 3 ] = curNodes [ i0t ];
07829             nbUniqueNodes = 4;
07830             // tetrahedron 2
07831             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
07832                                                          curNodes[ i2 ],
07833                                                          curNodes[ i3d ],
07834                                                          curNodes[ i2t ]);
07835             myLastCreatedElems.Append(newElem);
07836             if ( aShapeId )
07837               aMesh->SetMeshElementOnShape( newElem, aShapeId );
07838             isOk = true;
07839           }
07840           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
07841                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
07842             // --------------------------------------------> prism
07843             // find 2 opposite triangles
07844             nbUniqueNodes = 6;
07845             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
07846               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
07847                 // find indices of kept and replaced nodes
07848                 // and fill unique nodes of 2 opposite triangles
07849                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
07850                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
07851                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
07852                 // fill unique nodes
07853                 iUnique = 0;
07854                 isOk = true;
07855                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
07856                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
07857                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
07858                   if ( n == nInit ) {
07859                     // iCur of a linked node of the opposite face (make normals co-directed):
07860                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
07861                     // check that correspondent corners of triangles are linked
07862                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
07863                       isOk = false;
07864                     else {
07865                       uniqueNodes[ iUnique ] = n;
07866                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
07867                       iUnique++;
07868                     }
07869                   }
07870                 }
07871                 break;
07872               }
07873             }
07874           }
07875         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
07876         else
07877         {
07878           MESSAGE("MergeNodes() removes hexahedron "<< elem);
07879         }
07880         break;
07881       } // HEXAHEDRON
07882 
07883       default:
07884         isOk = false;
07885       } // switch ( nbNodes )
07886 
07887     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
07888 
07889     if ( isOk ) { // the elem remains valid after sticking nodes
07890       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
07891       {
07892         // Change nodes of polyedre
07893         const SMDS_VtkVolume* aPolyedre =
07894           dynamic_cast<const SMDS_VtkVolume*>( elem );
07895         if (aPolyedre) {
07896           int nbFaces = aPolyedre->NbFaces();
07897 
07898           vector<const SMDS_MeshNode *> poly_nodes;
07899           vector<int> quantities (nbFaces);
07900 
07901           for (int iface = 1; iface <= nbFaces; iface++) {
07902             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
07903             quantities[iface - 1] = nbFaceNodes;
07904 
07905             for (inode = 1; inode <= nbFaceNodes; inode++) {
07906               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
07907 
07908               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
07909               if (nnIt != nodeNodeMap.end()) { // curNode sticks
07910                 curNode = (*nnIt).second;
07911               }
07912               poly_nodes.push_back(curNode);
07913             }
07914           }
07915           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
07916         }
07917       }
07918       else // replace non-polyhedron elements
07919       {
07920         const SMDSAbs_ElementType etyp = elem->GetType();
07921         const int elemId               = elem->GetID();
07922         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
07923         uniqueNodes.resize(nbUniqueNodes);
07924 
07925         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
07926 
07927         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
07928         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
07929         if ( sm && newElem )
07930           sm->AddElement( newElem );
07931         if ( elem != newElem )
07932           ReplaceElemInGroups( elem, newElem, aMesh );
07933       }
07934     }
07935     else {
07936       // Remove invalid regular element or invalid polygon
07937       rmElemIds.push_back( elem->GetID() );
07938     }
07939 
07940   } // loop on elements
07941 
07942   // Remove bad elements, then equal nodes (order important)
07943 
07944   Remove( rmElemIds, false );
07945   Remove( rmNodeIds, true );
07946 
07947 }
07948 
07949 
07950 // ========================================================
07951 // class   : SortableElement
07952 // purpose : allow sorting elements basing on their nodes
07953 // ========================================================
07954 class SortableElement : public set <const SMDS_MeshElement*>
07955 {
07956 public:
07957 
07958   SortableElement( const SMDS_MeshElement* theElem )
07959   {
07960     myElem = theElem;
07961     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
07962     while ( nodeIt->more() )
07963       this->insert( nodeIt->next() );
07964   }
07965 
07966   const SMDS_MeshElement* Get() const
07967   { return myElem; }
07968 
07969   void Set(const SMDS_MeshElement* e) const
07970   { myElem = e; }
07971 
07972 
07973 private:
07974   mutable const SMDS_MeshElement* myElem;
07975 };
07976 
07977 //=======================================================================
07978 //function : FindEqualElements
07979 //purpose  : Return list of group of elements built on the same nodes.
07980 //           Search among theElements or in the whole mesh if theElements is empty
07981 //=======================================================================
07982 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
07983                                          TListOfListOfElementsID &      theGroupsOfElementsID)
07984 {
07985   myLastCreatedElems.Clear();
07986   myLastCreatedNodes.Clear();
07987 
07988   typedef set<const SMDS_MeshElement*> TElemsSet;
07989   typedef map< SortableElement, int > TMapOfNodeSet;
07990   typedef list<int> TGroupOfElems;
07991 
07992   TElemsSet elems;
07993   if ( theElements.empty() )
07994   { // get all elements in the mesh
07995     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
07996     while ( eIt->more() )
07997       elems.insert( elems.end(), eIt->next());
07998   }
07999   else
08000     elems = theElements;
08001 
08002   vector< TGroupOfElems > arrayOfGroups;
08003   TGroupOfElems groupOfElems;
08004   TMapOfNodeSet mapOfNodeSet;
08005 
08006   TElemsSet::iterator elemIt = elems.begin();
08007   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
08008     const SMDS_MeshElement* curElem = *elemIt;
08009     SortableElement SE(curElem);
08010     int ind = -1;
08011     // check uniqueness
08012     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
08013     if( !(pp.second) ) {
08014       TMapOfNodeSet::iterator& itSE = pp.first;
08015       ind = (*itSE).second;
08016       arrayOfGroups[ind].push_back(curElem->GetID());
08017     }
08018     else {
08019       groupOfElems.clear();
08020       groupOfElems.push_back(curElem->GetID());
08021       arrayOfGroups.push_back(groupOfElems);
08022       i++;
08023     }
08024   }
08025 
08026   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
08027   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
08028     groupOfElems = *groupIt;
08029     if ( groupOfElems.size() > 1 ) {
08030       groupOfElems.sort();
08031       theGroupsOfElementsID.push_back(groupOfElems);
08032     }
08033   }
08034 }
08035 
08036 //=======================================================================
08037 //function : MergeElements
08038 //purpose  : In each given group, substitute all elements by the first one.
08039 //=======================================================================
08040 
08041 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
08042 {
08043   myLastCreatedElems.Clear();
08044   myLastCreatedNodes.Clear();
08045 
08046   typedef list<int> TListOfIDs;
08047   TListOfIDs rmElemIds; // IDs of elems to remove
08048 
08049   SMESHDS_Mesh* aMesh = GetMeshDS();
08050 
08051   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
08052   while ( groupsIt != theGroupsOfElementsID.end() ) {
08053     TListOfIDs& aGroupOfElemID = *groupsIt;
08054     aGroupOfElemID.sort();
08055     int elemIDToKeep = aGroupOfElemID.front();
08056     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
08057     aGroupOfElemID.pop_front();
08058     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
08059     while ( idIt != aGroupOfElemID.end() ) {
08060       int elemIDToRemove = *idIt;
08061       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
08062       // add the kept element in groups of removed one (PAL15188)
08063       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
08064       rmElemIds.push_back( elemIDToRemove );
08065       ++idIt;
08066     }
08067     ++groupsIt;
08068   }
08069 
08070   Remove( rmElemIds, false );
08071 }
08072 
08073 //=======================================================================
08074 //function : MergeEqualElements
08075 //purpose  : Remove all but one of elements built on the same nodes.
08076 //=======================================================================
08077 
08078 void SMESH_MeshEditor::MergeEqualElements()
08079 {
08080   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
08081                                                  to merge equal elements in the whole mesh */
08082   TListOfListOfElementsID aGroupsOfElementsID;
08083   FindEqualElements(aMeshElements, aGroupsOfElementsID);
08084   MergeElements(aGroupsOfElementsID);
08085 }
08086 
08087 //=======================================================================
08088 //function : FindFaceInSet
08089 //purpose  : Return a face having linked nodes n1 and n2 and which is
08090 //           - not in avoidSet,
08091 //           - in elemSet provided that !elemSet.empty()
08092 //           i1 and i2 optionally returns indices of n1 and n2
08093 //=======================================================================
08094 
08095 const SMDS_MeshElement*
08096 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
08097                                 const SMDS_MeshNode*    n2,
08098                                 const TIDSortedElemSet& elemSet,
08099                                 const TIDSortedElemSet& avoidSet,
08100                                 int*                    n1ind,
08101                                 int*                    n2ind)
08102 
08103 {
08104   int i1, i2;
08105   const SMDS_MeshElement* face = 0;
08106 
08107   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
08108   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
08109   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
08110   {
08111     //MESSAGE("in while ( invElemIt->more() && !face )");
08112     const SMDS_MeshElement* elem = invElemIt->next();
08113     if (avoidSet.count( elem ))
08114       continue;
08115     if ( !elemSet.empty() && !elemSet.count( elem ))
08116       continue;
08117     // index of n1
08118     i1 = elem->GetNodeIndex( n1 );
08119     // find a n2 linked to n1
08120     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
08121     for ( int di = -1; di < 2 && !face; di += 2 )
08122     {
08123       i2 = (i1+di+nbN) % nbN;
08124       if ( elem->GetNode( i2 ) == n2 )
08125         face = elem;
08126     }
08127     if ( !face && elem->IsQuadratic())
08128     {
08129       // analysis for quadratic elements using all nodes
08130       const SMDS_VtkFace* F =
08131         dynamic_cast<const SMDS_VtkFace*>(elem);
08132       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
08133       // use special nodes iterator
08134       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
08135       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
08136       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
08137       {
08138         const SMDS_MeshNode* n = cast2Node( anIter->next() );
08139         if ( n1 == prevN && n2 == n )
08140         {
08141           face = elem;
08142         }
08143         else if ( n2 == prevN && n1 == n )
08144         {
08145           face = elem; swap( i1, i2 );
08146         }
08147         prevN = n;
08148       }
08149     }
08150   }
08151   if ( n1ind ) *n1ind = i1;
08152   if ( n2ind ) *n2ind = i2;
08153   return face;
08154 }
08155 
08156 //=======================================================================
08157 //function : findAdjacentFace
08158 //purpose  :
08159 //=======================================================================
08160 
08161 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
08162                                                 const SMDS_MeshNode* n2,
08163                                                 const SMDS_MeshElement* elem)
08164 {
08165   TIDSortedElemSet elemSet, avoidSet;
08166   if ( elem )
08167     avoidSet.insert ( elem );
08168   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
08169 }
08170 
08171 //=======================================================================
08172 //function : FindFreeBorder
08173 //purpose  :
08174 //=======================================================================
08175 
08176 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
08177 
08178 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
08179                                        const SMDS_MeshNode*             theSecondNode,
08180                                        const SMDS_MeshNode*             theLastNode,
08181                                        list< const SMDS_MeshNode* > &   theNodes,
08182                                        list< const SMDS_MeshElement* >& theFaces)
08183 {
08184   if ( !theFirstNode || !theSecondNode )
08185     return false;
08186   // find border face between theFirstNode and theSecondNode
08187   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
08188   if ( !curElem )
08189     return false;
08190 
08191   theFaces.push_back( curElem );
08192   theNodes.push_back( theFirstNode );
08193   theNodes.push_back( theSecondNode );
08194 
08195   //vector<const SMDS_MeshNode*> nodes;
08196   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
08197   TIDSortedElemSet foundElems;
08198   bool needTheLast = ( theLastNode != 0 );
08199 
08200   while ( nStart != theLastNode ) {
08201     if ( nStart == theFirstNode )
08202       return !needTheLast;
08203 
08204     // find all free border faces sharing form nStart
08205 
08206     list< const SMDS_MeshElement* > curElemList;
08207     list< const SMDS_MeshNode* > nStartList;
08208     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
08209     while ( invElemIt->more() ) {
08210       const SMDS_MeshElement* e = invElemIt->next();
08211       if ( e == curElem || foundElems.insert( e ).second ) {
08212         // get nodes
08213         int iNode = 0, nbNodes = e->NbNodes();
08214         //const SMDS_MeshNode* nodes[nbNodes+1];
08215         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
08216 
08217         if(e->IsQuadratic()) {
08218           const SMDS_VtkFace* F =
08219             dynamic_cast<const SMDS_VtkFace*>(e);
08220           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
08221           // use special nodes iterator
08222           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
08223           while( anIter->more() ) {
08224             nodes[ iNode++ ] = cast2Node(anIter->next());
08225           }
08226         }
08227         else {
08228           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
08229           while ( nIt->more() )
08230             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
08231         }
08232         nodes[ iNode ] = nodes[ 0 ];
08233         // check 2 links
08234         for ( iNode = 0; iNode < nbNodes; iNode++ )
08235           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
08236                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
08237               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
08238           {
08239             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
08240             curElemList.push_back( e );
08241           }
08242       }
08243     }
08244     // analyse the found
08245 
08246     int nbNewBorders = curElemList.size();
08247     if ( nbNewBorders == 0 ) {
08248       // no free border furthermore
08249       return !needTheLast;
08250     }
08251     else if ( nbNewBorders == 1 ) {
08252       // one more element found
08253       nIgnore = nStart;
08254       nStart = nStartList.front();
08255       curElem = curElemList.front();
08256       theFaces.push_back( curElem );
08257       theNodes.push_back( nStart );
08258     }
08259     else {
08260       // several continuations found
08261       list< const SMDS_MeshElement* >::iterator curElemIt;
08262       list< const SMDS_MeshNode* >::iterator nStartIt;
08263       // check if one of them reached the last node
08264       if ( needTheLast ) {
08265         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
08266              curElemIt!= curElemList.end();
08267              curElemIt++, nStartIt++ )
08268           if ( *nStartIt == theLastNode ) {
08269             theFaces.push_back( *curElemIt );
08270             theNodes.push_back( *nStartIt );
08271             return true;
08272           }
08273       }
08274       // find the best free border by the continuations
08275       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
08276       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
08277       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
08278            curElemIt!= curElemList.end();
08279            curElemIt++, nStartIt++ )
08280       {
08281         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
08282         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
08283         // find one more free border
08284         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
08285           cNL->clear();
08286           cFL->clear();
08287         }
08288         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
08289           // choice: clear a worse one
08290           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
08291           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
08292           contNodes[ iWorse ].clear();
08293           contFaces[ iWorse ].clear();
08294         }
08295       }
08296       if ( contNodes[0].empty() && contNodes[1].empty() )
08297         return false;
08298 
08299       // append the best free border
08300       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
08301       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
08302       theNodes.pop_back(); // remove nIgnore
08303       theNodes.pop_back(); // remove nStart
08304       theFaces.pop_back(); // remove curElem
08305       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
08306       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
08307       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
08308       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
08309       return true;
08310 
08311     } // several continuations found
08312   } // while ( nStart != theLastNode )
08313 
08314   return true;
08315 }
08316 
08317 //=======================================================================
08318 //function : CheckFreeBorderNodes
08319 //purpose  : Return true if the tree nodes are on a free border
08320 //=======================================================================
08321 
08322 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
08323                                             const SMDS_MeshNode* theNode2,
08324                                             const SMDS_MeshNode* theNode3)
08325 {
08326   list< const SMDS_MeshNode* > nodes;
08327   list< const SMDS_MeshElement* > faces;
08328   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
08329 }
08330 
08331 //=======================================================================
08332 //function : SewFreeBorder
08333 //purpose  :
08334 //=======================================================================
08335 
08336 SMESH_MeshEditor::Sew_Error
08337 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
08338                                  const SMDS_MeshNode* theBordSecondNode,
08339                                  const SMDS_MeshNode* theBordLastNode,
08340                                  const SMDS_MeshNode* theSideFirstNode,
08341                                  const SMDS_MeshNode* theSideSecondNode,
08342                                  const SMDS_MeshNode* theSideThirdNode,
08343                                  const bool           theSideIsFreeBorder,
08344                                  const bool           toCreatePolygons,
08345                                  const bool           toCreatePolyedrs)
08346 {
08347   myLastCreatedElems.Clear();
08348   myLastCreatedNodes.Clear();
08349 
08350   MESSAGE("::SewFreeBorder()");
08351   Sew_Error aResult = SEW_OK;
08352 
08353   // ====================================
08354   //    find side nodes and elements
08355   // ====================================
08356 
08357   list< const SMDS_MeshNode* > nSide[ 2 ];
08358   list< const SMDS_MeshElement* > eSide[ 2 ];
08359   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
08360   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
08361 
08362   // Free border 1
08363   // --------------
08364   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
08365                       nSide[0], eSide[0])) {
08366     MESSAGE(" Free Border 1 not found " );
08367     aResult = SEW_BORDER1_NOT_FOUND;
08368   }
08369   if (theSideIsFreeBorder) {
08370     // Free border 2
08371     // --------------
08372     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
08373                         nSide[1], eSide[1])) {
08374       MESSAGE(" Free Border 2 not found " );
08375       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
08376     }
08377   }
08378   if ( aResult != SEW_OK )
08379     return aResult;
08380 
08381   if (!theSideIsFreeBorder) {
08382     // Side 2
08383     // --------------
08384 
08385     // -------------------------------------------------------------------------
08386     // Algo:
08387     // 1. If nodes to merge are not coincident, move nodes of the free border
08388     //    from the coord sys defined by the direction from the first to last
08389     //    nodes of the border to the correspondent sys of the side 2
08390     // 2. On the side 2, find the links most co-directed with the correspondent
08391     //    links of the free border
08392     // -------------------------------------------------------------------------
08393 
08394     // 1. Since sewing may break if there are volumes to split on the side 2,
08395     //    we wont move nodes but just compute new coordinates for them
08396     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
08397     TNodeXYZMap nBordXYZ;
08398     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
08399     list< const SMDS_MeshNode* >::iterator nBordIt;
08400 
08401     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
08402     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
08403     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
08404     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
08405     double tol2 = 1.e-8;
08406     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
08407     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
08408       // Need node movement.
08409 
08410       // find X and Z axes to create trsf
08411       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
08412       gp_Vec X = Zs ^ Zb;
08413       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
08414         // Zb || Zs
08415         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
08416 
08417       // coord systems
08418       gp_Ax3 toBordAx( Pb1, Zb, X );
08419       gp_Ax3 fromSideAx( Ps1, Zs, X );
08420       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
08421       // set trsf
08422       gp_Trsf toBordSys, fromSide2Sys;
08423       toBordSys.SetTransformation( toBordAx );
08424       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
08425       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
08426 
08427       // move
08428       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
08429         const SMDS_MeshNode* n = *nBordIt;
08430         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
08431         toBordSys.Transforms( xyz );
08432         fromSide2Sys.Transforms( xyz );
08433         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
08434       }
08435     }
08436     else {
08437       // just insert nodes XYZ in the nBordXYZ map
08438       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
08439         const SMDS_MeshNode* n = *nBordIt;
08440         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
08441       }
08442     }
08443 
08444     // 2. On the side 2, find the links most co-directed with the correspondent
08445     //    links of the free border
08446 
08447     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
08448     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
08449     sideNodes.push_back( theSideFirstNode );
08450 
08451     bool hasVolumes = false;
08452     LinkID_Gen aLinkID_Gen( GetMeshDS() );
08453     set<long> foundSideLinkIDs, checkedLinkIDs;
08454     SMDS_VolumeTool volume;
08455     //const SMDS_MeshNode* faceNodes[ 4 ];
08456 
08457     const SMDS_MeshNode*    sideNode;
08458     const SMDS_MeshElement* sideElem;
08459     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
08460     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
08461     nBordIt = bordNodes.begin();
08462     nBordIt++;
08463     // border node position and border link direction to compare with
08464     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
08465     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
08466     // choose next side node by link direction or by closeness to
08467     // the current border node:
08468     bool searchByDir = ( *nBordIt != theBordLastNode );
08469     do {
08470       // find the next node on the Side 2
08471       sideNode = 0;
08472       double maxDot = -DBL_MAX, minDist = DBL_MAX;
08473       long linkID;
08474       checkedLinkIDs.clear();
08475       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
08476 
08477       // loop on inverse elements of current node (prevSideNode) on the Side 2
08478       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
08479       while ( invElemIt->more() )
08480       {
08481         const SMDS_MeshElement* elem = invElemIt->next();
08482         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
08483         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
08484         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
08485         bool isVolume = volume.Set( elem );
08486         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
08487         if ( isVolume ) // --volume
08488           hasVolumes = true;
08489         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
08490           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
08491           if(elem->IsQuadratic()) {
08492             const SMDS_VtkFace* F =
08493               dynamic_cast<const SMDS_VtkFace*>(elem);
08494             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
08495             // use special nodes iterator
08496             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
08497             while( anIter->more() ) {
08498               nodes[ iNode ] = cast2Node(anIter->next());
08499               if ( nodes[ iNode++ ] == prevSideNode )
08500                 iPrevNode = iNode - 1;
08501             }
08502           }
08503           else {
08504             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
08505             while ( nIt->more() ) {
08506               nodes[ iNode ] = cast2Node( nIt->next() );
08507               if ( nodes[ iNode++ ] == prevSideNode )
08508                 iPrevNode = iNode - 1;
08509             }
08510           }
08511           // there are 2 links to check
08512           nbNodes = 2;
08513         }
08514         else // --edge
08515           continue;
08516         // loop on links, to be precise, on the second node of links
08517         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
08518           const SMDS_MeshNode* n = nodes[ iNode ];
08519           if ( isVolume ) {
08520             if ( !volume.IsLinked( n, prevSideNode ))
08521               continue;
08522           }
08523           else {
08524             if ( iNode ) // a node before prevSideNode
08525               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
08526             else         // a node after prevSideNode
08527               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
08528           }
08529           // check if this link was already used
08530           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
08531           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
08532           if (!isJustChecked &&
08533               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
08534           {
08535             // test a link geometrically
08536             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
08537             bool linkIsBetter = false;
08538             double dot = 0.0, dist = 0.0;
08539             if ( searchByDir ) { // choose most co-directed link
08540               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
08541               linkIsBetter = ( dot > maxDot );
08542             }
08543             else { // choose link with the node closest to bordPos
08544               dist = ( nextXYZ - bordPos ).SquareModulus();
08545               linkIsBetter = ( dist < minDist );
08546             }
08547             if ( linkIsBetter ) {
08548               maxDot = dot;
08549               minDist = dist;
08550               linkID = iLink;
08551               sideNode = n;
08552               sideElem = elem;
08553             }
08554           }
08555         }
08556       } // loop on inverse elements of prevSideNode
08557 
08558       if ( !sideNode ) {
08559         MESSAGE(" Cant find path by links of the Side 2 ");
08560         return SEW_BAD_SIDE_NODES;
08561       }
08562       sideNodes.push_back( sideNode );
08563       sideElems.push_back( sideElem );
08564       foundSideLinkIDs.insert ( linkID );
08565       prevSideNode = sideNode;
08566 
08567       if ( *nBordIt == theBordLastNode )
08568         searchByDir = false;
08569       else {
08570         // find the next border link to compare with
08571         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
08572         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
08573         // move to next border node if sideNode is before forward border node (bordPos)
08574         while ( *nBordIt != theBordLastNode && !searchByDir ) {
08575           prevBordNode = *nBordIt;
08576           nBordIt++;
08577           bordPos = nBordXYZ[ *nBordIt ];
08578           bordDir = bordPos - nBordXYZ[ prevBordNode ];
08579           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
08580         }
08581       }
08582     }
08583     while ( sideNode != theSideSecondNode );
08584 
08585     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
08586       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
08587       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
08588     }
08589   } // end nodes search on the side 2
08590 
08591   // ============================
08592   // sew the border to the side 2
08593   // ============================
08594 
08595   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
08596   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
08597 
08598   TListOfListOfNodes nodeGroupsToMerge;
08599   if ( nbNodes[0] == nbNodes[1] ||
08600        ( theSideIsFreeBorder && !theSideThirdNode)) {
08601 
08602     // all nodes are to be merged
08603 
08604     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
08605          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
08606          nIt[0]++, nIt[1]++ )
08607     {
08608       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
08609       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
08610       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
08611     }
08612   }
08613   else {
08614 
08615     // insert new nodes into the border and the side to get equal nb of segments
08616 
08617     // get normalized parameters of nodes on the borders
08618     //double param[ 2 ][ maxNbNodes ];
08619     double* param[ 2 ];
08620     param[0] = new double [ maxNbNodes ];
08621     param[1] = new double [ maxNbNodes ];
08622     int iNode, iBord;
08623     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
08624       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
08625       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
08626       const SMDS_MeshNode* nPrev = *nIt;
08627       double bordLength = 0;
08628       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
08629         const SMDS_MeshNode* nCur = *nIt;
08630         gp_XYZ segment (nCur->X() - nPrev->X(),
08631                         nCur->Y() - nPrev->Y(),
08632                         nCur->Z() - nPrev->Z());
08633         double segmentLen = segment.Modulus();
08634         bordLength += segmentLen;
08635         param[ iBord ][ iNode ] = bordLength;
08636         nPrev = nCur;
08637       }
08638       // normalize within [0,1]
08639       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
08640         param[ iBord ][ iNode ] /= bordLength;
08641       }
08642     }
08643 
08644     // loop on border segments
08645     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
08646     int i[ 2 ] = { 0, 0 };
08647     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
08648     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
08649 
08650     TElemOfNodeListMap insertMap;
08651     TElemOfNodeListMap::iterator insertMapIt;
08652     // insertMap is
08653     // key:   elem to insert nodes into
08654     // value: 2 nodes to insert between + nodes to be inserted
08655     do {
08656       bool next[ 2 ] = { false, false };
08657 
08658       // find min adjacent segment length after sewing
08659       double nextParam = 10., prevParam = 0;
08660       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
08661         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
08662           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
08663         if ( i[ iBord ] > 0 )
08664           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
08665       }
08666       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
08667       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
08668       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
08669 
08670       // choose to insert or to merge nodes
08671       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
08672       if ( Abs( du ) <= minSegLen * 0.2 ) {
08673         // merge
08674         // ------
08675         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
08676         const SMDS_MeshNode* n0 = *nIt[0];
08677         const SMDS_MeshNode* n1 = *nIt[1];
08678         nodeGroupsToMerge.back().push_back( n1 );
08679         nodeGroupsToMerge.back().push_back( n0 );
08680         // position of node of the border changes due to merge
08681         param[ 0 ][ i[0] ] += du;
08682         // move n1 for the sake of elem shape evaluation during insertion.
08683         // n1 will be removed by MergeNodes() anyway
08684         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
08685         next[0] = next[1] = true;
08686       }
08687       else {
08688         // insert
08689         // ------
08690         int intoBord = ( du < 0 ) ? 0 : 1;
08691         const SMDS_MeshElement* elem = *eIt[ intoBord ];
08692         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
08693         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
08694         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
08695         if ( intoBord == 1 ) {
08696           // move node of the border to be on a link of elem of the side
08697           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
08698           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
08699           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
08700           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
08701           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
08702         }
08703         insertMapIt = insertMap.find( elem );
08704         bool notFound = ( insertMapIt == insertMap.end() );
08705         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
08706         if ( otherLink ) {
08707           // insert into another link of the same element:
08708           // 1. perform insertion into the other link of the elem
08709           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
08710           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
08711           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
08712           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
08713           // 2. perform insertion into the link of adjacent faces
08714           while (true) {
08715             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
08716             if ( adjElem )
08717               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
08718             else
08719               break;
08720           }
08721           if (toCreatePolyedrs) {
08722             // perform insertion into the links of adjacent volumes
08723             UpdateVolumes(n12, n22, nodeList);
08724           }
08725           // 3. find an element appeared on n1 and n2 after the insertion
08726           insertMap.erase( elem );
08727           elem = findAdjacentFace( n1, n2, 0 );
08728         }
08729         if ( notFound || otherLink ) {
08730           // add element and nodes of the side into the insertMap
08731           insertMapIt = insertMap.insert
08732             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
08733           (*insertMapIt).second.push_back( n1 );
08734           (*insertMapIt).second.push_back( n2 );
08735         }
08736         // add node to be inserted into elem
08737         (*insertMapIt).second.push_back( nIns );
08738         next[ 1 - intoBord ] = true;
08739       }
08740 
08741       // go to the next segment
08742       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
08743         if ( next[ iBord ] ) {
08744           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
08745             eIt[ iBord ]++;
08746           nPrev[ iBord ] = *nIt[ iBord ];
08747           nIt[ iBord ]++; i[ iBord ]++;
08748         }
08749       }
08750     }
08751     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
08752 
08753     // perform insertion of nodes into elements
08754 
08755     for (insertMapIt = insertMap.begin();
08756          insertMapIt != insertMap.end();
08757          insertMapIt++ )
08758     {
08759       const SMDS_MeshElement* elem = (*insertMapIt).first;
08760       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
08761       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
08762       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
08763 
08764       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
08765 
08766       if ( !theSideIsFreeBorder ) {
08767         // look for and insert nodes into the faces adjacent to elem
08768         while (true) {
08769           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
08770           if ( adjElem )
08771             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
08772           else
08773             break;
08774         }
08775       }
08776       if (toCreatePolyedrs) {
08777         // perform insertion into the links of adjacent volumes
08778         UpdateVolumes(n1, n2, nodeList);
08779       }
08780     }
08781 
08782     delete param[0];
08783     delete param[1];
08784   } // end: insert new nodes
08785 
08786   MergeNodes ( nodeGroupsToMerge );
08787 
08788   return aResult;
08789 }
08790 
08791 //=======================================================================
08792 //function : InsertNodesIntoLink
08793 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
08794 //           and theBetweenNode2 and split theElement
08795 //=======================================================================
08796 
08797 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
08798                                            const SMDS_MeshNode*        theBetweenNode1,
08799                                            const SMDS_MeshNode*        theBetweenNode2,
08800                                            list<const SMDS_MeshNode*>& theNodesToInsert,
08801                                            const bool                  toCreatePoly)
08802 {
08803   if ( theFace->GetType() != SMDSAbs_Face ) return;
08804 
08805   // find indices of 2 link nodes and of the rest nodes
08806   int iNode = 0, il1, il2, i3, i4;
08807   il1 = il2 = i3 = i4 = -1;
08808   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
08809   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
08810 
08811   if(theFace->IsQuadratic()) {
08812     const SMDS_VtkFace* F =
08813       dynamic_cast<const SMDS_VtkFace*>(theFace);
08814     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
08815     // use special nodes iterator
08816     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
08817     while( anIter->more() ) {
08818       const SMDS_MeshNode* n = cast2Node(anIter->next());
08819       if ( n == theBetweenNode1 )
08820         il1 = iNode;
08821       else if ( n == theBetweenNode2 )
08822         il2 = iNode;
08823       else if ( i3 < 0 )
08824         i3 = iNode;
08825       else
08826         i4 = iNode;
08827       nodes[ iNode++ ] = n;
08828     }
08829   }
08830   else {
08831     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
08832     while ( nodeIt->more() ) {
08833       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
08834       if ( n == theBetweenNode1 )
08835         il1 = iNode;
08836       else if ( n == theBetweenNode2 )
08837         il2 = iNode;
08838       else if ( i3 < 0 )
08839         i3 = iNode;
08840       else
08841         i4 = iNode;
08842       nodes[ iNode++ ] = n;
08843     }
08844   }
08845   if ( il1 < 0 || il2 < 0 || i3 < 0 )
08846     return ;
08847 
08848   // arrange link nodes to go one after another regarding the face orientation
08849   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
08850   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
08851   if ( reverse ) {
08852     iNode = il1;
08853     il1 = il2;
08854     il2 = iNode;
08855     aNodesToInsert.reverse();
08856   }
08857   // check that not link nodes of a quadrangles are in good order
08858   int nbFaceNodes = theFace->NbNodes();
08859   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
08860     iNode = i3;
08861     i3 = i4;
08862     i4 = iNode;
08863   }
08864 
08865   if (toCreatePoly || theFace->IsPoly()) {
08866 
08867     iNode = 0;
08868     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
08869 
08870     // add nodes of face up to first node of link
08871     bool isFLN = false;
08872 
08873     if(theFace->IsQuadratic()) {
08874       const SMDS_VtkFace* F =
08875         dynamic_cast<const SMDS_VtkFace*>(theFace);
08876       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
08877       // use special nodes iterator
08878       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
08879       while( anIter->more()  && !isFLN ) {
08880         const SMDS_MeshNode* n = cast2Node(anIter->next());
08881         poly_nodes[iNode++] = n;
08882         if (n == nodes[il1]) {
08883           isFLN = true;
08884         }
08885       }
08886       // add nodes to insert
08887       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
08888       for (; nIt != aNodesToInsert.end(); nIt++) {
08889         poly_nodes[iNode++] = *nIt;
08890       }
08891       // add nodes of face starting from last node of link
08892       while ( anIter->more() ) {
08893         poly_nodes[iNode++] = cast2Node(anIter->next());
08894       }
08895     }
08896     else {
08897       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
08898       while ( nodeIt->more() && !isFLN ) {
08899         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
08900         poly_nodes[iNode++] = n;
08901         if (n == nodes[il1]) {
08902           isFLN = true;
08903         }
08904       }
08905       // add nodes to insert
08906       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
08907       for (; nIt != aNodesToInsert.end(); nIt++) {
08908         poly_nodes[iNode++] = *nIt;
08909       }
08910       // add nodes of face starting from last node of link
08911       while ( nodeIt->more() ) {
08912         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
08913         poly_nodes[iNode++] = n;
08914       }
08915     }
08916 
08917     // edit or replace the face
08918     SMESHDS_Mesh *aMesh = GetMeshDS();
08919 
08920     if (theFace->IsPoly()) {
08921       aMesh->ChangePolygonNodes(theFace, poly_nodes);
08922     }
08923     else {
08924       int aShapeId = FindShape( theFace );
08925 
08926       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
08927       myLastCreatedElems.Append(newElem);
08928       if ( aShapeId && newElem )
08929         aMesh->SetMeshElementOnShape( newElem, aShapeId );
08930 
08931       aMesh->RemoveElement(theFace);
08932     }
08933     return;
08934   }
08935 
08936   SMESHDS_Mesh *aMesh = GetMeshDS();
08937   if( !theFace->IsQuadratic() ) {
08938 
08939     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
08940     int nbLinkNodes = 2 + aNodesToInsert.size();
08941     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
08942     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
08943     linkNodes[ 0 ] = nodes[ il1 ];
08944     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
08945     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
08946     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
08947       linkNodes[ iNode++ ] = *nIt;
08948     }
08949     // decide how to split a quadrangle: compare possible variants
08950     // and choose which of splits to be a quadrangle
08951     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
08952     if ( nbFaceNodes == 3 ) {
08953       iBestQuad = nbSplits;
08954       i4 = i3;
08955     }
08956     else if ( nbFaceNodes == 4 ) {
08957       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
08958       double aBestRate = DBL_MAX;
08959       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
08960         i1 = 0; i2 = 1;
08961         double aBadRate = 0;
08962         // evaluate elements quality
08963         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
08964           if ( iSplit == iQuad ) {
08965             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
08966                                    linkNodes[ i2++ ],
08967                                    nodes[ i3 ],
08968                                    nodes[ i4 ]);
08969             aBadRate += getBadRate( &quad, aCrit );
08970           }
08971           else {
08972             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
08973                                    linkNodes[ i2++ ],
08974                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
08975             aBadRate += getBadRate( &tria, aCrit );
08976           }
08977         }
08978         // choice
08979         if ( aBadRate < aBestRate ) {
08980           iBestQuad = iQuad;
08981           aBestRate = aBadRate;
08982         }
08983       }
08984     }
08985 
08986     // create new elements
08987     int aShapeId = FindShape( theFace );
08988 
08989     i1 = 0; i2 = 1;
08990     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
08991       SMDS_MeshElement* newElem = 0;
08992       if ( iSplit == iBestQuad )
08993         newElem = aMesh->AddFace (linkNodes[ i1++ ],
08994                                   linkNodes[ i2++ ],
08995                                   nodes[ i3 ],
08996                                   nodes[ i4 ]);
08997       else
08998         newElem = aMesh->AddFace (linkNodes[ i1++ ],
08999                                   linkNodes[ i2++ ],
09000                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
09001       myLastCreatedElems.Append(newElem);
09002       if ( aShapeId && newElem )
09003         aMesh->SetMeshElementOnShape( newElem, aShapeId );
09004     }
09005 
09006     // change nodes of theFace
09007     const SMDS_MeshNode* newNodes[ 4 ];
09008     newNodes[ 0 ] = linkNodes[ i1 ];
09009     newNodes[ 1 ] = linkNodes[ i2 ];
09010     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
09011     newNodes[ 3 ] = nodes[ i4 ];
09012     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
09013     const SMDS_MeshElement* newElem = 0;
09014     if (iSplit == iBestQuad)
09015       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
09016     else
09017       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
09018     myLastCreatedElems.Append(newElem);
09019     if ( aShapeId && newElem )
09020       aMesh->SetMeshElementOnShape( newElem, aShapeId );
09021 } // end if(!theFace->IsQuadratic())
09022   else { // theFace is quadratic
09023     // we have to split theFace on simple triangles and one simple quadrangle
09024     int tmp = il1/2;
09025     int nbshift = tmp*2;
09026     // shift nodes in nodes[] by nbshift
09027     int i,j;
09028     for(i=0; i<nbshift; i++) {
09029       const SMDS_MeshNode* n = nodes[0];
09030       for(j=0; j<nbFaceNodes-1; j++) {
09031         nodes[j] = nodes[j+1];
09032       }
09033       nodes[nbFaceNodes-1] = n;
09034     }
09035     il1 = il1 - nbshift;
09036     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
09037     //   n0      n1     n2    n0      n1     n2
09038     //     +-----+-----+        +-----+-----+
09039     //      \         /         |           |
09040     //       \       /          |           |
09041     //      n5+     +n3       n7+           +n3
09042     //         \   /            |           |
09043     //          \ /             |           |
09044     //           +              +-----+-----+
09045     //           n4           n6      n5     n4
09046 
09047     // create new elements
09048     int aShapeId = FindShape( theFace );
09049 
09050     int n1,n2,n3;
09051     if(nbFaceNodes==6) { // quadratic triangle
09052       SMDS_MeshElement* newElem =
09053         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
09054       myLastCreatedElems.Append(newElem);
09055       if ( aShapeId && newElem )
09056         aMesh->SetMeshElementOnShape( newElem, aShapeId );
09057       if(theFace->IsMediumNode(nodes[il1])) {
09058         // create quadrangle
09059         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
09060         myLastCreatedElems.Append(newElem);
09061         if ( aShapeId && newElem )
09062           aMesh->SetMeshElementOnShape( newElem, aShapeId );
09063         n1 = 1;
09064         n2 = 2;
09065         n3 = 3;
09066       }
09067       else {
09068         // create quadrangle
09069         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
09070         myLastCreatedElems.Append(newElem);
09071         if ( aShapeId && newElem )
09072           aMesh->SetMeshElementOnShape( newElem, aShapeId );
09073         n1 = 0;
09074         n2 = 1;
09075         n3 = 5;
09076       }
09077     }
09078     else { // nbFaceNodes==8 - quadratic quadrangle
09079       SMDS_MeshElement* newElem =
09080         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
09081       myLastCreatedElems.Append(newElem);
09082       if ( aShapeId && newElem )
09083         aMesh->SetMeshElementOnShape( newElem, aShapeId );
09084       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
09085       myLastCreatedElems.Append(newElem);
09086       if ( aShapeId && newElem )
09087         aMesh->SetMeshElementOnShape( newElem, aShapeId );
09088       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
09089       myLastCreatedElems.Append(newElem);
09090       if ( aShapeId && newElem )
09091         aMesh->SetMeshElementOnShape( newElem, aShapeId );
09092       if(theFace->IsMediumNode(nodes[il1])) {
09093         // create quadrangle
09094         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
09095         myLastCreatedElems.Append(newElem);
09096         if ( aShapeId && newElem )
09097           aMesh->SetMeshElementOnShape( newElem, aShapeId );
09098         n1 = 1;
09099         n2 = 2;
09100         n3 = 3;
09101       }
09102       else {
09103         // create quadrangle
09104         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
09105         myLastCreatedElems.Append(newElem);
09106         if ( aShapeId && newElem )
09107           aMesh->SetMeshElementOnShape( newElem, aShapeId );
09108         n1 = 0;
09109         n2 = 1;
09110         n3 = 7;
09111       }
09112     }
09113     // create needed triangles using n1,n2,n3 and inserted nodes
09114     int nbn = 2 + aNodesToInsert.size();
09115     //const SMDS_MeshNode* aNodes[nbn];
09116     vector<const SMDS_MeshNode*> aNodes(nbn);
09117     aNodes[0] = nodes[n1];
09118     aNodes[nbn-1] = nodes[n2];
09119     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
09120     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
09121       aNodes[iNode++] = *nIt;
09122     }
09123     for(i=1; i<nbn; i++) {
09124       SMDS_MeshElement* newElem =
09125         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
09126       myLastCreatedElems.Append(newElem);
09127       if ( aShapeId && newElem )
09128         aMesh->SetMeshElementOnShape( newElem, aShapeId );
09129     }
09130   }
09131   // remove old face
09132   aMesh->RemoveElement(theFace);
09133 }
09134 
09135 //=======================================================================
09136 //function : UpdateVolumes
09137 //purpose  :
09138 //=======================================================================
09139 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
09140                                       const SMDS_MeshNode*        theBetweenNode2,
09141                                       list<const SMDS_MeshNode*>& theNodesToInsert)
09142 {
09143   myLastCreatedElems.Clear();
09144   myLastCreatedNodes.Clear();
09145 
09146   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
09147   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
09148     const SMDS_MeshElement* elem = invElemIt->next();
09149 
09150     // check, if current volume has link theBetweenNode1 - theBetweenNode2
09151     SMDS_VolumeTool aVolume (elem);
09152     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
09153       continue;
09154 
09155     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
09156     int iface, nbFaces = aVolume.NbFaces();
09157     vector<const SMDS_MeshNode *> poly_nodes;
09158     vector<int> quantities (nbFaces);
09159 
09160     for (iface = 0; iface < nbFaces; iface++) {
09161       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
09162       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
09163       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
09164 
09165       for (int inode = 0; inode < nbFaceNodes; inode++) {
09166         poly_nodes.push_back(faceNodes[inode]);
09167 
09168         if (nbInserted == 0) {
09169           if (faceNodes[inode] == theBetweenNode1) {
09170             if (faceNodes[inode + 1] == theBetweenNode2) {
09171               nbInserted = theNodesToInsert.size();
09172 
09173               // add nodes to insert
09174               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
09175               for (; nIt != theNodesToInsert.end(); nIt++) {
09176                 poly_nodes.push_back(*nIt);
09177               }
09178             }
09179           }
09180           else if (faceNodes[inode] == theBetweenNode2) {
09181             if (faceNodes[inode + 1] == theBetweenNode1) {
09182               nbInserted = theNodesToInsert.size();
09183 
09184               // add nodes to insert in reversed order
09185               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
09186               nIt--;
09187               for (; nIt != theNodesToInsert.begin(); nIt--) {
09188                 poly_nodes.push_back(*nIt);
09189               }
09190               poly_nodes.push_back(*nIt);
09191             }
09192           }
09193           else {
09194           }
09195         }
09196       }
09197       quantities[iface] = nbFaceNodes + nbInserted;
09198     }
09199 
09200     // Replace or update the volume
09201     SMESHDS_Mesh *aMesh = GetMeshDS();
09202 
09203     if (elem->IsPoly()) {
09204       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
09205 
09206     }
09207     else {
09208       int aShapeId = FindShape( elem );
09209 
09210       SMDS_MeshElement* newElem =
09211         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
09212       myLastCreatedElems.Append(newElem);
09213       if (aShapeId && newElem)
09214         aMesh->SetMeshElementOnShape(newElem, aShapeId);
09215 
09216       aMesh->RemoveElement(elem);
09217     }
09218   }
09219 }
09220 
09221 //=======================================================================
09226 //=======================================================================
09227 
09228 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
09229                                              SMESH_MesherHelper& theHelper,
09230                                              const bool          theForce3d)
09231 {
09232   int nbElem = 0;
09233   if( !theSm ) return nbElem;
09234 
09235   vector<int> nbNodeInFaces;
09236   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
09237   while(ElemItr->more())
09238   {
09239     nbElem++;
09240     const SMDS_MeshElement* elem = ElemItr->next();
09241     if( !elem || elem->IsQuadratic() ) continue;
09242 
09243     int id = elem->GetID();
09244     int nbNodes = elem->NbNodes();
09245     SMDSAbs_ElementType aType = elem->GetType();
09246 
09247     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
09248     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
09249       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
09250 
09251     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
09252 
09253     const SMDS_MeshElement* NewElem = 0;
09254 
09255     switch( aType )
09256     {
09257     case SMDSAbs_Edge :
09258       {
09259         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
09260         break;
09261       }
09262     case SMDSAbs_Face :
09263       {
09264         switch(nbNodes)
09265         {
09266         case 3:
09267           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
09268           break;
09269         case 4:
09270           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09271           break;
09272         default:
09273           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
09274           continue;
09275         }
09276         break;
09277       }
09278     case SMDSAbs_Volume :
09279       {
09280         switch(nbNodes)
09281         {
09282         case 4:
09283           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09284           break;
09285         case 5:
09286           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
09287           break;
09288         case 6:
09289           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
09290           break;
09291         case 8:
09292           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09293                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
09294           break;
09295         default:
09296           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
09297         }
09298         break;
09299       }
09300     default :
09301       continue;
09302     }
09303     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
09304     if( NewElem )
09305       theSm->AddElement( NewElem );
09306   }
09307 //  if (!GetMeshDS()->isCompacted())
09308 //    GetMeshDS()->compactMesh();
09309   return nbElem;
09310 }
09311 
09312 //=======================================================================
09313 //function : ConvertToQuadratic
09314 //purpose  :
09315 //=======================================================================
09316 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
09317 {
09318   SMESHDS_Mesh* meshDS = GetMeshDS();
09319 
09320   SMESH_MesherHelper aHelper(*myMesh);
09321   aHelper.SetIsQuadratic( true );
09322 
09323   int nbCheckedElems = 0;
09324   if ( myMesh->HasShapeToMesh() )
09325   {
09326     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
09327     {
09328       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
09329       while ( smIt->more() ) {
09330         SMESH_subMesh* sm = smIt->next();
09331         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
09332           aHelper.SetSubShape( sm->GetSubShape() );
09333           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
09334         }
09335       }
09336     }
09337   }
09338   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
09339   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
09340   {
09341     SMESHDS_SubMesh *smDS = 0;
09342     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
09343     while(aEdgeItr->more())
09344     {
09345       const SMDS_MeshEdge* edge = aEdgeItr->next();
09346       if(edge && !edge->IsQuadratic())
09347       {
09348         int id = edge->GetID();
09349         //MESSAGE("edge->GetID() " << id);
09350         const SMDS_MeshNode* n1 = edge->GetNode(0);
09351         const SMDS_MeshNode* n2 = edge->GetNode(1);
09352 
09353         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
09354 
09355         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
09356         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
09357       }
09358     }
09359     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
09360     while(aFaceItr->more())
09361     {
09362       const SMDS_MeshFace* face = aFaceItr->next();
09363       if(!face || face->IsQuadratic() ) continue;
09364 
09365       int id = face->GetID();
09366       int nbNodes = face->NbNodes();
09367       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
09368 
09369       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
09370 
09371       SMDS_MeshFace * NewFace = 0;
09372       switch(nbNodes)
09373       {
09374       case 3:
09375         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
09376         break;
09377       case 4:
09378         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09379         break;
09380       default:
09381         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
09382       }
09383       ReplaceElemInGroups( face, NewFace, GetMeshDS());
09384     }
09385     vector<int> nbNodeInFaces;
09386     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
09387     while(aVolumeItr->more())
09388     {
09389       const SMDS_MeshVolume* volume = aVolumeItr->next();
09390       if(!volume || volume->IsQuadratic() ) continue;
09391 
09392       int id = volume->GetID();
09393       int nbNodes = volume->NbNodes();
09394       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
09395       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
09396         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
09397 
09398       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
09399 
09400       SMDS_MeshVolume * NewVolume = 0;
09401       switch(nbNodes)
09402       {
09403       case 4:
09404         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
09405                                       nodes[3], id, theForce3d );
09406         break;
09407       case 5:
09408         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
09409                                       nodes[3], nodes[4], id, theForce3d);
09410         break;
09411       case 6:
09412         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
09413                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
09414         break;
09415       case 8:
09416         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09417                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
09418         break;
09419       default:
09420         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
09421       }
09422       ReplaceElemInGroups(volume, NewVolume, meshDS);
09423     }
09424   }
09425 
09426   if ( !theForce3d )
09427   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
09428     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
09429     aHelper.FixQuadraticElements();
09430   }
09431 }
09432 
09433 //================================================================================
09439 //================================================================================
09440 
09441 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
09442                                           TIDSortedElemSet& theElements)
09443 {
09444   if ( theElements.empty() ) return;
09445 
09446   // we believe that all theElements are of the same type
09447   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
09448   
09449   // get all nodes shared by theElements
09450   TIDSortedNodeSet allNodes;
09451   TIDSortedElemSet::iterator eIt = theElements.begin();
09452   for ( ; eIt != theElements.end(); ++eIt )
09453     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
09454 
09455   // complete theElements with elements of lower dim whose all nodes are in allNodes
09456 
09457   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
09458   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
09459   TIDSortedNodeSet::iterator nIt = allNodes.begin();
09460   for ( ; nIt != allNodes.end(); ++nIt )
09461   {
09462     const SMDS_MeshNode* n = *nIt;
09463     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
09464     while ( invIt->more() )
09465     {
09466       const SMDS_MeshElement* e = invIt->next();
09467       if ( e->IsQuadratic() )
09468       {
09469         quadAdjacentElems[ e->GetType() ].insert( e );
09470         continue;
09471       }
09472       if ( e->GetType() >= elemType )
09473       {
09474         continue; // same type of more complex linear element
09475       }
09476 
09477       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
09478         continue; // e is already checked
09479 
09480       // check nodes
09481       bool allIn = true;
09482       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
09483       while ( nodeIt->more() && allIn )
09484         allIn = allNodes.count( cast2Node( nodeIt->next() ));
09485       if ( allIn )
09486         theElements.insert(e );
09487     }
09488   }
09489 
09490   SMESH_MesherHelper helper(*myMesh);
09491   helper.SetIsQuadratic( true );
09492 
09493   // add links of quadratic adjacent elements to the helper
09494 
09495   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
09496     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
09497           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
09498     {
09499       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
09500     }
09501   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
09502     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
09503           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
09504     {
09505       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
09506     }
09507   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
09508     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
09509           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
09510     {
09511       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
09512     }
09513 
09514   // make quadratic elements instead of linear ones
09515 
09516   SMESHDS_Mesh* meshDS = GetMeshDS();
09517   SMESHDS_SubMesh* smDS = 0;
09518   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
09519   {
09520     const SMDS_MeshElement* elem = *eIt;
09521     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
09522       continue;
09523 
09524     int id = elem->GetID();
09525     SMDSAbs_ElementType type = elem->GetType();
09526     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
09527 
09528     if ( !smDS || !smDS->Contains( elem ))
09529       smDS = meshDS->MeshElements( elem->getshapeId() );
09530     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
09531 
09532     SMDS_MeshElement * newElem = 0;
09533     switch( nodes.size() )
09534     {
09535     case 4: // cases for most multiple element types go first (for optimization)
09536       if ( type == SMDSAbs_Volume )
09537         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09538       else
09539         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09540       break;
09541     case 8:
09542       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09543                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
09544       break;
09545     case 3:
09546       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
09547       break;
09548     case 2:
09549       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
09550       break;
09551     case 5:
09552       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09553                                  nodes[4], id, theForce3d);
09554       break;
09555     case 6:
09556       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09557                                  nodes[4], nodes[5], id, theForce3d);
09558       break;
09559     default:;
09560     }
09561     ReplaceElemInGroups( elem, newElem, meshDS);
09562     if( newElem && smDS )
09563       smDS->AddElement( newElem );
09564   }
09565 
09566   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
09567   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
09568     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
09569     helper.FixQuadraticElements();
09570   }
09571 }
09572 
09573 //=======================================================================
09578 //=======================================================================
09579 
09580 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
09581                                      SMDS_ElemIteratorPtr theItr,
09582                                      const int            theShapeID)
09583 {
09584   int nbElem = 0;
09585   SMESHDS_Mesh* meshDS = GetMeshDS();
09586 
09587   while( theItr->more() )
09588   {
09589     const SMDS_MeshElement* elem = theItr->next();
09590     nbElem++;
09591     if( elem && elem->IsQuadratic())
09592     {
09593       int id                    = elem->GetID();
09594       int nbCornerNodes         = elem->NbCornerNodes();
09595       SMDSAbs_ElementType aType = elem->GetType();
09596 
09597       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
09598 
09599       //remove a quadratic element
09600       if ( !theSm || !theSm->Contains( elem ))
09601         theSm = meshDS->MeshElements( elem->getshapeId() );
09602       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
09603 
09604       // remove medium nodes
09605       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
09606         if ( nodes[i]->NbInverseElements() == 0 )
09607           meshDS->RemoveFreeNode( nodes[i], theSm );
09608 
09609       // add a linear element
09610       nodes.resize( nbCornerNodes );
09611       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
09612       ReplaceElemInGroups(elem, newElem, meshDS);
09613       if( theSm && newElem )
09614         theSm->AddElement( newElem );
09615     }
09616   }
09617   return nbElem;
09618 }
09619 
09620 //=======================================================================
09621 //function : ConvertFromQuadratic
09622 //purpose  :
09623 //=======================================================================
09624 
09625 bool SMESH_MeshEditor::ConvertFromQuadratic()
09626 {
09627   int nbCheckedElems = 0;
09628   if ( myMesh->HasShapeToMesh() )
09629   {
09630     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
09631     {
09632       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
09633       while ( smIt->more() ) {
09634         SMESH_subMesh* sm = smIt->next();
09635         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
09636           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
09637       }
09638     }
09639   }
09640 
09641   int totalNbElems =
09642     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
09643   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
09644   {
09645     SMESHDS_SubMesh *aSM = 0;
09646     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
09647   }
09648 
09649   return true;
09650 }
09651 
09652 namespace
09653 {
09654   //================================================================================
09658   //================================================================================
09659 
09660   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
09661   {
09662     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
09663       if ( !nodeSet.count( elem->GetNode(i) ))
09664         return false;
09665     return true;
09666   }
09667 }
09668 
09669 //================================================================================
09673 //================================================================================
09674 
09675 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
09676 {
09677   if ( theElements.empty() ) return;
09678 
09679   // collect IDs of medium nodes of theElements; some of these nodes will be removed
09680   set<int> mediumNodeIDs;
09681   TIDSortedElemSet::iterator eIt = theElements.begin();
09682   for ( ; eIt != theElements.end(); ++eIt )
09683   {
09684     const SMDS_MeshElement* e = *eIt;
09685     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
09686       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
09687   }
09688 
09689   // replace given elements by linear ones
09690   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
09691   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
09692   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
09693 
09694   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
09695   // except those elements sharing medium nodes of quadratic element whose medium nodes
09696   // are not all in mediumNodeIDs
09697 
09698   // get remaining medium nodes
09699   TIDSortedNodeSet mediumNodes;
09700   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
09701   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
09702     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
09703       mediumNodes.insert( mediumNodes.end(), n );
09704 
09705   // find more quadratic elements to convert
09706   TIDSortedElemSet moreElemsToConvert;
09707   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
09708   for ( ; nIt != mediumNodes.end(); ++nIt )
09709   {
09710     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
09711     while ( invIt->more() )
09712     {
09713       const SMDS_MeshElement* e = invIt->next();
09714       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
09715       {
09716         // find a more complex element including e and
09717         // whose medium nodes are not in mediumNodes
09718         bool complexFound = false;
09719         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
09720         {
09721           SMDS_ElemIteratorPtr invIt2 =
09722             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
09723           while ( invIt2->more() )
09724           {
09725             const SMDS_MeshElement* eComplex = invIt2->next();
09726             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
09727             {
09728               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
09729               if ( nbCommonNodes == e->NbNodes())
09730               {
09731                 complexFound = true;
09732                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
09733                 break;
09734               }
09735             }
09736           }
09737         }
09738         if ( !complexFound )
09739           moreElemsToConvert.insert( e );
09740       }
09741     }
09742   }
09743   elemIt = SMDS_ElemIteratorPtr
09744     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
09745   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
09746 }
09747 
09748 //=======================================================================
09749 //function : SewSideElements
09750 //purpose  :
09751 //=======================================================================
09752 
09753 SMESH_MeshEditor::Sew_Error
09754 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
09755                                    TIDSortedElemSet&    theSide2,
09756                                    const SMDS_MeshNode* theFirstNode1,
09757                                    const SMDS_MeshNode* theFirstNode2,
09758                                    const SMDS_MeshNode* theSecondNode1,
09759                                    const SMDS_MeshNode* theSecondNode2)
09760 {
09761   myLastCreatedElems.Clear();
09762   myLastCreatedNodes.Clear();
09763 
09764   MESSAGE ("::::SewSideElements()");
09765   if ( theSide1.size() != theSide2.size() )
09766     return SEW_DIFF_NB_OF_ELEMENTS;
09767 
09768   Sew_Error aResult = SEW_OK;
09769   // Algo:
09770   // 1. Build set of faces representing each side
09771   // 2. Find which nodes of the side 1 to merge with ones on the side 2
09772   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
09773 
09774   // =======================================================================
09775   // 1. Build set of faces representing each side:
09776   // =======================================================================
09777   // a. build set of nodes belonging to faces
09778   // b. complete set of faces: find missing faces whose nodes are in set of nodes
09779   // c. create temporary faces representing side of volumes if correspondent
09780   //    face does not exist
09781 
09782   SMESHDS_Mesh* aMesh = GetMeshDS();
09783   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
09784   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
09785   set<const SMDS_MeshElement*> faceSet1, faceSet2;
09786   set<const SMDS_MeshElement*> volSet1,  volSet2;
09787   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
09788   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
09789   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
09790   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
09791   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
09792   int iSide, iFace, iNode;
09793 
09794   list<const SMDS_MeshElement* > tempFaceList;
09795   for ( iSide = 0; iSide < 2; iSide++ ) {
09796     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
09797     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
09798     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
09799     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
09800     set<const SMDS_MeshElement*>::iterator vIt;
09801     TIDSortedElemSet::iterator eIt;
09802     set<const SMDS_MeshNode*>::iterator    nIt;
09803 
09804     // check that given nodes belong to given elements
09805     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
09806     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
09807     int firstIndex = -1, secondIndex = -1;
09808     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
09809       const SMDS_MeshElement* elem = *eIt;
09810       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
09811       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
09812       if ( firstIndex > -1 && secondIndex > -1 ) break;
09813     }
09814     if ( firstIndex < 0 || secondIndex < 0 ) {
09815       // we can simply return until temporary faces created
09816       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
09817     }
09818 
09819     // -----------------------------------------------------------
09820     // 1a. Collect nodes of existing faces
09821     //     and build set of face nodes in order to detect missing
09822     //     faces corresponding to sides of volumes
09823     // -----------------------------------------------------------
09824 
09825     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
09826 
09827     // loop on the given element of a side
09828     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
09829       //const SMDS_MeshElement* elem = *eIt;
09830       const SMDS_MeshElement* elem = *eIt;
09831       if ( elem->GetType() == SMDSAbs_Face ) {
09832         faceSet->insert( elem );
09833         set <const SMDS_MeshNode*> faceNodeSet;
09834         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
09835         while ( nodeIt->more() ) {
09836           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09837           nodeSet->insert( n );
09838           faceNodeSet.insert( n );
09839         }
09840         setOfFaceNodeSet.insert( faceNodeSet );
09841       }
09842       else if ( elem->GetType() == SMDSAbs_Volume )
09843         volSet->insert( elem );
09844     }
09845     // ------------------------------------------------------------------------------
09846     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
09847     // ------------------------------------------------------------------------------
09848 
09849     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
09850       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
09851       while ( fIt->more() ) { // loop on faces sharing a node
09852         const SMDS_MeshElement* f = fIt->next();
09853         if ( faceSet->find( f ) == faceSet->end() ) {
09854           // check if all nodes are in nodeSet and
09855           // complete setOfFaceNodeSet if they are
09856           set <const SMDS_MeshNode*> faceNodeSet;
09857           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
09858           bool allInSet = true;
09859           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
09860             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09861             if ( nodeSet->find( n ) == nodeSet->end() )
09862               allInSet = false;
09863             else
09864               faceNodeSet.insert( n );
09865           }
09866           if ( allInSet ) {
09867             faceSet->insert( f );
09868             setOfFaceNodeSet.insert( faceNodeSet );
09869           }
09870         }
09871       }
09872     }
09873 
09874     // -------------------------------------------------------------------------
09875     // 1c. Create temporary faces representing sides of volumes if correspondent
09876     //     face does not exist
09877     // -------------------------------------------------------------------------
09878 
09879     if ( !volSet->empty() ) {
09880       //int nodeSetSize = nodeSet->size();
09881 
09882       // loop on given volumes
09883       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
09884         SMDS_VolumeTool vol (*vIt);
09885         // loop on volume faces: find free faces
09886         // --------------------------------------
09887         list<const SMDS_MeshElement* > freeFaceList;
09888         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
09889           if ( !vol.IsFreeFace( iFace ))
09890             continue;
09891           // check if there is already a face with same nodes in a face set
09892           const SMDS_MeshElement* aFreeFace = 0;
09893           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
09894           int nbNodes = vol.NbFaceNodes( iFace );
09895           set <const SMDS_MeshNode*> faceNodeSet;
09896           vol.GetFaceNodes( iFace, faceNodeSet );
09897           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
09898           if ( isNewFace ) {
09899             // no such a face is given but it still can exist, check it
09900             if ( nbNodes == 3 ) {
09901               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
09902             }
09903             else if ( nbNodes == 4 ) {
09904               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
09905             }
09906             else {
09907               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
09908               aFreeFace = aMesh->FindFace(poly_nodes);
09909             }
09910           }
09911           if ( !aFreeFace ) {
09912             // create a temporary face
09913             if ( nbNodes == 3 ) {
09914               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
09915               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
09916             }
09917             else if ( nbNodes == 4 ) {
09918               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
09919               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
09920             }
09921             else {
09922               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
09923               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
09924               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
09925             }
09926           }
09927           if ( aFreeFace ) {
09928             freeFaceList.push_back( aFreeFace );
09929             tempFaceList.push_back( aFreeFace );
09930           }
09931 
09932         } // loop on faces of a volume
09933 
09934         // choose one of several free faces
09935         // --------------------------------------
09936         if ( freeFaceList.size() > 1 ) {
09937           // choose a face having max nb of nodes shared by other elems of a side
09938           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
09939           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
09940           while ( fIt != freeFaceList.end() ) { // loop on free faces
09941             int nbSharedNodes = 0;
09942             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
09943             while ( nodeIt->more() ) { // loop on free face nodes
09944               const SMDS_MeshNode* n =
09945                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09946               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
09947               while ( invElemIt->more() ) {
09948                 const SMDS_MeshElement* e = invElemIt->next();
09949                 if ( faceSet->find( e ) != faceSet->end() )
09950                   nbSharedNodes++;
09951                 if ( elemSet->find( e ) != elemSet->end() )
09952                   nbSharedNodes++;
09953               }
09954             }
09955             if ( nbSharedNodes >= maxNbNodes ) {
09956               maxNbNodes = nbSharedNodes;
09957               fIt++;
09958             }
09959             else
09960               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
09961           }
09962           if ( freeFaceList.size() > 1 )
09963           {
09964             // could not choose one face, use another way
09965             // choose a face most close to the bary center of the opposite side
09966             gp_XYZ aBC( 0., 0., 0. );
09967             set <const SMDS_MeshNode*> addedNodes;
09968             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
09969             eIt = elemSet2->begin();
09970             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
09971               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
09972               while ( nodeIt->more() ) { // loop on free face nodes
09973                 const SMDS_MeshNode* n =
09974                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09975                 if ( addedNodes.insert( n ).second )
09976                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
09977               }
09978             }
09979             aBC /= addedNodes.size();
09980             double minDist = DBL_MAX;
09981             fIt = freeFaceList.begin();
09982             while ( fIt != freeFaceList.end() ) { // loop on free faces
09983               double dist = 0;
09984               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
09985               while ( nodeIt->more() ) { // loop on free face nodes
09986                 const SMDS_MeshNode* n =
09987                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09988                 gp_XYZ p( n->X(),n->Y(),n->Z() );
09989                 dist += ( aBC - p ).SquareModulus();
09990               }
09991               if ( dist < minDist ) {
09992                 minDist = dist;
09993                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
09994               }
09995               else
09996                 fIt = freeFaceList.erase( fIt++ );
09997             }
09998           }
09999         } // choose one of several free faces of a volume
10000 
10001         if ( freeFaceList.size() == 1 ) {
10002           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10003           faceSet->insert( aFreeFace );
10004           // complete a node set with nodes of a found free face
10005           //           for ( iNode = 0; iNode < ; iNode++ )
10006           //             nodeSet->insert( fNodes[ iNode ] );
10007         }
10008 
10009       } // loop on volumes of a side
10010 
10011       //       // complete a set of faces if new nodes in a nodeSet appeared
10012       //       // ----------------------------------------------------------
10013       //       if ( nodeSetSize != nodeSet->size() ) {
10014       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10015       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10016       //           while ( fIt->more() ) { // loop on faces sharing a node
10017       //             const SMDS_MeshElement* f = fIt->next();
10018       //             if ( faceSet->find( f ) == faceSet->end() ) {
10019       //               // check if all nodes are in nodeSet and
10020       //               // complete setOfFaceNodeSet if they are
10021       //               set <const SMDS_MeshNode*> faceNodeSet;
10022       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10023       //               bool allInSet = true;
10024       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10025       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10026       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10027       //                   allInSet = false;
10028       //                 else
10029       //                   faceNodeSet.insert( n );
10030       //               }
10031       //               if ( allInSet ) {
10032       //                 faceSet->insert( f );
10033       //                 setOfFaceNodeSet.insert( faceNodeSet );
10034       //               }
10035       //             }
10036       //           }
10037       //         }
10038       //       }
10039     } // Create temporary faces, if there are volumes given
10040   } // loop on sides
10041 
10042   if ( faceSet1.size() != faceSet2.size() ) {
10043     // delete temporary faces: they are in reverseElements of actual nodes
10044 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10045 //    while ( tmpFaceIt->more() )
10046 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10047 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10048 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10049 //      aMesh->RemoveElement(*tmpFaceIt);
10050     MESSAGE("Diff nb of faces");
10051     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10052   }
10053 
10054   // ============================================================
10055   // 2. Find nodes to merge:
10056   //              bind a node to remove to a node to put instead
10057   // ============================================================
10058 
10059   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10060   if ( theFirstNode1 != theFirstNode2 )
10061     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10062   if ( theSecondNode1 != theSecondNode2 )
10063     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10064 
10065   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10066   set< long > linkIdSet; // links to process
10067   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10068 
10069   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10070   list< NLink > linkList[2];
10071   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10072   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10073   // loop on links in linkList; find faces by links and append links
10074   // of the found faces to linkList
10075   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10076   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10077     NLink link[] = { *linkIt[0], *linkIt[1] };
10078     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10079     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10080       continue;
10081 
10082     // by links, find faces in the face sets,
10083     // and find indices of link nodes in the found faces;
10084     // in a face set, there is only one or no face sharing a link
10085     // ---------------------------------------------------------------
10086 
10087     const SMDS_MeshElement* face[] = { 0, 0 };
10088     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10089     vector<const SMDS_MeshNode*> fnodes1(9);
10090     vector<const SMDS_MeshNode*> fnodes2(9);
10091     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10092     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10093     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10094     int iLinkNode[2][2];
10095     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10096       const SMDS_MeshNode* n1 = link[iSide].first;
10097       const SMDS_MeshNode* n2 = link[iSide].second;
10098       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10099       set< const SMDS_MeshElement* > fMap;
10100       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10101         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10102         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10103         while ( fIt->more() ) { // loop on faces sharing a node
10104           const SMDS_MeshElement* f = fIt->next();
10105           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10106               ! fMap.insert( f ).second ) // f encounters twice
10107           {
10108             if ( face[ iSide ] ) {
10109               MESSAGE( "2 faces per link " );
10110               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10111               break;
10112             }
10113             face[ iSide ] = f;
10114             faceSet->erase( f );
10115             // get face nodes and find ones of a link
10116             iNode = 0;
10117             int nbl = -1;
10118             if(f->IsPoly()) {
10119               if(iSide==0) {
10120                 fnodes1.resize(f->NbNodes()+1);
10121                 notLinkNodes1.resize(f->NbNodes()-2);
10122               }
10123               else {
10124                 fnodes2.resize(f->NbNodes()+1);
10125                 notLinkNodes2.resize(f->NbNodes()-2);
10126               }
10127             }
10128             if(!f->IsQuadratic()) {
10129               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10130               while ( nIt->more() ) {
10131                 const SMDS_MeshNode* n =
10132                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10133                 if ( n == n1 ) {
10134                   iLinkNode[ iSide ][ 0 ] = iNode;
10135                 }
10136                 else if ( n == n2 ) {
10137                   iLinkNode[ iSide ][ 1 ] = iNode;
10138                 }
10139                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10140                 //  notLinkNodes[ iSide ][ 1 ] = n;
10141                 //else
10142                 //  notLinkNodes[ iSide ][ 0 ] = n;
10143                 else {
10144                   nbl++;
10145                   if(iSide==0)
10146                     notLinkNodes1[nbl] = n;
10147                   //notLinkNodes1.push_back(n);
10148                   else
10149                     notLinkNodes2[nbl] = n;
10150                   //notLinkNodes2.push_back(n);
10151                 }
10152                 //faceNodes[ iSide ][ iNode++ ] = n;
10153                 if(iSide==0) {
10154                   fnodes1[iNode++] = n;
10155                 }
10156                 else {
10157                   fnodes2[iNode++] = n;
10158                 }
10159               }
10160             }
10161             else { // f->IsQuadratic()
10162               const SMDS_VtkFace* F =
10163                 dynamic_cast<const SMDS_VtkFace*>(f);
10164               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10165               // use special nodes iterator
10166               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10167               while ( anIter->more() ) {
10168                 const SMDS_MeshNode* n =
10169                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10170                 if ( n == n1 ) {
10171                   iLinkNode[ iSide ][ 0 ] = iNode;
10172                 }
10173                 else if ( n == n2 ) {
10174                   iLinkNode[ iSide ][ 1 ] = iNode;
10175                 }
10176                 else {
10177                   nbl++;
10178                   if(iSide==0) {
10179                     notLinkNodes1[nbl] = n;
10180                   }
10181                   else {
10182                     notLinkNodes2[nbl] = n;
10183                   }
10184                 }
10185                 if(iSide==0) {
10186                   fnodes1[iNode++] = n;
10187                 }
10188                 else {
10189                   fnodes2[iNode++] = n;
10190                 }
10191               }
10192             }
10193             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10194             if(iSide==0) {
10195               fnodes1[iNode] = fnodes1[0];
10196             }
10197             else {
10198               fnodes2[iNode] = fnodes1[0];
10199             }
10200           }
10201         }
10202       }
10203     }
10204 
10205     // check similarity of elements of the sides
10206     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10207       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10208       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10209         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10210       }
10211       else {
10212         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10213       }
10214       break; // do not return because it s necessary to remove tmp faces
10215     }
10216 
10217     // set nodes to merge
10218     // -------------------
10219 
10220     if ( face[0] && face[1] )  {
10221       int nbNodes = face[0]->NbNodes();
10222       if ( nbNodes != face[1]->NbNodes() ) {
10223         MESSAGE("Diff nb of face nodes");
10224         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10225         break; // do not return because it s necessary to remove tmp faces
10226       }
10227       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10228       if ( nbNodes == 3 ) {
10229         //nReplaceMap.insert( TNodeNodeMap::value_type
10230         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10231         nReplaceMap.insert( TNodeNodeMap::value_type
10232                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10233       }
10234       else {
10235         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10236           // analyse link orientation in faces
10237           int i1 = iLinkNode[ iSide ][ 0 ];
10238           int i2 = iLinkNode[ iSide ][ 1 ];
10239           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10240           // if notLinkNodes are the first and the last ones, then
10241           // their order does not correspond to the link orientation
10242           if (( i1 == 1 && i2 == 2 ) ||
10243               ( i1 == 2 && i2 == 1 ))
10244             reverse[ iSide ] = !reverse[ iSide ];
10245         }
10246         if ( reverse[0] == reverse[1] ) {
10247           //nReplaceMap.insert( TNodeNodeMap::value_type
10248           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10249           //nReplaceMap.insert( TNodeNodeMap::value_type
10250           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10251           for(int nn=0; nn<nbNodes-2; nn++) {
10252             nReplaceMap.insert( TNodeNodeMap::value_type
10253                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10254           }
10255         }
10256         else {
10257           //nReplaceMap.insert( TNodeNodeMap::value_type
10258           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10259           //nReplaceMap.insert( TNodeNodeMap::value_type
10260           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10261           for(int nn=0; nn<nbNodes-2; nn++) {
10262             nReplaceMap.insert( TNodeNodeMap::value_type
10263                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10264           }
10265         }
10266       }
10267 
10268       // add other links of the faces to linkList
10269       // -----------------------------------------
10270 
10271       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10272       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10273         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10274         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10275         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10276         if ( !iter_isnew.second ) { // already in a set: no need to process
10277           linkIdSet.erase( iter_isnew.first );
10278         }
10279         else // new in set == encountered for the first time: add
10280         {
10281           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10282           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10283           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10284           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10285           linkList[0].push_back ( NLink( n1, n2 ));
10286           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10287         }
10288       }
10289     } // 2 faces found
10290   } // loop on link lists
10291 
10292   if ( aResult == SEW_OK &&
10293        ( linkIt[0] != linkList[0].end() ||
10294          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10295     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10296              " " << (faceSetPtr[1]->empty()));
10297     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10298   }
10299 
10300   // ====================================================================
10301   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10302   // ====================================================================
10303 
10304   // delete temporary faces: they are in reverseElements of actual nodes
10305 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10306 //  while ( tmpFaceIt->more() )
10307 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10308 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10309 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10310 //    aMesh->RemoveElement(*tmpFaceIt);
10311 
10312   if ( aResult != SEW_OK)
10313     return aResult;
10314 
10315   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10316   // loop on nodes replacement map
10317   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10318   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10319     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10320       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10321       nodeIDsToRemove.push_back( nToRemove->GetID() );
10322       // loop on elements sharing nToRemove
10323       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10324       while ( invElemIt->more() ) {
10325         const SMDS_MeshElement* e = invElemIt->next();
10326         // get a new suite of nodes: make replacement
10327         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10328         vector< const SMDS_MeshNode*> nodes( nbNodes );
10329         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10330         while ( nIt->more() ) {
10331           const SMDS_MeshNode* n =
10332             static_cast<const SMDS_MeshNode*>( nIt->next() );
10333           nnIt = nReplaceMap.find( n );
10334           if ( nnIt != nReplaceMap.end() ) {
10335             nbReplaced++;
10336             n = (*nnIt).second;
10337           }
10338           nodes[ i++ ] = n;
10339         }
10340         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10341         //         elemIDsToRemove.push_back( e->GetID() );
10342         //       else
10343         if ( nbReplaced )
10344           {
10345             SMDSAbs_ElementType etyp = e->GetType();
10346             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10347             if (newElem)
10348               {
10349                 myLastCreatedElems.Append(newElem);
10350                 AddToSameGroups(newElem, e, aMesh);
10351                 int aShapeId = e->getshapeId();
10352                 if ( aShapeId )
10353                   {
10354                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10355                   }
10356               }
10357             aMesh->RemoveElement(e);
10358           }
10359       }
10360     }
10361 
10362   Remove( nodeIDsToRemove, true );
10363 
10364   return aResult;
10365 }
10366 
10367 //================================================================================
10379 //================================================================================
10380 
10381 #ifdef _DEBUG_
10382 //#define DEBUG_MATCHING_NODES
10383 #endif
10384 
10385 SMESH_MeshEditor::Sew_Error
10386 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10387                                     set<const SMDS_MeshElement*>& theSide2,
10388                                     const SMDS_MeshNode*          theFirstNode1,
10389                                     const SMDS_MeshNode*          theFirstNode2,
10390                                     const SMDS_MeshNode*          theSecondNode1,
10391                                     const SMDS_MeshNode*          theSecondNode2,
10392                                     TNodeNodeMap &                nReplaceMap)
10393 {
10394   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10395 
10396   nReplaceMap.clear();
10397   if ( theFirstNode1 != theFirstNode2 )
10398     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10399   if ( theSecondNode1 != theSecondNode2 )
10400     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10401 
10402   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10403   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10404 
10405   list< NLink > linkList[2];
10406   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10407   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10408 
10409   // loop on links in linkList; find faces by links and append links
10410   // of the found faces to linkList
10411   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10412   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10413     NLink link[] = { *linkIt[0], *linkIt[1] };
10414     if ( linkSet.find( link[0] ) == linkSet.end() )
10415       continue;
10416 
10417     // by links, find faces in the face sets,
10418     // and find indices of link nodes in the found faces;
10419     // in a face set, there is only one or no face sharing a link
10420     // ---------------------------------------------------------------
10421 
10422     const SMDS_MeshElement* face[] = { 0, 0 };
10423     list<const SMDS_MeshNode*> notLinkNodes[2];
10424     //bool reverse[] = { false, false }; // order of notLinkNodes
10425     int nbNodes[2];
10426     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10427     {
10428       const SMDS_MeshNode* n1 = link[iSide].first;
10429       const SMDS_MeshNode* n2 = link[iSide].second;
10430       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10431       set< const SMDS_MeshElement* > facesOfNode1;
10432       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10433       {
10434         // during a loop of the first node, we find all faces around n1,
10435         // during a loop of the second node, we find one face sharing both n1 and n2
10436         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10437         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10438         while ( fIt->more() ) { // loop on faces sharing a node
10439           const SMDS_MeshElement* f = fIt->next();
10440           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10441               ! facesOfNode1.insert( f ).second ) // f encounters twice
10442           {
10443             if ( face[ iSide ] ) {
10444               MESSAGE( "2 faces per link " );
10445               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10446             }
10447             face[ iSide ] = f;
10448             faceSet->erase( f );
10449 
10450             // get not link nodes
10451             int nbN = f->NbNodes();
10452             if ( f->IsQuadratic() )
10453               nbN /= 2;
10454             nbNodes[ iSide ] = nbN;
10455             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10456             int i1 = f->GetNodeIndex( n1 );
10457             int i2 = f->GetNodeIndex( n2 );
10458             int iEnd = nbN, iBeg = -1, iDelta = 1;
10459             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10460             if ( reverse ) {
10461               std::swap( iEnd, iBeg ); iDelta = -1;
10462             }
10463             int i = i2;
10464             while ( true ) {
10465               i += iDelta;
10466               if ( i == iEnd ) i = iBeg + iDelta;
10467               if ( i == i1 ) break;
10468               nodes.push_back ( f->GetNode( i ) );
10469             }
10470           }
10471         }
10472       }
10473     }
10474     // check similarity of elements of the sides
10475     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10476       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10477       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10478         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10479       }
10480       else {
10481         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10482       }
10483     }
10484 
10485     // set nodes to merge
10486     // -------------------
10487 
10488     if ( face[0] && face[1] )  {
10489       if ( nbNodes[0] != nbNodes[1] ) {
10490         MESSAGE("Diff nb of face nodes");
10491         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10492       }
10493 #ifdef DEBUG_MATCHING_NODES
10494       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10495                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10496                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10497 #endif
10498       int nbN = nbNodes[0];
10499       {
10500         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10501         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10502         for ( int i = 0 ; i < nbN - 2; ++i ) {
10503 #ifdef DEBUG_MATCHING_NODES
10504           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10505 #endif
10506           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10507         }
10508       }
10509 
10510       // add other links of the face 1 to linkList
10511       // -----------------------------------------
10512 
10513       const SMDS_MeshElement* f0 = face[0];
10514       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10515       for ( int i = 0; i < nbN; i++ )
10516       {
10517         const SMDS_MeshNode* n2 = f0->GetNode( i );
10518         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10519           linkSet.insert( SMESH_TLink( n1, n2 ));
10520         if ( !iter_isnew.second ) { // already in a set: no need to process
10521           linkSet.erase( iter_isnew.first );
10522         }
10523         else // new in set == encountered for the first time: add
10524         {
10525 #ifdef DEBUG_MATCHING_NODES
10526           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10527                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10528 #endif
10529           linkList[0].push_back ( NLink( n1, n2 ));
10530           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10531         }
10532         n1 = n2;
10533       }
10534     } // 2 faces found
10535   } // loop on link lists
10536 
10537   return SEW_OK;
10538 }
10539 
10540 //================================================================================
10550 //================================================================================
10551 
10552 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10553                                     const TIDSortedElemSet& theNodesNot,
10554                                     const TIDSortedElemSet& theAffectedElems )
10555 {
10556   myLastCreatedElems.Clear();
10557   myLastCreatedNodes.Clear();
10558 
10559   if ( theElems.size() == 0 )
10560     return false;
10561 
10562   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10563   if ( !aMeshDS )
10564     return false;
10565 
10566   bool res = false;
10567   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10568   // duplicate elements and nodes
10569   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10570   // replce nodes by duplications
10571   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10572   return res;
10573 }
10574 
10575 //================================================================================
10585 //================================================================================
10586 
10587 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10588                                     const TIDSortedElemSet& theElems,
10589                                     const TIDSortedElemSet& theNodesNot,
10590                                     std::map< const SMDS_MeshNode*,
10591                                     const SMDS_MeshNode* >& theNodeNodeMap,
10592                                     const bool theIsDoubleElem )
10593 {
10594   MESSAGE("doubleNodes");
10595   // iterate on through element and duplicate them (by nodes duplication)
10596   bool res = false;
10597   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10598   for ( ;  elemItr != theElems.end(); ++elemItr )
10599   {
10600     const SMDS_MeshElement* anElem = *elemItr;
10601     if (!anElem)
10602       continue;
10603 
10604     bool isDuplicate = false;
10605     // duplicate nodes to duplicate element
10606     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10607     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10608     int ind = 0;
10609     while ( anIter->more() ) 
10610     { 
10611 
10612       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10613       SMDS_MeshNode* aNewNode = aCurrNode;
10614       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10615         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10616       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10617       {
10618         // duplicate node
10619         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10620         theNodeNodeMap[ aCurrNode ] = aNewNode;
10621         myLastCreatedNodes.Append( aNewNode );
10622       }
10623       isDuplicate |= (aCurrNode != aNewNode);
10624       newNodes[ ind++ ] = aNewNode;
10625     }
10626     if ( !isDuplicate )
10627       continue;
10628 
10629     if ( theIsDoubleElem )
10630       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10631     else
10632       {
10633       MESSAGE("ChangeElementNodes");
10634       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10635       }
10636     res = true;
10637   }
10638   return res;
10639 }
10640 
10641 //================================================================================
10650 //================================================================================
10651 
10652 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10653                                     const std::list< int >& theListOfModifiedElems )
10654 {
10655   MESSAGE("DoubleNodes");
10656   myLastCreatedElems.Clear();
10657   myLastCreatedNodes.Clear();
10658 
10659   if ( theListOfNodes.size() == 0 )
10660     return false;
10661 
10662   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10663   if ( !aMeshDS )
10664     return false;
10665 
10666   // iterate through nodes and duplicate them
10667 
10668   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10669 
10670   std::list< int >::const_iterator aNodeIter;
10671   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10672   {
10673     int aCurr = *aNodeIter;
10674     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10675     if ( !aNode )
10676       continue;
10677 
10678     // duplicate node
10679 
10680     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10681     if ( aNewNode )
10682     {
10683       anOldNodeToNewNode[ aNode ] = aNewNode;
10684       myLastCreatedNodes.Append( aNewNode );
10685     }
10686   }
10687 
10688   // Create map of new nodes for modified elements
10689 
10690   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10691 
10692   std::list< int >::const_iterator anElemIter;
10693   for ( anElemIter = theListOfModifiedElems.begin(); 
10694         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10695   {
10696     int aCurr = *anElemIter;
10697     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10698     if ( !anElem )
10699       continue;
10700 
10701     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10702 
10703     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10704     int ind = 0;
10705     while ( anIter->more() ) 
10706     { 
10707       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10708       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10709       {
10710         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10711         aNodeArr[ ind++ ] = aNewNode;
10712       }
10713       else
10714         aNodeArr[ ind++ ] = aCurrNode;
10715     }
10716     anElemToNodes[ anElem ] = aNodeArr;
10717   }
10718 
10719   // Change nodes of elements  
10720 
10721   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10722     anElemToNodesIter = anElemToNodes.begin();
10723   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10724   {
10725     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10726     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10727     if ( anElem )
10728       {
10729       MESSAGE("ChangeElementNodes");
10730       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10731       }
10732   }
10733 
10734   return true;
10735 }
10736 
10737 namespace {
10738 
10739   //================================================================================
10744   //================================================================================
10745 
10746   template<class Classifier>
10747   bool isInside(const SMDS_MeshElement* theElem,
10748                 Classifier&             theClassifier,
10749                 const double            theTol)
10750   {
10751     gp_XYZ centerXYZ (0, 0, 0);
10752     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10753     while (aNodeItr->more())
10754       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10755 
10756     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10757     theClassifier.Perform(aPnt, theTol);
10758     TopAbs_State aState = theClassifier.State();
10759     return (aState == TopAbs_IN || aState == TopAbs_ON );
10760   }
10761 
10762   //================================================================================
10767   //================================================================================
10768 
10769   struct _FaceClassifier
10770   {
10771     Extrema_ExtPS       _extremum;
10772     BRepAdaptor_Surface _surface;
10773     TopAbs_State        _state;
10774 
10775     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10776     {
10777       _extremum.Initialize( _surface,
10778                             _surface.FirstUParameter(), _surface.LastUParameter(),
10779                             _surface.FirstVParameter(), _surface.LastVParameter(),
10780                             _surface.Tolerance(), _surface.Tolerance() );
10781     }
10782     void Perform(const gp_Pnt& aPnt, double theTol)
10783     {
10784       _state = TopAbs_OUT;
10785       _extremum.Perform(aPnt);
10786       if ( _extremum.IsDone() )
10787         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10788           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10789     }
10790     TopAbs_State State() const
10791     {
10792       return _state;
10793     }
10794   };
10795 }
10796 
10797 //================================================================================
10807 //================================================================================
10808 
10809 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10810                                             const TIDSortedElemSet& theNodesNot,
10811                                             const TopoDS_Shape&     theShape )
10812 {
10813   if ( theShape.IsNull() )
10814     return false;
10815 
10816   const double aTol = Precision::Confusion();
10817   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10818   auto_ptr<_FaceClassifier>              aFaceClassifier;
10819   if ( theShape.ShapeType() == TopAbs_SOLID )
10820   {
10821     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10822     bsc3d->PerformInfinitePoint(aTol);
10823   }
10824   else if (theShape.ShapeType() == TopAbs_FACE )
10825   {
10826     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10827   }
10828 
10829   // iterates on indicated elements and get elements by back references from their nodes
10830   TIDSortedElemSet anAffected;
10831   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10832   for ( ;  elemItr != theElems.end(); ++elemItr )
10833   {
10834     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10835     if (!anElem)
10836       continue;
10837 
10838     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10839     while ( nodeItr->more() )
10840     {
10841       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10842       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10843         continue;
10844       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10845       while ( backElemItr->more() )
10846       {
10847         const SMDS_MeshElement* curElem = backElemItr->next();
10848         if ( curElem && theElems.find(curElem) == theElems.end() &&
10849              ( bsc3d.get() ?
10850                isInside( curElem, *bsc3d, aTol ) :
10851                isInside( curElem, *aFaceClassifier, aTol )))
10852           anAffected.insert( curElem );
10853       }
10854     }
10855   }
10856   return DoubleNodes( theElems, theNodesNot, anAffected );
10857 }
10858 
10867 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10868 {
10869 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10870 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10871 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10872 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10873   gp_Vec vref(p0, p1);
10874   gp_Vec v1(p0, g1);
10875   gp_Vec v2(p0, g2);
10876   gp_Vec n1 = vref.Crossed(v1);
10877   gp_Vec n2 = vref.Crossed(v2);
10878   return n2.AngleWithRef(n1, vref);
10879 }
10880 
10893 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10894                                                      bool createJointElems)
10895 {
10896   MESSAGE("----------------------------------------------");
10897   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10898   MESSAGE("----------------------------------------------");
10899 
10900   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10901   meshDS->BuildDownWardConnectivity(true);
10902   CHRONO(50);
10903   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10904 
10905   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10906   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10907   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10908 
10909   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10910   std::map<int,int>celldom; // cell vtkId --> domain
10911   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10912   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10913   faceDomains.clear();
10914   celldom.clear();
10915   cellDomains.clear();
10916   nodeDomains.clear();
10917   std::map<int,int> emptyMap;
10918   std::set<int> emptySet;
10919   emptyMap.clear();
10920 
10921   for (int idom = 0; idom < theElems.size(); idom++)
10922     {
10923 
10924       // --- build a map (face to duplicate --> volume to modify)
10925       //     with all the faces shared by 2 domains (group of elements)
10926       //     and corresponding volume of this domain, for each shared face.
10927       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10928 
10929       const TIDSortedElemSet& domain = theElems[idom];
10930       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10931       for (; elemItr != domain.end(); ++elemItr)
10932         {
10933           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10934           if (!anElem)
10935             continue;
10936           int vtkId = anElem->getVtkId();
10937           int neighborsVtkIds[NBMAXNEIGHBORS];
10938           int downIds[NBMAXNEIGHBORS];
10939           unsigned char downTypes[NBMAXNEIGHBORS];
10940           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10941           for (int n = 0; n < nbNeighbors; n++)
10942             {
10943               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10944               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10945               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10946                 {
10947                   DownIdType face(downIds[n], downTypes[n]);
10948                   if (!faceDomains.count(face))
10949                     faceDomains[face] = emptyMap; // create an empty entry for face
10950                   if (!faceDomains[face].count(idom))
10951                     {
10952                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10953                       celldom[vtkId] = idom;
10954                     }
10955                 }
10956             }
10957         }
10958     }
10959 
10960   //MESSAGE("Number of shared faces " << faceDomains.size());
10961   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10962 
10963   // --- explore the shared faces domain by domain,
10964   //     explore the nodes of the face and see if they belong to a cell in the domain,
10965   //     which has only a node or an edge on the border (not a shared face)
10966 
10967   for (int idomain = 0; idomain < theElems.size(); idomain++)
10968     {
10969       const TIDSortedElemSet& domain = theElems[idomain];
10970       itface = faceDomains.begin();
10971       for (; itface != faceDomains.end(); ++itface)
10972         {
10973           std::map<int, int> domvol = itface->second;
10974           if (!domvol.count(idomain))
10975             continue;
10976           DownIdType face = itface->first;
10977           //MESSAGE(" --- face " << face.cellId);
10978           std::set<int> oldNodes;
10979           oldNodes.clear();
10980           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10981           std::set<int>::iterator itn = oldNodes.begin();
10982           for (; itn != oldNodes.end(); ++itn)
10983             {
10984               int oldId = *itn;
10985               //MESSAGE("     node " << oldId);
10986               std::set<int> cells;
10987               cells.clear();
10988               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10989               for (int i=0; i<l.ncells; i++)
10990                 {
10991                   int vtkId = l.cells[i];
10992                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10993                   if (!domain.count(anElem))
10994                     continue;
10995                   int vtkType = grid->GetCellType(vtkId);
10996                   int downId = grid->CellIdToDownId(vtkId);
10997                   if (downId < 0)
10998                     {
10999                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11000                       continue; // not OK at this stage of the algorithm:
11001                                 //no cells created after BuildDownWardConnectivity
11002                     }
11003                   DownIdType aCell(downId, vtkType);
11004                   if (celldom.count(vtkId))
11005                     continue;
11006                   cellDomains[aCell][idomain] = vtkId;
11007                   celldom[vtkId] = idomain;
11008                 }
11009             }
11010         }
11011     }
11012 
11013   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11014   //     for each shared face, get the nodes
11015   //     for each node, for each domain of the face, create a clone of the node
11016 
11017   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11018   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11019   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11020 
11021   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11022   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
11023 
11024   for (int idomain = 0; idomain < theElems.size(); idomain++)
11025     {
11026       itface = faceDomains.begin();
11027       for (; itface != faceDomains.end(); ++itface)
11028         {
11029           std::map<int, int> domvol = itface->second;
11030           if (!domvol.count(idomain))
11031             continue;
11032           DownIdType face = itface->first;
11033           //MESSAGE(" --- face " << face.cellId);
11034           std::set<int> oldNodes;
11035           oldNodes.clear();
11036           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11037           bool isMultipleDetected = false;
11038           std::set<int>::iterator itn = oldNodes.begin();
11039           for (; itn != oldNodes.end(); ++itn)
11040             {
11041               int oldId = *itn;
11042               //MESSAGE("     node " << oldId);
11043               if (!nodeDomains.count(oldId))
11044                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11045               if (nodeDomains[oldId].empty())
11046                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11047               std::map<int, int>::iterator itdom = domvol.begin();
11048               for (; itdom != domvol.end(); ++itdom)
11049                 {
11050                   int idom = itdom->first;
11051                   //MESSAGE("         domain " << idom);
11052                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11053                     {
11054                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11055                         {
11056                           vector<int> orderedDoms;
11057                           //MESSAGE("multiple node " << oldId);
11058                           isMultipleDetected =true;
11059                           if (mutipleNodes.count(oldId))
11060                             orderedDoms = mutipleNodes[oldId];
11061                           else
11062                             {
11063                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11064                               for (; it != nodeDomains[oldId].end(); ++it)
11065                                 orderedDoms.push_back(it->first);
11066                             }
11067                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11068                           //stringstream txt;
11069                           //for (int i=0; i<orderedDoms.size(); i++)
11070                           //  txt << orderedDoms[i] << " ";
11071                           //MESSAGE("orderedDoms " << txt.str());
11072                           mutipleNodes[oldId] = orderedDoms;
11073                         }
11074                       double *coords = grid->GetPoint(oldId);
11075                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11076                       int newId = newNode->getVtkId();
11077                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11078                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11079                     }
11080                   if (nodeDomains[oldId].size() >= 3)
11081                     {
11082                       //MESSAGE("confirm multiple node " << oldId);
11083                       isMultipleDetected =true;
11084                     }
11085                 }
11086             }
11087           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11088             {
11089               //MESSAGE("multiple Nodes detected on a shared face");
11090               int downId = itface->first.cellId;
11091               unsigned char cellType = itface->first.cellType;
11092               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11093               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11094               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11095               for (int ie =0; ie < nbEdges; ie++)
11096                 {
11097                   int nodes[3];
11098                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11099                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11100                     {
11101                       vector<int> vn0 = mutipleNodes[nodes[0]];
11102                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11103                       sort( vn0.begin(), vn0.end() );
11104                       sort( vn1.begin(), vn1.end() );
11105                       if (vn0 == vn1)
11106                         {
11107                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11108                           double *coords = grid->GetPoint(nodes[0]);
11109                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11110                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11111                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11112                           gp_Pnt gref;
11113                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11114                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11115                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11116                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11117                           for (int id=0; id < vn0.size(); id++)
11118                             {
11119                               int idom = vn0[id];
11120                               for (int ivol=0; ivol<nbvol; ivol++)
11121                                 {
11122                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11123                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11124                                   if (theElems[idom].count(elem))
11125                                     {
11126                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11127                                       domvol[idom] = svol;
11128                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11129                                       double values[3];
11130                                       vtkIdType npts = 0;
11131                                       vtkIdType* pts = 0;
11132                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11133                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11134                                       if (id ==0)
11135                                         {
11136                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11137                                           angleDom[idom] = 0;
11138                                         }
11139                                       else
11140                                         {
11141                                           gp_Pnt g(values[0], values[1], values[2]);
11142                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11143                                           //MESSAGE("  angle=" << angleDom[idom]);
11144                                         }
11145                                       break;
11146                                     }
11147                                 }
11148                             }
11149                           map<double, int> sortedDom; // sort domains by angle
11150                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11151                             sortedDom[ia->second] = ia->first;
11152                           vector<int> vnodes;
11153                           vector<int> vdom;
11154                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11155                             {
11156                               vdom.push_back(ib->second);
11157                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11158                             }
11159                           for (int ino = 0; ino < nbNodes; ino++)
11160                             vnodes.push_back(nodes[ino]);
11161                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11162                         }
11163                     }
11164                 }
11165             }
11166         }
11167     }
11168 
11169   // --- iterate on shared faces (volumes to modify, face to extrude)
11170   //     get node id's of the face (id SMDS = id VTK)
11171   //     create flat element with old and new nodes if requested
11172 
11173   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11174   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11175 
11176   std::map<int, std::map<long,int> > nodeQuadDomains;
11177   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11178 
11179   if (createJointElems)
11180     {
11181       itface = faceDomains.begin();
11182       for (; itface != faceDomains.end(); ++itface)
11183         {
11184           DownIdType face = itface->first;
11185           std::set<int> oldNodes;
11186           std::set<int>::iterator itn;
11187           oldNodes.clear();
11188           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11189 
11190           std::map<int, int> domvol = itface->second;
11191           std::map<int, int>::iterator itdom = domvol.begin();
11192           int dom1 = itdom->first;
11193           int vtkVolId = itdom->second;
11194           itdom++;
11195           int dom2 = itdom->first;
11196           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11197                                                              nodeQuadDomains);
11198           stringstream grpname;
11199           grpname << "j_";
11200           if (dom1 < dom2)
11201             grpname << dom1 << "_" << dom2;
11202           else
11203             grpname << dom2 << "_" << dom1;
11204           int idg;
11205           string namegrp = grpname.str();
11206           if (!mapOfJunctionGroups.count(namegrp))
11207             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11208           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11209           if (sgrp)
11210             sgrp->Add(vol->GetID());
11211         }
11212     }
11213 
11214   // --- create volumes on multiple domain intersection if requested
11215   //     iterate on edgesMultiDomains
11216 
11217   if (createJointElems)
11218     {
11219       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11220       for (; ite != edgesMultiDomains.end(); ++ite)
11221         {
11222           vector<int> nodes = ite->first;
11223           vector<int> orderDom = ite->second;
11224           vector<vtkIdType> orderedNodes;
11225           if (nodes.size() == 2)
11226             {
11227               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11228               for (int ino=0; ino < nodes.size(); ino++)
11229                 if (orderDom.size() == 3)
11230                   for (int idom = 0; idom <orderDom.size(); idom++)
11231                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11232                 else
11233                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11234                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11235               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11236 
11237               stringstream grpname;
11238               grpname << "mj_";
11239               grpname << 0 << "_" << 0;
11240               int idg;
11241               string namegrp = grpname.str();
11242               if (!mapOfJunctionGroups.count(namegrp))
11243                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11244               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11245               if (sgrp)
11246                 sgrp->Add(vol->GetID());
11247             }
11248           else
11249             {
11250               //MESSAGE("Quadratic multiple joints not implemented");
11251               // TODO quadratic nodes
11252             }
11253         }
11254     }
11255 
11256   // --- list the explicit faces and edges of the mesh that need to be modified,
11257   //     i.e. faces and edges built with one or more duplicated nodes.
11258   //     associate these faces or edges to their corresponding domain.
11259   //     only the first domain found is kept when a face or edge is shared
11260 
11261   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11262   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11263   faceOrEdgeDom.clear();
11264   feDom.clear();
11265 
11266   for (int idomain = 0; idomain < theElems.size(); idomain++)
11267     {
11268       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11269       for (; itnod != nodeDomains.end(); ++itnod)
11270         {
11271           int oldId = itnod->first;
11272           //MESSAGE("     node " << oldId);
11273           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11274           for (int i = 0; i < l.ncells; i++)
11275             {
11276               int vtkId = l.cells[i];
11277               int vtkType = grid->GetCellType(vtkId);
11278               int downId = grid->CellIdToDownId(vtkId);
11279               if (downId < 0)
11280                 continue; // new cells: not to be modified
11281               DownIdType aCell(downId, vtkType);
11282               int volParents[1000];
11283               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11284               for (int j = 0; j < nbvol; j++)
11285                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11286                   if (!feDom.count(vtkId))
11287                     {
11288                       feDom[vtkId] = idomain;
11289                       faceOrEdgeDom[aCell] = emptyMap;
11290                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11291                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11292                       //        << " type " << vtkType << " downId " << downId);
11293                     }
11294             }
11295         }
11296     }
11297 
11298   // --- iterate on shared faces (volumes to modify, face to extrude)
11299   //     get node id's of the face
11300   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11301 
11302   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11303   for (int m=0; m<3; m++)
11304     {
11305       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11306       itface = (*amap).begin();
11307       for (; itface != (*amap).end(); ++itface)
11308         {
11309           DownIdType face = itface->first;
11310           std::set<int> oldNodes;
11311           std::set<int>::iterator itn;
11312           oldNodes.clear();
11313           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11314           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11315           std::map<int, int> localClonedNodeIds;
11316 
11317           std::map<int, int> domvol = itface->second;
11318           std::map<int, int>::iterator itdom = domvol.begin();
11319           for (; itdom != domvol.end(); ++itdom)
11320             {
11321               int idom = itdom->first;
11322               int vtkVolId = itdom->second;
11323               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11324               localClonedNodeIds.clear();
11325               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11326                 {
11327                   int oldId = *itn;
11328                   if (nodeDomains[oldId].count(idom))
11329                     {
11330                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11331                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11332                     }
11333                 }
11334               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11335             }
11336         }
11337     }
11338 
11339   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11340   grid->BuildLinks();
11341 
11342   CHRONOSTOP(50);
11343   counters::stats();
11344   return true;
11345 }
11346 
11357 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11358 {
11359   MESSAGE("-------------------------------------------------");
11360   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11361   MESSAGE("-------------------------------------------------");
11362 
11363   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11364 
11365   // --- For each group of faces
11366   //     duplicate the nodes, create a flat element based on the face
11367   //     replace the nodes of the faces by their clones
11368 
11369   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11370   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11371   clonedNodes.clear();
11372   intermediateNodes.clear();
11373   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11374   mapOfJunctionGroups.clear();
11375 
11376   for (int idom = 0; idom < theElems.size(); idom++)
11377     {
11378       const TIDSortedElemSet& domain = theElems[idom];
11379       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11380       for (; elemItr != domain.end(); ++elemItr)
11381         {
11382           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11383           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11384           if (!aFace)
11385             continue;
11386           // MESSAGE("aFace=" << aFace->GetID());
11387           bool isQuad = aFace->IsQuadratic();
11388           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11389 
11390           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11391 
11392           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11393           while (nodeIt->more())
11394             {
11395               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11396               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11397               if (isMedium)
11398                 ln2.push_back(node);
11399               else
11400                 ln0.push_back(node);
11401 
11402               const SMDS_MeshNode* clone = 0;
11403               if (!clonedNodes.count(node))
11404                 {
11405                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11406                   clonedNodes[node] = clone;
11407                 }
11408               else
11409                 clone = clonedNodes[node];
11410 
11411               if (isMedium)
11412                 ln3.push_back(clone);
11413               else
11414                 ln1.push_back(clone);
11415 
11416               const SMDS_MeshNode* inter = 0;
11417               if (isQuad && (!isMedium))
11418                 {
11419                   if (!intermediateNodes.count(node))
11420                     {
11421                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11422                       intermediateNodes[node] = inter;
11423                     }
11424                   else
11425                     inter = intermediateNodes[node];
11426                   ln4.push_back(inter);
11427                 }
11428             }
11429 
11430           // --- extrude the face
11431 
11432           vector<const SMDS_MeshNode*> ln;
11433           SMDS_MeshVolume* vol = 0;
11434           vtkIdType aType = aFace->GetVtkType();
11435           switch (aType)
11436           {
11437             case VTK_TRIANGLE:
11438               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11439               // MESSAGE("vol prism " << vol->GetID());
11440               ln.push_back(ln1[0]);
11441               ln.push_back(ln1[1]);
11442               ln.push_back(ln1[2]);
11443               break;
11444             case VTK_QUAD:
11445               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11446               // MESSAGE("vol hexa " << vol->GetID());
11447               ln.push_back(ln1[0]);
11448               ln.push_back(ln1[1]);
11449               ln.push_back(ln1[2]);
11450               ln.push_back(ln1[3]);
11451               break;
11452             case VTK_QUADRATIC_TRIANGLE:
11453               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11454                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11455               // MESSAGE("vol quad prism " << vol->GetID());
11456               ln.push_back(ln1[0]);
11457               ln.push_back(ln1[1]);
11458               ln.push_back(ln1[2]);
11459               ln.push_back(ln3[0]);
11460               ln.push_back(ln3[1]);
11461               ln.push_back(ln3[2]);
11462               break;
11463             case VTK_QUADRATIC_QUAD:
11464 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11465 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11466 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11467               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11468                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11469                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11470               // MESSAGE("vol quad hexa " << vol->GetID());
11471               ln.push_back(ln1[0]);
11472               ln.push_back(ln1[1]);
11473               ln.push_back(ln1[2]);
11474               ln.push_back(ln1[3]);
11475               ln.push_back(ln3[0]);
11476               ln.push_back(ln3[1]);
11477               ln.push_back(ln3[2]);
11478               ln.push_back(ln3[3]);
11479               break;
11480             case VTK_POLYGON:
11481               break;
11482             default:
11483               break;
11484           }
11485 
11486           if (vol)
11487             {
11488               stringstream grpname;
11489               grpname << "jf_";
11490               grpname << idom;
11491               int idg;
11492               string namegrp = grpname.str();
11493               if (!mapOfJunctionGroups.count(namegrp))
11494                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11495               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11496               if (sgrp)
11497                 sgrp->Add(vol->GetID());
11498             }
11499 
11500           // --- modify the face
11501 
11502           aFace->ChangeNodes(&ln[0], ln.size());
11503         }
11504     }
11505   return true;
11506 }
11507 
11508 //================================================================================
11514 //================================================================================
11515 
11516 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11517 {
11518   // iterates on volume elements and detect all free faces on them
11519   SMESHDS_Mesh* aMesh = GetMeshDS();
11520   if (!aMesh)
11521     return false;
11522   //bool res = false;
11523   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11524   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11525   while(vIt->more())
11526   {
11527     const SMDS_MeshVolume* volume = vIt->next();
11528     SMDS_VolumeTool vTool( volume );
11529     vTool.SetExternalNormal();
11530     const bool isPoly = volume->IsPoly();
11531     const bool isQuad = volume->IsQuadratic();
11532     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11533     {
11534       if (!vTool.IsFreeFace(iface))
11535         continue;
11536       nbFree++;
11537       vector<const SMDS_MeshNode *> nodes;
11538       int nbFaceNodes = vTool.NbFaceNodes(iface);
11539       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11540       int inode = 0;
11541       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11542         nodes.push_back(faceNodes[inode]);
11543       if (isQuad)
11544         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11545           nodes.push_back(faceNodes[inode]);
11546 
11547       // add new face based on volume nodes
11548       if (aMesh->FindFace( nodes ) ) {
11549         nbExisted++;
11550         continue; // face already exsist
11551       }
11552       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11553       nbCreated++;
11554     }
11555   }
11556   return ( nbFree==(nbExisted+nbCreated) );
11557 }
11558 
11559 namespace
11560 {
11561   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11562   {
11563     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11564       return n;
11565     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11566   }
11567 }
11568 //================================================================================
11584 //================================================================================
11585 
11586 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11587                                        Bnd_Dimension           dimension,
11588                                        SMESH_Group*            group/*=0*/,
11589                                        SMESH_Mesh*             targetMesh/*=0*/,
11590                                        bool                    toCopyElements/*=false*/,
11591                                        bool                    toCopyExistingBoundary/*=false*/,
11592                                        bool                    toAddExistingBondary/*= false*/,
11593                                        bool                    aroundElements/*= false*/)
11594 {
11595   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11596   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11597   // hope that all elements are of the same type, do not check them all
11598   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11599     throw SALOME_Exception(LOCALIZED("wrong element type"));
11600 
11601   if ( !targetMesh )
11602     toCopyElements = toCopyExistingBoundary = false;
11603 
11604   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11605   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11606   int nbAddedBnd = 0;
11607 
11608   // editor adding present bnd elements and optionally holding elements to add to the group
11609   SMESH_MeshEditor* presentEditor;
11610   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11611   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11612 
11613   SMDS_VolumeTool vTool;
11614   TIDSortedElemSet avoidSet;
11615   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11616   int inode;
11617 
11618   typedef vector<const SMDS_MeshNode*> TConnectivity;
11619 
11620   SMDS_ElemIteratorPtr eIt;
11621   if (elements.empty())
11622     eIt = aMesh->elementsIterator(elemType);
11623   else
11624     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11625 
11626   while (eIt->more())
11627   {
11628     const SMDS_MeshElement* elem = eIt->next();
11629     const int iQuad = elem->IsQuadratic();
11630 
11631     // ------------------------------------------------------------------------------------
11632     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11633     // ------------------------------------------------------------------------------------
11634     vector<const SMDS_MeshElement*> presentBndElems;
11635     vector<TConnectivity>           missingBndElems;
11636     TConnectivity nodes;
11637     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11638     {
11639       vTool.SetExternalNormal();
11640       const SMDS_MeshElement* otherVol = 0;
11641       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11642       {
11643         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11644              ( !aroundElements || elements.count( otherVol )))
11645           continue;
11646         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11647         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11648         if ( missType == SMDSAbs_Edge ) // boundary edges
11649         {
11650           nodes.resize( 2+iQuad );
11651           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11652           {
11653             for ( int j = 0; j < nodes.size(); ++j )
11654               nodes[j] =nn[i+j];
11655             if ( const SMDS_MeshElement* edge =
11656                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11657               presentBndElems.push_back( edge );
11658             else
11659               missingBndElems.push_back( nodes );
11660           }
11661         }
11662         else // boundary face
11663         {
11664           nodes.clear();
11665           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11666             nodes.push_back( nn[inode] );
11667           if (iQuad)
11668             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11669               nodes.push_back( nn[inode] );
11670 
11671           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11672             presentBndElems.push_back( f );
11673           else
11674             missingBndElems.push_back( nodes );
11675 
11676           if ( targetMesh != myMesh )
11677           {
11678             // add 1D elements on face boundary to be added to a new mesh
11679             const SMDS_MeshElement* edge;
11680             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11681             {
11682               if ( iQuad )
11683                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11684               else
11685                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11686               if ( edge && avoidSet.insert( edge ).second )
11687                 presentBndElems.push_back( edge );
11688             }
11689           }
11690         }
11691       }
11692     }
11693     else                     // elem is a face ------------------------------------------
11694     {
11695       avoidSet.clear(), avoidSet.insert( elem );
11696       int nbNodes = elem->NbCornerNodes();
11697       nodes.resize( 2 /*+ iQuad*/);
11698       for ( int i = 0; i < nbNodes; i++ )
11699       {
11700         nodes[0] = elem->GetNode(i);
11701         nodes[1] = elem->GetNode((i+1)%nbNodes);
11702         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11703           continue; // not free link
11704 
11705         //if ( iQuad )
11706         //nodes[2] = elem->GetNode( i + nbNodes );
11707         if ( const SMDS_MeshElement* edge =
11708              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11709           presentBndElems.push_back( edge );
11710         else
11711           missingBndElems.push_back( nodes );
11712       }
11713     }
11714 
11715     // ---------------------------------
11716     // 2. Add missing boundary elements
11717     // ---------------------------------
11718     if ( targetMesh != myMesh )
11719       // instead of making a map of nodes in this mesh and targetMesh,
11720       // we create nodes with same IDs.
11721       for ( int i = 0; i < missingBndElems.size(); ++i )
11722       {
11723         TConnectivity& srcNodes = missingBndElems[i];
11724         TConnectivity  nodes( srcNodes.size() );
11725         for ( inode = 0; inode < nodes.size(); ++inode )
11726           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11727         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11728                                                                    missType,
11729                                                                    /*noMedium=*/true))
11730           continue;
11731         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11732         ++nbAddedBnd;
11733       }
11734     else
11735       for ( int i = 0; i < missingBndElems.size(); ++i )
11736       {
11737         TConnectivity& nodes = missingBndElems[i];
11738         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11739                                                                    missType,
11740                                                                    /*noMedium=*/true))
11741           continue;
11742         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11743         ++nbAddedBnd;
11744       }
11745 
11746     // ----------------------------------
11747     // 3. Copy present boundary elements
11748     // ----------------------------------
11749     if ( toCopyExistingBoundary )
11750       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11751       {
11752         const SMDS_MeshElement* e = presentBndElems[i];
11753         TConnectivity nodes( e->NbNodes() );
11754         for ( inode = 0; inode < nodes.size(); ++inode )
11755           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11756         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11757       }
11758     else // store present elements to add them to a group
11759       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11760       {
11761         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11762       }
11763       
11764   } // loop on given elements
11765 
11766   // ---------------------------------------------
11767   // 4. Fill group with boundary elements
11768   // ---------------------------------------------
11769   if ( group )
11770   {
11771     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11772       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11773         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11774   }
11775   tgtEditor.myLastCreatedElems.Clear();
11776   tgtEditor2.myLastCreatedElems.Clear();
11777 
11778   // -----------------------
11779   // 5. Copy given elements
11780   // -----------------------
11781   if ( toCopyElements && targetMesh != myMesh )
11782   {
11783     if (elements.empty())
11784       eIt = aMesh->elementsIterator(elemType);
11785     else
11786       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11787     while (eIt->more())
11788     {
11789       const SMDS_MeshElement* elem = eIt->next();
11790       TConnectivity nodes( elem->NbNodes() );
11791       for ( inode = 0; inode < nodes.size(); ++inode )
11792         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11793       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11794 
11795       tgtEditor.myLastCreatedElems.Clear();
11796     }
11797   }
11798   return nbAddedBnd;
11799 }
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