Back to index

salome-smesh  6.5.0
SMESH_MeshEditor.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  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 #include "SMESH_MeshEditor.hxx"
00029 
00030 #include "SMDS_FaceOfNodes.hxx"
00031 #include "SMDS_VolumeTool.hxx"
00032 #include "SMDS_EdgePosition.hxx"
00033 #include "SMDS_FacePosition.hxx"
00034 #include "SMDS_SpacePosition.hxx"
00035 #include "SMDS_MeshGroup.hxx"
00036 #include "SMDS_LinearEdge.hxx"
00037 #include "SMDS_Downward.hxx"
00038 #include "SMDS_SetIterator.hxx"
00039 
00040 #include "SMESHDS_Group.hxx"
00041 #include "SMESHDS_Mesh.hxx"
00042 
00043 #include "SMESH_Algo.hxx"
00044 #include "SMESH_ControlsDef.hxx"
00045 #include "SMESH_Group.hxx"
00046 #include "SMESH_MesherHelper.hxx"
00047 #include "SMESH_OctreeNode.hxx"
00048 #include "SMESH_subMesh.hxx"
00049 
00050 #include <Basics_OCCTVersion.hxx>
00051 
00052 #include "utilities.h"
00053 
00054 #include <BRepAdaptor_Surface.hxx>
00055 #include <BRepBuilderAPI_MakeEdge.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 <cmath>
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 if (nbnode == 9) {
00160         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
00161                                                node[4], node[5], node[6], node[7], node[8], ID);
00162         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
00163                                                node[4], node[5], node[6], node[7], node[8] );
00164       }
00165     } else {
00166       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
00167       else           e = mesh->AddPolygonalFace      (node    );
00168     }
00169     break;
00170 
00171   case SMDSAbs_Volume:
00172     if ( !isPoly ) {
00173       if      (nbnode == 4) {
00174         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
00175         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
00176       }
00177       else if (nbnode == 5) {
00178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00179                                                  node[4], ID);
00180         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00181                                                  node[4] );
00182       }
00183       else if (nbnode == 6) {
00184         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00185                                                  node[4], node[5], ID);
00186         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00187                                                  node[4], node[5] );
00188       }
00189       else if (nbnode == 8) {
00190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00191                                                  node[4], node[5], node[6], node[7], ID);
00192         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00193                                                  node[4], node[5], node[6], node[7] );
00194       }
00195       else if (nbnode == 10) {
00196         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00197                                                  node[4], node[5], node[6], node[7],
00198                                                  node[8], node[9], ID);
00199         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00200                                                  node[4], node[5], node[6], node[7],
00201                                                  node[8], node[9] );
00202       }
00203       else if (nbnode == 12) {
00204         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00205                                                  node[4], node[5], node[6], node[7],
00206                                                  node[8], node[9], node[10], node[11], ID);
00207         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00208                                                  node[4], node[5], node[6], node[7],
00209                                                  node[8], node[9], node[10], node[11] );
00210       }
00211       else if (nbnode == 13) {
00212         if ( ID >= 1 ) e = mesh->AddVolumeWithID(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],ID);
00216         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00217                                                  node[4], node[5], node[6], node[7],
00218                                                  node[8], node[9], node[10],node[11],
00219                                                  node[12] );
00220       }
00221       else if (nbnode == 15) {
00222         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00223                                                  node[4], node[5], node[6], node[7],
00224                                                  node[8], node[9], node[10],node[11],
00225                                                  node[12],node[13],node[14],ID);
00226         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00227                                                  node[4], node[5], node[6], node[7],
00228                                                  node[8], node[9], node[10],node[11],
00229                                                  node[12],node[13],node[14] );
00230       }
00231       else if (nbnode == 20) {
00232         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00233                                                  node[4], node[5], node[6], node[7],
00234                                                  node[8], node[9], node[10],node[11],
00235                                                  node[12],node[13],node[14],node[15],
00236                                                  node[16],node[17],node[18],node[19],ID);
00237         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00238                                                  node[4], node[5], node[6], node[7],
00239                                                  node[8], node[9], node[10],node[11],
00240                                                  node[12],node[13],node[14],node[15],
00241                                                  node[16],node[17],node[18],node[19] );
00242       }
00243       else if (nbnode == 27) {
00244         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
00245                                                  node[4], node[5], node[6], node[7],
00246                                                  node[8], node[9], node[10],node[11],
00247                                                  node[12],node[13],node[14],node[15],
00248                                                  node[16],node[17],node[18],node[19],
00249                                                  node[20],node[21],node[22],node[23],
00250                                                  node[24],node[25],node[26], ID);
00251         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
00252                                                  node[4], node[5], node[6], node[7],
00253                                                  node[8], node[9], node[10],node[11],
00254                                                  node[12],node[13],node[14],node[15],
00255                                                  node[16],node[17],node[18],node[19],
00256                                                  node[20],node[21],node[22],node[23],
00257                                                  node[24],node[25],node[26] );
00258       }
00259     }
00260     break;
00261 
00262   case SMDSAbs_Edge:
00263     if ( nbnode == 2 ) {
00264       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
00265       else           e = mesh->AddEdge      (node[0], node[1] );
00266     }
00267     else if ( nbnode == 3 ) {
00268       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
00269       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
00270     }
00271     break;
00272 
00273   case SMDSAbs_0DElement:
00274     if ( nbnode == 1 ) {
00275       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
00276       else           e = mesh->Add0DElement      (node[0] );
00277     }
00278     break;
00279 
00280   case SMDSAbs_Node:
00281     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
00282     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
00283     break;
00284 
00285   default:;
00286   }
00287   if ( e ) myLastCreatedElems.Append( e );
00288   return e;
00289 }
00290 
00291 //=======================================================================
00295 //=======================================================================
00296 
00297 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
00298                                                const SMDSAbs_ElementType type,
00299                                                const bool                isPoly,
00300                                                const int                 ID)
00301 {
00302   vector<const SMDS_MeshNode*> nodes;
00303   nodes.reserve( nodeIDs.size() );
00304   vector<int>::const_iterator id = nodeIDs.begin();
00305   while ( id != nodeIDs.end() ) {
00306     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
00307       nodes.push_back( node );
00308     else
00309       return 0;
00310   }
00311   return AddElement( nodes, type, isPoly, ID );
00312 }
00313 
00314 //=======================================================================
00315 //function : Remove
00316 //purpose  : Remove a node or an element.
00317 //           Modify a compute state of sub-meshes which become empty
00318 //=======================================================================
00319 
00320 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
00321                               const bool         isNodes )
00322 {
00323   myLastCreatedElems.Clear();
00324   myLastCreatedNodes.Clear();
00325 
00326   SMESHDS_Mesh* aMesh = GetMeshDS();
00327   set< SMESH_subMesh *> smmap;
00328 
00329   int removed = 0;
00330   list<int>::const_iterator it = theIDs.begin();
00331   for ( ; it != theIDs.end(); it++ ) {
00332     const SMDS_MeshElement * elem;
00333     if ( isNodes )
00334       elem = aMesh->FindNode( *it );
00335     else
00336       elem = aMesh->FindElement( *it );
00337     if ( !elem )
00338       continue;
00339 
00340     // Notify VERTEX sub-meshes about modification
00341     if ( isNodes ) {
00342       const SMDS_MeshNode* node = cast2Node( elem );
00343       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
00344         if ( int aShapeID = node->getshapeId() )
00345           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
00346             smmap.insert( sm );
00347     }
00348     // Find sub-meshes to notify about modification
00349     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
00350     //     while ( nodeIt->more() ) {
00351     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
00352     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
00353     //       if ( aPosition.get() ) {
00354     //         if ( int aShapeID = aPosition->GetShapeId() ) {
00355     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
00356     //             smmap.insert( sm );
00357     //         }
00358     //       }
00359     //     }
00360 
00361     // Do remove
00362     if ( isNodes )
00363       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
00364     else
00365       aMesh->RemoveElement( elem );
00366     removed++;
00367   }
00368 
00369   // Notify sub-meshes about modification
00370   if ( !smmap.empty() ) {
00371     set< SMESH_subMesh *>::iterator smIt;
00372     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
00373       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
00374   }
00375 
00376   //   // Check if the whole mesh becomes empty
00377   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
00378   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
00379 
00380   return removed;
00381 }
00382 
00383 //=======================================================================
00384 //function : FindShape
00385 //purpose  : Return an index of the shape theElem is on
00386 //           or zero if a shape not found
00387 //=======================================================================
00388 
00389 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
00390 {
00391   myLastCreatedElems.Clear();
00392   myLastCreatedNodes.Clear();
00393 
00394   SMESHDS_Mesh * aMesh = GetMeshDS();
00395   if ( aMesh->ShapeToMesh().IsNull() )
00396     return 0;
00397 
00398   int aShapeID = theElem->getshapeId();
00399   if ( aShapeID < 1 )
00400     return 0;
00401 
00402   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
00403     if ( sm->Contains( theElem ))
00404       return aShapeID;
00405 
00406   if ( theElem->GetType() == SMDSAbs_Node ) {
00407     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
00408   }
00409   else {
00410     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
00411   }
00412 
00413   TopoDS_Shape aShape; // the shape a node of theElem is on
00414   if ( theElem->GetType() != SMDSAbs_Node )
00415   {
00416     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
00417     while ( nodeIt->more() ) {
00418       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
00419       if ((aShapeID = node->getshapeId()) > 0) {
00420         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
00421           if ( sm->Contains( theElem ))
00422             return aShapeID;
00423           if ( aShape.IsNull() )
00424             aShape = aMesh->IndexToShape( aShapeID );
00425         }
00426       }
00427     }
00428   }
00429 
00430   // None of nodes is on a proper shape,
00431   // find the shape among ancestors of aShape on which a node is
00432   if ( !aShape.IsNull() ) {
00433     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
00434     for ( ; ancIt.More(); ancIt.Next() ) {
00435       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
00436       if ( sm && sm->Contains( theElem ))
00437         return aMesh->ShapeToIndex( ancIt.Value() );
00438     }
00439   }
00440   else
00441   {
00442     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
00443     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
00444     for ( ; id_sm != id2sm.end(); ++id_sm )
00445       if ( id_sm->second->Contains( theElem ))
00446         return id_sm->first;
00447   }
00448 
00449   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
00450   return 0;
00451 }
00452 
00453 //=======================================================================
00454 //function : IsMedium
00455 //purpose  :
00456 //=======================================================================
00457 
00458 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
00459                                 const SMDSAbs_ElementType typeToCheck)
00460 {
00461   bool isMedium = false;
00462   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
00463   while (it->more() && !isMedium ) {
00464     const SMDS_MeshElement* elem = it->next();
00465     isMedium = elem->IsMediumNode(node);
00466   }
00467   return isMedium;
00468 }
00469 
00470 //=======================================================================
00471 //function : ShiftNodesQuadTria
00472 //purpose  : auxilary
00473 //           Shift nodes in the array corresponded to quadratic triangle
00474 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
00475 //=======================================================================
00476 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
00477 {
00478   const SMDS_MeshNode* nd1 = aNodes[0];
00479   aNodes[0] = aNodes[1];
00480   aNodes[1] = aNodes[2];
00481   aNodes[2] = nd1;
00482   const SMDS_MeshNode* nd2 = aNodes[3];
00483   aNodes[3] = aNodes[4];
00484   aNodes[4] = aNodes[5];
00485   aNodes[5] = nd2;
00486 }
00487 
00488 //=======================================================================
00489 //function : edgeConnectivity
00490 //purpose  : auxilary 
00491 //           return number of the edges connected with the theNode.
00492 //           if theEdges has connections with the other type of the
00493 //           elements, return -1 
00494 //=======================================================================
00495 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
00496 {
00497   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
00498   int nb=0;
00499   while(elemIt->more()) {
00500     elemIt->next();
00501     nb++;
00502   }
00503   return nb;
00504 }
00505 
00506 
00507 //=======================================================================
00508 //function : GetNodesFromTwoTria
00509 //purpose  : auxilary
00510 //           Shift nodes in the array corresponded to quadratic triangle
00511 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
00512 //=======================================================================
00513 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
00514                                 const SMDS_MeshElement * theTria2,
00515                                 const SMDS_MeshNode* N1[],
00516                                 const SMDS_MeshNode* N2[])
00517 {
00518   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
00519   int i=0;
00520   while(i<6) {
00521     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
00522     i++;
00523   }
00524   if(it->more()) return false;
00525   it = theTria2->nodesIterator();
00526   i=0;
00527   while(i<6) {
00528     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
00529     i++;
00530   }
00531   if(it->more()) return false;
00532 
00533   int sames[3] = {-1,-1,-1};
00534   int nbsames = 0;
00535   int j;
00536   for(i=0; i<3; i++) {
00537     for(j=0; j<3; j++) {
00538       if(N1[i]==N2[j]) {
00539         sames[i] = j;
00540         nbsames++;
00541         break;
00542       }
00543     }
00544   }
00545   if(nbsames!=2) return false;
00546   if(sames[0]>-1) {
00547     ShiftNodesQuadTria(N1);
00548     if(sames[1]>-1) {
00549       ShiftNodesQuadTria(N1);
00550     }
00551   }
00552   i = sames[0] + sames[1] + sames[2];
00553   for(; i<2; i++) {
00554     ShiftNodesQuadTria(N2);
00555   }
00556   // now we receive following N1 and N2 (using numeration as above image)
00557   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
00558   // i.e. first nodes from both arrays determ new diagonal
00559   return true;
00560 }
00561 
00562 //=======================================================================
00563 //function : InverseDiag
00564 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
00565 //           but having other common link.
00566 //           Return False if args are improper
00567 //=======================================================================
00568 
00569 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
00570                                     const SMDS_MeshElement * theTria2 )
00571 {
00572   MESSAGE("InverseDiag");
00573   myLastCreatedElems.Clear();
00574   myLastCreatedNodes.Clear();
00575 
00576   if (!theTria1 || !theTria2)
00577     return false;
00578 
00579   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
00580   if (!F1) return false;
00581   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
00582   if (!F2) return false;
00583   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
00584       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
00585 
00586     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
00587     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
00588     //    |/ |                                         | \|
00589     //  B +--+ 2                                     B +--+ 2
00590 
00591     // put nodes in array and find out indices of the same ones
00592     const SMDS_MeshNode* aNodes [6];
00593     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
00594     int i = 0;
00595     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
00596     while ( it->more() ) {
00597       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
00598 
00599       if ( i > 2 ) // theTria2
00600         // find same node of theTria1
00601         for ( int j = 0; j < 3; j++ )
00602           if ( aNodes[ i ] == aNodes[ j ]) {
00603             sameInd[ j ] = i;
00604             sameInd[ i ] = j;
00605             break;
00606           }
00607       // next
00608       i++;
00609       if ( i == 3 ) {
00610         if ( it->more() )
00611           return false; // theTria1 is not a triangle
00612         it = theTria2->nodesIterator();
00613       }
00614       if ( i == 6 && it->more() )
00615         return false; // theTria2 is not a triangle
00616     }
00617 
00618     // find indices of 1,2 and of A,B in theTria1
00619     int iA = 0, iB = 0, i1 = 0, i2 = 0;
00620     for ( i = 0; i < 6; i++ ) {
00621       if ( sameInd [ i ] == 0 ) {
00622         if ( i < 3 ) i1 = i;
00623         else         i2 = i;
00624       }
00625       else if (i < 3) {
00626         if ( iA ) iB = i;
00627         else      iA = i;
00628       }
00629     }
00630     // nodes 1 and 2 should not be the same
00631     if ( aNodes[ i1 ] == aNodes[ i2 ] )
00632       return false;
00633 
00634     // theTria1: A->2
00635     aNodes[ iA ] = aNodes[ i2 ];
00636     // theTria2: B->1
00637     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
00638 
00639     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
00640     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
00641 
00642     return true;
00643 
00644   } // end if(F1 && F2)
00645 
00646   // check case of quadratic faces
00647   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
00648     return false;
00649   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
00650     return false;
00651 
00652   //       5
00653   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
00654   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
00655   //    |   / |
00656   //  7 +  +  + 6
00657   //    | /9  |
00658   //    |/    |
00659   //  4 +--+--+ 3
00660   //       8
00661 
00662   const SMDS_MeshNode* N1 [6];
00663   const SMDS_MeshNode* N2 [6];
00664   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
00665     return false;
00666   // now we receive following N1 and N2 (using numeration as above image)
00667   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
00668   // i.e. first nodes from both arrays determ new diagonal
00669 
00670   const SMDS_MeshNode* N1new [6];
00671   const SMDS_MeshNode* N2new [6];
00672   N1new[0] = N1[0];
00673   N1new[1] = N2[0];
00674   N1new[2] = N2[1];
00675   N1new[3] = N1[4];
00676   N1new[4] = N2[3];
00677   N1new[5] = N1[5];
00678   N2new[0] = N1[0];
00679   N2new[1] = N1[1];
00680   N2new[2] = N2[0];
00681   N2new[3] = N1[3];
00682   N2new[4] = N2[5];
00683   N2new[5] = N1[4];
00684   // replaces nodes in faces
00685   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
00686   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
00687 
00688   return true;
00689 }
00690 
00691 //=======================================================================
00692 //function : findTriangles
00693 //purpose  : find triangles sharing theNode1-theNode2 link
00694 //=======================================================================
00695 
00696 static bool findTriangles(const SMDS_MeshNode *    theNode1,
00697                           const SMDS_MeshNode *    theNode2,
00698                           const SMDS_MeshElement*& theTria1,
00699                           const SMDS_MeshElement*& theTria2)
00700 {
00701   if ( !theNode1 || !theNode2 ) return false;
00702 
00703   theTria1 = theTria2 = 0;
00704 
00705   set< const SMDS_MeshElement* > emap;
00706   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
00707   while (it->more()) {
00708     const SMDS_MeshElement* elem = it->next();
00709     if ( elem->NbNodes() == 3 )
00710       emap.insert( elem );
00711   }
00712   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
00713   while (it->more()) {
00714     const SMDS_MeshElement* elem = it->next();
00715     if ( emap.find( elem ) != emap.end() ) {
00716       if ( theTria1 ) {
00717         // theTria1 must be element with minimum ID
00718         if( theTria1->GetID() < elem->GetID() ) {
00719           theTria2 = elem;
00720         }
00721         else {
00722           theTria2 = theTria1;
00723           theTria1 = elem;
00724         }
00725         break;
00726       }
00727       else {
00728         theTria1 = elem;
00729       }
00730     }
00731   }
00732   return ( theTria1 && theTria2 );
00733 }
00734 
00735 //=======================================================================
00736 //function : InverseDiag
00737 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
00738 //           with ones built on the same 4 nodes but having other common link.
00739 //           Return false if proper faces not found
00740 //=======================================================================
00741 
00742 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
00743                                     const SMDS_MeshNode * theNode2)
00744 {
00745   myLastCreatedElems.Clear();
00746   myLastCreatedNodes.Clear();
00747 
00748   MESSAGE( "::InverseDiag()" );
00749 
00750   const SMDS_MeshElement *tr1, *tr2;
00751   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
00752     return false;
00753 
00754   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
00755   if (!F1) return false;
00756   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
00757   if (!F2) return false;
00758   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
00759       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
00760 
00761     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
00762     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
00763     //    |/ |                                    | \|
00764     //  B +--+ 2                                B +--+ 2
00765 
00766     // put nodes in array
00767     // and find indices of 1,2 and of A in tr1 and of B in tr2
00768     int i, iA1 = 0, i1 = 0;
00769     const SMDS_MeshNode* aNodes1 [3];
00770     SMDS_ElemIteratorPtr it;
00771     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
00772       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
00773       if ( aNodes1[ i ] == theNode1 )
00774         iA1 = i; // node A in tr1
00775       else if ( aNodes1[ i ] != theNode2 )
00776         i1 = i;  // node 1
00777     }
00778     int iB2 = 0, i2 = 0;
00779     const SMDS_MeshNode* aNodes2 [3];
00780     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
00781       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
00782       if ( aNodes2[ i ] == theNode2 )
00783         iB2 = i; // node B in tr2
00784       else if ( aNodes2[ i ] != theNode1 )
00785         i2 = i;  // node 2
00786     }
00787 
00788     // nodes 1 and 2 should not be the same
00789     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
00790       return false;
00791 
00792     // tr1: A->2
00793     aNodes1[ iA1 ] = aNodes2[ i2 ];
00794     // tr2: B->1
00795     aNodes2[ iB2 ] = aNodes1[ i1 ];
00796 
00797     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
00798     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
00799 
00800     return true;
00801   }
00802 
00803   // check case of quadratic faces
00804   return InverseDiag(tr1,tr2);
00805 }
00806 
00807 //=======================================================================
00808 //function : getQuadrangleNodes
00809 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
00810 //           fusion of triangles tr1 and tr2 having shared link on
00811 //           theNode1 and theNode2
00812 //=======================================================================
00813 
00814 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
00815                         const SMDS_MeshNode *    theNode1,
00816                         const SMDS_MeshNode *    theNode2,
00817                         const SMDS_MeshElement * tr1,
00818                         const SMDS_MeshElement * tr2 )
00819 {
00820   if( tr1->NbNodes() != tr2->NbNodes() )
00821     return false;
00822   // find the 4-th node to insert into tr1
00823   const SMDS_MeshNode* n4 = 0;
00824   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
00825   int i=0;
00826   while ( !n4 && i<3 ) {
00827     const SMDS_MeshNode * n = cast2Node( it->next() );
00828     i++;
00829     bool isDiag = ( n == theNode1 || n == theNode2 );
00830     if ( !isDiag )
00831       n4 = n;
00832   }
00833   // Make an array of nodes to be in a quadrangle
00834   int iNode = 0, iFirstDiag = -1;
00835   it = tr1->nodesIterator();
00836   i=0;
00837   while ( i<3 ) {
00838     const SMDS_MeshNode * n = cast2Node( it->next() );
00839     i++;
00840     bool isDiag = ( n == theNode1 || n == theNode2 );
00841     if ( isDiag ) {
00842       if ( iFirstDiag < 0 )
00843         iFirstDiag = iNode;
00844       else if ( iNode - iFirstDiag == 1 )
00845         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
00846     }
00847     else if ( n == n4 ) {
00848       return false; // tr1 and tr2 should not have all the same nodes
00849     }
00850     theQuadNodes[ iNode++ ] = n;
00851   }
00852   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
00853     theQuadNodes[ iNode ] = n4;
00854 
00855   return true;
00856 }
00857 
00858 //=======================================================================
00859 //function : DeleteDiag
00860 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
00861 //           with a quadrangle built on the same 4 nodes.
00862 //           Return false if proper faces not found
00863 //=======================================================================
00864 
00865 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
00866                                    const SMDS_MeshNode * theNode2)
00867 {
00868   myLastCreatedElems.Clear();
00869   myLastCreatedNodes.Clear();
00870 
00871   MESSAGE( "::DeleteDiag()" );
00872 
00873   const SMDS_MeshElement *tr1, *tr2;
00874   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
00875     return false;
00876 
00877   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
00878   if (!F1) return false;
00879   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
00880   if (!F2) return false;
00881   SMESHDS_Mesh * aMesh = GetMeshDS();
00882 
00883   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
00884       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
00885 
00886     const SMDS_MeshNode* aNodes [ 4 ];
00887     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
00888       return false;
00889 
00890     const SMDS_MeshElement* newElem = 0;
00891     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
00892     myLastCreatedElems.Append(newElem);
00893     AddToSameGroups( newElem, tr1, aMesh );
00894     int aShapeId = tr1->getshapeId();
00895     if ( aShapeId )
00896       {
00897         aMesh->SetMeshElementOnShape( newElem, aShapeId );
00898       }
00899     aMesh->RemoveElement( tr1 );
00900     aMesh->RemoveElement( tr2 );
00901 
00902     return true;
00903   }
00904 
00905   // check case of quadratic faces
00906   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
00907     return false;
00908   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
00909     return false;
00910 
00911   //       5
00912   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
00913   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
00914   //    |   / |
00915   //  7 +  +  + 6
00916   //    | /9  |
00917   //    |/    |
00918   //  4 +--+--+ 3
00919   //       8
00920 
00921   const SMDS_MeshNode* N1 [6];
00922   const SMDS_MeshNode* N2 [6];
00923   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
00924     return false;
00925   // now we receive following N1 and N2 (using numeration as above image)
00926   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
00927   // i.e. first nodes from both arrays determ new diagonal
00928 
00929   const SMDS_MeshNode* aNodes[8];
00930   aNodes[0] = N1[0];
00931   aNodes[1] = N1[1];
00932   aNodes[2] = N2[0];
00933   aNodes[3] = N2[1];
00934   aNodes[4] = N1[3];
00935   aNodes[5] = N2[5];
00936   aNodes[6] = N2[3];
00937   aNodes[7] = N1[5];
00938 
00939   const SMDS_MeshElement* newElem = 0;
00940   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
00941                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
00942   myLastCreatedElems.Append(newElem);
00943   AddToSameGroups( newElem, tr1, aMesh );
00944   int aShapeId = tr1->getshapeId();
00945   if ( aShapeId )
00946     {
00947       aMesh->SetMeshElementOnShape( newElem, aShapeId );
00948     }
00949   aMesh->RemoveElement( tr1 );
00950   aMesh->RemoveElement( tr2 );
00951 
00952   // remove middle node (9)
00953   GetMeshDS()->RemoveNode( N1[4] );
00954 
00955   return true;
00956 }
00957 
00958 //=======================================================================
00959 //function : Reorient
00960 //purpose  : Reverse theElement orientation
00961 //=======================================================================
00962 
00963 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
00964 {
00965   MESSAGE("Reorient");
00966   myLastCreatedElems.Clear();
00967   myLastCreatedNodes.Clear();
00968 
00969   if (!theElem)
00970     return false;
00971   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
00972   if ( !it || !it->more() )
00973     return false;
00974 
00975   switch ( theElem->GetType() ) {
00976 
00977   case SMDSAbs_Edge:
00978   case SMDSAbs_Face: {
00979     if(!theElem->IsQuadratic()) {
00980       int i = theElem->NbNodes();
00981       vector<const SMDS_MeshNode*> aNodes( i );
00982       while ( it->more() )
00983         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
00984       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
00985     }
00986     else {
00987       // quadratic elements
00988       if(theElem->GetType()==SMDSAbs_Edge) {
00989         vector<const SMDS_MeshNode*> aNodes(3);
00990         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
00991         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
00992         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
00993         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
00994       }
00995       else {
00996         int nbn = theElem->NbNodes();
00997         vector<const SMDS_MeshNode*> aNodes(nbn);
00998         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
00999         int i=1;
01000         for(; i<nbn/2; i++) {
01001           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
01002         }
01003         for(i=0; i<nbn/2; i++) {
01004           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
01005         }
01006         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
01007       }
01008     }
01009   }
01010   case SMDSAbs_Volume: {
01011     if (theElem->IsPoly()) {
01012       // TODO reorient vtk polyhedron
01013       MESSAGE("reorient vtk polyhedron ?");
01014       const SMDS_VtkVolume* aPolyedre =
01015         dynamic_cast<const SMDS_VtkVolume*>( theElem );
01016       if (!aPolyedre) {
01017         MESSAGE("Warning: bad volumic element");
01018         return false;
01019       }
01020 
01021       int nbFaces = aPolyedre->NbFaces();
01022       vector<const SMDS_MeshNode *> poly_nodes;
01023       vector<int> quantities (nbFaces);
01024 
01025       // reverse each face of the polyedre
01026       for (int iface = 1; iface <= nbFaces; iface++) {
01027         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
01028         quantities[iface - 1] = nbFaceNodes;
01029 
01030         for (inode = nbFaceNodes; inode >= 1; inode--) {
01031           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
01032           poly_nodes.push_back(curNode);
01033         }
01034       }
01035 
01036       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
01037 
01038     }
01039     else {
01040       SMDS_VolumeTool vTool;
01041       if ( !vTool.Set( theElem ))
01042         return false;
01043       vTool.Inverse();
01044       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
01045       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
01046     }
01047   }
01048   default:;
01049   }
01050 
01051   return false;
01052 }
01053 
01054 //=======================================================================
01055 //function : getBadRate
01056 //purpose  :
01057 //=======================================================================
01058 
01059 static double getBadRate (const SMDS_MeshElement*               theElem,
01060                           SMESH::Controls::NumericalFunctorPtr& theCrit)
01061 {
01062   SMESH::Controls::TSequenceOfXYZ P;
01063   if ( !theElem || !theCrit->GetPoints( theElem, P ))
01064     return 1e100;
01065   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
01066   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
01067 }
01068 
01069 //=======================================================================
01070 //function : QuadToTri
01071 //purpose  : Cut quadrangles into triangles.
01072 //           theCrit is used to select a diagonal to cut
01073 //=======================================================================
01074 
01075 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
01076                                   SMESH::Controls::NumericalFunctorPtr theCrit)
01077 {
01078   myLastCreatedElems.Clear();
01079   myLastCreatedNodes.Clear();
01080 
01081   MESSAGE( "::QuadToTri()" );
01082 
01083   if ( !theCrit.get() )
01084     return false;
01085 
01086   SMESHDS_Mesh * aMesh = GetMeshDS();
01087 
01088   Handle(Geom_Surface) surface;
01089   SMESH_MesherHelper   helper( *GetMesh() );
01090 
01091   TIDSortedElemSet::iterator itElem;
01092   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
01093     const SMDS_MeshElement* elem = *itElem;
01094     if ( !elem || elem->GetType() != SMDSAbs_Face )
01095       continue;
01096     if ( elem->NbCornerNodes() != 4 )
01097       continue;
01098 
01099     // retrieve element nodes
01100     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
01101 
01102     // compare two sets of possible triangles
01103     double aBadRate1, aBadRate2; // to what extent a set is bad
01104     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
01105     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
01106     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
01107 
01108     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
01109     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
01110     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
01111 
01112     int aShapeId = FindShape( elem );
01113     const SMDS_MeshElement* newElem1 = 0;
01114     const SMDS_MeshElement* newElem2 = 0;
01115 
01116     if( !elem->IsQuadratic() ) {
01117 
01118       // split liner quadrangle
01119 
01120       if ( aBadRate1 <= aBadRate2 ) {
01121         // tr1 + tr2 is better
01122         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
01123         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
01124       }
01125       else {
01126         // tr3 + tr4 is better
01127         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
01128         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
01129       }
01130     }
01131     else {
01132 
01133       // split quadratic quadrangle
01134 
01135       // get surface elem is on
01136       if ( aShapeId != helper.GetSubShapeID() ) {
01137         surface.Nullify();
01138         TopoDS_Shape shape;
01139         if ( aShapeId > 0 )
01140           shape = aMesh->IndexToShape( aShapeId );
01141         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
01142           TopoDS_Face face = TopoDS::Face( shape );
01143           surface = BRep_Tool::Surface( face );
01144           if ( !surface.IsNull() )
01145             helper.SetSubShape( shape );
01146         }
01147       }
01148       // find middle point for (0,1,2,3)
01149       // and create a node in this point;
01150       const SMDS_MeshNode* newN = 0;
01151       if ( aNodes.size() == 9 )
01152       {
01153         // SMDSEntity_BiQuad_Quadrangle
01154         newN = aNodes.back();
01155       }
01156       else
01157       {
01158         gp_XYZ p( 0,0,0 );
01159         if ( surface.IsNull() )
01160         {
01161           for ( int i = 0; i < 4; i++ )
01162             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
01163           p /= 4;
01164         }
01165         else
01166         {
01167           const SMDS_MeshNode* inFaceNode = 0;
01168           if ( helper.GetNodeUVneedInFaceNode() )
01169             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
01170               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
01171                 inFaceNode = aNodes[ i ];
01172 
01173           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
01174           gp_XY uv( 0,0 );
01175           for ( int i = 0; i < 4; i++ )
01176             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
01177           uv /= 4.;
01178           p = surface->Value( uv.X(), uv.Y() ).XYZ();
01179         }
01180         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
01181         myLastCreatedNodes.Append(newN);
01182       }
01183       // create a new element
01184       if ( aBadRate1 <= aBadRate2 ) {
01185         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
01186                                   aNodes[6], aNodes[7], newN );
01187         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
01188                                   newN,      aNodes[4], aNodes[5] );
01189       }
01190       else {
01191         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
01192                                   aNodes[7], aNodes[4], newN );
01193         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
01194                                   newN,      aNodes[5], aNodes[6] );
01195       }
01196     } // quadratic case
01197 
01198     // care of a new element
01199 
01200     myLastCreatedElems.Append(newElem1);
01201     myLastCreatedElems.Append(newElem2);
01202     AddToSameGroups( newElem1, elem, aMesh );
01203     AddToSameGroups( newElem2, elem, aMesh );
01204 
01205     // put a new triangle on the same shape
01206     if ( aShapeId )
01207       {
01208         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
01209         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
01210       }
01211     aMesh->RemoveElement( elem );
01212   }
01213   return true;
01214 }
01215 
01216 //=======================================================================
01217 //function : BestSplit
01218 //purpose  : Find better diagonal for cutting.
01219 //=======================================================================
01220 
01221 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
01222                                  SMESH::Controls::NumericalFunctorPtr theCrit)
01223 {
01224   myLastCreatedElems.Clear();
01225   myLastCreatedNodes.Clear();
01226 
01227   if (!theCrit.get())
01228     return -1;
01229 
01230   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
01231     return -1;
01232 
01233   if( theQuad->NbNodes()==4 ||
01234       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
01235 
01236     // retrieve element nodes
01237     const SMDS_MeshNode* aNodes [4];
01238     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
01239     int i = 0;
01240     //while (itN->more())
01241     while (i<4) {
01242       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
01243     }
01244     // compare two sets of possible triangles
01245     double aBadRate1, aBadRate2; // to what extent a set is bad
01246     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
01247     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
01248     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
01249 
01250     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
01251     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
01252     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
01253 
01254     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
01255       return 1; // diagonal 1-3
01256 
01257     return 2; // diagonal 2-4
01258   }
01259   return -1;
01260 }
01261 
01262 namespace
01263 {
01264   // Methods of splitting volumes into tetra
01265 
01266   const int theHexTo5_1[5*4+1] =
01267     {
01268       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
01269     };
01270   const int theHexTo5_2[5*4+1] =
01271     {
01272       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
01273     };
01274   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
01275 
01276   const int theHexTo6_1[6*4+1] =
01277     {
01278       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
01279     };
01280   const int theHexTo6_2[6*4+1] =
01281     {
01282       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
01283     };
01284   const int theHexTo6_3[6*4+1] =
01285     {
01286       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
01287     };
01288   const int theHexTo6_4[6*4+1] =
01289     {
01290       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
01291     };
01292   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
01293 
01294   const int thePyraTo2_1[2*4+1] =
01295     {
01296       0, 1, 2, 4,    0, 2, 3, 4,   -1
01297     };
01298   const int thePyraTo2_2[2*4+1] =
01299     {
01300       1, 2, 3, 4,    1, 3, 0, 4,   -1
01301     };
01302   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
01303 
01304   const int thePentaTo3_1[3*4+1] =
01305     {
01306       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
01307     };
01308   const int thePentaTo3_2[3*4+1] =
01309     {
01310       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
01311     };
01312   const int thePentaTo3_3[3*4+1] =
01313     {
01314       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
01315     };
01316   const int thePentaTo3_4[3*4+1] =
01317     {
01318       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
01319     };
01320   const int thePentaTo3_5[3*4+1] =
01321     {
01322       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
01323     };
01324   const int thePentaTo3_6[3*4+1] =
01325     {
01326       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
01327     };
01328   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
01329                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
01330 
01331   struct TTriangleFacet 
01332   {
01333     int _n1, _n2, _n3;
01334     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
01335     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
01336     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
01337   };
01338   struct TSplitMethod
01339   {
01340     int        _nbTetra;
01341     const int* _connectivity; 
01342     bool       _baryNode;     
01343     bool       _ownConn;      
01344     map<int, const SMDS_MeshNode*> _faceBaryNode; 
01345 
01346     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
01347       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
01348     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
01349     bool hasFacet( const TTriangleFacet& facet ) const
01350     {
01351       const int* tetConn = _connectivity;
01352       for ( ; tetConn[0] >= 0; tetConn += 4 )
01353         if (( facet.contains( tetConn[0] ) +
01354               facet.contains( tetConn[1] ) +
01355               facet.contains( tetConn[2] ) +
01356               facet.contains( tetConn[3] )) == 3 )
01357           return true;
01358       return false;
01359     }
01360   };
01361 
01362   //=======================================================================
01366   //=======================================================================
01367 
01368   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
01369   {
01370     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
01371 
01372     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
01373     // an edge and a face barycenter; tertaherdons are based on triangles and
01374     // a volume barycenter
01375     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
01376 
01377     // Find out how adjacent volumes are split
01378 
01379     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
01380     int hasAdjacentSplits = 0, maxTetConnSize = 0;
01381     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
01382     {
01383       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
01384       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
01385       if ( nbNodes < 4 ) continue;
01386 
01387       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
01388       const int* nInd = vol.GetFaceNodesIndices( iF );
01389       if ( nbNodes == 4 )
01390       {
01391         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
01392         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
01393         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
01394         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
01395       }
01396       else
01397       {
01398         int iCom = 0; // common node of triangle faces to split into
01399         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
01400         {
01401           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
01402                                nInd[ iQ * ( (iCom+1)%nbNodes )],
01403                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
01404           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
01405                                nInd[ iQ * ( (iCom+2)%nbNodes )],
01406                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
01407           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
01408           {
01409             triaSplits.push_back( t012 );
01410             triaSplits.push_back( t023 );
01411             break;
01412           }
01413         }
01414       }
01415       if ( !triaSplits.empty() )
01416         hasAdjacentSplits = true;
01417     }
01418 
01419     // Among variants of split method select one compliant with adjacent volumes
01420 
01421     TSplitMethod method;
01422     if ( !vol.Element()->IsPoly() && !is24TetMode )
01423     {
01424       int nbVariants = 2, nbTet = 0;
01425       const int** connVariants = 0;
01426       switch ( vol.Element()->GetEntityType() )
01427       {
01428       case SMDSEntity_Hexa:
01429       case SMDSEntity_Quad_Hexa:
01430       case SMDSEntity_TriQuad_Hexa:
01431         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
01432           connVariants = theHexTo5, nbTet = 5;
01433         else
01434           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
01435         break;
01436       case SMDSEntity_Pyramid:
01437       case SMDSEntity_Quad_Pyramid:
01438         connVariants = thePyraTo2;  nbTet = 2;
01439         break;
01440       case SMDSEntity_Penta:
01441       case SMDSEntity_Quad_Penta:
01442         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
01443         break;
01444       default:
01445         nbVariants = 0;
01446       }
01447       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
01448       {
01449         // check method compliancy with adjacent tetras,
01450         // all found splits must be among facets of tetras described by this method
01451         method = TSplitMethod( nbTet, connVariants[variant] );
01452         if ( hasAdjacentSplits && method._nbTetra > 0 )
01453         {
01454           bool facetCreated = true;
01455           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
01456           {
01457             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
01458             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
01459               facetCreated = method.hasFacet( *facet );
01460           }
01461           if ( !facetCreated )
01462             method = TSplitMethod(0); // incompatible method
01463         }
01464       }
01465     }
01466     if ( method._nbTetra < 1 )
01467     {
01468       // No standard method is applicable, use a generic solution:
01469       // each facet of a volume is split into triangles and
01470       // each of triangles and a volume barycenter form a tetrahedron.
01471 
01472       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
01473 
01474       int* connectivity = new int[ maxTetConnSize + 1 ];
01475       method._connectivity = connectivity;
01476       method._ownConn = true;
01477       method._baryNode = !isHex27; // to create central node or not
01478 
01479       int connSize = 0;
01480       int baryCenInd = vol.NbNodes() - int( isHex27 );
01481       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
01482       {
01483         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
01484         const int*   nInd = vol.GetFaceNodesIndices( iF );
01485         // find common node of triangle facets of tetra to create
01486         int iCommon = 0; // index in linear numeration
01487         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
01488         if ( !triaSplits.empty() )
01489         {
01490           // by found facets
01491           const TTriangleFacet* facet = &triaSplits.front();
01492           for ( ; iCommon < nbNodes-1 ; ++iCommon )
01493             if ( facet->contains( nInd[ iQ * iCommon ]) &&
01494                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
01495               break;
01496         }
01497         else if ( nbNodes > 3 && !is24TetMode )
01498         {
01499           // find the best method of splitting into triangles by aspect ratio
01500           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
01501           map< double, int > badness2iCommon;
01502           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
01503           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
01504           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
01505           {
01506             double badness = 0;
01507             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
01508             {
01509               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
01510                                       nodes[ iQ*((iLast-1)%nbNodes)],
01511                                       nodes[ iQ*((iLast  )%nbNodes)]);
01512               badness += getBadRate( &tria, aspectRatio );
01513             }
01514             badness2iCommon.insert( make_pair( badness, iCommon ));
01515           }
01516           // use iCommon with lowest badness
01517           iCommon = badness2iCommon.begin()->second;
01518         }
01519         if ( iCommon >= nbNodes )
01520           iCommon = 0; // something wrong
01521 
01522         // fill connectivity of tetrahedra based on a current face
01523         int nbTet = nbNodes - 2;
01524         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
01525         {
01526           int faceBaryCenInd;
01527           if ( isHex27 )
01528           {
01529             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
01530             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
01531           }
01532           else
01533           {
01534             method._faceBaryNode[ iF ] = 0;
01535             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
01536           }
01537           nbTet = nbNodes;
01538           for ( int i = 0; i < nbTet; ++i )
01539           {
01540             int i1 = i, i2 = (i+1) % nbNodes;
01541             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
01542             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
01543             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
01544             connectivity[ connSize++ ] = faceBaryCenInd;
01545             connectivity[ connSize++ ] = baryCenInd;
01546           }
01547         }
01548         else
01549         {
01550           for ( int i = 0; i < nbTet; ++i )
01551           {
01552             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
01553             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
01554             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
01555             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
01556             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
01557             connectivity[ connSize++ ] = baryCenInd;
01558           }
01559         }
01560         method._nbTetra += nbTet;
01561 
01562       } // loop on volume faces
01563 
01564       connectivity[ connSize++ ] = -1;
01565 
01566     } // end of generic solution
01567 
01568     return method;
01569   }
01570   //================================================================================
01574   //================================================================================
01575 
01576   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
01577   {
01578     // find the tetrahedron including the three nodes of facet
01579     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
01580     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
01581     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
01582     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
01583     while ( volIt1->more() )
01584     {
01585       const SMDS_MeshElement* v = volIt1->next();
01586       SMDSAbs_EntityType type = v->GetEntityType();
01587       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
01588         continue;
01589       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
01590         continue; // medium node not allowed
01591       const int ind2 = v->GetNodeIndex( n2 );
01592       if ( ind2 < 0 || 3 < ind2 )
01593         continue;
01594       const int ind3 = v->GetNodeIndex( n3 );
01595       if ( ind3 < 0 || 3 < ind3 )
01596         continue;
01597       return true;
01598     }
01599     return false;
01600   }
01601 
01602   //=======================================================================
01606   //=======================================================================
01607 
01608   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
01609   {
01610     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
01611     {
01612       TIDSortedNodeSet sortedNodes;
01613       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
01614       int nbNodes = vol.NbFaceNodes( iF );
01615       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
01616       for ( int i = 0; i < nbNodes; i += iQ )
01617         sortedNodes.insert( fNodes[i] );
01618       TIDSortedNodeSet::iterator n = sortedNodes.begin();
01619       first.first   = (*(n++))->GetID();
01620       first.second  = (*(n++))->GetID();
01621       second.first  = (*(n++))->GetID();
01622       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
01623     }
01624   };
01625 } // namespace
01626 
01627 //=======================================================================
01628 //function : SplitVolumesIntoTetra
01629 //purpose  : Split volume elements into tetrahedra.
01630 //=======================================================================
01631 
01632 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
01633                                               const int                theMethodFlags)
01634 {
01635   // std-like iterator on coordinates of nodes of mesh element
01636   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
01637   NXyzIterator xyzEnd;
01638 
01639   SMDS_VolumeTool    volTool;
01640   SMESH_MesherHelper helper( *GetMesh());
01641 
01642   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
01643   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
01644   
01645   SMESH_SequenceOfElemPtr newNodes, newElems;
01646 
01647   // map face of volume to it's baricenrtic node
01648   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
01649   double bc[3];
01650 
01651   TIDSortedElemSet::const_iterator elem = theElems.begin();
01652   for ( ; elem != theElems.end(); ++elem )
01653   {
01654     if ( (*elem)->GetType() != SMDSAbs_Volume )
01655       continue;
01656     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
01657     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
01658       continue;
01659 
01660     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
01661 
01662     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
01663     if ( splitMethod._nbTetra < 1 ) continue;
01664 
01665     // find submesh to add new tetras to
01666     if ( !subMesh || !subMesh->Contains( *elem ))
01667     {
01668       int shapeID = FindShape( *elem );
01669       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
01670       subMesh = GetMeshDS()->MeshElements( shapeID );
01671     }
01672     int iQ;
01673     if ( (*elem)->IsQuadratic() )
01674     {
01675       iQ = 2;
01676       // add quadratic links to the helper
01677       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
01678       {
01679         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
01680         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
01681         for ( int iN = 0; iN < nbN; iN += iQ )
01682           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
01683       }
01684       helper.SetIsQuadratic( true );
01685     }
01686     else
01687     {
01688       iQ = 1;
01689       helper.SetIsQuadratic( false );
01690     }
01691     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
01692     helper.SetElementsOnShape( true );
01693     if ( splitMethod._baryNode )
01694     {
01695       // make a node at barycenter
01696       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
01697       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
01698       nodes.push_back( gcNode );
01699       newNodes.Append( gcNode );
01700     }
01701     if ( !splitMethod._faceBaryNode.empty() )
01702     {
01703       // make or find baricentric nodes of faces
01704       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
01705       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
01706       {
01707         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
01708           volFace2BaryNode.insert
01709           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
01710         if ( !f_n->second )
01711         {
01712           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
01713           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
01714         }
01715         nodes.push_back( iF_n->second = f_n->second );
01716       }
01717     }
01718 
01719     // make tetras
01720     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
01721     const int* tetConn = splitMethod._connectivity;
01722     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
01723       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
01724                                                        nodes[ tetConn[1] ],
01725                                                        nodes[ tetConn[2] ],
01726                                                        nodes[ tetConn[3] ]));
01727 
01728     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
01729 
01730     // Split faces on sides of the split volume
01731 
01732     const SMDS_MeshNode** volNodes = volTool.GetNodes();
01733     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
01734     {
01735       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
01736       if ( nbNodes < 4 ) continue;
01737 
01738       // find an existing face
01739       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
01740                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
01741       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
01742                                                                        /*noMedium=*/false))
01743       {
01744         // make triangles
01745         helper.SetElementsOnShape( false );
01746         vector< const SMDS_MeshElement* > triangles;
01747 
01748         // find submesh to add new triangles in
01749         if ( !fSubMesh || !fSubMesh->Contains( face ))
01750         {
01751           int shapeID = FindShape( face );
01752           fSubMesh = GetMeshDS()->MeshElements( shapeID );
01753         }
01754         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
01755         if ( iF_n != splitMethod._faceBaryNode.end() )
01756         {
01757           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
01758           {
01759             const SMDS_MeshNode* n1 = fNodes[iN];
01760             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
01761             const SMDS_MeshNode *n3 = iF_n->second;
01762             if ( !volTool.IsFaceExternal( iF ))
01763               swap( n2, n3 );
01764             triangles.push_back( helper.AddFace( n1,n2,n3 ));
01765 
01766             if ( fSubMesh && n3->getshapeId() < 1 )
01767               fSubMesh->AddNode( n3 );
01768           }
01769         }
01770         else
01771         {
01772           // among possible triangles create ones discribed by split method
01773           const int* nInd = volTool.GetFaceNodesIndices( iF );
01774           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
01775           int iCom = 0; // common node of triangle faces to split into
01776           list< TTriangleFacet > facets;
01777           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
01778           {
01779             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
01780                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
01781                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
01782             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
01783                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
01784                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
01785             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
01786             {
01787               facets.push_back( t012 );
01788               facets.push_back( t023 );
01789               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
01790                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
01791                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
01792                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
01793               break;
01794             }
01795           }
01796           list< TTriangleFacet >::iterator facet = facets.begin();
01797           for ( ; facet != facets.end(); ++facet )
01798           {
01799             if ( !volTool.IsFaceExternal( iF ))
01800               swap( facet->_n2, facet->_n3 );
01801             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
01802                                                  volNodes[ facet->_n2 ],
01803                                                  volNodes[ facet->_n3 ]));
01804           }
01805         }
01806         for ( int i = 0; i < triangles.size(); ++i )
01807         {
01808           if ( !triangles[i] ) continue;
01809           if ( fSubMesh )
01810             fSubMesh->AddElement( triangles[i]);
01811           newElems.Append( triangles[i] );
01812         }
01813         ReplaceElemInGroups( face, triangles, GetMeshDS() );
01814         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
01815       }
01816 
01817     } // loop on volume faces to split them into triangles
01818 
01819     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
01820 
01821     if ( geomType == SMDSEntity_TriQuad_Hexa )
01822     {
01823       // remove medium nodes that could become free
01824       for ( int i = 20; i < volTool.NbNodes(); ++i )
01825         if ( volNodes[i]->NbInverseElements() == 0 )
01826           GetMeshDS()->RemoveNode( volNodes[i] );
01827     }
01828   } // loop on volumes to split
01829 
01830   myLastCreatedNodes = newNodes;
01831   myLastCreatedElems = newElems;
01832 }
01833 
01834 //=======================================================================
01835 //function : AddToSameGroups
01836 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
01837 //=======================================================================
01838 
01839 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
01840                                         const SMDS_MeshElement* elemInGroups,
01841                                         SMESHDS_Mesh *          aMesh)
01842 {
01843   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
01844   if (!groups.empty()) {
01845     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
01846     for ( ; grIt != groups.end(); grIt++ ) {
01847       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
01848       if ( group && group->Contains( elemInGroups ))
01849         group->SMDSGroup().Add( elemToAdd );
01850     }
01851   }
01852 }
01853 
01854 
01855 //=======================================================================
01856 //function : RemoveElemFromGroups
01857 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
01858 //=======================================================================
01859 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
01860                                              SMESHDS_Mesh *          aMesh)
01861 {
01862   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
01863   if (!groups.empty())
01864   {
01865     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
01866     for (; GrIt != groups.end(); GrIt++)
01867     {
01868       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
01869       if (!grp || grp->IsEmpty()) continue;
01870       grp->SMDSGroup().Remove(removeelem);
01871     }
01872   }
01873 }
01874 
01875 //================================================================================
01879 //================================================================================
01880 
01881 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
01882                                             const SMDS_MeshElement* elemToAdd,
01883                                             SMESHDS_Mesh *          aMesh)
01884 {
01885   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
01886   if (!groups.empty()) {
01887     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
01888     for ( ; grIt != groups.end(); grIt++ ) {
01889       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
01890       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
01891         group->SMDSGroup().Add( elemToAdd );
01892     }
01893   }
01894 }
01895 
01896 //================================================================================
01900 //================================================================================
01901 
01902 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
01903                                             const vector<const SMDS_MeshElement*>& elemToAdd,
01904                                             SMESHDS_Mesh *                         aMesh)
01905 {
01906   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
01907   if (!groups.empty())
01908   {
01909     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
01910     for ( ; grIt != groups.end(); grIt++ ) {
01911       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
01912       if ( group && group->SMDSGroup().Remove( elemToRm ) )
01913         for ( int i = 0; i < elemToAdd.size(); ++i )
01914           group->SMDSGroup().Add( elemToAdd[ i ] );
01915     }
01916   }
01917 }
01918 
01919 //=======================================================================
01920 //function : QuadToTri
01921 //purpose  : Cut quadrangles into triangles.
01922 //           theCrit is used to select a diagonal to cut
01923 //=======================================================================
01924 
01925 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
01926                                   const bool         the13Diag)
01927 {
01928   myLastCreatedElems.Clear();
01929   myLastCreatedNodes.Clear();
01930 
01931   MESSAGE( "::QuadToTri()" );
01932 
01933   SMESHDS_Mesh * aMesh = GetMeshDS();
01934 
01935   Handle(Geom_Surface) surface;
01936   SMESH_MesherHelper   helper( *GetMesh() );
01937 
01938   TIDSortedElemSet::iterator itElem;
01939   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
01940     const SMDS_MeshElement* elem = *itElem;
01941     if ( !elem || elem->GetType() != SMDSAbs_Face )
01942       continue;
01943     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
01944     if(!isquad) continue;
01945 
01946     if(elem->NbNodes()==4) {
01947       // retrieve element nodes
01948       const SMDS_MeshNode* aNodes [4];
01949       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
01950       int i = 0;
01951       while ( itN->more() )
01952         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
01953 
01954       int aShapeId = FindShape( elem );
01955       const SMDS_MeshElement* newElem1 = 0;
01956       const SMDS_MeshElement* newElem2 = 0;
01957       if ( the13Diag ) {
01958         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
01959         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
01960       }
01961       else {
01962         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
01963         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
01964       }
01965       myLastCreatedElems.Append(newElem1);
01966       myLastCreatedElems.Append(newElem2);
01967       // put a new triangle on the same shape and add to the same groups
01968       if ( aShapeId )
01969         {
01970           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
01971           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
01972         }
01973       AddToSameGroups( newElem1, elem, aMesh );
01974       AddToSameGroups( newElem2, elem, aMesh );
01975       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
01976       aMesh->RemoveElement( elem );
01977     }
01978 
01979     // Quadratic quadrangle
01980 
01981     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
01982 
01983       // get surface elem is on
01984       int aShapeId = FindShape( elem );
01985       if ( aShapeId != helper.GetSubShapeID() ) {
01986         surface.Nullify();
01987         TopoDS_Shape shape;
01988         if ( aShapeId > 0 )
01989           shape = aMesh->IndexToShape( aShapeId );
01990         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
01991           TopoDS_Face face = TopoDS::Face( shape );
01992           surface = BRep_Tool::Surface( face );
01993           if ( !surface.IsNull() )
01994             helper.SetSubShape( shape );
01995         }
01996       }
01997 
01998       const SMDS_MeshNode* aNodes [8];
01999       const SMDS_MeshNode* inFaceNode = 0;
02000       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
02001       int i = 0;
02002       while ( itN->more() ) {
02003         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
02004         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
02005              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
02006         {
02007           inFaceNode = aNodes[ i-1 ];
02008         }
02009       }
02010 
02011       // find middle point for (0,1,2,3)
02012       // and create a node in this point;
02013       gp_XYZ p( 0,0,0 );
02014       if ( surface.IsNull() ) {
02015         for(i=0; i<4; i++)
02016           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
02017         p /= 4;
02018       }
02019       else {
02020         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
02021         gp_XY uv( 0,0 );
02022         for(i=0; i<4; i++)
02023           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
02024         uv /= 4.;
02025         p = surface->Value( uv.X(), uv.Y() ).XYZ();
02026       }
02027       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
02028       myLastCreatedNodes.Append(newN);
02029 
02030       // create a new element
02031       const SMDS_MeshElement* newElem1 = 0;
02032       const SMDS_MeshElement* newElem2 = 0;
02033       if ( the13Diag ) {
02034         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
02035                                   aNodes[6], aNodes[7], newN );
02036         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
02037                                   newN,      aNodes[4], aNodes[5] );
02038       }
02039       else {
02040         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
02041                                   aNodes[7], aNodes[4], newN );
02042         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
02043                                   newN,      aNodes[5], aNodes[6] );
02044       }
02045       myLastCreatedElems.Append(newElem1);
02046       myLastCreatedElems.Append(newElem2);
02047       // put a new triangle on the same shape and add to the same groups
02048       if ( aShapeId )
02049         {
02050           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
02051           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
02052         }
02053       AddToSameGroups( newElem1, elem, aMesh );
02054       AddToSameGroups( newElem2, elem, aMesh );
02055       aMesh->RemoveElement( elem );
02056     }
02057   }
02058 
02059   return true;
02060 }
02061 
02062 //=======================================================================
02063 //function : getAngle
02064 //purpose  :
02065 //=======================================================================
02066 
02067 double getAngle(const SMDS_MeshElement * tr1,
02068                 const SMDS_MeshElement * tr2,
02069                 const SMDS_MeshNode *    n1,
02070                 const SMDS_MeshNode *    n2)
02071 {
02072   double angle = 2. * M_PI; // bad angle
02073 
02074   // get normals
02075   SMESH::Controls::TSequenceOfXYZ P1, P2;
02076   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
02077        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
02078     return angle;
02079   gp_Vec N1,N2;
02080   if(!tr1->IsQuadratic())
02081     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
02082   else
02083     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
02084   if ( N1.SquareMagnitude() <= gp::Resolution() )
02085     return angle;
02086   if(!tr2->IsQuadratic())
02087     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
02088   else
02089     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
02090   if ( N2.SquareMagnitude() <= gp::Resolution() )
02091     return angle;
02092 
02093   // find the first diagonal node n1 in the triangles:
02094   // take in account a diagonal link orientation
02095   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
02096   for ( int t = 0; t < 2; t++ ) {
02097     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
02098     int i = 0, iDiag = -1;
02099     while ( it->more()) {
02100       const SMDS_MeshElement *n = it->next();
02101       if ( n == n1 || n == n2 ) {
02102         if ( iDiag < 0)
02103           iDiag = i;
02104         else {
02105           if ( i - iDiag == 1 )
02106             nFirst[ t ] = ( n == n1 ? n2 : n1 );
02107           else
02108             nFirst[ t ] = n;
02109           break;
02110         }
02111       }
02112       i++;
02113     }
02114   }
02115   if ( nFirst[ 0 ] == nFirst[ 1 ] )
02116     N2.Reverse();
02117 
02118   angle = N1.Angle( N2 );
02119   //SCRUTE( angle );
02120   return angle;
02121 }
02122 
02123 // =================================================
02124 // class generating a unique ID for a pair of nodes
02125 // and able to return nodes by that ID
02126 // =================================================
02127 class LinkID_Gen {
02128 public:
02129 
02130   LinkID_Gen( const SMESHDS_Mesh* theMesh )
02131     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
02132   {}
02133 
02134   long GetLinkID (const SMDS_MeshNode * n1,
02135                   const SMDS_MeshNode * n2) const
02136   {
02137     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
02138   }
02139 
02140   bool GetNodes (const long             theLinkID,
02141                  const SMDS_MeshNode* & theNode1,
02142                  const SMDS_MeshNode* & theNode2) const
02143   {
02144     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
02145     if ( !theNode1 ) return false;
02146     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
02147     if ( !theNode2 ) return false;
02148     return true;
02149   }
02150 
02151 private:
02152   LinkID_Gen();
02153   const SMESHDS_Mesh* myMesh;
02154   long                myMaxID;
02155 };
02156 
02157 
02158 //=======================================================================
02159 //function : TriToQuad
02160 //purpose  : Fuse neighbour triangles into quadrangles.
02161 //           theCrit is used to select a neighbour to fuse with.
02162 //           theMaxAngle is a max angle between element normals at which
02163 //           fusion is still performed.
02164 //=======================================================================
02165 
02166 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
02167                                   SMESH::Controls::NumericalFunctorPtr theCrit,
02168                                   const double                         theMaxAngle)
02169 {
02170   myLastCreatedElems.Clear();
02171   myLastCreatedNodes.Clear();
02172 
02173   MESSAGE( "::TriToQuad()" );
02174 
02175   if ( !theCrit.get() )
02176     return false;
02177 
02178   SMESHDS_Mesh * aMesh = GetMeshDS();
02179 
02180   // Prepare data for algo: build
02181   // 1. map of elements with their linkIDs
02182   // 2. map of linkIDs with their elements
02183 
02184   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
02185   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
02186   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
02187   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
02188 
02189   TIDSortedElemSet::iterator itElem;
02190   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
02191     const SMDS_MeshElement* elem = *itElem;
02192     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
02193     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
02194     if(!IsTria) continue;
02195 
02196     // retrieve element nodes
02197     const SMDS_MeshNode* aNodes [4];
02198     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
02199     int i = 0;
02200     while ( i<3 )
02201       aNodes[ i++ ] = cast2Node( itN->next() );
02202     aNodes[ 3 ] = aNodes[ 0 ];
02203 
02204     // fill maps
02205     for ( i = 0; i < 3; i++ ) {
02206       SMESH_TLink link( aNodes[i], aNodes[i+1] );
02207       // check if elements sharing a link can be fused
02208       itLE = mapLi_listEl.find( link );
02209       if ( itLE != mapLi_listEl.end() ) {
02210         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
02211           continue;
02212         const SMDS_MeshElement* elem2 = (*itLE).second.front();
02213         //if ( FindShape( elem ) != FindShape( elem2 ))
02214         //  continue; // do not fuse triangles laying on different shapes
02215         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
02216           continue; // avoid making badly shaped quads
02217         (*itLE).second.push_back( elem );
02218       }
02219       else {
02220         mapLi_listEl[ link ].push_back( elem );
02221       }
02222       mapEl_setLi [ elem ].insert( link );
02223     }
02224   }
02225   // Clean the maps from the links shared by a sole element, ie
02226   // links to which only one element is bound in mapLi_listEl
02227 
02228   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
02229     int nbElems = (*itLE).second.size();
02230     if ( nbElems < 2  ) {
02231       const SMDS_MeshElement* elem = (*itLE).second.front();
02232       SMESH_TLink link = (*itLE).first;
02233       mapEl_setLi[ elem ].erase( link );
02234       if ( mapEl_setLi[ elem ].empty() )
02235         mapEl_setLi.erase( elem );
02236     }
02237   }
02238 
02239   // Algo: fuse triangles into quadrangles
02240 
02241   while ( ! mapEl_setLi.empty() ) {
02242     // Look for the start element:
02243     // the element having the least nb of shared links
02244     const SMDS_MeshElement* startElem = 0;
02245     int minNbLinks = 4;
02246     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
02247       int nbLinks = (*itEL).second.size();
02248       if ( nbLinks < minNbLinks ) {
02249         startElem = (*itEL).first;
02250         minNbLinks = nbLinks;
02251         if ( minNbLinks == 1 )
02252           break;
02253       }
02254     }
02255 
02256     // search elements to fuse starting from startElem or links of elements
02257     // fused earlyer - startLinks
02258     list< SMESH_TLink > startLinks;
02259     while ( startElem || !startLinks.empty() ) {
02260       while ( !startElem && !startLinks.empty() ) {
02261         // Get an element to start, by a link
02262         SMESH_TLink linkId = startLinks.front();
02263         startLinks.pop_front();
02264         itLE = mapLi_listEl.find( linkId );
02265         if ( itLE != mapLi_listEl.end() ) {
02266           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
02267           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
02268           for ( ; itE != listElem.end() ; itE++ )
02269             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
02270               startElem = (*itE);
02271           mapLi_listEl.erase( itLE );
02272         }
02273       }
02274 
02275       if ( startElem ) {
02276         // Get candidates to be fused
02277         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
02278         const SMESH_TLink *link12, *link13;
02279         startElem = 0;
02280         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
02281         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
02282         ASSERT( !setLi.empty() );
02283         set< SMESH_TLink >::iterator itLi;
02284         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
02285         {
02286           const SMESH_TLink & link = (*itLi);
02287           itLE = mapLi_listEl.find( link );
02288           if ( itLE == mapLi_listEl.end() )
02289             continue;
02290 
02291           const SMDS_MeshElement* elem = (*itLE).second.front();
02292           if ( elem == tr1 )
02293             elem = (*itLE).second.back();
02294           mapLi_listEl.erase( itLE );
02295           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
02296             continue;
02297           if ( tr2 ) {
02298             tr3 = elem;
02299             link13 = &link;
02300           }
02301           else {
02302             tr2 = elem;
02303             link12 = &link;
02304           }
02305 
02306           // add other links of elem to list of links to re-start from
02307           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
02308           set< SMESH_TLink >::iterator it;
02309           for ( it = links.begin(); it != links.end(); it++ ) {
02310             const SMESH_TLink& link2 = (*it);
02311             if ( link2 != link )
02312               startLinks.push_back( link2 );
02313           }
02314         }
02315 
02316         // Get nodes of possible quadrangles
02317         const SMDS_MeshNode *n12 [4], *n13 [4];
02318         bool Ok12 = false, Ok13 = false;
02319         const SMDS_MeshNode *linkNode1, *linkNode2;
02320         if(tr2) {
02321           linkNode1 = link12->first;
02322           linkNode2 = link12->second;
02323           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
02324             Ok12 = true;
02325         }
02326         if(tr3) {
02327           linkNode1 = link13->first;
02328           linkNode2 = link13->second;
02329           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
02330             Ok13 = true;
02331         }
02332 
02333         // Choose a pair to fuse
02334         if ( Ok12 && Ok13 ) {
02335           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
02336           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
02337           double aBadRate12 = getBadRate( &quad12, theCrit );
02338           double aBadRate13 = getBadRate( &quad13, theCrit );
02339           if (  aBadRate13 < aBadRate12 )
02340             Ok12 = false;
02341           else
02342             Ok13 = false;
02343         }
02344 
02345         // Make quadrangles
02346         // and remove fused elems and removed links from the maps
02347         mapEl_setLi.erase( tr1 );
02348         if ( Ok12 ) {
02349           mapEl_setLi.erase( tr2 );
02350           mapLi_listEl.erase( *link12 );
02351           if(tr1->NbNodes()==3) {
02352             const SMDS_MeshElement* newElem = 0;
02353             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
02354             myLastCreatedElems.Append(newElem);
02355             AddToSameGroups( newElem, tr1, aMesh );
02356             int aShapeId = tr1->getshapeId();
02357             if ( aShapeId )
02358               {
02359                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
02360               }
02361             aMesh->RemoveElement( tr1 );
02362             aMesh->RemoveElement( tr2 );
02363           }
02364           else {
02365             const SMDS_MeshNode* N1 [6];
02366             const SMDS_MeshNode* N2 [6];
02367             GetNodesFromTwoTria(tr1,tr2,N1,N2);
02368             // now we receive following N1 and N2 (using numeration as above image)
02369             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
02370             // i.e. first nodes from both arrays determ new diagonal
02371             const SMDS_MeshNode* aNodes[8];
02372             aNodes[0] = N1[0];
02373             aNodes[1] = N1[1];
02374             aNodes[2] = N2[0];
02375             aNodes[3] = N2[1];
02376             aNodes[4] = N1[3];
02377             aNodes[5] = N2[5];
02378             aNodes[6] = N2[3];
02379             aNodes[7] = N1[5];
02380             const SMDS_MeshElement* newElem = 0;
02381             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
02382                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
02383             myLastCreatedElems.Append(newElem);
02384             AddToSameGroups( newElem, tr1, aMesh );
02385             int aShapeId = tr1->getshapeId();
02386             if ( aShapeId )
02387               {
02388                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
02389               }
02390             aMesh->RemoveElement( tr1 );
02391             aMesh->RemoveElement( tr2 );
02392             // remove middle node (9)
02393             GetMeshDS()->RemoveNode( N1[4] );
02394           }
02395         }
02396         else if ( Ok13 ) {
02397           mapEl_setLi.erase( tr3 );
02398           mapLi_listEl.erase( *link13 );
02399           if(tr1->NbNodes()==3) {
02400             const SMDS_MeshElement* newElem = 0;
02401             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
02402             myLastCreatedElems.Append(newElem);
02403             AddToSameGroups( newElem, tr1, aMesh );
02404             int aShapeId = tr1->getshapeId();
02405             if ( aShapeId )
02406               {
02407                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
02408               }
02409             aMesh->RemoveElement( tr1 );
02410             aMesh->RemoveElement( tr3 );
02411           }
02412           else {
02413             const SMDS_MeshNode* N1 [6];
02414             const SMDS_MeshNode* N2 [6];
02415             GetNodesFromTwoTria(tr1,tr3,N1,N2);
02416             // now we receive following N1 and N2 (using numeration as above image)
02417             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
02418             // i.e. first nodes from both arrays determ new diagonal
02419             const SMDS_MeshNode* aNodes[8];
02420             aNodes[0] = N1[0];
02421             aNodes[1] = N1[1];
02422             aNodes[2] = N2[0];
02423             aNodes[3] = N2[1];
02424             aNodes[4] = N1[3];
02425             aNodes[5] = N2[5];
02426             aNodes[6] = N2[3];
02427             aNodes[7] = N1[5];
02428             const SMDS_MeshElement* newElem = 0;
02429             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
02430                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
02431             myLastCreatedElems.Append(newElem);
02432             AddToSameGroups( newElem, tr1, aMesh );
02433             int aShapeId = tr1->getshapeId();
02434             if ( aShapeId )
02435               {
02436                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
02437               }
02438             aMesh->RemoveElement( tr1 );
02439             aMesh->RemoveElement( tr3 );
02440             // remove middle node (9)
02441             GetMeshDS()->RemoveNode( N1[4] );
02442           }
02443         }
02444 
02445         // Next element to fuse: the rejected one
02446         if ( tr3 )
02447           startElem = Ok12 ? tr3 : tr2;
02448 
02449       } // if ( startElem )
02450     } // while ( startElem || !startLinks.empty() )
02451   } // while ( ! mapEl_setLi.empty() )
02452 
02453   return true;
02454 }
02455 
02456 
02457 /*#define DUMPSO(txt) \
02458 //  cout << txt << endl;
02459 //=============================================================================
02460 //
02461 //
02462 //
02463 //=============================================================================
02464 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
02465 {
02466 if ( i1 == i2 )
02467 return;
02468 int tmp = idNodes[ i1 ];
02469 idNodes[ i1 ] = idNodes[ i2 ];
02470 idNodes[ i2 ] = tmp;
02471 gp_Pnt Ptmp = P[ i1 ];
02472 P[ i1 ] = P[ i2 ];
02473 P[ i2 ] = Ptmp;
02474 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
02475 }
02476 
02477 //=======================================================================
02478 //function : SortQuadNodes
02479 //purpose  : Set 4 nodes of a quadrangle face in a good order.
02480 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
02481 //           1 or 2 else 0.
02482 //=======================================================================
02483 
02484 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
02485 int               idNodes[] )
02486 {
02487   gp_Pnt P[4];
02488   int i;
02489   for ( i = 0; i < 4; i++ ) {
02490     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
02491     if ( !n ) return 0;
02492     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
02493   }
02494 
02495   gp_Vec V1(P[0], P[1]);
02496   gp_Vec V2(P[0], P[2]);
02497   gp_Vec V3(P[0], P[3]);
02498 
02499   gp_Vec Cross1 = V1 ^ V2;
02500   gp_Vec Cross2 = V2 ^ V3;
02501 
02502   i = 0;
02503   if (Cross1.Dot(Cross2) < 0)
02504   {
02505     Cross1 = V2 ^ V1;
02506     Cross2 = V1 ^ V3;
02507 
02508     if (Cross1.Dot(Cross2) < 0)
02509       i = 2;
02510     else
02511       i = 1;
02512     swap ( i, i + 1, idNodes, P );
02513 
02514     //     for ( int ii = 0; ii < 4; ii++ ) {
02515     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
02516     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
02517     //     }
02518   }
02519   return i;
02520 }
02521 
02522 //=======================================================================
02523 //function : SortHexaNodes
02524 //purpose  : Set 8 nodes of a hexahedron in a good order.
02525 //           Return success status
02526 //=======================================================================
02527 
02528 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
02529                                       int               idNodes[] )
02530 {
02531   gp_Pnt P[8];
02532   int i;
02533   DUMPSO( "INPUT: ========================================");
02534   for ( i = 0; i < 8; i++ ) {
02535     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
02536     if ( !n ) return false;
02537     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
02538     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
02539   }
02540   DUMPSO( "========================================");
02541 
02542 
02543   set<int> faceNodes;  // ids of bottom face nodes, to be found
02544   set<int> checkedId1; // ids of tried 2-nd nodes
02545   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
02546   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
02547   int iMin, iLoop1 = 0;
02548 
02549   // Loop to try the 2-nd nodes
02550 
02551   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
02552   {
02553     // Find not checked 2-nd node
02554     for ( i = 1; i < 8; i++ )
02555       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
02556         int id1 = idNodes[i];
02557         swap ( 1, i, idNodes, P );
02558         checkedId1.insert ( id1 );
02559         break;
02560       }
02561 
02562     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
02563     // ie that all but meybe one (id3 which is on the same face) nodes
02564     // lay on the same side from the triangle plane.
02565 
02566     bool manyInPlane = false; // more than 4 nodes lay in plane
02567     int iLoop2 = 0;
02568     while ( ++iLoop2 < 6 ) {
02569 
02570       // get 1-2-3 plane coeffs
02571       Standard_Real A, B, C, D;
02572       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
02573       if ( N.SquareMagnitude() > gp::Resolution() )
02574       {
02575         gp_Pln pln ( P[0], N );
02576         pln.Coefficients( A, B, C, D );
02577 
02578         // find the node (iMin) closest to pln
02579         Standard_Real dist[ 8 ], minDist = DBL_MAX;
02580         set<int> idInPln;
02581         for ( i = 3; i < 8; i++ ) {
02582           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
02583           if ( fabs( dist[i] ) < minDist ) {
02584             minDist = fabs( dist[i] );
02585             iMin = i;
02586           }
02587           if ( fabs( dist[i] ) <= tol )
02588             idInPln.insert( idNodes[i] );
02589         }
02590 
02591         // there should not be more than 4 nodes in bottom plane
02592         if ( idInPln.size() > 1 )
02593         {
02594           DUMPSO( "### idInPln.size() = " << idInPln.size());
02595           // idInPlane does not contain the first 3 nodes
02596           if ( manyInPlane || idInPln.size() == 5)
02597             return false; // all nodes in one plane
02598           manyInPlane = true;
02599 
02600           // set the 1-st node to be not in plane
02601           for ( i = 3; i < 8; i++ ) {
02602             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
02603               DUMPSO( "### Reset 0-th node");
02604               swap( 0, i, idNodes, P );
02605               break;
02606             }
02607           }
02608 
02609           // reset to re-check second nodes
02610           leastDist = DBL_MAX;
02611           faceNodes.clear();
02612           checkedId1.clear();
02613           iLoop1 = 0;
02614           break; // from iLoop2;
02615         }
02616 
02617         // check that the other 4 nodes are on the same side
02618         bool sameSide = true;
02619         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
02620         for ( i = 3; sameSide && i < 8; i++ ) {
02621           if ( i != iMin )
02622             sameSide = ( isNeg == dist[i] <= 0.);
02623         }
02624 
02625         // keep best solution
02626         if ( sameSide && minDist < leastDist ) {
02627           leastDist = minDist;
02628           faceNodes.clear();
02629           faceNodes.insert( idNodes[ 1 ] );
02630           faceNodes.insert( idNodes[ 2 ] );
02631           faceNodes.insert( idNodes[ iMin ] );
02632           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
02633                   << " leastDist = " << leastDist);
02634           if ( leastDist <= DBL_MIN )
02635             break;
02636         }
02637       }
02638 
02639       // set next 3-d node to check
02640       int iNext = 2 + iLoop2;
02641       if ( iNext < 8 ) {
02642         DUMPSO( "Try 2-nd");
02643         swap ( 2, iNext, idNodes, P );
02644       }
02645     } // while ( iLoop2 < 6 )
02646   } // iLoop1
02647 
02648   if ( faceNodes.empty() ) return false;
02649 
02650   // Put the faceNodes in proper places
02651   for ( i = 4; i < 8; i++ ) {
02652     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
02653       // find a place to put
02654       int iTo = 1;
02655       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
02656         iTo++;
02657       DUMPSO( "Set faceNodes");
02658       swap ( iTo, i, idNodes, P );
02659     }
02660   }
02661 
02662 
02663   // Set nodes of the found bottom face in good order
02664   DUMPSO( " Found bottom face: ");
02665   i = SortQuadNodes( theMesh, idNodes );
02666   if ( i ) {
02667     gp_Pnt Ptmp = P[ i ];
02668     P[ i ] = P[ i+1 ];
02669     P[ i+1 ] = Ptmp;
02670   }
02671   //   else
02672   //     for ( int ii = 0; ii < 4; ii++ ) {
02673   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
02674   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
02675   //    }
02676 
02677   // Gravity center of the top and bottom faces
02678   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
02679   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
02680 
02681   // Get direction from the bottom to the top face
02682   gp_Vec upDir ( aGCb, aGCt );
02683   Standard_Real upDirSize = upDir.Magnitude();
02684   if ( upDirSize <= gp::Resolution() ) return false;
02685   upDir / upDirSize;
02686 
02687   // Assure that the bottom face normal points up
02688   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
02689   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
02690   if ( Nb.Dot( upDir ) < 0 ) {
02691     DUMPSO( "Reverse bottom face");
02692     swap( 1, 3, idNodes, P );
02693   }
02694 
02695   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
02696   Standard_Real minDist = DBL_MAX;
02697   for ( i = 4; i < 8; i++ ) {
02698     // projection of P[i] to the plane defined by P[0] and upDir
02699     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
02700     Standard_Real sqDist = P[0].SquareDistance( Pp );
02701     if ( sqDist < minDist ) {
02702       minDist = sqDist;
02703       iMin = i;
02704     }
02705   }
02706   DUMPSO( "Set 4-th");
02707   swap ( 4, iMin, idNodes, P );
02708 
02709   // Set nodes of the top face in good order
02710   DUMPSO( "Sort top face");
02711   i = SortQuadNodes( theMesh, &idNodes[4] );
02712   if ( i ) {
02713     i += 4;
02714     gp_Pnt Ptmp = P[ i ];
02715     P[ i ] = P[ i+1 ];
02716     P[ i+1 ] = Ptmp;
02717   }
02718 
02719   // Assure that direction of the top face normal is from the bottom face
02720   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
02721   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
02722   if ( Nt.Dot( upDir ) < 0 ) {
02723     DUMPSO( "Reverse top face");
02724     swap( 5, 7, idNodes, P );
02725   }
02726 
02727   //   DUMPSO( "OUTPUT: ========================================");
02728   //   for ( i = 0; i < 8; i++ ) {
02729   //     float *p = ugrid->GetPoint(idNodes[i]);
02730   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
02731   //   }
02732 
02733   return true;
02734 }*/
02735 
02736 //================================================================================
02745 //================================================================================
02746 
02747 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
02748                                        TIDSortedElemSet &   linkedNodes,
02749                                        SMDSAbs_ElementType  type )
02750 {
02751   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
02752   while ( elemIt->more() )
02753   {
02754     const SMDS_MeshElement* elem = elemIt->next();
02755     if(elem->GetType() == SMDSAbs_0DElement)
02756       continue;
02757     
02758     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
02759     if ( elem->GetType() == SMDSAbs_Volume )
02760     {
02761       SMDS_VolumeTool vol( elem );
02762       while ( nodeIt->more() ) {
02763         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
02764         if ( theNode != n && vol.IsLinked( theNode, n ))
02765           linkedNodes.insert( n );
02766       }
02767     }
02768     else
02769     {
02770       for ( int i = 0; nodeIt->more(); ++i ) {
02771         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
02772         if ( n == theNode ) {
02773           int iBefore = i - 1;
02774           int iAfter  = i + 1;
02775           if ( elem->IsQuadratic() ) {
02776             int nb = elem->NbNodes() / 2;
02777             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
02778             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
02779           }
02780           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
02781           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
02782         }
02783       }
02784     }
02785   }
02786 }
02787 
02788 //=======================================================================
02789 //function : laplacianSmooth
02790 //purpose  : pulls theNode toward the center of surrounding nodes directly
02791 //           connected to that node along an element edge
02792 //=======================================================================
02793 
02794 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
02795                      const Handle(Geom_Surface)&          theSurface,
02796                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
02797 {
02798   // find surrounding nodes
02799 
02800   TIDSortedElemSet nodeSet;
02801   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
02802 
02803   // compute new coodrs
02804 
02805   double coord[] = { 0., 0., 0. };
02806   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
02807   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
02808     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
02809     if ( theSurface.IsNull() ) { // smooth in 3D
02810       coord[0] += node->X();
02811       coord[1] += node->Y();
02812       coord[2] += node->Z();
02813     }
02814     else { // smooth in 2D
02815       ASSERT( theUVMap.find( node ) != theUVMap.end() );
02816       gp_XY* uv = theUVMap[ node ];
02817       coord[0] += uv->X();
02818       coord[1] += uv->Y();
02819     }
02820   }
02821   int nbNodes = nodeSet.size();
02822   if ( !nbNodes )
02823     return;
02824   coord[0] /= nbNodes;
02825   coord[1] /= nbNodes;
02826 
02827   if ( !theSurface.IsNull() ) {
02828     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
02829     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
02830     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
02831     coord[0] = p3d.X();
02832     coord[1] = p3d.Y();
02833     coord[2] = p3d.Z();
02834   }
02835   else
02836     coord[2] /= nbNodes;
02837 
02838   // move node
02839 
02840   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
02841 }
02842 
02843 //=======================================================================
02844 //function : centroidalSmooth
02845 //purpose  : pulls theNode toward the element-area-weighted centroid of the
02846 //           surrounding elements
02847 //=======================================================================
02848 
02849 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
02850                       const Handle(Geom_Surface)&          theSurface,
02851                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
02852 {
02853   gp_XYZ aNewXYZ(0.,0.,0.);
02854   SMESH::Controls::Area anAreaFunc;
02855   double totalArea = 0.;
02856   int nbElems = 0;
02857 
02858   // compute new XYZ
02859 
02860   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
02861   while ( elemIt->more() )
02862   {
02863     const SMDS_MeshElement* elem = elemIt->next();
02864     nbElems++;
02865 
02866     gp_XYZ elemCenter(0.,0.,0.);
02867     SMESH::Controls::TSequenceOfXYZ aNodePoints;
02868     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
02869     int nn = elem->NbNodes();
02870     if(elem->IsQuadratic()) nn = nn/2;
02871     int i=0;
02872     //while ( itN->more() ) {
02873     while ( i<nn ) {
02874       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
02875       i++;
02876       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
02877       aNodePoints.push_back( aP );
02878       if ( !theSurface.IsNull() ) { // smooth in 2D
02879         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
02880         gp_XY* uv = theUVMap[ aNode ];
02881         aP.SetCoord( uv->X(), uv->Y(), 0. );
02882       }
02883       elemCenter += aP;
02884     }
02885     double elemArea = anAreaFunc.GetValue( aNodePoints );
02886     totalArea += elemArea;
02887     elemCenter /= nn;
02888     aNewXYZ += elemCenter * elemArea;
02889   }
02890   aNewXYZ /= totalArea;
02891   if ( !theSurface.IsNull() ) {
02892     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
02893     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
02894   }
02895 
02896   // move node
02897 
02898   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
02899 }
02900 
02901 //=======================================================================
02902 //function : getClosestUV
02903 //purpose  : return UV of closest projection
02904 //=======================================================================
02905 
02906 static bool getClosestUV (Extrema_GenExtPS& projector,
02907                           const gp_Pnt&     point,
02908                           gp_XY &           result)
02909 {
02910   projector.Perform( point );
02911   if ( projector.IsDone() ) {
02912     double u, v, minVal = DBL_MAX;
02913     for ( int i = projector.NbExt(); i > 0; i-- )
02914 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
02915       if ( projector.SquareDistance( i ) < minVal ) {
02916         minVal = projector.SquareDistance( i );
02917 #else
02918       if ( projector.Value( i ) < minVal ) {
02919         minVal = projector.Value( i );
02920 #endif
02921         projector.Point( i ).Parameter( u, v );
02922       }
02923     result.SetCoord( u, v );
02924     return true;
02925   }
02926   return false;
02927 }
02928 
02929 //=======================================================================
02930 //function : Smooth
02931 //purpose  : Smooth theElements during theNbIterations or until a worst
02932 //           element has aspect ratio <= theTgtAspectRatio.
02933 //           Aspect Ratio varies in range [1.0, inf].
02934 //           If theElements is empty, the whole mesh is smoothed.
02935 //           theFixedNodes contains additionally fixed nodes. Nodes built
02936 //           on edges and boundary nodes are always fixed.
02937 //=======================================================================
02938 
02939 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
02940                                set<const SMDS_MeshNode*> & theFixedNodes,
02941                                const SmoothMethod          theSmoothMethod,
02942                                const int                   theNbIterations,
02943                                double                      theTgtAspectRatio,
02944                                const bool                  the2D)
02945 {
02946   myLastCreatedElems.Clear();
02947   myLastCreatedNodes.Clear();
02948 
02949   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
02950 
02951   if ( theTgtAspectRatio < 1.0 )
02952     theTgtAspectRatio = 1.0;
02953 
02954   const double disttol = 1.e-16;
02955 
02956   SMESH::Controls::AspectRatio aQualityFunc;
02957 
02958   SMESHDS_Mesh* aMesh = GetMeshDS();
02959 
02960   if ( theElems.empty() ) {
02961     // add all faces to theElems
02962     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
02963     while ( fIt->more() ) {
02964       const SMDS_MeshElement* face = fIt->next();
02965       theElems.insert( face );
02966     }
02967   }
02968   // get all face ids theElems are on
02969   set< int > faceIdSet;
02970   TIDSortedElemSet::iterator itElem;
02971   if ( the2D )
02972     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
02973       int fId = FindShape( *itElem );
02974       // check that corresponding submesh exists and a shape is face
02975       if (fId &&
02976           faceIdSet.find( fId ) == faceIdSet.end() &&
02977           aMesh->MeshElements( fId )) {
02978         TopoDS_Shape F = aMesh->IndexToShape( fId );
02979         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
02980           faceIdSet.insert( fId );
02981       }
02982     }
02983   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
02984 
02985   // ===============================================
02986   // smooth elements on each TopoDS_Face separately
02987   // ===============================================
02988 
02989   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
02990   for ( ; fId != faceIdSet.rend(); ++fId ) {
02991     // get face surface and submesh
02992     Handle(Geom_Surface) surface;
02993     SMESHDS_SubMesh* faceSubMesh = 0;
02994     TopoDS_Face face;
02995     double fToler2 = 0, f,l;
02996     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
02997     bool isUPeriodic = false, isVPeriodic = false;
02998     if ( *fId ) {
02999       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
03000       surface = BRep_Tool::Surface( face );
03001       faceSubMesh = aMesh->MeshElements( *fId );
03002       fToler2 = BRep_Tool::Tolerance( face );
03003       fToler2 *= fToler2 * 10.;
03004       isUPeriodic = surface->IsUPeriodic();
03005       if ( isUPeriodic )
03006         surface->UPeriod();
03007       isVPeriodic = surface->IsVPeriodic();
03008       if ( isVPeriodic )
03009         surface->VPeriod();
03010       surface->Bounds( u1, u2, v1, v2 );
03011     }
03012     // ---------------------------------------------------------
03013     // for elements on a face, find movable and fixed nodes and
03014     // compute UV for them
03015     // ---------------------------------------------------------
03016     bool checkBoundaryNodes = false;
03017     bool isQuadratic = false;
03018     set<const SMDS_MeshNode*> setMovableNodes;
03019     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
03020     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
03021     list< const SMDS_MeshElement* > elemsOnFace;
03022 
03023     Extrema_GenExtPS projector;
03024     GeomAdaptor_Surface surfAdaptor;
03025     if ( !surface.IsNull() ) {
03026       surfAdaptor.Load( surface );
03027       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
03028     }
03029     int nbElemOnFace = 0;
03030     itElem = theElems.begin();
03031     // loop on not yet smoothed elements: look for elems on a face
03032     while ( itElem != theElems.end() ) {
03033       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
03034         break; // all elements found
03035 
03036       const SMDS_MeshElement* elem = *itElem;
03037       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
03038            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
03039         ++itElem;
03040         continue;
03041       }
03042       elemsOnFace.push_back( elem );
03043       theElems.erase( itElem++ );
03044       nbElemOnFace++;
03045 
03046       if ( !isQuadratic )
03047         isQuadratic = elem->IsQuadratic();
03048 
03049       // get movable nodes of elem
03050       const SMDS_MeshNode* node;
03051       SMDS_TypeOfPosition posType;
03052       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
03053       int nn = 0, nbn =  elem->NbNodes();
03054       if(elem->IsQuadratic())
03055         nbn = nbn/2;
03056       while ( nn++ < nbn ) {
03057         node = static_cast<const SMDS_MeshNode*>( itN->next() );
03058         const SMDS_PositionPtr& pos = node->GetPosition();
03059         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
03060         if (posType != SMDS_TOP_EDGE &&
03061             posType != SMDS_TOP_VERTEX &&
03062             theFixedNodes.find( node ) == theFixedNodes.end())
03063         {
03064           // check if all faces around the node are on faceSubMesh
03065           // because a node on edge may be bound to face
03066           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
03067           bool all = true;
03068           if ( faceSubMesh ) {
03069             while ( eIt->more() && all ) {
03070               const SMDS_MeshElement* e = eIt->next();
03071               all = faceSubMesh->Contains( e );
03072             }
03073           }
03074           if ( all )
03075             setMovableNodes.insert( node );
03076           else
03077             checkBoundaryNodes = true;
03078         }
03079         if ( posType == SMDS_TOP_3DSPACE )
03080           checkBoundaryNodes = true;
03081       }
03082 
03083       if ( surface.IsNull() )
03084         continue;
03085 
03086       // get nodes to check UV
03087       list< const SMDS_MeshNode* > uvCheckNodes;
03088       itN = elem->nodesIterator();
03089       nn = 0; nbn =  elem->NbNodes();
03090       if(elem->IsQuadratic())
03091         nbn = nbn/2;
03092       while ( nn++ < nbn ) {
03093         node = static_cast<const SMDS_MeshNode*>( itN->next() );
03094         if ( uvMap.find( node ) == uvMap.end() )
03095           uvCheckNodes.push_back( node );
03096         // add nodes of elems sharing node
03097         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
03098         //         while ( eIt->more() ) {
03099         //           const SMDS_MeshElement* e = eIt->next();
03100         //           if ( e != elem ) {
03101         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
03102         //             while ( nIt->more() ) {
03103         //               const SMDS_MeshNode* n =
03104         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
03105         //               if ( uvMap.find( n ) == uvMap.end() )
03106         //                 uvCheckNodes.push_back( n );
03107         //             }
03108         //           }
03109         //         }
03110       }
03111       // check UV on face
03112       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
03113       for ( ; n != uvCheckNodes.end(); ++n ) {
03114         node = *n;
03115         gp_XY uv( 0, 0 );
03116         const SMDS_PositionPtr& pos = node->GetPosition();
03117         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
03118         // get existing UV
03119         switch ( posType ) {
03120         case SMDS_TOP_FACE: {
03121           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
03122           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
03123           break;
03124         }
03125         case SMDS_TOP_EDGE: {
03126           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
03127           Handle(Geom2d_Curve) pcurve;
03128           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
03129             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
03130           if ( !pcurve.IsNull() ) {
03131             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
03132             uv = pcurve->Value( u ).XY();
03133           }
03134           break;
03135         }
03136         case SMDS_TOP_VERTEX: {
03137           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
03138           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
03139             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
03140           break;
03141         }
03142         default:;
03143         }
03144         // check existing UV
03145         bool project = true;
03146         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
03147         double dist1 = DBL_MAX, dist2 = 0;
03148         if ( posType != SMDS_TOP_3DSPACE ) {
03149           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
03150           project = dist1 > fToler2;
03151         }
03152         if ( project ) { // compute new UV
03153           gp_XY newUV;
03154           if ( !getClosestUV( projector, pNode, newUV )) {
03155             MESSAGE("Node Projection Failed " << node);
03156           }
03157           else {
03158             if ( isUPeriodic )
03159               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
03160             if ( isVPeriodic )
03161               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
03162             // check new UV
03163             if ( posType != SMDS_TOP_3DSPACE )
03164               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
03165             if ( dist2 < dist1 )
03166               uv = newUV;
03167           }
03168         }
03169         // store UV in the map
03170         listUV.push_back( uv );
03171         uvMap.insert( make_pair( node, &listUV.back() ));
03172       }
03173     } // loop on not yet smoothed elements
03174 
03175     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
03176       checkBoundaryNodes = true;
03177 
03178     // fix nodes on mesh boundary
03179 
03180     if ( checkBoundaryNodes ) {
03181       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
03182       map< SMESH_TLink, int >::iterator link_nb;
03183       // put all elements links to linkNbMap
03184       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
03185       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
03186         const SMDS_MeshElement* elem = (*elemIt);
03187         int nbn =  elem->NbCornerNodes();
03188         // loop on elem links: insert them in linkNbMap
03189         for ( int iN = 0; iN < nbn; ++iN ) {
03190           const SMDS_MeshNode* n1 = elem->GetNode( iN );
03191           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
03192           SMESH_TLink link( n1, n2 );
03193           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
03194           link_nb->second++;
03195         }
03196       }
03197       // remove nodes that are in links encountered only once from setMovableNodes
03198       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
03199         if ( link_nb->second == 1 ) {
03200           setMovableNodes.erase( link_nb->first.node1() );
03201           setMovableNodes.erase( link_nb->first.node2() );
03202         }
03203       }
03204     }
03205 
03206     // -----------------------------------------------------
03207     // for nodes on seam edge, compute one more UV ( uvMap2 );
03208     // find movable nodes linked to nodes on seam and which
03209     // are to be smoothed using the second UV ( uvMap2 )
03210     // -----------------------------------------------------
03211 
03212     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
03213     if ( !surface.IsNull() ) {
03214       TopExp_Explorer eExp( face, TopAbs_EDGE );
03215       for ( ; eExp.More(); eExp.Next() ) {
03216         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
03217         if ( !BRep_Tool::IsClosed( edge, face ))
03218           continue;
03219         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
03220         if ( !sm ) continue;
03221         // find out which parameter varies for a node on seam
03222         double f,l;
03223         gp_Pnt2d uv1, uv2;
03224         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
03225         if ( pcurve.IsNull() ) continue;
03226         uv1 = pcurve->Value( f );
03227         edge.Reverse();
03228         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
03229         if ( pcurve.IsNull() ) continue;
03230         uv2 = pcurve->Value( f );
03231         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
03232         // assure uv1 < uv2
03233         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
03234           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
03235         }
03236         // get nodes on seam and its vertices
03237         list< const SMDS_MeshNode* > seamNodes;
03238         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
03239         while ( nSeamIt->more() ) {
03240           const SMDS_MeshNode* node = nSeamIt->next();
03241           if ( !isQuadratic || !IsMedium( node ))
03242             seamNodes.push_back( node );
03243         }
03244         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
03245         for ( ; vExp.More(); vExp.Next() ) {
03246           sm = aMesh->MeshElements( vExp.Current() );
03247           if ( sm ) {
03248             nSeamIt = sm->GetNodes();
03249             while ( nSeamIt->more() )
03250               seamNodes.push_back( nSeamIt->next() );
03251           }
03252         }
03253         // loop on nodes on seam
03254         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
03255         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
03256           const SMDS_MeshNode* nSeam = *noSeIt;
03257           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
03258           if ( n_uv == uvMap.end() )
03259             continue;
03260           // set the first UV
03261           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
03262           // set the second UV
03263           listUV.push_back( *n_uv->second );
03264           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
03265           if ( uvMap2.empty() )
03266             uvMap2 = uvMap; // copy the uvMap contents
03267           uvMap2[ nSeam ] = &listUV.back();
03268 
03269           // collect movable nodes linked to ones on seam in nodesNearSeam
03270           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
03271           while ( eIt->more() ) {
03272             const SMDS_MeshElement* e = eIt->next();
03273             int nbUseMap1 = 0, nbUseMap2 = 0;
03274             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
03275             int nn = 0, nbn =  e->NbNodes();
03276             if(e->IsQuadratic()) nbn = nbn/2;
03277             while ( nn++ < nbn )
03278             {
03279               const SMDS_MeshNode* n =
03280                 static_cast<const SMDS_MeshNode*>( nIt->next() );
03281               if (n == nSeam ||
03282                   setMovableNodes.find( n ) == setMovableNodes.end() )
03283                 continue;
03284               // add only nodes being closer to uv2 than to uv1
03285               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
03286                            0.5 * ( n->Y() + nSeam->Y() ),
03287                            0.5 * ( n->Z() + nSeam->Z() ));
03288               gp_XY uv;
03289               getClosestUV( projector, pMid, uv );
03290               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
03291                 nodesNearSeam.insert( n );
03292                 nbUseMap2++;
03293               }
03294               else
03295                 nbUseMap1++;
03296             }
03297             // for centroidalSmooth all element nodes must
03298             // be on one side of a seam
03299             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
03300               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
03301               nn = 0;
03302               while ( nn++ < nbn ) {
03303                 const SMDS_MeshNode* n =
03304                   static_cast<const SMDS_MeshNode*>( nIt->next() );
03305                 setMovableNodes.erase( n );
03306               }
03307             }
03308           }
03309         } // loop on nodes on seam
03310       } // loop on edge of a face
03311     } // if ( !face.IsNull() )
03312 
03313     if ( setMovableNodes.empty() ) {
03314       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
03315       continue; // goto next face
03316     }
03317 
03318     // -------------
03319     // SMOOTHING //
03320     // -------------
03321 
03322     int it = -1;
03323     double maxRatio = -1., maxDisplacement = -1.;
03324     set<const SMDS_MeshNode*>::iterator nodeToMove;
03325     for ( it = 0; it < theNbIterations; it++ ) {
03326       maxDisplacement = 0.;
03327       nodeToMove = setMovableNodes.begin();
03328       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
03329         const SMDS_MeshNode* node = (*nodeToMove);
03330         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
03331 
03332         // smooth
03333         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
03334         if ( theSmoothMethod == LAPLACIAN )
03335           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
03336         else
03337           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
03338 
03339         // node displacement
03340         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
03341         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
03342         if ( aDispl > maxDisplacement )
03343           maxDisplacement = aDispl;
03344       }
03345       // no node movement => exit
03346       //if ( maxDisplacement < 1.e-16 ) {
03347       if ( maxDisplacement < disttol ) {
03348         MESSAGE("-- no node movement --");
03349         break;
03350       }
03351 
03352       // check elements quality
03353       maxRatio  = 0;
03354       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
03355       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
03356         const SMDS_MeshElement* elem = (*elemIt);
03357         if ( !elem || elem->GetType() != SMDSAbs_Face )
03358           continue;
03359         SMESH::Controls::TSequenceOfXYZ aPoints;
03360         if ( aQualityFunc.GetPoints( elem, aPoints )) {
03361           double aValue = aQualityFunc.GetValue( aPoints );
03362           if ( aValue > maxRatio )
03363             maxRatio = aValue;
03364         }
03365       }
03366       if ( maxRatio <= theTgtAspectRatio ) {
03367         MESSAGE("-- quality achived --");
03368         break;
03369       }
03370       if (it+1 == theNbIterations) {
03371         MESSAGE("-- Iteration limit exceeded --");
03372       }
03373     } // smoothing iterations
03374 
03375     MESSAGE(" Face id: " << *fId <<
03376             " Nb iterstions: " << it <<
03377             " Displacement: " << maxDisplacement <<
03378             " Aspect Ratio " << maxRatio);
03379 
03380     // ---------------------------------------
03381     // new nodes positions are computed,
03382     // record movement in DS and set new UV
03383     // ---------------------------------------
03384     nodeToMove = setMovableNodes.begin();
03385     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
03386       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
03387       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
03388       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
03389       if ( node_uv != uvMap.end() ) {
03390         gp_XY* uv = node_uv->second;
03391         node->SetPosition
03392           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
03393       }
03394     }
03395 
03396     // move medium nodes of quadratic elements
03397     if ( isQuadratic )
03398     {
03399       SMESH_MesherHelper helper( *GetMesh() );
03400       if ( !face.IsNull() )
03401         helper.SetSubShape( face );
03402       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
03403       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
03404         const SMDS_VtkFace* QF =
03405           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
03406         if(QF && QF->IsQuadratic()) {
03407           vector<const SMDS_MeshNode*> Ns;
03408           Ns.reserve(QF->NbNodes()+1);
03409           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
03410           while ( anIter->more() )
03411             Ns.push_back( cast2Node(anIter->next()) );
03412           Ns.push_back( Ns[0] );
03413           double x, y, z;
03414           for(int i=0; i<QF->NbNodes(); i=i+2) {
03415             if ( !surface.IsNull() ) {
03416               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
03417               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
03418               gp_XY uv = ( uv1 + uv2 ) / 2.;
03419               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
03420               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
03421             }
03422             else {
03423               x = (Ns[i]->X() + Ns[i+2]->X())/2;
03424               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
03425               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
03426             }
03427             if( fabs( Ns[i+1]->X() - x ) > disttol ||
03428                 fabs( Ns[i+1]->Y() - y ) > disttol ||
03429                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
03430               // we have to move i+1 node
03431               aMesh->MoveNode( Ns[i+1], x, y, z );
03432             }
03433           }
03434         }
03435       }
03436     }
03437 
03438   } // loop on face ids
03439 
03440 }
03441 
03442 //=======================================================================
03443 //function : isReverse
03444 //purpose  : Return true if normal of prevNodes is not co-directied with
03445 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
03446 //           iNotSame is where prevNodes and nextNodes are different.
03447 //           If result is true then future volume orientation is OK
03448 //=======================================================================
03449 
03450 static bool isReverse(const SMDS_MeshElement*             face,
03451                       const vector<const SMDS_MeshNode*>& prevNodes,
03452                       const vector<const SMDS_MeshNode*>& nextNodes,
03453                       const int                           iNotSame)
03454 {
03455 
03456   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
03457   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
03458   gp_XYZ extrDir( pN - pP ), faceNorm;
03459   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
03460 
03461   return faceNorm * extrDir < 0.0;
03462 }
03463 
03464 //=======================================================================
03473 //=======================================================================
03474 
03475 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
03476                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
03477                                     list<const SMDS_MeshElement*>&        newElems,
03478                                     const int                             nbSteps,
03479                                     SMESH_SequenceOfElemPtr&              srcElements)
03480 {
03481   //MESSAGE("sweepElement " << nbSteps);
03482   SMESHDS_Mesh* aMesh = GetMeshDS();
03483 
03484   const int           nbNodes = elem->NbNodes();          
03485   const int         nbCorners = elem->NbCornerNodes();
03486   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of 
03487                                                           polyhedron creation !!! */
03488   // Loop on elem nodes:
03489   // find new nodes and detect same nodes indices
03490   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
03491   vector<const SMDS_MeshNode*> prevNod( nbNodes );
03492   vector<const SMDS_MeshNode*> nextNod( nbNodes );
03493   vector<const SMDS_MeshNode*> midlNod( nbNodes );
03494 
03495   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
03496   vector<int> sames(nbNodes);
03497   vector<bool> isSingleNode(nbNodes);
03498 
03499   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
03500     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
03501     const SMDS_MeshNode*                         node = nnIt->first;
03502     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
03503     if ( listNewNodes.empty() )
03504       return;
03505 
03506     itNN   [ iNode ] = listNewNodes.begin();
03507     prevNod[ iNode ] = node;
03508     nextNod[ iNode ] = listNewNodes.front();
03509 
03510     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
03511                                                              corner node of linear */
03512     if ( prevNod[ iNode ] != nextNod [ iNode ])
03513       nbDouble += !isSingleNode[iNode];
03514 
03515     if( iNode < nbCorners ) { // check corners only
03516       if ( prevNod[ iNode ] == nextNod [ iNode ])
03517         sames[nbSame++] = iNode;
03518       else
03519         iNotSameNode = iNode;
03520     }
03521   }
03522 
03523   if ( nbSame == nbNodes || nbSame > 2) {
03524     MESSAGE( " Too many same nodes of element " << elem->GetID() );
03525     return;
03526   }
03527 
03528   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
03529   {
03530     // fix nodes order to have bottom normal external
03531     if ( baseType == SMDSEntity_Polygon )
03532     {
03533       std::reverse( itNN.begin(), itNN.end() );
03534       std::reverse( prevNod.begin(), prevNod.end() );
03535       std::reverse( midlNod.begin(), midlNod.end() );
03536       std::reverse( nextNod.begin(), nextNod.end() );
03537       std::reverse( isSingleNode.begin(), isSingleNode.end() );
03538     }
03539     else
03540     {
03541       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
03542       SMDS_MeshCell::applyInterlace( ind, itNN );
03543       SMDS_MeshCell::applyInterlace( ind, prevNod );
03544       SMDS_MeshCell::applyInterlace( ind, nextNod );
03545       SMDS_MeshCell::applyInterlace( ind, midlNod );
03546       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
03547       if ( nbSame > 0 )
03548       {
03549         sames[nbSame] = iNotSameNode;
03550         for ( int j = 0; j <= nbSame; ++j )
03551           for ( size_t i = 0; i < ind.size(); ++i )
03552             if ( ind[i] == sames[j] )
03553             {
03554               sames[j] = i;
03555               break;
03556             }
03557         iNotSameNode = sames[nbSame];
03558       }
03559     }
03560   }
03561 
03562   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
03563   if ( nbSame > 0 ) {
03564     iSameNode    = sames[ nbSame-1 ];
03565     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
03566     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
03567     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
03568   }
03569 
03570   // make new elements
03571   for (int iStep = 0; iStep < nbSteps; iStep++ )
03572   {
03573     // get next nodes
03574     for ( iNode = 0; iNode < nbNodes; iNode++ )
03575     {
03576       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
03577       nextNod[ iNode ] = *itNN[ iNode ]++;
03578     }
03579 
03580     SMDS_MeshElement* aNewElem = 0;
03581     /*if(!elem->IsPoly())*/ {
03582       switch ( baseType ) {
03583       case SMDSEntity_0D:
03584       case SMDSEntity_Node: { // sweep NODE
03585         if ( nbSame == 0 ) {
03586           if ( isSingleNode[0] )
03587             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
03588           else
03589             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
03590         }
03591         else
03592           return;
03593         break;
03594       }
03595       case SMDSEntity_Edge: { // sweep EDGE
03596         if ( nbDouble == 0 )
03597         {
03598           if ( nbSame == 0 ) // ---> quadrangle
03599             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
03600                                       nextNod[ 1 ], nextNod[ 0 ] );
03601           else               // ---> triangle
03602             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
03603                                       nextNod[ iNotSameNode ] );
03604         }
03605         else                 // ---> polygon
03606         {
03607           vector<const SMDS_MeshNode*> poly_nodes;
03608           poly_nodes.push_back( prevNod[0] );
03609           poly_nodes.push_back( prevNod[1] );
03610           if ( prevNod[1] != nextNod[1] )
03611           {
03612             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
03613             poly_nodes.push_back( nextNod[1] );
03614           }
03615           if ( prevNod[0] != nextNod[0] )
03616           {
03617             poly_nodes.push_back( nextNod[0] );
03618             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
03619           }
03620           switch ( poly_nodes.size() ) {
03621           case 3:
03622             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
03623             break;
03624           case 4:
03625             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
03626                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
03627             break;
03628           default:
03629             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
03630           }
03631         }
03632         break;
03633       }
03634       case SMDSEntity_Triangle: // TRIANGLE --->
03635         {
03636           if ( nbDouble > 0 ) break;
03637           if ( nbSame == 0 )       // ---> pentahedron
03638             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
03639                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
03640 
03641           else if ( nbSame == 1 )  // ---> pyramid
03642             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
03643                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
03644                                          nextNod[ iSameNode ]);
03645 
03646           else // 2 same nodes:       ---> tetrahedron
03647             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
03648                                          nextNod[ iNotSameNode ]);
03649           break;
03650         }
03651       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
03652         {
03653           if ( nbSame == 2 )
03654             return;
03655           if ( nbDouble+nbSame == 2 )
03656           {
03657             if(nbSame==0) {      // ---> quadratic quadrangle
03658               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
03659                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
03660             }
03661             else { //(nbSame==1) // ---> quadratic triangle
03662               if(sames[0]==2) {
03663                 return; // medium node on axis
03664               }
03665               else if(sames[0]==0)
03666                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
03667                                           nextNod[2], midlNod[1], prevNod[2]);
03668               else // sames[0]==1
03669                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
03670                                           midlNod[0], nextNod[2], prevNod[2]);
03671             }
03672           }
03673           else if ( nbDouble == 3 )
03674           {
03675             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
03676               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
03677                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
03678             }
03679           }
03680           else
03681             return;
03682           break;
03683         }
03684       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
03685         if ( nbDouble > 0 ) break;
03686 
03687         if ( nbSame == 0 )       // ---> hexahedron
03688           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
03689                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
03690 
03691         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
03692           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
03693                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
03694                                        nextNod[ iSameNode ]);
03695           newElems.push_back( aNewElem );
03696           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
03697                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
03698                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
03699         }
03700         else if ( nbSame == 2 ) { // ---> pentahedron
03701           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
03702             // iBeforeSame is same too
03703             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
03704                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
03705                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
03706           else
03707             // iAfterSame is same too
03708             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
03709                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
03710                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
03711         }
03712         break;
03713       }
03714       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
03715         if ( nbDouble+nbSame != 3 ) break;
03716         if(nbSame==0) {
03717           // --->  pentahedron with 15 nodes
03718           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
03719                                        nextNod[0], nextNod[1], nextNod[2],
03720                                        prevNod[3], prevNod[4], prevNod[5],
03721                                        nextNod[3], nextNod[4], nextNod[5],
03722                                        midlNod[0], midlNod[1], midlNod[2]);
03723         }
03724         else if(nbSame==1) {
03725           // --->  2d order pyramid of 13 nodes
03726           int apex = iSameNode;
03727           int i0 = ( apex + 1 ) % nbCorners;
03728           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
03729           int i0a = apex + 3;
03730           int i1a = i1 + 3;
03731           int i01 = i0 + 3;
03732           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
03733                                       nextNod[i0], nextNod[i1], prevNod[apex],
03734                                       prevNod[i01], midlNod[i0],
03735                                       nextNod[i01], midlNod[i1],
03736                                       prevNod[i1a], prevNod[i0a],
03737                                       nextNod[i0a], nextNod[i1a]);
03738         }
03739         else if(nbSame==2) {
03740           // --->  2d order tetrahedron of 10 nodes
03741           int n1 = iNotSameNode;
03742           int n2 = ( n1 + 1             ) % nbCorners;
03743           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
03744           int n12 = n1 + 3;
03745           int n23 = n2 + 3;
03746           int n31 = n3 + 3;
03747           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
03748                                        prevNod[n12], prevNod[n23], prevNod[n31],
03749                                        midlNod[n1], nextNod[n12], nextNod[n31]);
03750         }
03751         break;
03752       }
03753       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
03754         if( nbSame == 0 ) {
03755           if ( nbDouble != 4 ) break;
03756           // --->  hexahedron with 20 nodes
03757           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
03758                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
03759                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
03760                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
03761                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
03762         }
03763         else if(nbSame==1) {
03764           // ---> pyramid + pentahedron - can not be created since it is needed 
03765           // additional middle node at the center of face
03766           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
03767           return;
03768         }
03769         else if( nbSame == 2 ) {
03770           if ( nbDouble != 2 ) break;
03771           // --->  2d order Pentahedron with 15 nodes
03772           int n1,n2,n4,n5;
03773           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
03774             // iBeforeSame is same too
03775             n1 = iBeforeSame;
03776             n2 = iOpposSame;
03777             n4 = iSameNode;
03778             n5 = iAfterSame;
03779           }
03780           else {
03781             // iAfterSame is same too
03782             n1 = iSameNode;
03783             n2 = iBeforeSame;
03784             n4 = iAfterSame;
03785             n5 = iOpposSame;
03786           }
03787           int n12 = n2 + 4;
03788           int n45 = n4 + 4;
03789           int n14 = n1 + 4;
03790           int n25 = n5 + 4;
03791           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
03792                                        prevNod[n4], prevNod[n5], nextNod[n5],
03793                                        prevNod[n12], midlNod[n2], nextNod[n12],
03794                                        prevNod[n45], midlNod[n5], nextNod[n45],
03795                                        prevNod[n14], prevNod[n25], nextNod[n25]);
03796         }
03797         break;
03798       }
03799       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
03800 
03801         if( nbSame == 0 && nbDouble == 9 ) {
03802           // --->  tri-quadratic hexahedron with 27 nodes
03803           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
03804                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
03805                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
03806                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
03807                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
03808                                        prevNod[8], // bottom center
03809                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
03810                                        nextNod[8], // top center
03811                                        midlNod[8]);// elem center
03812         }
03813         else
03814         {
03815           return;
03816         }
03817         break;
03818       }
03819       case SMDSEntity_Polygon: { // sweep POLYGON
03820 
03821         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
03822           // --->  hexagonal prism
03823           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
03824                                        prevNod[3], prevNod[4], prevNod[5],
03825                                        nextNod[0], nextNod[1], nextNod[2],
03826                                        nextNod[3], nextNod[4], nextNod[5]);
03827         }
03828         break;
03829       }
03830       default:
03831         break;
03832       }
03833     }
03834 
03835     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
03836     {
03837       if ( baseType != SMDSEntity_Polygon )
03838       {
03839         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
03840         SMDS_MeshCell::applyInterlace( ind, prevNod );
03841         SMDS_MeshCell::applyInterlace( ind, nextNod );
03842         SMDS_MeshCell::applyInterlace( ind, midlNod );
03843         SMDS_MeshCell::applyInterlace( ind, itNN );
03844         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
03845         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
03846       }
03847       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
03848       vector<int> quantities (nbNodes + 2);
03849       polyedre_nodes.clear();
03850       quantities.clear();
03851 
03852       // bottom of prism
03853       for (int inode = 0; inode < nbNodes; inode++)
03854         polyedre_nodes.push_back( prevNod[inode] );
03855       quantities.push_back( nbNodes );
03856 
03857       // top of prism
03858       polyedre_nodes.push_back( nextNod[0] );
03859       for (int inode = nbNodes; inode-1; --inode )
03860         polyedre_nodes.push_back( nextNod[inode-1] );
03861       quantities.push_back( nbNodes );
03862 
03863       // side faces
03864       for (int iface = 0; iface < nbNodes; iface++)
03865       {
03866         const int prevNbNodes = polyedre_nodes.size();
03867         int inextface = (iface+1) % nbNodes;
03868         polyedre_nodes.push_back( prevNod[inextface] );
03869         polyedre_nodes.push_back( prevNod[iface] );
03870         if ( prevNod[iface] != nextNod[iface] )
03871         {
03872           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
03873           polyedre_nodes.push_back( nextNod[iface] );
03874         }
03875         if ( prevNod[inextface] != nextNod[inextface] )
03876         {
03877           polyedre_nodes.push_back( nextNod[inextface] );
03878           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
03879         }
03880         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
03881         if ( nbFaceNodes > 2 )
03882           quantities.push_back( nbFaceNodes );
03883         else // degenerated face
03884           polyedre_nodes.resize( prevNbNodes );
03885       }
03886       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
03887     }
03888 
03889     if ( aNewElem ) {
03890       newElems.push_back( aNewElem );
03891       myLastCreatedElems.Append(aNewElem);
03892       srcElements.Append( elem );
03893     }
03894 
03895     // set new prev nodes
03896     for ( iNode = 0; iNode < nbNodes; iNode++ )
03897       prevNod[ iNode ] = nextNod[ iNode ];
03898 
03899   } // for steps
03900 }
03901 
03902 //=======================================================================
03912 //=======================================================================
03913 
03914 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
03915                                   TElemOfElemListMap &     newElemsMap,
03916                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
03917                                   TIDSortedElemSet&        elemSet,
03918                                   const int                nbSteps,
03919                                   SMESH_SequenceOfElemPtr& srcElements)
03920 {
03921   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
03922   SMESHDS_Mesh* aMesh = GetMeshDS();
03923 
03924   // Find nodes belonging to only one initial element - sweep them to get edges.
03925 
03926   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
03927   for ( ; nList != mapNewNodes.end(); nList++ )
03928   {
03929     const SMDS_MeshNode* node =
03930       static_cast<const SMDS_MeshNode*>( nList->first );
03931     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
03932     int nbInitElems = 0;
03933     const SMDS_MeshElement* el = 0;
03934     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
03935     while ( eIt->more() && nbInitElems < 2 ) {
03936       el = eIt->next();
03937       SMDSAbs_ElementType type = el->GetType();
03938       if ( type == SMDSAbs_Volume || type < highType ) continue;
03939       if ( type > highType ) {
03940         nbInitElems = 0;
03941         highType = type;
03942       }
03943       nbInitElems += elemSet.count(el);
03944     }
03945     if ( nbInitElems < 2 ) {
03946       bool NotCreateEdge = el && el->IsMediumNode(node);
03947       if(!NotCreateEdge) {
03948         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
03949         list<const SMDS_MeshElement*> newEdges;
03950         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
03951       }
03952     }
03953   }
03954 
03955   // Make a ceiling for each element ie an equal element of last new nodes.
03956   // Find free links of faces - make edges and sweep them into faces.
03957 
03958   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
03959   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
03960   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
03961   {
03962     const SMDS_MeshElement* elem = itElem->first;
03963     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
03964 
03965     if(itElem->second.size()==0) continue;
03966 
03967     const bool isQuadratic = elem->IsQuadratic();
03968 
03969     if ( elem->GetType() == SMDSAbs_Edge ) {
03970       // create a ceiling edge
03971       if ( !isQuadratic ) {
03972         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
03973                                vecNewNodes[ 1 ]->second.back())) {
03974           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
03975                                                    vecNewNodes[ 1 ]->second.back()));
03976           srcElements.Append( myLastCreatedElems.Last() );
03977         }
03978       }
03979       else {
03980         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
03981                                vecNewNodes[ 1 ]->second.back(),
03982                                vecNewNodes[ 2 ]->second.back())) {
03983           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
03984                                                    vecNewNodes[ 1 ]->second.back(),
03985                                                    vecNewNodes[ 2 ]->second.back()));
03986           srcElements.Append( myLastCreatedElems.Last() );
03987         }
03988       }
03989     }
03990     if ( elem->GetType() != SMDSAbs_Face )
03991       continue;
03992 
03993     bool hasFreeLinks = false;
03994 
03995     TIDSortedElemSet avoidSet;
03996     avoidSet.insert( elem );
03997 
03998     set<const SMDS_MeshNode*> aFaceLastNodes;
03999     int iNode, nbNodes = vecNewNodes.size();
04000     if ( !isQuadratic ) {
04001       // loop on the face nodes
04002       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
04003         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
04004         // look for free links of the face
04005         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
04006         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
04007         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
04008         // check if a link is free
04009         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
04010           hasFreeLinks = true;
04011           // make an edge and a ceiling for a new edge
04012           if ( !aMesh->FindEdge( n1, n2 )) {
04013             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
04014             srcElements.Append( myLastCreatedElems.Last() );
04015           }
04016           n1 = vecNewNodes[ iNode ]->second.back();
04017           n2 = vecNewNodes[ iNext ]->second.back();
04018           if ( !aMesh->FindEdge( n1, n2 )) {
04019             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
04020             srcElements.Append( myLastCreatedElems.Last() );
04021           }
04022         }
04023       }
04024     }
04025     else { // elem is quadratic face
04026       int nbn = nbNodes/2;
04027       for ( iNode = 0; iNode < nbn; iNode++ ) {
04028         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
04029         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
04030         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
04031         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
04032         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
04033         // check if a link is free
04034         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
04035              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
04036              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
04037           hasFreeLinks = true;
04038           // make an edge and a ceiling for a new edge
04039           // find medium node
04040           if ( !aMesh->FindEdge( n1, n2, n3 )) {
04041             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
04042             srcElements.Append( myLastCreatedElems.Last() );
04043           }
04044           n1 = vecNewNodes[ iNode ]->second.back();
04045           n2 = vecNewNodes[ iNext ]->second.back();
04046           n3 = vecNewNodes[ iNode+nbn ]->second.back();
04047           if ( !aMesh->FindEdge( n1, n2, n3 )) {
04048             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
04049             srcElements.Append( myLastCreatedElems.Last() );
04050           }
04051         }
04052       }
04053       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
04054         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
04055       }
04056     }
04057 
04058     // sweep free links into faces
04059 
04060     if ( hasFreeLinks )  {
04061       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
04062       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
04063 
04064       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
04065       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
04066         initNodeSet.insert( vecNewNodes[ iNode ]->first );
04067         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
04068       }
04069       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
04070         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
04071         std::advance( v, volNb );
04072         // find indices of free faces of a volume and their source edges
04073         list< int > freeInd;
04074         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
04075         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
04076         int iF, nbF = vTool.NbFaces();
04077         for ( iF = 0; iF < nbF; iF ++ ) {
04078           if (vTool.IsFreeFace( iF ) &&
04079               vTool.GetFaceNodes( iF, faceNodeSet ) &&
04080               initNodeSet != faceNodeSet) // except an initial face
04081           {
04082             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
04083               continue;
04084             freeInd.push_back( iF );
04085             // find source edge of a free face iF
04086             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
04087             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
04088             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
04089                                    initNodeSet.begin(), initNodeSet.end(),
04090                                    commonNodes.begin());
04091             if ( (*v)->IsQuadratic() )
04092               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
04093             else
04094               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
04095 #ifdef _DEBUG_
04096             if ( !srcEdges.back() )
04097             {
04098               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
04099                    << iF << " of volume #" << vTool.ID() << endl;
04100             }
04101 #endif
04102           }
04103         }
04104         if ( freeInd.empty() )
04105           continue;
04106 
04107         // create faces for all steps;
04108         // if such a face has been already created by sweep of edge,
04109         // assure that its orientation is OK
04110         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
04111           vTool.Set( *v, /*ignoreCentralNodes=*/false );
04112           vTool.SetExternalNormal();
04113           const int nextShift = vTool.IsForward() ? +1 : -1;
04114           list< int >::iterator ind = freeInd.begin();
04115           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
04116           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
04117           {
04118             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
04119             int nbn = vTool.NbFaceNodes( *ind );
04120             const SMDS_MeshElement * f = 0;
04121             if ( nbn == 3 )              
04122             {
04123               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
04124               if ( !f ||
04125                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
04126               {
04127                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
04128                                                      nodes[ 1 ],
04129                                                      nodes[ 1 + nextShift ] };
04130                 if ( f )
04131                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
04132                 else
04133                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
04134                                                             newOrder[ 2 ] ));
04135               }
04136             }
04137             else if ( nbn == 4 )       
04138             {
04139               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
04140               if ( !f ||
04141                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
04142               {
04143                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
04144                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
04145                 if ( f )
04146                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
04147                 else
04148                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
04149                                                             newOrder[ 2 ], newOrder[ 3 ]));
04150               }
04151             }
04152             else if ( nbn == 6 && isQuadratic ) 
04153             {
04154               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
04155               if ( !f ||
04156                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
04157               {
04158                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
04159                                                      nodes[2],
04160                                                      nodes[2 + 2*nextShift],
04161                                                      nodes[3 - 2*nextShift],
04162                                                      nodes[3],
04163                                                      nodes[3 + 2*nextShift]};
04164                 if ( f )
04165                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
04166                 else
04167                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
04168                                                             newOrder[ 1 ],
04169                                                             newOrder[ 2 ],
04170                                                             newOrder[ 3 ],
04171                                                             newOrder[ 4 ],
04172                                                             newOrder[ 5 ] ));
04173               }
04174             }
04175             else if ( nbn == 8 && isQuadratic ) 
04176             {
04177               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
04178                                    nodes[1], nodes[3], nodes[5], nodes[7] );
04179               if ( !f ||
04180                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
04181               {
04182                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
04183                                                      nodes[4 - 2*nextShift],
04184                                                      nodes[4],
04185                                                      nodes[4 + 2*nextShift],
04186                                                      nodes[1],
04187                                                      nodes[5 - 2*nextShift],
04188                                                      nodes[5],
04189                                                      nodes[5 + 2*nextShift] };
04190                 if ( f )
04191                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
04192                 else
04193                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
04194                                                            newOrder[ 2 ], newOrder[ 3 ],
04195                                                            newOrder[ 4 ], newOrder[ 5 ],
04196                                                            newOrder[ 6 ], newOrder[ 7 ]));
04197               }
04198             }
04199             else if ( nbn == 9 && isQuadratic ) 
04200             {
04201               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
04202                                       SMDSAbs_Face, /*noMedium=*/false);
04203               if ( !f ||
04204                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
04205               {
04206                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
04207                                                      nodes[4 - 2*nextShift],
04208                                                      nodes[4],
04209                                                      nodes[4 + 2*nextShift],
04210                                                      nodes[1],
04211                                                      nodes[5 - 2*nextShift],
04212                                                      nodes[5],
04213                                                      nodes[5 + 2*nextShift],
04214                                                      nodes[8] };
04215                 if ( f )
04216                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
04217                 else
04218                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
04219                                                            newOrder[ 2 ], newOrder[ 3 ],
04220                                                            newOrder[ 4 ], newOrder[ 5 ],
04221                                                            newOrder[ 6 ], newOrder[ 7 ],
04222                                                            newOrder[ 8 ]));
04223               }
04224             }
04225             else  
04226             {
04227               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
04228               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
04229               if ( !f ||
04230                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
04231               {
04232                 if ( !vTool.IsForward() )
04233                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
04234                 if ( f )
04235                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
04236                 else
04237                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
04238               }
04239             }
04240 
04241             while ( srcElements.Length() < myLastCreatedElems.Length() )
04242               srcElements.Append( *srcEdge );
04243 
04244           }  // loop on free faces
04245 
04246           // go to the next volume
04247           iVol = 0;
04248           while ( iVol++ < nbVolumesByStep ) v++;
04249 
04250         } // loop on steps
04251       } // loop on volumes of one step
04252     } // sweep free links into faces
04253 
04254     // Make a ceiling face with a normal external to a volume
04255 
04256     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
04257 
04258     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
04259     if ( iF >= 0 ) {
04260       lastVol.SetExternalNormal();
04261       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
04262       int nbn = lastVol.NbFaceNodes( iF );
04263       if ( nbn == 3 ) {
04264         if (!hasFreeLinks ||
04265             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
04266           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
04267       }
04268       else if ( nbn == 4 )
04269       {
04270         if (!hasFreeLinks ||
04271             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
04272           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
04273       }
04274       else if ( nbn == 6 && isQuadratic )
04275       {
04276         if (!hasFreeLinks ||
04277             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
04278           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
04279                                                    nodes[1], nodes[3], nodes[5]));
04280       }
04281       else if ( nbn == 8 && isQuadratic )
04282       {
04283         if (!hasFreeLinks ||
04284             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
04285                              nodes[1], nodes[3], nodes[5], nodes[7]) )
04286           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
04287                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
04288       }
04289       else if ( nbn == 9 && isQuadratic )
04290       {
04291         if (!hasFreeLinks ||
04292             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
04293                                 SMDSAbs_Face, /*noMedium=*/false) )
04294           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
04295                                                    nodes[1], nodes[3], nodes[5], nodes[7],
04296                                                    nodes[8]));
04297       }
04298       else {
04299         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
04300         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
04301           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
04302       }
04303 
04304       while ( srcElements.Length() < myLastCreatedElems.Length() )
04305         srcElements.Append( myLastCreatedElems.Last() );
04306     }
04307   } // loop on swept elements
04308 }
04309 
04310 //=======================================================================
04311 //function : RotationSweep
04312 //purpose  :
04313 //=======================================================================
04314 
04315 SMESH_MeshEditor::PGroupIDs
04316 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
04317                                 const gp_Ax1&      theAxis,
04318                                 const double       theAngle,
04319                                 const int          theNbSteps,
04320                                 const double       theTol,
04321                                 const bool         theMakeGroups,
04322                                 const bool         theMakeWalls)
04323 {
04324   myLastCreatedElems.Clear();
04325   myLastCreatedNodes.Clear();
04326 
04327   // source elements for each generated one
04328   SMESH_SequenceOfElemPtr srcElems, srcNodes;
04329 
04330   MESSAGE( "RotationSweep()");
04331   gp_Trsf aTrsf;
04332   aTrsf.SetRotation( theAxis, theAngle );
04333   gp_Trsf aTrsf2;
04334   aTrsf2.SetRotation( theAxis, theAngle/2. );
04335 
04336   gp_Lin aLine( theAxis );
04337   double aSqTol = theTol * theTol;
04338 
04339   SMESHDS_Mesh* aMesh = GetMeshDS();
04340 
04341   TNodeOfNodeListMap mapNewNodes;
04342   TElemOfVecOfNnlmiMap mapElemNewNodes;
04343   TElemOfElemListMap newElemsMap;
04344 
04345   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
04346                                      myMesh->NbFaces(ORDER_QUADRATIC) +
04347                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
04348   // loop on theElems
04349   TIDSortedElemSet::iterator itElem;
04350   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
04351     const SMDS_MeshElement* elem = *itElem;
04352     if ( !elem || elem->GetType() == SMDSAbs_Volume )
04353       continue;
04354     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
04355     newNodesItVec.reserve( elem->NbNodes() );
04356 
04357     // loop on elem nodes
04358     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
04359     while ( itN->more() )
04360     {
04361       // check if a node has been already sweeped
04362       const SMDS_MeshNode* node = cast2Node( itN->next() );
04363 
04364       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
04365       double coord[3];
04366       aXYZ.Coord( coord[0], coord[1], coord[2] );
04367       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
04368 
04369       TNodeOfNodeListMapItr nIt =
04370         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
04371       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
04372       if ( listNewNodes.empty() )
04373       {
04374         // check if we are to create medium nodes between corner ones
04375         bool needMediumNodes = false;
04376         if ( isQuadraticMesh )
04377         {
04378           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
04379           while (it->more() && !needMediumNodes )
04380           {
04381             const SMDS_MeshElement* invElem = it->next();
04382             if ( invElem != elem && !theElems.count( invElem )) continue;
04383             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
04384             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
04385               needMediumNodes = true;
04386           }
04387         }
04388 
04389         // make new nodes
04390         const SMDS_MeshNode * newNode = node;
04391         for ( int i = 0; i < theNbSteps; i++ ) {
04392           if ( !isOnAxis ) {
04393             if ( needMediumNodes )  // create a medium node
04394             {
04395               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
04396               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
04397               myLastCreatedNodes.Append(newNode);
04398               srcNodes.Append( node );
04399               listNewNodes.push_back( newNode );
04400               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
04401             }
04402             else {
04403               aTrsf.Transforms( coord[0], coord[1], coord[2] );
04404             }
04405             // create a corner node
04406             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
04407             myLastCreatedNodes.Append(newNode);
04408             srcNodes.Append( node );
04409             listNewNodes.push_back( newNode );
04410           }
04411           else {
04412             listNewNodes.push_back( newNode );
04413             // if ( needMediumNodes )
04414             //   listNewNodes.push_back( newNode );
04415           }
04416         }
04417       }
04418       newNodesItVec.push_back( nIt );
04419     }
04420     // make new elements
04421     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
04422   }
04423 
04424   if ( theMakeWalls )
04425     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
04426 
04427   PGroupIDs newGroupIDs;
04428   if ( theMakeGroups )
04429     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
04430 
04431   return newGroupIDs;
04432 }
04433 
04434 
04435 //=======================================================================
04436 //function : CreateNode
04437 //purpose  :
04438 //=======================================================================
04439 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
04440                                                   const double y,
04441                                                   const double z,
04442                                                   const double tolnode,
04443                                                   SMESH_SequenceOfNode& aNodes)
04444 {
04445   // myLastCreatedElems.Clear();
04446   // myLastCreatedNodes.Clear();
04447 
04448   gp_Pnt P1(x,y,z);
04449   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
04450 
04451   // try to search in sequence of existing nodes
04452   // if aNodes.Length()>0 we 'nave to use given sequence
04453   // else - use all nodes of mesh
04454   if(aNodes.Length()>0) {
04455     int i;
04456     for(i=1; i<=aNodes.Length(); i++) {
04457       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
04458       if(P1.Distance(P2)<tolnode)
04459         return aNodes.Value(i);
04460     }
04461   }
04462   else {
04463     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
04464     while(itn->more()) {
04465       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
04466       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
04467       if(P1.Distance(P2)<tolnode)
04468         return aN;
04469     }
04470   }
04471 
04472   // create new node and return it
04473   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
04474   //myLastCreatedNodes.Append(NewNode);
04475   return NewNode;
04476 }
04477 
04478 
04479 //=======================================================================
04480 //function : ExtrusionSweep
04481 //purpose  :
04482 //=======================================================================
04483 
04484 SMESH_MeshEditor::PGroupIDs
04485 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
04486                                   const gp_Vec&       theStep,
04487                                   const int           theNbSteps,
04488                                   TElemOfElemListMap& newElemsMap,
04489                                   const bool          theMakeGroups,
04490                                   const int           theFlags,
04491                                   const double        theTolerance)
04492 {
04493   ExtrusParam aParams;
04494   aParams.myDir = gp_Dir(theStep);
04495   aParams.myNodes.Clear();
04496   aParams.mySteps = new TColStd_HSequenceOfReal;
04497   int i;
04498   for(i=1; i<=theNbSteps; i++)
04499     aParams.mySteps->Append(theStep.Magnitude());
04500 
04501   return
04502     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
04503 }
04504 
04505 
04506 //=======================================================================
04507 //function : ExtrusionSweep
04508 //purpose  :
04509 //=======================================================================
04510 
04511 SMESH_MeshEditor::PGroupIDs
04512 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
04513                                   ExtrusParam&        theParams,
04514                                   TElemOfElemListMap& newElemsMap,
04515                                   const bool          theMakeGroups,
04516                                   const int           theFlags,
04517                                   const double        theTolerance)
04518 {
04519   myLastCreatedElems.Clear();
04520   myLastCreatedNodes.Clear();
04521 
04522   // source elements for each generated one
04523   SMESH_SequenceOfElemPtr srcElems, srcNodes;
04524 
04525   SMESHDS_Mesh* aMesh = GetMeshDS();
04526 
04527   int nbsteps = theParams.mySteps->Length();
04528 
04529   TNodeOfNodeListMap mapNewNodes;
04530   //TNodeOfNodeVecMap mapNewNodes;
04531   TElemOfVecOfNnlmiMap mapElemNewNodes;
04532   //TElemOfVecOfMapNodesMap mapElemNewNodes;
04533 
04534   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
04535                                      myMesh->NbFaces(ORDER_QUADRATIC) +
04536                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
04537   // loop on theElems
04538   TIDSortedElemSet::iterator itElem;
04539   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
04540     // check element type
04541     const SMDS_MeshElement* elem = *itElem;
04542     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
04543       continue;
04544 
04545     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
04546     newNodesItVec.reserve( elem->NbNodes() );
04547 
04548     // loop on elem nodes
04549     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
04550     while ( itN->more() )
04551     {
04552       // check if a node has been already sweeped
04553       const SMDS_MeshNode* node = cast2Node( itN->next() );
04554       TNodeOfNodeListMap::iterator nIt =
04555         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
04556       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
04557       if ( listNewNodes.empty() )
04558       {
04559         // make new nodes
04560 
04561         // check if we are to create medium nodes between corner ones
04562         bool needMediumNodes = false;
04563         if ( isQuadraticMesh )
04564         {
04565           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
04566           while (it->more() && !needMediumNodes )
04567           {
04568             const SMDS_MeshElement* invElem = it->next();
04569             if ( invElem != elem && !theElems.count( invElem )) continue;
04570             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
04571             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
04572               needMediumNodes = true;
04573           }
04574         }
04575 
04576         double coord[] = { node->X(), node->Y(), node->Z() };
04577         for ( int i = 0; i < nbsteps; i++ )
04578         {
04579           if ( needMediumNodes ) // create a medium node
04580           {
04581             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
04582             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
04583             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
04584             if( theFlags & EXTRUSION_FLAG_SEW ) {
04585               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
04586                                                          theTolerance, theParams.myNodes);
04587               listNewNodes.push_back( newNode );
04588             }
04589             else {
04590               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
04591               myLastCreatedNodes.Append(newNode);
04592               srcNodes.Append( node );
04593               listNewNodes.push_back( newNode );
04594             }
04595           }
04596           // create a corner node
04597           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
04598           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
04599           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
04600           if( theFlags & EXTRUSION_FLAG_SEW ) {
04601             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
04602                                                        theTolerance, theParams.myNodes);
04603             listNewNodes.push_back( newNode );
04604           }
04605           else {
04606             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
04607             myLastCreatedNodes.Append(newNode);
04608             srcNodes.Append( node );
04609             listNewNodes.push_back( newNode );
04610           }
04611         }
04612       }
04613       newNodesItVec.push_back( nIt );
04614     }
04615     // make new elements
04616     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
04617   }
04618 
04619   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
04620     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
04621   }
04622   PGroupIDs newGroupIDs;
04623   if ( theMakeGroups )
04624     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
04625 
04626   return newGroupIDs;
04627 }
04628 
04629 //=======================================================================
04630 //function : ExtrusionAlongTrack
04631 //purpose  :
04632 //=======================================================================
04633 SMESH_MeshEditor::Extrusion_Error
04634 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
04635                                        SMESH_subMesh*       theTrack,
04636                                        const SMDS_MeshNode* theN1,
04637                                        const bool           theHasAngles,
04638                                        list<double>&        theAngles,
04639                                        const bool           theLinearVariation,
04640                                        const bool           theHasRefPoint,
04641                                        const gp_Pnt&        theRefPoint,
04642                                        const bool           theMakeGroups)
04643 {
04644   MESSAGE("ExtrusionAlongTrack");
04645   myLastCreatedElems.Clear();
04646   myLastCreatedNodes.Clear();
04647 
04648   int aNbE;
04649   std::list<double> aPrms;
04650   TIDSortedElemSet::iterator itElem;
04651 
04652   gp_XYZ aGC;
04653   TopoDS_Edge aTrackEdge;
04654   TopoDS_Vertex aV1, aV2;
04655 
04656   SMDS_ElemIteratorPtr aItE;
04657   SMDS_NodeIteratorPtr aItN;
04658   SMDSAbs_ElementType aTypeE;
04659 
04660   TNodeOfNodeListMap mapNewNodes;
04661 
04662   // 1. Check data
04663   aNbE = theElements.size();
04664   // nothing to do
04665   if ( !aNbE )
04666     return EXTR_NO_ELEMENTS;
04667 
04668   // 1.1 Track Pattern
04669   ASSERT( theTrack );
04670 
04671   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
04672 
04673   aItE = pSubMeshDS->GetElements();
04674   while ( aItE->more() ) {
04675     const SMDS_MeshElement* pE = aItE->next();
04676     aTypeE = pE->GetType();
04677     // Pattern must contain links only
04678     if ( aTypeE != SMDSAbs_Edge )
04679       return EXTR_PATH_NOT_EDGE;
04680   }
04681 
04682   list<SMESH_MeshEditor_PathPoint> fullList;
04683 
04684   const TopoDS_Shape& aS = theTrack->GetSubShape();
04685   // Sub-shape for the Pattern must be an Edge or Wire
04686   if( aS.ShapeType() == TopAbs_EDGE ) {
04687     aTrackEdge = TopoDS::Edge( aS );
04688     // the Edge must not be degenerated
04689     if ( BRep_Tool::Degenerated( aTrackEdge ) )
04690       return EXTR_BAD_PATH_SHAPE;
04691     TopExp::Vertices( aTrackEdge, aV1, aV2 );
04692     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
04693     const SMDS_MeshNode* aN1 = aItN->next();
04694     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
04695     const SMDS_MeshNode* aN2 = aItN->next();
04696     // starting node must be aN1 or aN2
04697     if ( !( aN1 == theN1 || aN2 == theN1 ) )
04698       return EXTR_BAD_STARTING_NODE;
04699     aItN = pSubMeshDS->GetNodes();
04700     while ( aItN->more() ) {
04701       const SMDS_MeshNode* pNode = aItN->next();
04702       const SMDS_EdgePosition* pEPos =
04703         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
04704       double aT = pEPos->GetUParameter();
04705       aPrms.push_back( aT );
04706     }
04707     //Extrusion_Error err =
04708     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
04709   } else if( aS.ShapeType() == TopAbs_WIRE ) {
04710     list< SMESH_subMesh* > LSM;
04711     TopTools_SequenceOfShape Edges;
04712     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
04713     while(itSM->more()) {
04714       SMESH_subMesh* SM = itSM->next();
04715       LSM.push_back(SM);
04716       const TopoDS_Shape& aS = SM->GetSubShape();
04717       Edges.Append(aS);
04718     }
04719     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
04720     int startNid = theN1->GetID();
04721     TColStd_MapOfInteger UsedNums;
04722     
04723     int NbEdges = Edges.Length();
04724     int i = 1;
04725     for(; i<=NbEdges; i++) {
04726       int k = 0;
04727       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
04728       for(; itLSM!=LSM.end(); itLSM++) {
04729         k++;
04730         if(UsedNums.Contains(k)) continue;
04731         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
04732         SMESH_subMesh* locTrack = *itLSM;
04733         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
04734         TopExp::Vertices( aTrackEdge, aV1, aV2 );
04735         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
04736         const SMDS_MeshNode* aN1 = aItN->next();
04737         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
04738         const SMDS_MeshNode* aN2 = aItN->next();
04739         // starting node must be aN1 or aN2
04740         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
04741         // 2. Collect parameters on the track edge
04742         aPrms.clear();
04743         aItN = locMeshDS->GetNodes();
04744         while ( aItN->more() ) {
04745           const SMDS_MeshNode* pNode = aItN->next();
04746           const SMDS_EdgePosition* pEPos =
04747             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
04748           double aT = pEPos->GetUParameter();
04749           aPrms.push_back( aT );
04750         }
04751         list<SMESH_MeshEditor_PathPoint> LPP;
04752         //Extrusion_Error err =
04753         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
04754         LLPPs.push_back(LPP);
04755         UsedNums.Add(k);
04756         // update startN for search following egde
04757         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
04758         else startNid = aN1->GetID();
04759         break;
04760       }
04761     }
04762     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
04763     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
04764     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
04765     for(; itPP!=firstList.end(); itPP++) {
04766       fullList.push_back( *itPP );
04767     }
04768     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
04769     fullList.pop_back();
04770     itLLPP++;
04771     for(; itLLPP!=LLPPs.end(); itLLPP++) {
04772       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
04773       itPP = currList.begin();
04774       SMESH_MeshEditor_PathPoint PP2 = currList.front();
04775       gp_Dir D1 = PP1.Tangent();
04776       gp_Dir D2 = PP2.Tangent();
04777       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
04778                            (D1.Z()+D2.Z())/2 ) );
04779       PP1.SetTangent(Dnew);
04780       fullList.push_back(PP1);
04781       itPP++;
04782       for(; itPP!=firstList.end(); itPP++) {
04783         fullList.push_back( *itPP );
04784       }
04785       PP1 = fullList.back();
04786       fullList.pop_back();
04787     }
04788     // if wire not closed
04789     fullList.push_back(PP1);
04790     // else ???
04791   }
04792   else {
04793     return EXTR_BAD_PATH_SHAPE;
04794   }
04795 
04796   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
04797                           theHasRefPoint, theRefPoint, theMakeGroups);
04798 }
04799 
04800 
04801 //=======================================================================
04802 //function : ExtrusionAlongTrack
04803 //purpose  :
04804 //=======================================================================
04805 SMESH_MeshEditor::Extrusion_Error
04806 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
04807                                        SMESH_Mesh*          theTrack,
04808                                        const SMDS_MeshNode* theN1,
04809                                        const bool           theHasAngles,
04810                                        list<double>&        theAngles,
04811                                        const bool           theLinearVariation,
04812                                        const bool           theHasRefPoint,
04813                                        const gp_Pnt&        theRefPoint,
04814                                        const bool           theMakeGroups)
04815 {
04816   myLastCreatedElems.Clear();
04817   myLastCreatedNodes.Clear();
04818 
04819   int aNbE;
04820   std::list<double> aPrms;
04821   TIDSortedElemSet::iterator itElem;
04822 
04823   gp_XYZ aGC;
04824   TopoDS_Edge aTrackEdge;
04825   TopoDS_Vertex aV1, aV2;
04826 
04827   SMDS_ElemIteratorPtr aItE;
04828   SMDS_NodeIteratorPtr aItN;
04829   SMDSAbs_ElementType aTypeE;
04830 
04831   TNodeOfNodeListMap mapNewNodes;
04832 
04833   // 1. Check data
04834   aNbE = theElements.size();
04835   // nothing to do
04836   if ( !aNbE )
04837     return EXTR_NO_ELEMENTS;
04838 
04839   // 1.1 Track Pattern
04840   ASSERT( theTrack );
04841 
04842   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
04843 
04844   aItE = pMeshDS->elementsIterator();
04845   while ( aItE->more() ) {
04846     const SMDS_MeshElement* pE = aItE->next();
04847     aTypeE = pE->GetType();
04848     // Pattern must contain links only
04849     if ( aTypeE != SMDSAbs_Edge )
04850       return EXTR_PATH_NOT_EDGE;
04851   }
04852 
04853   list<SMESH_MeshEditor_PathPoint> fullList;
04854 
04855   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
04856 
04857   if( aS == SMESH_Mesh::PseudoShape() ) {
04858     //Mesh without shape
04859     const SMDS_MeshNode* currentNode = NULL;
04860     const SMDS_MeshNode* prevNode = theN1;
04861     std::vector<const SMDS_MeshNode*> aNodesList;
04862     aNodesList.push_back(theN1);
04863     int nbEdges = 0, conn=0;
04864     const SMDS_MeshElement* prevElem = NULL;
04865     const SMDS_MeshElement* currentElem = NULL;
04866     int totalNbEdges = theTrack->NbEdges();
04867     SMDS_ElemIteratorPtr nIt;
04868     bool isClosed = false;
04869 
04870     //check start node
04871     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
04872       return EXTR_BAD_STARTING_NODE;
04873     }
04874     
04875     conn = nbEdgeConnectivity(theN1);
04876     if(conn > 2)
04877       return EXTR_PATH_NOT_EDGE;
04878 
04879     aItE = theN1->GetInverseElementIterator();
04880     prevElem = aItE->next();
04881     currentElem = prevElem;
04882     //Get all nodes
04883     if(totalNbEdges == 1 ) {
04884       nIt = currentElem->nodesIterator();
04885       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
04886       if(currentNode == prevNode)
04887         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
04888       aNodesList.push_back(currentNode);
04889     } else { 
04890       nIt = currentElem->nodesIterator();
04891       while( nIt->more() ) {
04892         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
04893         if(currentNode == prevNode)
04894           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
04895         aNodesList.push_back(currentNode);
04896         
04897         //case of the closed mesh
04898         if(currentNode == theN1) {
04899           nbEdges++;
04900           isClosed = true;
04901           break;
04902         }
04903 
04904         conn = nbEdgeConnectivity(currentNode);
04905         if(conn > 2) {
04906           return EXTR_PATH_NOT_EDGE;    
04907         }else if( conn == 1 && nbEdges > 0 ) {
04908           //End of the path
04909           nbEdges++;
04910           break;
04911         }else {
04912           prevNode = currentNode;
04913           aItE = currentNode->GetInverseElementIterator();
04914           currentElem = aItE->next();
04915           if( currentElem  == prevElem)
04916             currentElem = aItE->next();
04917           nIt = currentElem->nodesIterator();
04918           prevElem = currentElem;
04919           nbEdges++;
04920         }
04921       }
04922     } 
04923     
04924     if(nbEdges != totalNbEdges)
04925       return EXTR_PATH_NOT_EDGE;
04926 
04927     TopTools_SequenceOfShape Edges;
04928     double x1,x2,y1,y2,z1,z2;
04929     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
04930     int startNid = theN1->GetID();
04931     for(int i = 1; i < aNodesList.size(); i++) {
04932       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
04933       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
04934       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
04935       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
04936       list<SMESH_MeshEditor_PathPoint> LPP;
04937       aPrms.clear();
04938       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
04939       LLPPs.push_back(LPP);
04940       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
04941       else startNid = aNodesList[i-1]->GetID();
04942 
04943     }
04944 
04945     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
04946     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
04947     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
04948     for(; itPP!=firstList.end(); itPP++) {
04949       fullList.push_back( *itPP );
04950     }
04951 
04952     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
04953     SMESH_MeshEditor_PathPoint PP2;
04954     fullList.pop_back();
04955     itLLPP++;
04956     for(; itLLPP!=LLPPs.end(); itLLPP++) {
04957       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
04958       itPP = currList.begin();
04959       PP2 = currList.front();
04960       gp_Dir D1 = PP1.Tangent();
04961       gp_Dir D2 = PP2.Tangent();
04962       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
04963                            (D1.Z()+D2.Z())/2 ) );
04964       PP1.SetTangent(Dnew);
04965       fullList.push_back(PP1);
04966       itPP++;
04967       for(; itPP!=currList.end(); itPP++) {
04968         fullList.push_back( *itPP );
04969       }
04970       PP1 = fullList.back();
04971       fullList.pop_back();
04972     }
04973     fullList.push_back(PP1);
04974     
04975   } // Sub-shape for the Pattern must be an Edge or Wire
04976   else if( aS.ShapeType() == TopAbs_EDGE ) {
04977     aTrackEdge = TopoDS::Edge( aS );
04978     // the Edge must not be degenerated
04979     if ( BRep_Tool::Degenerated( aTrackEdge ) )
04980       return EXTR_BAD_PATH_SHAPE;
04981     TopExp::Vertices( aTrackEdge, aV1, aV2 );
04982     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
04983     const SMDS_MeshNode* aN1 = aItN->next();
04984     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
04985     const SMDS_MeshNode* aN2 = aItN->next();
04986     // starting node must be aN1 or aN2
04987     if ( !( aN1 == theN1 || aN2 == theN1 ) )
04988       return EXTR_BAD_STARTING_NODE;
04989     aItN = pMeshDS->nodesIterator();
04990     while ( aItN->more() ) {
04991       const SMDS_MeshNode* pNode = aItN->next();
04992       if( pNode==aN1 || pNode==aN2 ) continue;
04993       const SMDS_EdgePosition* pEPos =
04994         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
04995       double aT = pEPos->GetUParameter();
04996       aPrms.push_back( aT );
04997     }
04998     //Extrusion_Error err =
04999     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
05000   }
05001   else if( aS.ShapeType() == TopAbs_WIRE ) {
05002     list< SMESH_subMesh* > LSM;
05003     TopTools_SequenceOfShape Edges;
05004     TopExp_Explorer eExp(aS, TopAbs_EDGE);
05005     for(; eExp.More(); eExp.Next()) {
05006       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
05007       if( BRep_Tool::Degenerated(E) ) continue;
05008       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
05009       if(SM) {
05010         LSM.push_back(SM);
05011         Edges.Append(E);
05012       }
05013     }
05014     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
05015     int startNid = theN1->GetID();
05016     TColStd_MapOfInteger UsedNums;
05017     int NbEdges = Edges.Length();
05018     int i = 1;
05019     for(; i<=NbEdges; i++) {
05020       int k = 0;
05021       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
05022       for(; itLSM!=LSM.end(); itLSM++) {
05023         k++;
05024         if(UsedNums.Contains(k)) continue;
05025         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
05026         SMESH_subMesh* locTrack = *itLSM;
05027         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
05028         TopExp::Vertices( aTrackEdge, aV1, aV2 );
05029         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
05030         const SMDS_MeshNode* aN1 = aItN->next();
05031         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
05032         const SMDS_MeshNode* aN2 = aItN->next();
05033         // starting node must be aN1 or aN2
05034         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
05035         // 2. Collect parameters on the track edge
05036         aPrms.clear();
05037         aItN = locMeshDS->GetNodes();
05038         while ( aItN->more() ) {
05039           const SMDS_MeshNode* pNode = aItN->next();
05040           const SMDS_EdgePosition* pEPos =
05041             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
05042           double aT = pEPos->GetUParameter();
05043           aPrms.push_back( aT );
05044         }
05045         list<SMESH_MeshEditor_PathPoint> LPP;
05046         //Extrusion_Error err =
05047         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
05048         LLPPs.push_back(LPP);
05049         UsedNums.Add(k);
05050         // update startN for search following egde
05051         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
05052         else startNid = aN1->GetID();
05053         break;
05054       }
05055     }
05056     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
05057     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
05058     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
05059     for(; itPP!=firstList.end(); itPP++) {
05060       fullList.push_back( *itPP );
05061     }
05062     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
05063     fullList.pop_back();
05064     itLLPP++;
05065     for(; itLLPP!=LLPPs.end(); itLLPP++) {
05066       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
05067       itPP = currList.begin();
05068       SMESH_MeshEditor_PathPoint PP2 = currList.front();
05069       gp_Dir D1 = PP1.Tangent();
05070       gp_Dir D2 = PP2.Tangent();
05071       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
05072                            (D1.Z()+D2.Z())/2 ) );
05073       PP1.SetTangent(Dnew);
05074       fullList.push_back(PP1);
05075       itPP++;
05076       for(; itPP!=currList.end(); itPP++) {
05077         fullList.push_back( *itPP );
05078       }
05079       PP1 = fullList.back();
05080       fullList.pop_back();
05081     }
05082     // if wire not closed
05083     fullList.push_back(PP1);
05084     // else ???
05085   }
05086   else {
05087     return EXTR_BAD_PATH_SHAPE;
05088   }
05089 
05090   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
05091                           theHasRefPoint, theRefPoint, theMakeGroups);
05092 }
05093 
05094 
05095 //=======================================================================
05096 //function : MakeEdgePathPoints
05097 //purpose  : auxilary for ExtrusionAlongTrack
05098 //=======================================================================
05099 SMESH_MeshEditor::Extrusion_Error
05100 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
05101                                      const TopoDS_Edge& aTrackEdge,
05102                                      bool FirstIsStart,
05103                                      list<SMESH_MeshEditor_PathPoint>& LPP)
05104 {
05105   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
05106   aTolVec=1.e-7;
05107   aTolVec2=aTolVec*aTolVec;
05108   double aT1, aT2;
05109   TopoDS_Vertex aV1, aV2;
05110   TopExp::Vertices( aTrackEdge, aV1, aV2 );
05111   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
05112   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
05113   // 2. Collect parameters on the track edge
05114   aPrms.push_front( aT1 );
05115   aPrms.push_back( aT2 );
05116   // sort parameters
05117   aPrms.sort();
05118   if( FirstIsStart ) {
05119     if ( aT1 > aT2 ) {
05120       aPrms.reverse();
05121     }
05122   }
05123   else {
05124     if ( aT2 > aT1 ) {
05125       aPrms.reverse();
05126     }
05127   }
05128   // 3. Path Points
05129   SMESH_MeshEditor_PathPoint aPP;
05130   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
05131   std::list<double>::iterator aItD = aPrms.begin();
05132   for(; aItD != aPrms.end(); ++aItD) {
05133     double aT = *aItD;
05134     gp_Pnt aP3D;
05135     gp_Vec aVec;
05136     aC3D->D1( aT, aP3D, aVec );
05137     aL2 = aVec.SquareMagnitude();
05138     if ( aL2 < aTolVec2 )
05139       return EXTR_CANT_GET_TANGENT;
05140     gp_Dir aTgt( aVec );
05141     aPP.SetPnt( aP3D );
05142     aPP.SetTangent( aTgt );
05143     aPP.SetParameter( aT );
05144     LPP.push_back(aPP);
05145   }
05146   return EXTR_OK;
05147 }
05148 
05149 
05150 //=======================================================================
05151 //function : MakeExtrElements
05152 //purpose  : auxilary for ExtrusionAlongTrack
05153 //=======================================================================
05154 SMESH_MeshEditor::Extrusion_Error
05155 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
05156                                    list<SMESH_MeshEditor_PathPoint>& fullList,
05157                                    const bool theHasAngles,
05158                                    list<double>& theAngles,
05159                                    const bool theLinearVariation,
05160                                    const bool theHasRefPoint,
05161                                    const gp_Pnt& theRefPoint,
05162                                    const bool theMakeGroups)
05163 {
05164   MESSAGE("MakeExtrElements");
05165   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
05166   int aNbTP = fullList.size();
05167   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
05168   // Angles
05169   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
05170     LinearAngleVariation(aNbTP-1, theAngles);
05171   }
05172   vector<double> aAngles( aNbTP );
05173   int j = 0;
05174   for(; j<aNbTP; ++j) {
05175     aAngles[j] = 0.;
05176   }
05177   if ( theHasAngles ) {
05178     double anAngle;;
05179     std::list<double>::iterator aItD = theAngles.begin();
05180     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
05181       anAngle = *aItD;
05182       aAngles[j] = anAngle;
05183     }
05184   }
05185   // fill vector of path points with angles
05186   //aPPs.resize(fullList.size());
05187   j = -1;
05188   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
05189   for(; itPP!=fullList.end(); itPP++) {
05190     j++;
05191     SMESH_MeshEditor_PathPoint PP = *itPP;
05192     PP.SetAngle(aAngles[j]);
05193     aPPs[j] = PP;
05194   }
05195 
05196   TNodeOfNodeListMap mapNewNodes;
05197   TElemOfVecOfNnlmiMap mapElemNewNodes;
05198   TElemOfElemListMap newElemsMap;
05199   TIDSortedElemSet::iterator itElem;
05200   double aX, aY, aZ;
05201   int aNb;
05202   SMDSAbs_ElementType aTypeE;
05203   // source elements for each generated one
05204   SMESH_SequenceOfElemPtr srcElems, srcNodes;
05205 
05206   // 3. Center of rotation aV0
05207   gp_Pnt aV0 = theRefPoint;
05208   gp_XYZ aGC;
05209   if ( !theHasRefPoint ) {
05210     aNb = 0;
05211     aGC.SetCoord( 0.,0.,0. );
05212 
05213     itElem = theElements.begin();
05214     for ( ; itElem != theElements.end(); itElem++ ) {
05215       const SMDS_MeshElement* elem = *itElem;
05216 
05217       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05218       while ( itN->more() ) {
05219         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
05220         aX = node->X();
05221         aY = node->Y();
05222         aZ = node->Z();
05223 
05224         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
05225           list<const SMDS_MeshNode*> aLNx;
05226           mapNewNodes[node] = aLNx;
05227           //
05228           gp_XYZ aXYZ( aX, aY, aZ );
05229           aGC += aXYZ;
05230           ++aNb;
05231         }
05232       }
05233     }
05234     aGC /= aNb;
05235     aV0.SetXYZ( aGC );
05236   } // if (!theHasRefPoint) {
05237   mapNewNodes.clear();
05238 
05239   // 4. Processing the elements
05240   SMESHDS_Mesh* aMesh = GetMeshDS();
05241 
05242   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
05243     // check element type
05244     const SMDS_MeshElement* elem = *itElem;
05245     aTypeE = elem->GetType();
05246     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
05247       continue;
05248 
05249     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
05250     newNodesItVec.reserve( elem->NbNodes() );
05251 
05252     // loop on elem nodes
05253     int nodeIndex = -1;
05254     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05255     while ( itN->more() )
05256     {
05257       ++nodeIndex;
05258       // check if a node has been already processed
05259       const SMDS_MeshNode* node =
05260         static_cast<const SMDS_MeshNode*>( itN->next() );
05261       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
05262       if ( nIt == mapNewNodes.end() ) {
05263         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
05264         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
05265 
05266         // make new nodes
05267         aX = node->X();  aY = node->Y(); aZ = node->Z();
05268 
05269         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
05270         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
05271         gp_Ax1 anAx1, anAxT1T0;
05272         gp_Dir aDT1x, aDT0x, aDT1T0;
05273 
05274         aTolAng=1.e-4;
05275 
05276         aV0x = aV0;
05277         aPN0.SetCoord(aX, aY, aZ);
05278 
05279         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
05280         aP0x = aPP0.Pnt();
05281         aDT0x= aPP0.Tangent();
05282         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
05283 
05284         for ( j = 1; j < aNbTP; ++j ) {
05285           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
05286           aP1x = aPP1.Pnt();
05287           aDT1x = aPP1.Tangent();
05288           aAngle1x = aPP1.Angle();
05289 
05290           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
05291           // Translation
05292           gp_Vec aV01x( aP0x, aP1x );
05293           aTrsf.SetTranslation( aV01x );
05294 
05295           // traslated point
05296           aV1x = aV0x.Transformed( aTrsf );
05297           aPN1 = aPN0.Transformed( aTrsf );
05298 
05299           // rotation 1 [ T1,T0 ]
05300           aAngleT1T0=-aDT1x.Angle( aDT0x );
05301           if (fabs(aAngleT1T0) > aTolAng) {
05302             aDT1T0=aDT1x^aDT0x;
05303             anAxT1T0.SetLocation( aV1x );
05304             anAxT1T0.SetDirection( aDT1T0 );
05305             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
05306 
05307             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
05308           }
05309 
05310           // rotation 2
05311           if ( theHasAngles ) {
05312             anAx1.SetLocation( aV1x );
05313             anAx1.SetDirection( aDT1x );
05314             aTrsfRot.SetRotation( anAx1, aAngle1x );
05315 
05316             aPN1 = aPN1.Transformed( aTrsfRot );
05317           }
05318 
05319           // make new node
05320           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
05321           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
05322             // create additional node
05323             double x = ( aPN1.X() + aPN0.X() )/2.;
05324             double y = ( aPN1.Y() + aPN0.Y() )/2.;
05325             double z = ( aPN1.Z() + aPN0.Z() )/2.;
05326             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
05327             myLastCreatedNodes.Append(newNode);
05328             srcNodes.Append( node );
05329             listNewNodes.push_back( newNode );
05330           }
05331           aX = aPN1.X();
05332           aY = aPN1.Y();
05333           aZ = aPN1.Z();
05334           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
05335           myLastCreatedNodes.Append(newNode);
05336           srcNodes.Append( node );
05337           listNewNodes.push_back( newNode );
05338 
05339           aPN0 = aPN1;
05340           aP0x = aP1x;
05341           aV0x = aV1x;
05342           aDT0x = aDT1x;
05343         }
05344       }
05345 
05346       else {
05347         // if current elem is quadratic and current node is not medium
05348         // we have to check - may be it is needed to insert additional nodes
05349         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
05350           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
05351           if(listNewNodes.size()==aNbTP-1) {
05352             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
05353             gp_XYZ P(node->X(), node->Y(), node->Z());
05354             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
05355             int i;
05356             for(i=0; i<aNbTP-1; i++) {
05357               const SMDS_MeshNode* N = *it;
05358               double x = ( N->X() + P.X() )/2.;
05359               double y = ( N->Y() + P.Y() )/2.;
05360               double z = ( N->Z() + P.Z() )/2.;
05361               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
05362               srcNodes.Append( node );
05363               myLastCreatedNodes.Append(newN);
05364               aNodes[2*i] = newN;
05365               aNodes[2*i+1] = N;
05366               P = gp_XYZ(N->X(),N->Y(),N->Z());
05367             }
05368             listNewNodes.clear();
05369             for(i=0; i<2*(aNbTP-1); i++) {
05370               listNewNodes.push_back(aNodes[i]);
05371             }
05372           }
05373         }
05374       }
05375 
05376       newNodesItVec.push_back( nIt );
05377     }
05378     // make new elements
05379     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
05380     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
05381     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
05382   }
05383 
05384   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
05385 
05386   if ( theMakeGroups )
05387     generateGroups( srcNodes, srcElems, "extruded");
05388 
05389   return EXTR_OK;
05390 }
05391 
05392 
05393 //=======================================================================
05394 //function : LinearAngleVariation
05395 //purpose  : auxilary for ExtrusionAlongTrack
05396 //=======================================================================
05397 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
05398                                             list<double>& Angles)
05399 {
05400   int nbAngles = Angles.size();
05401   if( nbSteps > nbAngles ) {
05402     vector<double> theAngles(nbAngles);
05403     list<double>::iterator it = Angles.begin();
05404     int i = -1;
05405     for(; it!=Angles.end(); it++) {
05406       i++;
05407       theAngles[i] = (*it);
05408     }
05409     list<double> res;
05410     double rAn2St = double( nbAngles ) / double( nbSteps );
05411     double angPrev = 0, angle;
05412     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
05413       double angCur = rAn2St * ( iSt+1 );
05414       double angCurFloor  = floor( angCur );
05415       double angPrevFloor = floor( angPrev );
05416       if ( angPrevFloor == angCurFloor )
05417         angle = rAn2St * theAngles[ int( angCurFloor ) ];
05418       else {
05419         int iP = int( angPrevFloor );
05420         double angPrevCeil = ceil(angPrev);
05421         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
05422 
05423         int iC = int( angCurFloor );
05424         if ( iC < nbAngles )
05425           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
05426 
05427         iP = int( angPrevCeil );
05428         while ( iC-- > iP )
05429           angle += theAngles[ iC ];
05430       }
05431       res.push_back(angle);
05432       angPrev = angCur;
05433     }
05434     Angles.clear();
05435     it = res.begin();
05436     for(; it!=res.end(); it++)
05437       Angles.push_back( *it );
05438   }
05439 }
05440 
05441 
05442 //================================================================================
05452 //================================================================================
05453 
05454 SMESH_MeshEditor::PGroupIDs
05455 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
05456                              const gp_Trsf&     theTrsf,
05457                              const bool         theCopy,
05458                              const bool         theMakeGroups,
05459                              SMESH_Mesh*        theTargetMesh)
05460 {
05461   myLastCreatedElems.Clear();
05462   myLastCreatedNodes.Clear();
05463 
05464   bool needReverse = false;
05465   string groupPostfix;
05466   switch ( theTrsf.Form() ) {
05467   case gp_PntMirror:
05468     MESSAGE("gp_PntMirror");
05469     needReverse = true;
05470     groupPostfix = "mirrored";
05471     break;
05472   case gp_Ax1Mirror:
05473     MESSAGE("gp_Ax1Mirror");
05474     groupPostfix = "mirrored";
05475     break;
05476   case gp_Ax2Mirror:
05477     MESSAGE("gp_Ax2Mirror");
05478     needReverse = true;
05479     groupPostfix = "mirrored";
05480     break;
05481   case gp_Rotation:
05482     MESSAGE("gp_Rotation");
05483     groupPostfix = "rotated";
05484     break;
05485   case gp_Translation:
05486     MESSAGE("gp_Translation");
05487     groupPostfix = "translated";
05488     break;
05489   case gp_Scale:
05490     MESSAGE("gp_Scale");
05491     groupPostfix = "scaled";
05492     break;
05493   case gp_CompoundTrsf: // different scale by axis
05494     MESSAGE("gp_CompoundTrsf");
05495     groupPostfix = "scaled";
05496     break;
05497   default:
05498     MESSAGE("default");
05499     needReverse = false;
05500     groupPostfix = "transformed";
05501   }
05502 
05503   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
05504   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
05505   SMESHDS_Mesh* aMesh    = GetMeshDS();
05506 
05507 
05508   // map old node to new one
05509   TNodeNodeMap nodeMap;
05510 
05511   // elements sharing moved nodes; those of them which have all
05512   // nodes mirrored but are not in theElems are to be reversed
05513   TIDSortedElemSet inverseElemSet;
05514 
05515   // source elements for each generated one
05516   SMESH_SequenceOfElemPtr srcElems, srcNodes;
05517 
05518   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
05519   TIDSortedElemSet orphanNode;
05520 
05521   if ( theElems.empty() ) // transform the whole mesh
05522   {
05523     // add all elements
05524     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
05525     while ( eIt->more() ) theElems.insert( eIt->next() );
05526     // add orphan nodes
05527     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
05528     while ( nIt->more() )
05529     {
05530       const SMDS_MeshNode* node = nIt->next();
05531       if ( node->NbInverseElements() == 0)
05532         orphanNode.insert( node );
05533     }
05534   }
05535 
05536   // loop on elements to transform nodes : first orphan nodes then elems
05537   TIDSortedElemSet::iterator itElem;
05538   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
05539   for (int i=0; i<2; i++)
05540   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
05541     const SMDS_MeshElement* elem = *itElem;
05542     if ( !elem )
05543       continue;
05544 
05545     // loop on elem nodes
05546     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05547     while ( itN->more() ) {
05548 
05549       const SMDS_MeshNode* node = cast2Node( itN->next() );
05550       // check if a node has been already transformed
05551       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
05552         nodeMap.insert( make_pair ( node, node ));
05553       if ( !n2n_isnew.second )
05554         continue;
05555 
05556       double coord[3];
05557       coord[0] = node->X();
05558       coord[1] = node->Y();
05559       coord[2] = node->Z();
05560       theTrsf.Transforms( coord[0], coord[1], coord[2] );
05561       if ( theTargetMesh ) {
05562         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
05563         n2n_isnew.first->second = newNode;
05564         myLastCreatedNodes.Append(newNode);
05565         srcNodes.Append( node );
05566       }
05567       else if ( theCopy ) {
05568         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
05569         n2n_isnew.first->second = newNode;
05570         myLastCreatedNodes.Append(newNode);
05571         srcNodes.Append( node );
05572       }
05573       else {
05574         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
05575         // node position on shape becomes invalid
05576         const_cast< SMDS_MeshNode* > ( node )->SetPosition
05577           ( SMDS_SpacePosition::originSpacePosition() );
05578       }
05579 
05580       // keep inverse elements
05581       if ( !theCopy && !theTargetMesh && needReverse ) {
05582         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
05583         while ( invElemIt->more() ) {
05584           const SMDS_MeshElement* iel = invElemIt->next();
05585           inverseElemSet.insert( iel );
05586         }
05587       }
05588     }
05589   }
05590 
05591   // either create new elements or reverse mirrored ones
05592   if ( !theCopy && !needReverse && !theTargetMesh )
05593     return PGroupIDs();
05594 
05595   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
05596   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
05597     theElems.insert( *invElemIt );
05598 
05599   // Replicate or reverse elements
05600 
05601   std::vector<int> iForw;
05602   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
05603   {
05604     const SMDS_MeshElement* elem = *itElem;
05605     if ( !elem || elem->GetType() == SMDSAbs_Node )
05606       continue;
05607 
05608     int nbNodes = elem->NbNodes();
05609     int elemType = elem->GetType();
05610 
05611     if (elem->IsPoly()) {
05612 
05613       // polygon or polyhedral volume
05614       switch ( elemType ) {
05615       case SMDSAbs_Face:
05616         {
05617           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
05618           int iNode = 0;
05619           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05620           while (itN->more()) {
05621             const SMDS_MeshNode* node =
05622               static_cast<const SMDS_MeshNode*>(itN->next());
05623             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
05624             if (nodeMapIt == nodeMap.end())
05625               break; // not all nodes transformed
05626             if (needReverse) {
05627               // reverse mirrored faces and volumes
05628               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
05629             } else {
05630               poly_nodes[iNode] = (*nodeMapIt).second;
05631             }
05632             iNode++;
05633           }
05634           if ( iNode != nbNodes )
05635             continue; // not all nodes transformed
05636 
05637           if ( theTargetMesh ) {
05638             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
05639             srcElems.Append( elem );
05640           }
05641           else if ( theCopy ) {
05642             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
05643             srcElems.Append( elem );
05644           }
05645           else {
05646             aMesh->ChangePolygonNodes(elem, poly_nodes);
05647           }
05648         }
05649         break;
05650       case SMDSAbs_Volume:
05651         {
05652           const SMDS_VtkVolume* aPolyedre =
05653             dynamic_cast<const SMDS_VtkVolume*>( elem );
05654           if (!aPolyedre) {
05655             MESSAGE("Warning: bad volumic element");
05656             continue;
05657           }
05658 
05659           vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
05660           vector<int> quantities;
05661 
05662           bool allTransformed = true;
05663           int nbFaces = aPolyedre->NbFaces();
05664           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
05665             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
05666             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
05667               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
05668               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
05669               if (nodeMapIt == nodeMap.end()) {
05670                 allTransformed = false; // not all nodes transformed
05671               } else {
05672                 poly_nodes.push_back((*nodeMapIt).second);
05673               }
05674               if ( needReverse && allTransformed )
05675                 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
05676             }
05677             quantities.push_back(nbFaceNodes);
05678           }
05679           if ( !allTransformed )
05680             continue; // not all nodes transformed
05681 
05682           if ( theTargetMesh ) {
05683             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
05684             srcElems.Append( elem );
05685           }
05686           else if ( theCopy ) {
05687             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
05688             srcElems.Append( elem );
05689           }
05690           else {
05691             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
05692           }
05693         }
05694         break;
05695       default:;
05696       }
05697       continue;
05698 
05699     } // elem->isPoly()
05700 
05701     // Regular elements
05702 
05703     while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
05704     const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
05705     const std::vector<int>& i = needReverse ? iRev : iForw;
05706 
05707     // find transformed nodes
05708     vector<const SMDS_MeshNode*> nodes(nbNodes);
05709     int iNode = 0;
05710     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
05711     while ( itN->more() ) {
05712       const SMDS_MeshNode* node =
05713         static_cast<const SMDS_MeshNode*>( itN->next() );
05714       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
05715       if ( nodeMapIt == nodeMap.end() )
05716         break; // not all nodes transformed
05717       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
05718     }
05719     if ( iNode != nbNodes )
05720       continue; // not all nodes transformed
05721 
05722     if ( theTargetMesh ) {
05723       if ( SMDS_MeshElement* copy =
05724            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
05725         myLastCreatedElems.Append( copy );
05726         srcElems.Append( elem );
05727       }
05728     }
05729     else if ( theCopy ) {
05730       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
05731         srcElems.Append( elem );
05732     }
05733     else {
05734       // reverse element as it was reversed by transformation
05735       if ( nbNodes > 2 )
05736         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
05737     }
05738 
05739   } // loop on elements
05740 
05741   PGroupIDs newGroupIDs;
05742 
05743   if ( ( theMakeGroups && theCopy ) ||
05744        ( theMakeGroups && theTargetMesh ) )
05745     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
05746 
05747   return newGroupIDs;
05748 }
05749 
05750 //=======================================================================
05757 //=======================================================================
05758 
05759 SMESH_MeshEditor::PGroupIDs
05760 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
05761                                  const SMESH_SequenceOfElemPtr& elemGens,
05762                                  const std::string&             postfix,
05763                                  SMESH_Mesh*                    targetMesh)
05764 {
05765   PGroupIDs newGroupIDs( new list<int> );
05766   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
05767 
05768   // Sort existing groups by types and collect their names
05769 
05770   // to store an old group and a generated new one
05771   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
05772   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
05773   // group names
05774   set< string > groupNames;
05775   //
05776   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
05777   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
05778   while ( groupIt->more() ) {
05779     SMESH_Group * group = groupIt->next();
05780     if ( !group ) continue;
05781     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
05782     if ( !groupDS || groupDS->IsEmpty() ) continue;
05783     groupNames.insert( group->GetName() );
05784     groupDS->SetStoreName( group->GetName() );
05785     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
05786   }
05787 
05788   // Groups creation
05789 
05790   // loop on nodes and elements
05791   for ( int isNodes = 0; isNodes < 2; ++isNodes )
05792   {
05793     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
05794     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
05795     if ( gens.Length() != elems.Length() )
05796       throw SALOME_Exception(LOCALIZED("invalid args"));
05797 
05798     // loop on created elements
05799     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
05800     {
05801       const SMDS_MeshElement* sourceElem = gens( iElem );
05802       if ( !sourceElem ) {
05803         MESSAGE("generateGroups(): NULL source element");
05804         continue;
05805       }
05806       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
05807       if ( groupsOldNew.empty() ) {
05808         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
05809           ++iElem; // skip all elements made by sourceElem
05810         continue;
05811       }
05812       // collect all elements made by sourceElem
05813       list< const SMDS_MeshElement* > resultElems;
05814       if ( const SMDS_MeshElement* resElem = elems( iElem ))
05815         if ( resElem != sourceElem )
05816           resultElems.push_back( resElem );
05817       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
05818         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
05819           if ( resElem != sourceElem )
05820             resultElems.push_back( resElem );
05821       // do not generate element groups from node ones
05822 //      if ( sourceElem->GetType() == SMDSAbs_Node &&
05823 //           elems( iElem )->GetType() != SMDSAbs_Node )
05824 //        continue;
05825 
05826       // add resultElems to groups made by ones the sourceElem belongs to
05827       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
05828       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
05829       {
05830         SMESHDS_GroupBase* oldGroup = gOldNew->first;
05831         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
05832         {
05833           SMDS_MeshGroup* & newGroup = gOldNew->second;
05834           if ( !newGroup )// create a new group
05835           {
05836             // make a name
05837             string name = oldGroup->GetStoreName();
05838             if ( !targetMesh ) {
05839               name += "_";
05840               name += postfix;
05841               int nb = 0;
05842               while ( !groupNames.insert( name ).second ) // name exists
05843               {
05844                 if ( nb == 0 ) {
05845                   name += "_1";
05846                 }
05847                 else {
05848                   TCollection_AsciiString nbStr(nb+1);
05849                   name.resize( name.rfind('_')+1 );
05850                   name += nbStr.ToCString();
05851                 }
05852                 ++nb;
05853               }
05854             }
05855             // make a group
05856             int id;
05857             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
05858                                                  name.c_str(), id );
05859             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
05860             newGroup = & groupDS->SMDSGroup();
05861             newGroupIDs->push_back( id );
05862           }
05863 
05864           // fill in a new group
05865           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
05866           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
05867             newGroup->Add( *resElemIt );
05868         }
05869       }
05870     } // loop on created elements
05871   }// loop on nodes and elements
05872 
05873   return newGroupIDs;
05874 }
05875 
05876 //================================================================================
05882 //================================================================================
05883 
05884 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
05885                                             const double         theTolerance,
05886                                             TListOfListOfNodes & theGroupsOfNodes)
05887 {
05888   myLastCreatedElems.Clear();
05889   myLastCreatedNodes.Clear();
05890 
05891   if ( theNodes.empty() )
05892   { // get all nodes in the mesh
05893     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
05894     while ( nIt->more() )
05895       theNodes.insert( theNodes.end(),nIt->next());
05896   }
05897 
05898   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
05899 }
05900 
05901 
05902 //=======================================================================
05906 //=======================================================================
05907 
05908 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
05909 {
05910   //---------------------------------------------------------------------
05914   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
05915   {
05916     myMesh = ( SMESHDS_Mesh* ) theMesh;
05917 
05918     TIDSortedNodeSet nodes;
05919     if ( theMesh ) {
05920       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
05921       while ( nIt->more() )
05922         nodes.insert( nodes.end(), nIt->next() );
05923     }
05924     myOctreeNode = new SMESH_OctreeNode(nodes) ;
05925 
05926     // get max size of a leaf box
05927     SMESH_OctreeNode* tree = myOctreeNode;
05928     while ( !tree->isLeaf() )
05929     {
05930       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
05931       if ( cIt->more() )
05932         tree = cIt->next();
05933     }
05934     myHalfLeafSize = tree->maxSize() / 2.;
05935   }
05936 
05937   //---------------------------------------------------------------------
05941   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
05942   {
05943     myOctreeNode->UpdateByMoveNode( node, toPnt );
05944     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
05945   }
05946 
05947   //---------------------------------------------------------------------
05951   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
05952   {
05953     map<double, const SMDS_MeshNode*> dist2Nodes;
05954     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
05955     if ( !dist2Nodes.empty() )
05956       return dist2Nodes.begin()->second;
05957     list<const SMDS_MeshNode*> nodes;
05958     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
05959 
05960     double minSqDist = DBL_MAX;
05961     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
05962     {
05963       // sort leafs by their distance from thePnt
05964       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
05965       TDistTreeMap treeMap;
05966       list< SMESH_OctreeNode* > treeList;
05967       list< SMESH_OctreeNode* >::iterator trIt;
05968       treeList.push_back( myOctreeNode );
05969 
05970       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
05971       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
05972       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
05973       {
05974         SMESH_OctreeNode* tree = *trIt;
05975         if ( !tree->isLeaf() ) // put children to the queue
05976         {
05977           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
05978           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
05979           while ( cIt->more() )
05980             treeList.push_back( cIt->next() );
05981         }
05982         else if ( tree->NbNodes() ) // put a tree to the treeMap
05983         {
05984           const Bnd_B3d& box = tree->getBox();
05985           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
05986           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
05987           if ( !it_in.second ) // not unique distance to box center
05988             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
05989         }
05990       }
05991       // find distance after which there is no sense to check tree's
05992       double sqLimit = DBL_MAX;
05993       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
05994       if ( treeMap.size() > 5 ) {
05995         SMESH_OctreeNode* closestTree = sqDist_tree->second;
05996         const Bnd_B3d& box = closestTree->getBox();
05997         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
05998         sqLimit = limit * limit;
05999       }
06000       // get all nodes from trees
06001       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
06002         if ( sqDist_tree->first > sqLimit )
06003           break;
06004         SMESH_OctreeNode* tree = sqDist_tree->second;
06005         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
06006       }
06007     }
06008     // find closest among nodes
06009     minSqDist = DBL_MAX;
06010     const SMDS_MeshNode* closestNode = 0;
06011     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
06012     for ( ; nIt != nodes.end(); ++nIt ) {
06013       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
06014       if ( minSqDist > sqDist ) {
06015         closestNode = *nIt;
06016         minSqDist = sqDist;
06017       }
06018     }
06019     return closestNode;
06020   }
06021 
06022   //---------------------------------------------------------------------
06026   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
06027 
06028   //---------------------------------------------------------------------
06032   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
06033 
06034 private:
06035   SMESH_OctreeNode* myOctreeNode;
06036   SMESHDS_Mesh*     myMesh;
06037   double            myHalfLeafSize; // max size of a leaf box
06038 };
06039 
06040 //=======================================================================
06044 //=======================================================================
06045 
06046 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
06047 {
06048   return new SMESH_NodeSearcherImpl( GetMeshDS() );
06049 }
06050 
06051 // ========================================================================
06052 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
06053 {
06054   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
06055   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
06056   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
06057 
06058   //=======================================================================
06062   //=======================================================================
06063 
06064   class ElementBndBoxTree : public SMESH_Octree
06065   {
06066   public:
06067 
06068     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
06069     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
06070     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
06071     ~ElementBndBoxTree();
06072 
06073   protected:
06074     ElementBndBoxTree() {}
06075     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
06076     void buildChildrenData();
06077     Bnd_B3d* buildRootBox();
06078   private:
06080     struct ElementBox : public Bnd_B3d
06081     {
06082       const SMDS_MeshElement* _element;
06083       int                     _refCount; // an ElementBox can be included in several tree branches
06084       ElementBox(const SMDS_MeshElement* elem, double tolerance);
06085     };
06086     vector< ElementBox* > _elements;
06087   };
06088 
06089   //================================================================================
06093   //================================================================================
06094 
06095   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
06096     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
06097   {
06098     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
06099     _elements.reserve( nbElems );
06100 
06101     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
06102     while ( elemIt->more() )
06103       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
06104 
06105     if ( _elements.size() > MaxNbElemsInLeaf )
06106       compute();
06107     else
06108       myIsLeaf = true;
06109   }
06110 
06111   //================================================================================
06115   //================================================================================
06116 
06117   ElementBndBoxTree::~ElementBndBoxTree()
06118   {
06119     for ( int i = 0; i < _elements.size(); ++i )
06120       if ( --_elements[i]->_refCount <= 0 )
06121         delete _elements[i];
06122   }
06123 
06124   //================================================================================
06128   //================================================================================
06129 
06130   Bnd_B3d* ElementBndBoxTree::buildRootBox()
06131   {
06132     Bnd_B3d* box = new Bnd_B3d;
06133     for ( int i = 0; i < _elements.size(); ++i )
06134       box->Add( *_elements[i] );
06135     return box;
06136   }
06137 
06138   //================================================================================
06142   //================================================================================
06143 
06144   void ElementBndBoxTree::buildChildrenData()
06145   {
06146     for ( int i = 0; i < _elements.size(); ++i )
06147     {
06148       for (int j = 0; j < 8; j++)
06149       {
06150         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
06151         {
06152           _elements[i]->_refCount++;
06153           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
06154         }
06155       }
06156       _elements[i]->_refCount--;
06157     }
06158     _elements.clear();
06159 
06160     for (int j = 0; j < 8; j++)
06161     {
06162       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
06163       if ( child->_elements.size() <= MaxNbElemsInLeaf )
06164         child->myIsLeaf = true;
06165 
06166       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
06167         child->_elements.resize( child->_elements.size() ); // compact
06168     }
06169   }
06170 
06171   //================================================================================
06175   //================================================================================
06176 
06177   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
06178                                                 TIDSortedElemSet& foundElems)
06179   {
06180     if ( level() && getBox().IsOut( point.XYZ() ))
06181       return;
06182 
06183     if ( isLeaf() )
06184     {
06185       for ( int i = 0; i < _elements.size(); ++i )
06186         if ( !_elements[i]->IsOut( point.XYZ() ))
06187           foundElems.insert( _elements[i]->_element );
06188     }
06189     else
06190     {
06191       for (int i = 0; i < 8; i++)
06192         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
06193     }
06194   }
06195 
06196   //================================================================================
06200   //================================================================================
06201 
06202   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
06203                                                TIDSortedElemSet& foundElems)
06204   {
06205     if ( level() && getBox().IsOut( line ))
06206       return;
06207 
06208     if ( isLeaf() )
06209     {
06210       for ( int i = 0; i < _elements.size(); ++i )
06211         if ( !_elements[i]->IsOut( line ))
06212           foundElems.insert( _elements[i]->_element );
06213     }
06214     else
06215     {
06216       for (int i = 0; i < 8; i++)
06217         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
06218     }
06219   }
06220 
06221   //================================================================================
06225   //================================================================================
06226 
06227   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
06228   {
06229     _element  = elem;
06230     _refCount = 1;
06231     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
06232     while ( nIt->more() )
06233       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
06234     Enlarge( tolerance );
06235   }
06236 
06237 } // namespace
06238 
06239 //=======================================================================
06244 //=======================================================================
06245 
06246 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
06247 {
06248   SMESHDS_Mesh*                _mesh;
06249   SMDS_ElemIteratorPtr         _meshPartIt;
06250   ElementBndBoxTree*           _ebbTree;
06251   SMESH_NodeSearcherImpl*      _nodeSearcher;
06252   SMDSAbs_ElementType          _elementType;
06253   double                       _tolerance;
06254   bool                         _outerFacesFound;
06255   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
06256 
06257   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
06258     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
06259   ~SMESH_ElementSearcherImpl()
06260   {
06261     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
06262     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
06263   }
06264   virtual int FindElementsByPoint(const gp_Pnt&                      point,
06265                                   SMDSAbs_ElementType                type,
06266                                   vector< const SMDS_MeshElement* >& foundElements);
06267   virtual TopAbs_State GetPointState(const gp_Pnt& point);
06268 
06269   void GetElementsNearLine( const gp_Ax1&                      line,
06270                             SMDSAbs_ElementType                type,
06271                             vector< const SMDS_MeshElement* >& foundElems);
06272   double getTolerance();
06273   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
06274                             const double tolerance, double & param);
06275   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
06276   bool isOuterBoundary(const SMDS_MeshElement* face) const
06277   {
06278     return _outerFaces.empty() || _outerFaces.count(face);
06279   }
06280   struct TInters 
06281   {
06282     const SMDS_MeshElement* _face;
06283     gp_Vec                  _faceNorm;
06284     bool                    _coincides; 
06285     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
06286       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
06287   };
06288   struct TFaceLink 
06289   {
06290     SMESH_TLink      _link;
06291     TIDSortedElemSet _faces;
06292     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
06293       : _link( n1, n2 ), _faces( &face, &face + 1) {}
06294   };
06295 };
06296 
06297 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
06298 {
06299   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
06300              << ", _coincides="<<i._coincides << ")";
06301 }
06302 
06303 //=======================================================================
06307 //=======================================================================
06308 
06309 double SMESH_ElementSearcherImpl::getTolerance()
06310 {
06311   if ( _tolerance < 0 )
06312   {
06313     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
06314 
06315     _tolerance = 0;
06316     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
06317     {
06318       double boxSize = _nodeSearcher->getTree()->maxSize();
06319       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
06320     }
06321     else if ( _ebbTree && meshInfo.NbElements() > 0 )
06322     {
06323       double boxSize = _ebbTree->maxSize();
06324       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
06325     }
06326     if ( _tolerance == 0 )
06327     {
06328       // define tolerance by size of a most complex element
06329       int complexType = SMDSAbs_Volume;
06330       while ( complexType > SMDSAbs_All &&
06331               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
06332         --complexType;
06333       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
06334       double elemSize;
06335       if ( complexType == int( SMDSAbs_Node ))
06336       {
06337         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
06338         elemSize = 1;
06339         if ( meshInfo.NbNodes() > 2 )
06340           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
06341       }
06342       else
06343       {
06344         SMDS_ElemIteratorPtr elemIt =
06345             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
06346         const SMDS_MeshElement* elem = elemIt->next();
06347         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
06348         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
06349         elemSize = 0;
06350         while ( nodeIt->more() )
06351         {
06352           double dist = n1.Distance( cast2Node( nodeIt->next() ));
06353           elemSize = max( dist, elemSize );
06354         }
06355       }
06356       _tolerance = 1e-4 * elemSize;
06357     }
06358   }
06359   return _tolerance;
06360 }
06361 
06362 //================================================================================
06366 //================================================================================
06367 
06368 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
06369                                                      const SMDS_MeshElement* face,
06370                                                      const double            tol,
06371                                                      double &                param)
06372 {
06373   int nbInts = 0;
06374   param = 0;
06375 
06376   GeomAPI_ExtremaCurveCurve anExtCC;
06377   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
06378   
06379   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
06380   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
06381   {
06382     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
06383                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
06384     anExtCC.Init( lineCurve, edge);
06385     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
06386     {
06387       Quantity_Parameter pl, pe;
06388       anExtCC.LowerDistanceParameters( pl, pe );
06389       param += pl;
06390       if ( ++nbInts == 2 )
06391         break;
06392     }
06393   }
06394   if ( nbInts > 0 ) param /= nbInts;
06395   return nbInts > 0;
06396 }
06397 //================================================================================
06401 //================================================================================
06402 
06403 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
06404 {
06405   if ( _outerFacesFound ) return;
06406 
06407   // Collect all outer faces by passing from one outer face to another via their links
06408   // and BTW find out if there are internal faces at all.
06409 
06410   // checked links and links where outer boundary meets internal one
06411   set< SMESH_TLink > visitedLinks, seamLinks;
06412 
06413   // links to treat with already visited faces sharing them
06414   list < TFaceLink > startLinks;
06415 
06416   // load startLinks with the first outerFace
06417   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
06418   _outerFaces.insert( outerFace );
06419 
06420   TIDSortedElemSet emptySet;
06421   while ( !startLinks.empty() )
06422   {
06423     const SMESH_TLink& link  = startLinks.front()._link;
06424     TIDSortedElemSet&  faces = startLinks.front()._faces;
06425 
06426     outerFace = *faces.begin();
06427     // find other faces sharing the link
06428     const SMDS_MeshElement* f;
06429     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
06430       faces.insert( f );
06431 
06432     // select another outer face among the found 
06433     const SMDS_MeshElement* outerFace2 = 0;
06434     if ( faces.size() == 2 )
06435     {
06436       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
06437     }
06438     else if ( faces.size() > 2 )
06439     {
06440       seamLinks.insert( link );
06441 
06442       // link direction within the outerFace
06443       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
06444                    SMESH_TNodeXYZ( link.node2()));
06445       int i1 = outerFace->GetNodeIndex( link.node1() );
06446       int i2 = outerFace->GetNodeIndex( link.node2() );
06447       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
06448       if ( rev ) n1n2.Reverse();
06449       // outerFace normal
06450       gp_XYZ ofNorm, fNorm;
06451       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
06452       {
06453         // direction from the link inside outerFace
06454         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
06455         // sort all other faces by angle with the dirInOF
06456         map< double, const SMDS_MeshElement* > angle2Face;
06457         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
06458         for ( ; face != faces.end(); ++face )
06459         {
06460           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
06461             continue;
06462           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
06463           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
06464           if ( angle < 0 ) angle += 2. * M_PI;
06465           angle2Face.insert( make_pair( angle, *face ));
06466         }
06467         if ( !angle2Face.empty() )
06468           outerFace2 = angle2Face.begin()->second;
06469       }
06470     }
06471     // store the found outer face and add its links to continue seaching from
06472     if ( outerFace2 )
06473     {
06474       _outerFaces.insert( outerFace );
06475       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
06476       for ( int i = 0; i < nbNodes; ++i )
06477       {
06478         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
06479         if ( visitedLinks.insert( link2 ).second )
06480           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
06481       }
06482     }
06483     startLinks.pop_front();
06484   }
06485   _outerFacesFound = true;
06486 
06487   if ( !seamLinks.empty() )
06488   {
06489     // There are internal boundaries touching the outher one,
06490     // find all faces of internal boundaries in order to find
06491     // faces of boundaries of holes, if any.
06492     
06493   }
06494   else
06495   {
06496     _outerFaces.clear();
06497   }
06498 }
06499 
06500 //=======================================================================
06507 //=======================================================================
06508 
06509 int SMESH_ElementSearcherImpl::
06510 FindElementsByPoint(const gp_Pnt&                      point,
06511                     SMDSAbs_ElementType                type,
06512                     vector< const SMDS_MeshElement* >& foundElements)
06513 {
06514   foundElements.clear();
06515 
06516   double tolerance = getTolerance();
06517 
06518   // =================================================================================
06519   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
06520   {
06521     if ( !_nodeSearcher )
06522       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
06523 
06524     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
06525     if ( !closeNode ) return foundElements.size();
06526 
06527     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
06528       return foundElements.size(); // to far from any node
06529 
06530     if ( type == SMDSAbs_Node )
06531     {
06532       foundElements.push_back( closeNode );
06533     }
06534     else
06535     {
06536       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
06537       while ( elemIt->more() )
06538         foundElements.push_back( elemIt->next() );
06539     }
06540   }
06541   // =================================================================================
06542   else // elements more complex than 0D
06543   {
06544     if ( !_ebbTree || _elementType != type )
06545     {
06546       if ( _ebbTree ) delete _ebbTree;
06547       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
06548     }
06549     TIDSortedElemSet suspectElems;
06550     _ebbTree->getElementsNearPoint( point, suspectElems );
06551     TIDSortedElemSet::iterator elem = suspectElems.begin();
06552     for ( ; elem != suspectElems.end(); ++elem )
06553       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
06554         foundElements.push_back( *elem );
06555   }
06556   return foundElements.size();
06557 }
06558 
06559 //================================================================================
06563 //================================================================================
06564 
06565 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
06566 {
06567   double tolerance = getTolerance();
06568   if ( !_ebbTree || _elementType != SMDSAbs_Face )
06569   {
06570     if ( _ebbTree ) delete _ebbTree;
06571     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
06572   }
06573   // Algo: analyse transition of a line starting at the point through mesh boundary;
06574   // try three lines parallel to axis of the coordinate system and perform rough
06575   // analysis. If solution is not clear perform thorough analysis.
06576 
06577   const int nbAxes = 3;
06578   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
06579   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
06580   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
06581   multimap< int, int > nbInt2Axis; // to find the simplest case
06582   for ( int axis = 0; axis < nbAxes; ++axis )
06583   {
06584     gp_Ax1 lineAxis( point, axisDir[axis]);
06585     gp_Lin line    ( lineAxis );
06586 
06587     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
06588     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
06589 
06590     // Intersect faces with the line
06591 
06592     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
06593     TIDSortedElemSet::iterator face = suspectFaces.begin();
06594     for ( ; face != suspectFaces.end(); ++face )
06595     {
06596       // get face plane
06597       gp_XYZ fNorm;
06598       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
06599       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
06600 
06601       // perform intersection
06602       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
06603       if ( !intersection.IsDone() )
06604         continue;
06605       if ( intersection.IsInQuadric() )
06606       {
06607         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
06608       }
06609       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
06610       {
06611         gp_Pnt intersectionPoint = intersection.Point(1);
06612         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
06613           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
06614       }
06615     }
06616     // Analyse intersections roughly
06617 
06618     int nbInter = u2inters.size();
06619     if ( nbInter == 0 )
06620       return TopAbs_OUT; 
06621 
06622     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
06623     if ( nbInter == 1 ) // not closed mesh
06624       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
06625 
06626     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
06627       return TopAbs_ON;
06628 
06629     if ( (f<0) == (l<0) )
06630       return TopAbs_OUT;
06631 
06632     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
06633     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
06634     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
06635       return TopAbs_IN;
06636 
06637     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
06638 
06639     if ( _outerFacesFound ) break; // pass to thorough analysis
06640 
06641   } // three attempts - loop on CS axes
06642 
06643   // Analyse intersections thoroughly.
06644   // We make two loops maximum, on the first one we only exclude touching intersections,
06645   // on the second, if situation is still unclear, we gather and use information on
06646   // position of faces (internal or outer). If faces position is already gathered,
06647   // we make the second loop right away.
06648 
06649   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
06650   {
06651     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
06652     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
06653     {
06654       int axis = nb_axis->second;
06655       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
06656 
06657       gp_Ax1 lineAxis( point, axisDir[axis]);
06658       gp_Lin line    ( lineAxis );
06659 
06660       // add tangent intersections to u2inters
06661       double param;
06662       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
06663       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
06664         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
06665           u2inters.insert(make_pair( param, *tgtInt ));
06666       tangentInters[ axis ].clear();
06667 
06668       // Count intersections before and after the point excluding touching ones.
06669       // If hasPositionInfo we count intersections of outer boundary only
06670 
06671       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
06672       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
06673       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
06674       bool ok = ! u_int1->second._coincides;
06675       while ( ok && u_int1 != u2inters.end() )
06676       {
06677         double u = u_int1->first;
06678         bool touchingInt = false;
06679         if ( ++u_int2 != u2inters.end() )
06680         {
06681           // skip intersections at the same point (if the line passes through edge or node)
06682           int nbSamePnt = 0;
06683           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
06684           {
06685             ++nbSamePnt;
06686             ++u_int2;
06687           }
06688 
06689           // skip tangent intersections
06690           int nbTgt = 0;
06691           const SMDS_MeshElement* prevFace = u_int1->second._face;
06692           while ( ok && u_int2->second._coincides )
06693           {
06694             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
06695               ok = false;
06696             else
06697             {
06698               nbTgt++;
06699               u_int2++;
06700               ok = ( u_int2 != u2inters.end() );
06701             }
06702           }
06703           if ( !ok ) break;
06704 
06705           // skip intersections at the same point after tangent intersections
06706           if ( nbTgt > 0 )
06707           {
06708             double u2 = u_int2->first;
06709             ++u_int2;
06710             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
06711             {
06712               ++nbSamePnt;
06713               ++u_int2;
06714             }
06715           }
06716           // decide if we skipped a touching intersection
06717           if ( nbSamePnt + nbTgt > 0 )
06718           {
06719             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
06720             map< double, TInters >::iterator u_int = u_int1;
06721             for ( ; u_int != u_int2; ++u_int )
06722             {
06723               if ( u_int->second._coincides ) continue;
06724               double dot = u_int->second._faceNorm * line.Direction();
06725               if ( dot > maxDot ) maxDot = dot;
06726               if ( dot < minDot ) minDot = dot;
06727             }
06728             touchingInt = ( minDot*maxDot < 0 );
06729           }
06730         }
06731         if ( !touchingInt )
06732         {
06733           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
06734           {
06735             if ( u < 0 )
06736               ++nbIntBeforePoint;
06737             else
06738               ++nbIntAfterPoint;
06739           }
06740           if ( u < f ) f = u;
06741           if ( u > l ) l = u;
06742         }
06743 
06744         u_int1 = u_int2; // to next intersection
06745 
06746       } // loop on intersections with one line
06747 
06748       if ( ok )
06749       {
06750         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
06751           return TopAbs_ON;
06752 
06753         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
06754           return TopAbs_OUT; 
06755 
06756         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
06757           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
06758 
06759         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
06760           return TopAbs_IN;
06761 
06762         if ( (f<0) == (l<0) )
06763           return TopAbs_OUT;
06764 
06765         if ( hasPositionInfo )
06766           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
06767       }
06768     } // loop on intersections of the tree lines - thorough analysis
06769 
06770     if ( !hasPositionInfo )
06771     {
06772       // gather info on faces position - is face in the outer boundary or not
06773       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
06774       findOuterBoundary( u2inters.begin()->second._face );
06775     }
06776 
06777   } // two attempts - with and w/o faces position info in the mesh
06778 
06779   return TopAbs_UNKNOWN;
06780 }
06781 
06782 //=======================================================================
06786 //=======================================================================
06787 
06788 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
06789                                                      SMDSAbs_ElementType                type,
06790                                                      vector< const SMDS_MeshElement* >& foundElems)
06791 {
06792   if ( !_ebbTree || _elementType != type )
06793   {
06794     if ( _ebbTree ) delete _ebbTree;
06795     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
06796   }
06797   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
06798   _ebbTree->getElementsNearLine( line, suspectFaces );
06799   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
06800 }
06801 
06802 //=======================================================================
06806 //=======================================================================
06807 
06808 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
06809 {
06810   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
06811 }
06812 
06813 //=======================================================================
06817 //=======================================================================
06818 
06819 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
06820 {
06821   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
06822 }
06823 
06824 //=======================================================================
06828 //=======================================================================
06829 
06830 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
06831 {
06832   if ( element->GetType() == SMDSAbs_Volume)
06833   {
06834     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
06835   }
06836 
06837   // get ordered nodes
06838 
06839   vector< gp_XYZ > xyz;
06840   vector<const SMDS_MeshNode*> nodeList;
06841 
06842   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
06843   if ( element->IsQuadratic() ) {
06844     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
06845       nodeIt = f->interlacedNodesElemIterator();
06846     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
06847       nodeIt = e->interlacedNodesElemIterator();
06848   }
06849   while ( nodeIt->more() )
06850     {
06851       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
06852       xyz.push_back( SMESH_TNodeXYZ(node) );
06853       nodeList.push_back(node);
06854     }
06855 
06856   int i, nbNodes = element->NbNodes();
06857 
06858   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
06859   {
06860     // compute face normal
06861     gp_Vec faceNorm(0,0,0);
06862     xyz.push_back( xyz.front() );
06863     nodeList.push_back( nodeList.front() );
06864     for ( i = 0; i < nbNodes; ++i )
06865     {
06866       gp_Vec edge1( xyz[i+1], xyz[i]);
06867       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
06868       faceNorm += edge1 ^ edge2;
06869     }
06870     double normSize = faceNorm.Magnitude();
06871     if ( normSize <= tol )
06872     {
06873       // degenerated face: point is out if it is out of all face edges
06874       for ( i = 0; i < nbNodes; ++i )
06875       {
06876         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
06877         if ( !isOut( &edge, point, tol ))
06878           return false;
06879       }
06880       return true;
06881     }
06882     faceNorm /= normSize;
06883 
06884     // check if the point lays on face plane
06885     gp_Vec n2p( xyz[0], point );
06886     if ( fabs( n2p * faceNorm ) > tol )
06887       return true; // not on face plane
06888 
06889     // check if point is out of face boundary:
06890     // define it by closest transition of a ray point->infinity through face boundary
06891     // on the face plane.
06892     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
06893     // to find intersections of the ray with the boundary.
06894     gp_Vec ray = n2p;
06895     gp_Vec plnNorm = ray ^ faceNorm;
06896     normSize = plnNorm.Magnitude();
06897     if ( normSize <= tol ) return false; // point coincides with the first node
06898     plnNorm /= normSize;
06899     // for each node of the face, compute its signed distance to the plane
06900     vector<double> dist( nbNodes + 1);
06901     for ( i = 0; i < nbNodes; ++i )
06902     {
06903       gp_Vec n2p( xyz[i], point );
06904       dist[i] = n2p * plnNorm;
06905     }
06906     dist.back() = dist.front();
06907     // find the closest intersection
06908     int    iClosest = -1;
06909     double rClosest, distClosest = 1e100;;
06910     gp_Pnt pClosest;
06911     for ( i = 0; i < nbNodes; ++i )
06912     {
06913       double r;
06914       if ( fabs( dist[i]) < tol )
06915         r = 0.;
06916       else if ( fabs( dist[i+1]) < tol )
06917         r = 1.;
06918       else if ( dist[i] * dist[i+1] < 0 )
06919         r = dist[i] / ( dist[i] - dist[i+1] );
06920       else
06921         continue; // no intersection
06922       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
06923       gp_Vec p2int ( point, pInt);
06924       if ( p2int * ray > -tol ) // right half-space
06925       {
06926         double intDist = p2int.SquareMagnitude();
06927         if ( intDist < distClosest )
06928         {
06929           iClosest = i;
06930           rClosest = r;
06931           pClosest = pInt;
06932           distClosest = intDist;
06933         }
06934       }
06935     }
06936     if ( iClosest < 0 )
06937       return true; // no intesections - out
06938 
06939     // analyse transition
06940     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
06941     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
06942     gp_Vec p2int ( point, pClosest );
06943     bool out = (edgeNorm * p2int) < -tol;
06944     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
06945       return out;
06946 
06947     // ray pass through a face node; analyze transition through an adjacent edge
06948     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
06949     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
06950     gp_Vec edgeAdjacent( p1, p2 );
06951     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
06952     bool out2 = (edgeNorm2 * p2int) < -tol;
06953 
06954     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
06955     return covexCorner ? (out || out2) : (out && out2);
06956   }
06957   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
06958   {
06959     // point is out of edge if it is NOT ON any straight part of edge
06960     // (we consider quadratic edge as being composed of two straight parts)
06961     for ( i = 1; i < nbNodes; ++i )
06962     {
06963       gp_Vec edge( xyz[i-1], xyz[i]);
06964       gp_Vec n1p ( xyz[i-1], point);
06965       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
06966       if ( dist > tol )
06967         continue;
06968       gp_Vec n2p( xyz[i], point );
06969       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
06970         continue;
06971       return false; // point is ON this part
06972     }
06973     return true;
06974   }
06975   // Node or 0D element -------------------------------------------------------------------------
06976   {
06977     gp_Vec n2p ( xyz[0], point );
06978     return n2p.Magnitude() <= tol;
06979   }
06980   return true;
06981 }
06982 
06983 //=======================================================================
06984 //function : SimplifyFace
06985 //purpose  :
06986 //=======================================================================
06987 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
06988                                     vector<const SMDS_MeshNode *>&      poly_nodes,
06989                                     vector<int>&                        quantities) const
06990 {
06991   int nbNodes = faceNodes.size();
06992 
06993   if (nbNodes < 3)
06994     return 0;
06995 
06996   set<const SMDS_MeshNode*> nodeSet;
06997 
06998   // get simple seq of nodes
06999   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
07000   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
07001   int iSimple = 0, nbUnique = 0;
07002 
07003   simpleNodes[iSimple++] = faceNodes[0];
07004   nbUnique++;
07005   for (int iCur = 1; iCur < nbNodes; iCur++) {
07006     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
07007       simpleNodes[iSimple++] = faceNodes[iCur];
07008       if (nodeSet.insert( faceNodes[iCur] ).second)
07009         nbUnique++;
07010     }
07011   }
07012   int nbSimple = iSimple;
07013   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
07014     nbSimple--;
07015     iSimple--;
07016   }
07017 
07018   if (nbUnique < 3)
07019     return 0;
07020 
07021   // separate loops
07022   int nbNew = 0;
07023   bool foundLoop = (nbSimple > nbUnique);
07024   while (foundLoop) {
07025     foundLoop = false;
07026     set<const SMDS_MeshNode*> loopSet;
07027     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
07028       const SMDS_MeshNode* n = simpleNodes[iSimple];
07029       if (!loopSet.insert( n ).second) {
07030         foundLoop = true;
07031 
07032         // separate loop
07033         int iC = 0, curLast = iSimple;
07034         for (; iC < curLast; iC++) {
07035           if (simpleNodes[iC] == n) break;
07036         }
07037         int loopLen = curLast - iC;
07038         if (loopLen > 2) {
07039           // create sub-element
07040           nbNew++;
07041           quantities.push_back(loopLen);
07042           for (; iC < curLast; iC++) {
07043             poly_nodes.push_back(simpleNodes[iC]);
07044           }
07045         }
07046         // shift the rest nodes (place from the first loop position)
07047         for (iC = curLast + 1; iC < nbSimple; iC++) {
07048           simpleNodes[iC - loopLen] = simpleNodes[iC];
07049         }
07050         nbSimple -= loopLen;
07051         iSimple -= loopLen;
07052       }
07053     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
07054   } // while (foundLoop)
07055 
07056   if (iSimple > 2) {
07057     nbNew++;
07058     quantities.push_back(iSimple);
07059     for (int i = 0; i < iSimple; i++)
07060       poly_nodes.push_back(simpleNodes[i]);
07061   }
07062 
07063   return nbNew;
07064 }
07065 
07066 //=======================================================================
07067 //function : MergeNodes
07068 //purpose  : In each group, the cdr of nodes are substituted by the first one
07069 //           in all elements.
07070 //=======================================================================
07071 
07072 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
07073 {
07074   MESSAGE("MergeNodes");
07075   myLastCreatedElems.Clear();
07076   myLastCreatedNodes.Clear();
07077 
07078   SMESHDS_Mesh* aMesh = GetMeshDS();
07079 
07080   TNodeNodeMap nodeNodeMap; // node to replace - new node
07081   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
07082   list< int > rmElemIds, rmNodeIds;
07083 
07084   // Fill nodeNodeMap and elems
07085 
07086   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
07087   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
07088     list<const SMDS_MeshNode*>& nodes = *grIt;
07089     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
07090     const SMDS_MeshNode* nToKeep = *nIt;
07091     //MESSAGE("node to keep " << nToKeep->GetID());
07092     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
07093       const SMDS_MeshNode* nToRemove = *nIt;
07094       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
07095       if ( nToRemove != nToKeep ) {
07096         //MESSAGE("  node to remove " << nToRemove->GetID());
07097         rmNodeIds.push_back( nToRemove->GetID() );
07098         AddToSameGroups( nToKeep, nToRemove, aMesh );
07099       }
07100 
07101       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
07102       while ( invElemIt->more() ) {
07103         const SMDS_MeshElement* elem = invElemIt->next();
07104         elems.insert(elem);
07105       }
07106     }
07107   }
07108   // Change element nodes or remove an element
07109 
07110   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
07111   for ( ; eIt != elems.end(); eIt++ ) {
07112     const SMDS_MeshElement* elem = *eIt;
07113     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
07114     int nbNodes = elem->NbNodes();
07115     int aShapeId = FindShape( elem );
07116 
07117     set<const SMDS_MeshNode*> nodeSet;
07118     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
07119     int iUnique = 0, iCur = 0, nbRepl = 0;
07120     vector<int> iRepl( nbNodes );
07121 
07122     // get new seq of nodes
07123     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
07124     while ( itN->more() ) {
07125       const SMDS_MeshNode* n =
07126         static_cast<const SMDS_MeshNode*>( itN->next() );
07127 
07128       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
07129       if ( nnIt != nodeNodeMap.end() ) { // n sticks
07130         n = (*nnIt).second;
07131         // BUG 0020185: begin
07132         {
07133           bool stopRecur = false;
07134           set<const SMDS_MeshNode*> nodesRecur;
07135           nodesRecur.insert(n);
07136           while (!stopRecur) {
07137             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
07138             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
07139               n = (*nnIt_i).second;
07140               if (!nodesRecur.insert(n).second) {
07141                 // error: recursive dependancy
07142                 stopRecur = true;
07143               }
07144             }
07145             else
07146               stopRecur = true;
07147           }
07148         }
07149         // BUG 0020185: end
07150       }
07151       curNodes[ iCur ] = n;
07152       bool isUnique = nodeSet.insert( n ).second;
07153       if ( isUnique )
07154         uniqueNodes[ iUnique++ ] = n;
07155       else
07156         iRepl[ nbRepl++ ] = iCur;
07157       iCur++;
07158     }
07159 
07160     // Analyse element topology after replacement
07161 
07162     bool isOk = true;
07163     int nbUniqueNodes = nodeSet.size();
07164     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
07165     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
07166       // Polygons and Polyhedral volumes
07167       if (elem->IsPoly()) {
07168 
07169         if (elem->GetType() == SMDSAbs_Face) {
07170           // Polygon
07171           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
07172           int inode = 0;
07173           for (; inode < nbNodes; inode++) {
07174             face_nodes[inode] = curNodes[inode];
07175           }
07176 
07177           vector<const SMDS_MeshNode *> polygons_nodes;
07178           vector<int> quantities;
07179           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
07180           if (nbNew > 0) {
07181             inode = 0;
07182             for (int iface = 0; iface < nbNew; iface++) {
07183               int nbNodes = quantities[iface];
07184               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
07185               for (int ii = 0; ii < nbNodes; ii++, inode++) {
07186                 poly_nodes[ii] = polygons_nodes[inode];
07187               }
07188               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
07189               myLastCreatedElems.Append(newElem);
07190               if (aShapeId)
07191                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
07192             }
07193 
07194             MESSAGE("ChangeElementNodes MergeNodes Polygon");
07195             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
07196             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
07197             int quid =0;
07198             if (nbNew > 0) quid = nbNew - 1;
07199             vector<int> newquant(quantities.begin()+quid, quantities.end());
07200             const SMDS_MeshElement* newElem = 0;
07201             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
07202             myLastCreatedElems.Append(newElem);
07203             if ( aShapeId && newElem )
07204               aMesh->SetMeshElementOnShape( newElem, aShapeId );
07205             rmElemIds.push_back(elem->GetID());
07206           }
07207           else {
07208             rmElemIds.push_back(elem->GetID());
07209           }
07210 
07211         }
07212         else if (elem->GetType() == SMDSAbs_Volume) {
07213           // Polyhedral volume
07214           if (nbUniqueNodes < 4) {
07215             rmElemIds.push_back(elem->GetID());
07216           }
07217           else {
07218             // each face has to be analyzed in order to check volume validity
07219             const SMDS_VtkVolume* aPolyedre =
07220               dynamic_cast<const SMDS_VtkVolume*>( elem );
07221             if (aPolyedre) {
07222               int nbFaces = aPolyedre->NbFaces();
07223 
07224               vector<const SMDS_MeshNode *> poly_nodes;
07225               vector<int> quantities;
07226 
07227               for (int iface = 1; iface <= nbFaces; iface++) {
07228                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
07229                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
07230 
07231                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
07232                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
07233                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
07234                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
07235                     faceNode = (*nnIt).second;
07236                   }
07237                   faceNodes[inode - 1] = faceNode;
07238                 }
07239 
07240                 SimplifyFace(faceNodes, poly_nodes, quantities);
07241               }
07242 
07243               if (quantities.size() > 3) {
07244                 // to be done: remove coincident faces
07245               }
07246 
07247               if (quantities.size() > 3)
07248                 {
07249                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
07250                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
07251                   const SMDS_MeshElement* newElem = 0;
07252                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
07253                   myLastCreatedElems.Append(newElem);
07254                   if ( aShapeId && newElem )
07255                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
07256                   rmElemIds.push_back(elem->GetID());
07257                 }
07258             }
07259             else {
07260               rmElemIds.push_back(elem->GetID());
07261             }
07262           }
07263         }
07264         else {
07265         }
07266 
07267         continue;
07268       } // poly element
07269 
07270       // Regular elements
07271       // TODO not all the possible cases are solved. Find something more generic?
07272       switch ( nbNodes ) {
07273       case 2: 
07274         isOk = false; break;
07275       case 3: 
07276         isOk = false; break;
07277       case 4:
07278         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
07279           isOk = false;
07280         else { 
07281           if ( nbUniqueNodes < 3 )
07282             isOk = false;
07283           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
07284             isOk = false; // opposite nodes stick
07285           //MESSAGE("isOk " << isOk);
07286         }
07287         break;
07288       case 6: 
07289         if ( nbUniqueNodes == 4 ) {
07290           // ---------------------------------> tetrahedron
07291           if (nbRepl == 3 &&
07292               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
07293             // all top nodes stick: reverse a bottom
07294             uniqueNodes[ 0 ] = curNodes [ 1 ];
07295             uniqueNodes[ 1 ] = curNodes [ 0 ];
07296           }
07297           else if (nbRepl == 3 &&
07298                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
07299             // all bottom nodes stick: set a top before
07300             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
07301             uniqueNodes[ 0 ] = curNodes [ 3 ];
07302             uniqueNodes[ 1 ] = curNodes [ 4 ];
07303             uniqueNodes[ 2 ] = curNodes [ 5 ];
07304           }
07305           else if (nbRepl == 4 &&
07306                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
07307             // a lateral face turns into a line: reverse a bottom
07308             uniqueNodes[ 0 ] = curNodes [ 1 ];
07309             uniqueNodes[ 1 ] = curNodes [ 0 ];
07310           }
07311           else
07312             isOk = false;
07313         }
07314         else if ( nbUniqueNodes == 5 ) {
07315           // PENTAHEDRON --------------------> 2 tetrahedrons
07316           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
07317             // a bottom node sticks with a linked top one
07318             // 1.
07319             SMDS_MeshElement* newElem =
07320               aMesh->AddVolume(curNodes[ 3 ],
07321                                curNodes[ 4 ],
07322                                curNodes[ 5 ],
07323                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
07324             myLastCreatedElems.Append(newElem);
07325             if ( aShapeId )
07326               aMesh->SetMeshElementOnShape( newElem, aShapeId );
07327             // 2. : reverse a bottom
07328             uniqueNodes[ 0 ] = curNodes [ 1 ];
07329             uniqueNodes[ 1 ] = curNodes [ 0 ];
07330             nbUniqueNodes = 4;
07331           }
07332           else
07333             isOk = false;
07334         }
07335         else
07336           isOk = false;
07337         break;
07338       case 8: {
07339         if(elem->IsQuadratic()) { // Quadratic quadrangle
07340           //   1    5    2
07341           //    +---+---+
07342           //    |       |
07343           //    |       |
07344           //   4+       +6
07345           //    |       |
07346           //    |       |
07347           //    +---+---+
07348           //   0    7    3
07349           isOk = false;
07350           if(nbRepl==2) {
07351             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
07352           }
07353           if(nbRepl==3) {
07354             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
07355             nbUniqueNodes = 6;
07356             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
07357               uniqueNodes[0] = curNodes[0];
07358               uniqueNodes[1] = curNodes[2];
07359               uniqueNodes[2] = curNodes[3];
07360               uniqueNodes[3] = curNodes[5];
07361               uniqueNodes[4] = curNodes[6];
07362               uniqueNodes[5] = curNodes[7];
07363               isOk = true;
07364             }
07365             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
07366               uniqueNodes[0] = curNodes[0];
07367               uniqueNodes[1] = curNodes[1];
07368               uniqueNodes[2] = curNodes[2];
07369               uniqueNodes[3] = curNodes[4];
07370               uniqueNodes[4] = curNodes[5];
07371               uniqueNodes[5] = curNodes[6];
07372               isOk = true;
07373             }
07374             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
07375               uniqueNodes[0] = curNodes[1];
07376               uniqueNodes[1] = curNodes[2];
07377               uniqueNodes[2] = curNodes[3];
07378               uniqueNodes[3] = curNodes[5];
07379               uniqueNodes[4] = curNodes[6];
07380               uniqueNodes[5] = curNodes[0];
07381               isOk = true;
07382             }
07383             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
07384               uniqueNodes[0] = curNodes[0];
07385               uniqueNodes[1] = curNodes[1];
07386               uniqueNodes[2] = curNodes[3];
07387               uniqueNodes[3] = curNodes[4];
07388               uniqueNodes[4] = curNodes[6];
07389               uniqueNodes[5] = curNodes[7];
07390               isOk = true;
07391             }
07392             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
07393               uniqueNodes[0] = curNodes[0];
07394               uniqueNodes[1] = curNodes[2];
07395               uniqueNodes[2] = curNodes[3];
07396               uniqueNodes[3] = curNodes[1];
07397               uniqueNodes[4] = curNodes[6];
07398               uniqueNodes[5] = curNodes[7];
07399               isOk = true;
07400             }
07401             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
07402               uniqueNodes[0] = curNodes[0];
07403               uniqueNodes[1] = curNodes[1];
07404               uniqueNodes[2] = curNodes[2];
07405               uniqueNodes[3] = curNodes[4];
07406               uniqueNodes[4] = curNodes[5];
07407               uniqueNodes[5] = curNodes[7];
07408               isOk = true;
07409             }
07410             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
07411               uniqueNodes[0] = curNodes[0];
07412               uniqueNodes[1] = curNodes[1];
07413               uniqueNodes[2] = curNodes[3];
07414               uniqueNodes[3] = curNodes[4];
07415               uniqueNodes[4] = curNodes[2];
07416               uniqueNodes[5] = curNodes[7];
07417               isOk = true;
07418             }
07419             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
07420               uniqueNodes[0] = curNodes[0];
07421               uniqueNodes[1] = curNodes[1];
07422               uniqueNodes[2] = curNodes[2];
07423               uniqueNodes[3] = curNodes[4];
07424               uniqueNodes[4] = curNodes[5];
07425               uniqueNodes[5] = curNodes[3];
07426               isOk = true;
07427             }
07428           }
07429           if(nbRepl==4) {
07430             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
07431           }
07432           if(nbRepl==5) {
07433             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
07434           }
07435           break;
07436         }
07438         isOk = false;
07439         SMDS_VolumeTool hexa (elem);
07440         hexa.SetExternalNormal();
07441         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
07443           for ( int iFace = 0; iFace < 6; iFace++ ) {
07444             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
07445             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
07446                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
07447                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
07448               // one face turns into a point ...
07449               int iOppFace = hexa.GetOppFaceIndex( iFace );
07450               ind = hexa.GetFaceNodesIndices( iOppFace );
07451               int nbStick = 0;
07452               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
07453                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
07454                   nbStick++;
07455               }
07456               if ( nbStick == 1 ) {
07457                 // ... and the opposite one - into a triangle.
07458                 // set a top node
07459                 ind = hexa.GetFaceNodesIndices( iFace );
07460                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
07461                 isOk = true;
07462               }
07463               break;
07464             }
07465           }
07466         }
07467         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
07469           int nbTria = 0, iTria[3];
07470           const int *ind; // indices of face nodes
07471           // look for triangular faces
07472           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
07473             ind = hexa.GetFaceNodesIndices( iFace );
07474             TIDSortedNodeSet faceNodes;
07475             for ( iCur = 0; iCur < 4; iCur++ )
07476               faceNodes.insert( curNodes[ind[iCur]] );
07477             if ( faceNodes.size() == 3 )
07478               iTria[ nbTria++ ] = iFace;
07479           }
07480           // check if triangles are opposite
07481           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
07482           {
07483             isOk = true;
07484             // set nodes of the bottom triangle
07485             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
07486             vector<int> indB;
07487             for ( iCur = 0; iCur < 4; iCur++ )
07488               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
07489                 indB.push_back( ind[iCur] );
07490             if ( !hexa.IsForward() )
07491               std::swap( indB[0], indB[2] );
07492             for ( iCur = 0; iCur < 3; iCur++ )
07493               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
07494             // set nodes of the top triangle
07495             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
07496             for ( iCur = 0; iCur < 3; ++iCur )
07497               for ( int j = 0; j < 4; ++j )
07498                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
07499                 {
07500                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
07501                   break;
07502                 }
07503           }
07504           break;
07505         }
07506         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
07508           for ( int iFace = 0; iFace < 6; iFace++ ) {
07509             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
07510             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
07511                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
07512                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
07513               // one face turns into a point ...
07514               int iOppFace = hexa.GetOppFaceIndex( iFace );
07515               ind = hexa.GetFaceNodesIndices( iOppFace );
07516               int nbStick = 0;
07517               iUnique = 2;  // reverse a tetrahedron 1 bottom
07518               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
07519                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
07520                   nbStick++;
07521                 else if ( iUnique >= 0 )
07522                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
07523               }
07524               if ( nbStick == 0 ) {
07525                 // ... and the opposite one is a quadrangle
07526                 // set a top node
07527                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
07528                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
07529                 nbUniqueNodes = 4;
07530                 // tetrahedron 2
07531                 SMDS_MeshElement* newElem =
07532                   aMesh->AddVolume(curNodes[ind[ 0 ]],
07533                                    curNodes[ind[ 3 ]],
07534                                    curNodes[ind[ 2 ]],
07535                                    curNodes[indTop[ 0 ]]);
07536                 myLastCreatedElems.Append(newElem);
07537                 if ( aShapeId )
07538                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
07539                 isOk = true;
07540               }
07541               break;
07542             }
07543           }
07544         }
07545         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
07547           // find indices of quad and tri faces
07548           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
07549           for ( iFace = 0; iFace < 6; iFace++ ) {
07550             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
07551             nodeSet.clear();
07552             for ( iCur = 0; iCur < 4; iCur++ )
07553               nodeSet.insert( curNodes[ind[ iCur ]] );
07554             nbUniqueNodes = nodeSet.size();
07555             if ( nbUniqueNodes == 3 )
07556               iTriFace[ nbTri++ ] = iFace;
07557             else if ( nbUniqueNodes == 4 )
07558               iQuadFace[ nbQuad++ ] = iFace;
07559           }
07560           if (nbQuad == 2 && nbTri == 4 &&
07561               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
07562             // 2 opposite quadrangles stuck with a diagonal;
07563             // sample groups of merged indices: (0-4)(2-6)
07564             // --------------------------------------------> 2 tetrahedrons
07565             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
07566             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
07567             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
07568             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
07569                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
07570               // stuck with 0-2 diagonal
07571               i0  = ind1[ 3 ];
07572               i1d = ind1[ 0 ];
07573               i2  = ind1[ 1 ];
07574               i3d = ind1[ 2 ];
07575               i0t = ind2[ 1 ];
07576               i2t = ind2[ 3 ];
07577             }
07578             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
07579                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
07580               // stuck with 1-3 diagonal
07581               i0  = ind1[ 0 ];
07582               i1d = ind1[ 1 ];
07583               i2  = ind1[ 2 ];
07584               i3d = ind1[ 3 ];
07585               i0t = ind2[ 0 ];
07586               i2t = ind2[ 1 ];
07587             }
07588             else {
07589               ASSERT(0);
07590             }
07591             // tetrahedron 1
07592             uniqueNodes[ 0 ] = curNodes [ i0 ];
07593             uniqueNodes[ 1 ] = curNodes [ i1d ];
07594             uniqueNodes[ 2 ] = curNodes [ i3d ];
07595             uniqueNodes[ 3 ] = curNodes [ i0t ];
07596             nbUniqueNodes = 4;
07597             // tetrahedron 2
07598             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
07599                                                          curNodes[ i2 ],
07600                                                          curNodes[ i3d ],
07601                                                          curNodes[ i2t ]);
07602             myLastCreatedElems.Append(newElem);
07603             if ( aShapeId )
07604               aMesh->SetMeshElementOnShape( newElem, aShapeId );
07605             isOk = true;
07606           }
07607           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
07608                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
07609             // --------------------------------------------> prism
07610             // find 2 opposite triangles
07611             nbUniqueNodes = 6;
07612             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
07613               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
07614                 // find indices of kept and replaced nodes
07615                 // and fill unique nodes of 2 opposite triangles
07616                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
07617                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
07618                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
07619                 // fill unique nodes
07620                 iUnique = 0;
07621                 isOk = true;
07622                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
07623                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
07624                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
07625                   if ( n == nInit ) {
07626                     // iCur of a linked node of the opposite face (make normals co-directed):
07627                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
07628                     // check that correspondent corners of triangles are linked
07629                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
07630                       isOk = false;
07631                     else {
07632                       uniqueNodes[ iUnique ] = n;
07633                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
07634                       iUnique++;
07635                     }
07636                   }
07637                 }
07638                 break;
07639               }
07640             }
07641           }
07642         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
07643         else
07644         {
07645           MESSAGE("MergeNodes() removes hexahedron "<< elem);
07646         }
07647         break;
07648       } // HEXAHEDRON
07649 
07650       default:
07651         isOk = false;
07652       } // switch ( nbNodes )
07653 
07654     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
07655 
07656     if ( isOk ) { // the elem remains valid after sticking nodes
07657       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
07658       {
07659         // Change nodes of polyedre
07660         const SMDS_VtkVolume* aPolyedre =
07661           dynamic_cast<const SMDS_VtkVolume*>( elem );
07662         if (aPolyedre) {
07663           int nbFaces = aPolyedre->NbFaces();
07664 
07665           vector<const SMDS_MeshNode *> poly_nodes;
07666           vector<int> quantities (nbFaces);
07667 
07668           for (int iface = 1; iface <= nbFaces; iface++) {
07669             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
07670             quantities[iface - 1] = nbFaceNodes;
07671 
07672             for (inode = 1; inode <= nbFaceNodes; inode++) {
07673               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
07674 
07675               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
07676               if (nnIt != nodeNodeMap.end()) { // curNode sticks
07677                 curNode = (*nnIt).second;
07678               }
07679               poly_nodes.push_back(curNode);
07680             }
07681           }
07682           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
07683         }
07684       }
07685       else // replace non-polyhedron elements
07686       {
07687         const SMDSAbs_ElementType etyp = elem->GetType();
07688         const int elemId               = elem->GetID();
07689         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
07690         uniqueNodes.resize(nbUniqueNodes);
07691 
07692         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
07693 
07694         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
07695         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
07696         if ( sm && newElem )
07697           sm->AddElement( newElem );
07698         if ( elem != newElem )
07699           ReplaceElemInGroups( elem, newElem, aMesh );
07700       }
07701     }
07702     else {
07703       // Remove invalid regular element or invalid polygon
07704       rmElemIds.push_back( elem->GetID() );
07705     }
07706 
07707   } // loop on elements
07708 
07709   // Remove bad elements, then equal nodes (order important)
07710 
07711   Remove( rmElemIds, false );
07712   Remove( rmNodeIds, true );
07713 
07714 }
07715 
07716 
07717 // ========================================================
07718 // class   : SortableElement
07719 // purpose : allow sorting elements basing on their nodes
07720 // ========================================================
07721 class SortableElement : public set <const SMDS_MeshElement*>
07722 {
07723 public:
07724 
07725   SortableElement( const SMDS_MeshElement* theElem )
07726   {
07727     myElem = theElem;
07728     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
07729     while ( nodeIt->more() )
07730       this->insert( nodeIt->next() );
07731   }
07732 
07733   const SMDS_MeshElement* Get() const
07734   { return myElem; }
07735 
07736   void Set(const SMDS_MeshElement* e) const
07737   { myElem = e; }
07738 
07739 
07740 private:
07741   mutable const SMDS_MeshElement* myElem;
07742 };
07743 
07744 //=======================================================================
07745 //function : FindEqualElements
07746 //purpose  : Return list of group of elements built on the same nodes.
07747 //           Search among theElements or in the whole mesh if theElements is empty
07748 //=======================================================================
07749 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
07750                                          TListOfListOfElementsID &      theGroupsOfElementsID)
07751 {
07752   myLastCreatedElems.Clear();
07753   myLastCreatedNodes.Clear();
07754 
07755   typedef set<const SMDS_MeshElement*> TElemsSet;
07756   typedef map< SortableElement, int > TMapOfNodeSet;
07757   typedef list<int> TGroupOfElems;
07758 
07759   TElemsSet elems;
07760   if ( theElements.empty() )
07761   { // get all elements in the mesh
07762     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
07763     while ( eIt->more() )
07764       elems.insert( elems.end(), eIt->next());
07765   }
07766   else
07767     elems = theElements;
07768 
07769   vector< TGroupOfElems > arrayOfGroups;
07770   TGroupOfElems groupOfElems;
07771   TMapOfNodeSet mapOfNodeSet;
07772 
07773   TElemsSet::iterator elemIt = elems.begin();
07774   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
07775     const SMDS_MeshElement* curElem = *elemIt;
07776     SortableElement SE(curElem);
07777     int ind = -1;
07778     // check uniqueness
07779     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
07780     if( !(pp.second) ) {
07781       TMapOfNodeSet::iterator& itSE = pp.first;
07782       ind = (*itSE).second;
07783       arrayOfGroups[ind].push_back(curElem->GetID());
07784     }
07785     else {
07786       groupOfElems.clear();
07787       groupOfElems.push_back(curElem->GetID());
07788       arrayOfGroups.push_back(groupOfElems);
07789       i++;
07790     }
07791   }
07792 
07793   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
07794   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
07795     groupOfElems = *groupIt;
07796     if ( groupOfElems.size() > 1 ) {
07797       groupOfElems.sort();
07798       theGroupsOfElementsID.push_back(groupOfElems);
07799     }
07800   }
07801 }
07802 
07803 //=======================================================================
07804 //function : MergeElements
07805 //purpose  : In each given group, substitute all elements by the first one.
07806 //=======================================================================
07807 
07808 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
07809 {
07810   myLastCreatedElems.Clear();
07811   myLastCreatedNodes.Clear();
07812 
07813   typedef list<int> TListOfIDs;
07814   TListOfIDs rmElemIds; // IDs of elems to remove
07815 
07816   SMESHDS_Mesh* aMesh = GetMeshDS();
07817 
07818   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
07819   while ( groupsIt != theGroupsOfElementsID.end() ) {
07820     TListOfIDs& aGroupOfElemID = *groupsIt;
07821     aGroupOfElemID.sort();
07822     int elemIDToKeep = aGroupOfElemID.front();
07823     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
07824     aGroupOfElemID.pop_front();
07825     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
07826     while ( idIt != aGroupOfElemID.end() ) {
07827       int elemIDToRemove = *idIt;
07828       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
07829       // add the kept element in groups of removed one (PAL15188)
07830       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
07831       rmElemIds.push_back( elemIDToRemove );
07832       ++idIt;
07833     }
07834     ++groupsIt;
07835   }
07836 
07837   Remove( rmElemIds, false );
07838 }
07839 
07840 //=======================================================================
07841 //function : MergeEqualElements
07842 //purpose  : Remove all but one of elements built on the same nodes.
07843 //=======================================================================
07844 
07845 void SMESH_MeshEditor::MergeEqualElements()
07846 {
07847   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
07848                                                  to merge equal elements in the whole mesh */
07849   TListOfListOfElementsID aGroupsOfElementsID;
07850   FindEqualElements(aMeshElements, aGroupsOfElementsID);
07851   MergeElements(aGroupsOfElementsID);
07852 }
07853 
07854 //=======================================================================
07855 //function : FindFaceInSet
07856 //purpose  : Return a face having linked nodes n1 and n2 and which is
07857 //           - not in avoidSet,
07858 //           - in elemSet provided that !elemSet.empty()
07859 //           i1 and i2 optionally returns indices of n1 and n2
07860 //=======================================================================
07861 
07862 const SMDS_MeshElement*
07863 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
07864                                 const SMDS_MeshNode*    n2,
07865                                 const TIDSortedElemSet& elemSet,
07866                                 const TIDSortedElemSet& avoidSet,
07867                                 int*                    n1ind,
07868                                 int*                    n2ind)
07869 
07870 {
07871   int i1, i2;
07872   const SMDS_MeshElement* face = 0;
07873 
07874   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
07875   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
07876   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
07877   {
07878     //MESSAGE("in while ( invElemIt->more() && !face )");
07879     const SMDS_MeshElement* elem = invElemIt->next();
07880     if (avoidSet.count( elem ))
07881       continue;
07882     if ( !elemSet.empty() && !elemSet.count( elem ))
07883       continue;
07884     // index of n1
07885     i1 = elem->GetNodeIndex( n1 );
07886     // find a n2 linked to n1
07887     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
07888     for ( int di = -1; di < 2 && !face; di += 2 )
07889     {
07890       i2 = (i1+di+nbN) % nbN;
07891       if ( elem->GetNode( i2 ) == n2 )
07892         face = elem;
07893     }
07894     if ( !face && elem->IsQuadratic())
07895     {
07896       // analysis for quadratic elements using all nodes
07897       const SMDS_VtkFace* F =
07898         dynamic_cast<const SMDS_VtkFace*>(elem);
07899       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
07900       // use special nodes iterator
07901       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
07902       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
07903       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
07904       {
07905         const SMDS_MeshNode* n = cast2Node( anIter->next() );
07906         if ( n1 == prevN && n2 == n )
07907         {
07908           face = elem;
07909         }
07910         else if ( n2 == prevN && n1 == n )
07911         {
07912           face = elem; swap( i1, i2 );
07913         }
07914         prevN = n;
07915       }
07916     }
07917   }
07918   if ( n1ind ) *n1ind = i1;
07919   if ( n2ind ) *n2ind = i2;
07920   return face;
07921 }
07922 
07923 //=======================================================================
07924 //function : findAdjacentFace
07925 //purpose  :
07926 //=======================================================================
07927 
07928 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
07929                                                 const SMDS_MeshNode* n2,
07930                                                 const SMDS_MeshElement* elem)
07931 {
07932   TIDSortedElemSet elemSet, avoidSet;
07933   if ( elem )
07934     avoidSet.insert ( elem );
07935   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
07936 }
07937 
07938 //=======================================================================
07939 //function : FindFreeBorder
07940 //purpose  :
07941 //=======================================================================
07942 
07943 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
07944 
07945 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
07946                                        const SMDS_MeshNode*             theSecondNode,
07947                                        const SMDS_MeshNode*             theLastNode,
07948                                        list< const SMDS_MeshNode* > &   theNodes,
07949                                        list< const SMDS_MeshElement* >& theFaces)
07950 {
07951   if ( !theFirstNode || !theSecondNode )
07952     return false;
07953   // find border face between theFirstNode and theSecondNode
07954   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
07955   if ( !curElem )
07956     return false;
07957 
07958   theFaces.push_back( curElem );
07959   theNodes.push_back( theFirstNode );
07960   theNodes.push_back( theSecondNode );
07961 
07962   //vector<const SMDS_MeshNode*> nodes;
07963   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
07964   TIDSortedElemSet foundElems;
07965   bool needTheLast = ( theLastNode != 0 );
07966 
07967   while ( nStart != theLastNode ) {
07968     if ( nStart == theFirstNode )
07969       return !needTheLast;
07970 
07971     // find all free border faces sharing form nStart
07972 
07973     list< const SMDS_MeshElement* > curElemList;
07974     list< const SMDS_MeshNode* > nStartList;
07975     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
07976     while ( invElemIt->more() ) {
07977       const SMDS_MeshElement* e = invElemIt->next();
07978       if ( e == curElem || foundElems.insert( e ).second ) {
07979         // get nodes
07980         int iNode = 0, nbNodes = e->NbNodes();
07981         //const SMDS_MeshNode* nodes[nbNodes+1];
07982         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
07983 
07984         if(e->IsQuadratic()) {
07985           const SMDS_VtkFace* F =
07986             dynamic_cast<const SMDS_VtkFace*>(e);
07987           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
07988           // use special nodes iterator
07989           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
07990           while( anIter->more() ) {
07991             nodes[ iNode++ ] = cast2Node(anIter->next());
07992           }
07993         }
07994         else {
07995           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
07996           while ( nIt->more() )
07997             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
07998         }
07999         nodes[ iNode ] = nodes[ 0 ];
08000         // check 2 links
08001         for ( iNode = 0; iNode < nbNodes; iNode++ )
08002           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
08003                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
08004               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
08005           {
08006             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
08007             curElemList.push_back( e );
08008           }
08009       }
08010     }
08011     // analyse the found
08012 
08013     int nbNewBorders = curElemList.size();
08014     if ( nbNewBorders == 0 ) {
08015       // no free border furthermore
08016       return !needTheLast;
08017     }
08018     else if ( nbNewBorders == 1 ) {
08019       // one more element found
08020       nIgnore = nStart;
08021       nStart = nStartList.front();
08022       curElem = curElemList.front();
08023       theFaces.push_back( curElem );
08024       theNodes.push_back( nStart );
08025     }
08026     else {
08027       // several continuations found
08028       list< const SMDS_MeshElement* >::iterator curElemIt;
08029       list< const SMDS_MeshNode* >::iterator nStartIt;
08030       // check if one of them reached the last node
08031       if ( needTheLast ) {
08032         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
08033              curElemIt!= curElemList.end();
08034              curElemIt++, nStartIt++ )
08035           if ( *nStartIt == theLastNode ) {
08036             theFaces.push_back( *curElemIt );
08037             theNodes.push_back( *nStartIt );
08038             return true;
08039           }
08040       }
08041       // find the best free border by the continuations
08042       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
08043       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
08044       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
08045            curElemIt!= curElemList.end();
08046            curElemIt++, nStartIt++ )
08047       {
08048         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
08049         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
08050         // find one more free border
08051         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
08052           cNL->clear();
08053           cFL->clear();
08054         }
08055         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
08056           // choice: clear a worse one
08057           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
08058           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
08059           contNodes[ iWorse ].clear();
08060           contFaces[ iWorse ].clear();
08061         }
08062       }
08063       if ( contNodes[0].empty() && contNodes[1].empty() )
08064         return false;
08065 
08066       // append the best free border
08067       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
08068       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
08069       theNodes.pop_back(); // remove nIgnore
08070       theNodes.pop_back(); // remove nStart
08071       theFaces.pop_back(); // remove curElem
08072       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
08073       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
08074       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
08075       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
08076       return true;
08077 
08078     } // several continuations found
08079   } // while ( nStart != theLastNode )
08080 
08081   return true;
08082 }
08083 
08084 //=======================================================================
08085 //function : CheckFreeBorderNodes
08086 //purpose  : Return true if the tree nodes are on a free border
08087 //=======================================================================
08088 
08089 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
08090                                             const SMDS_MeshNode* theNode2,
08091                                             const SMDS_MeshNode* theNode3)
08092 {
08093   list< const SMDS_MeshNode* > nodes;
08094   list< const SMDS_MeshElement* > faces;
08095   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
08096 }
08097 
08098 //=======================================================================
08099 //function : SewFreeBorder
08100 //purpose  :
08101 //=======================================================================
08102 
08103 SMESH_MeshEditor::Sew_Error
08104 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
08105                                  const SMDS_MeshNode* theBordSecondNode,
08106                                  const SMDS_MeshNode* theBordLastNode,
08107                                  const SMDS_MeshNode* theSideFirstNode,
08108                                  const SMDS_MeshNode* theSideSecondNode,
08109                                  const SMDS_MeshNode* theSideThirdNode,
08110                                  const bool           theSideIsFreeBorder,
08111                                  const bool           toCreatePolygons,
08112                                  const bool           toCreatePolyedrs)
08113 {
08114   myLastCreatedElems.Clear();
08115   myLastCreatedNodes.Clear();
08116 
08117   MESSAGE("::SewFreeBorder()");
08118   Sew_Error aResult = SEW_OK;
08119 
08120   // ====================================
08121   //    find side nodes and elements
08122   // ====================================
08123 
08124   list< const SMDS_MeshNode* > nSide[ 2 ];
08125   list< const SMDS_MeshElement* > eSide[ 2 ];
08126   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
08127   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
08128 
08129   // Free border 1
08130   // --------------
08131   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
08132                       nSide[0], eSide[0])) {
08133     MESSAGE(" Free Border 1 not found " );
08134     aResult = SEW_BORDER1_NOT_FOUND;
08135   }
08136   if (theSideIsFreeBorder) {
08137     // Free border 2
08138     // --------------
08139     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
08140                         nSide[1], eSide[1])) {
08141       MESSAGE(" Free Border 2 not found " );
08142       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
08143     }
08144   }
08145   if ( aResult != SEW_OK )
08146     return aResult;
08147 
08148   if (!theSideIsFreeBorder) {
08149     // Side 2
08150     // --------------
08151 
08152     // -------------------------------------------------------------------------
08153     // Algo:
08154     // 1. If nodes to merge are not coincident, move nodes of the free border
08155     //    from the coord sys defined by the direction from the first to last
08156     //    nodes of the border to the correspondent sys of the side 2
08157     // 2. On the side 2, find the links most co-directed with the correspondent
08158     //    links of the free border
08159     // -------------------------------------------------------------------------
08160 
08161     // 1. Since sewing may break if there are volumes to split on the side 2,
08162     //    we wont move nodes but just compute new coordinates for them
08163     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
08164     TNodeXYZMap nBordXYZ;
08165     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
08166     list< const SMDS_MeshNode* >::iterator nBordIt;
08167 
08168     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
08169     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
08170     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
08171     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
08172     double tol2 = 1.e-8;
08173     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
08174     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
08175       // Need node movement.
08176 
08177       // find X and Z axes to create trsf
08178       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
08179       gp_Vec X = Zs ^ Zb;
08180       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
08181         // Zb || Zs
08182         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
08183 
08184       // coord systems
08185       gp_Ax3 toBordAx( Pb1, Zb, X );
08186       gp_Ax3 fromSideAx( Ps1, Zs, X );
08187       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
08188       // set trsf
08189       gp_Trsf toBordSys, fromSide2Sys;
08190       toBordSys.SetTransformation( toBordAx );
08191       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
08192       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
08193 
08194       // move
08195       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
08196         const SMDS_MeshNode* n = *nBordIt;
08197         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
08198         toBordSys.Transforms( xyz );
08199         fromSide2Sys.Transforms( xyz );
08200         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
08201       }
08202     }
08203     else {
08204       // just insert nodes XYZ in the nBordXYZ map
08205       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
08206         const SMDS_MeshNode* n = *nBordIt;
08207         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
08208       }
08209     }
08210 
08211     // 2. On the side 2, find the links most co-directed with the correspondent
08212     //    links of the free border
08213 
08214     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
08215     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
08216     sideNodes.push_back( theSideFirstNode );
08217 
08218     bool hasVolumes = false;
08219     LinkID_Gen aLinkID_Gen( GetMeshDS() );
08220     set<long> foundSideLinkIDs, checkedLinkIDs;
08221     SMDS_VolumeTool volume;
08222     //const SMDS_MeshNode* faceNodes[ 4 ];
08223 
08224     const SMDS_MeshNode*    sideNode;
08225     const SMDS_MeshElement* sideElem;
08226     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
08227     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
08228     nBordIt = bordNodes.begin();
08229     nBordIt++;
08230     // border node position and border link direction to compare with
08231     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
08232     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
08233     // choose next side node by link direction or by closeness to
08234     // the current border node:
08235     bool searchByDir = ( *nBordIt != theBordLastNode );
08236     do {
08237       // find the next node on the Side 2
08238       sideNode = 0;
08239       double maxDot = -DBL_MAX, minDist = DBL_MAX;
08240       long linkID;
08241       checkedLinkIDs.clear();
08242       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
08243 
08244       // loop on inverse elements of current node (prevSideNode) on the Side 2
08245       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
08246       while ( invElemIt->more() )
08247       {
08248         const SMDS_MeshElement* elem = invElemIt->next();
08249         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
08250         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
08251         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
08252         bool isVolume = volume.Set( elem );
08253         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
08254         if ( isVolume ) // --volume
08255           hasVolumes = true;
08256         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
08257           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
08258           if(elem->IsQuadratic()) {
08259             const SMDS_VtkFace* F =
08260               dynamic_cast<const SMDS_VtkFace*>(elem);
08261             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
08262             // use special nodes iterator
08263             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
08264             while( anIter->more() ) {
08265               nodes[ iNode ] = cast2Node(anIter->next());
08266               if ( nodes[ iNode++ ] == prevSideNode )
08267                 iPrevNode = iNode - 1;
08268             }
08269           }
08270           else {
08271             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
08272             while ( nIt->more() ) {
08273               nodes[ iNode ] = cast2Node( nIt->next() );
08274               if ( nodes[ iNode++ ] == prevSideNode )
08275                 iPrevNode = iNode - 1;
08276             }
08277           }
08278           // there are 2 links to check
08279           nbNodes = 2;
08280         }
08281         else // --edge
08282           continue;
08283         // loop on links, to be precise, on the second node of links
08284         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
08285           const SMDS_MeshNode* n = nodes[ iNode ];
08286           if ( isVolume ) {
08287             if ( !volume.IsLinked( n, prevSideNode ))
08288               continue;
08289           }
08290           else {
08291             if ( iNode ) // a node before prevSideNode
08292               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
08293             else         // a node after prevSideNode
08294               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
08295           }
08296           // check if this link was already used
08297           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
08298           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
08299           if (!isJustChecked &&
08300               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
08301           {
08302             // test a link geometrically
08303             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
08304             bool linkIsBetter = false;
08305             double dot = 0.0, dist = 0.0;
08306             if ( searchByDir ) { // choose most co-directed link
08307               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
08308               linkIsBetter = ( dot > maxDot );
08309             }
08310             else { // choose link with the node closest to bordPos
08311               dist = ( nextXYZ - bordPos ).SquareModulus();
08312               linkIsBetter = ( dist < minDist );
08313             }
08314             if ( linkIsBetter ) {
08315               maxDot = dot;
08316               minDist = dist;
08317               linkID = iLink;
08318               sideNode = n;
08319               sideElem = elem;
08320             }
08321           }
08322         }
08323       } // loop on inverse elements of prevSideNode
08324 
08325       if ( !sideNode ) {
08326         MESSAGE(" Cant find path by links of the Side 2 ");
08327         return SEW_BAD_SIDE_NODES;
08328       }
08329       sideNodes.push_back( sideNode );
08330       sideElems.push_back( sideElem );
08331       foundSideLinkIDs.insert ( linkID );
08332       prevSideNode = sideNode;
08333 
08334       if ( *nBordIt == theBordLastNode )
08335         searchByDir = false;
08336       else {
08337         // find the next border link to compare with
08338         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
08339         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
08340         // move to next border node if sideNode is before forward border node (bordPos)
08341         while ( *nBordIt != theBordLastNode && !searchByDir ) {
08342           prevBordNode = *nBordIt;
08343           nBordIt++;
08344           bordPos = nBordXYZ[ *nBordIt ];
08345           bordDir = bordPos - nBordXYZ[ prevBordNode ];
08346           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
08347         }
08348       }
08349     }
08350     while ( sideNode != theSideSecondNode );
08351 
08352     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
08353       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
08354       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
08355     }
08356   } // end nodes search on the side 2
08357 
08358   // ============================
08359   // sew the border to the side 2
08360   // ============================
08361 
08362   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
08363   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
08364 
08365   TListOfListOfNodes nodeGroupsToMerge;
08366   if ( nbNodes[0] == nbNodes[1] ||
08367        ( theSideIsFreeBorder && !theSideThirdNode)) {
08368 
08369     // all nodes are to be merged
08370 
08371     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
08372          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
08373          nIt[0]++, nIt[1]++ )
08374     {
08375       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
08376       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
08377       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
08378     }
08379   }
08380   else {
08381 
08382     // insert new nodes into the border and the side to get equal nb of segments
08383 
08384     // get normalized parameters of nodes on the borders
08385     //double param[ 2 ][ maxNbNodes ];
08386     double* param[ 2 ];
08387     param[0] = new double [ maxNbNodes ];
08388     param[1] = new double [ maxNbNodes ];
08389     int iNode, iBord;
08390     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
08391       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
08392       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
08393       const SMDS_MeshNode* nPrev = *nIt;
08394       double bordLength = 0;
08395       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
08396         const SMDS_MeshNode* nCur = *nIt;
08397         gp_XYZ segment (nCur->X() - nPrev->X(),
08398                         nCur->Y() - nPrev->Y(),
08399                         nCur->Z() - nPrev->Z());
08400         double segmentLen = segment.Modulus();
08401         bordLength += segmentLen;
08402         param[ iBord ][ iNode ] = bordLength;
08403         nPrev = nCur;
08404       }
08405       // normalize within [0,1]
08406       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
08407         param[ iBord ][ iNode ] /= bordLength;
08408       }
08409     }
08410 
08411     // loop on border segments
08412     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
08413     int i[ 2 ] = { 0, 0 };
08414     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
08415     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
08416 
08417     TElemOfNodeListMap insertMap;
08418     TElemOfNodeListMap::iterator insertMapIt;
08419     // insertMap is
08420     // key:   elem to insert nodes into
08421     // value: 2 nodes to insert between + nodes to be inserted
08422     do {
08423       bool next[ 2 ] = { false, false };
08424 
08425       // find min adjacent segment length after sewing
08426       double nextParam = 10., prevParam = 0;
08427       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
08428         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
08429           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
08430         if ( i[ iBord ] > 0 )
08431           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
08432       }
08433       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
08434       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
08435       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
08436 
08437       // choose to insert or to merge nodes
08438       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
08439       if ( Abs( du ) <= minSegLen * 0.2 ) {
08440         // merge
08441         // ------
08442         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
08443         const SMDS_MeshNode* n0 = *nIt[0];
08444         const SMDS_MeshNode* n1 = *nIt[1];
08445         nodeGroupsToMerge.back().push_back( n1 );
08446         nodeGroupsToMerge.back().push_back( n0 );
08447         // position of node of the border changes due to merge
08448         param[ 0 ][ i[0] ] += du;
08449         // move n1 for the sake of elem shape evaluation during insertion.
08450         // n1 will be removed by MergeNodes() anyway
08451         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
08452         next[0] = next[1] = true;
08453       }
08454       else {
08455         // insert
08456         // ------
08457         int intoBord = ( du < 0 ) ? 0 : 1;
08458         const SMDS_MeshElement* elem = *eIt[ intoBord ];
08459         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
08460         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
08461         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
08462         if ( intoBord == 1 ) {
08463           // move node of the border to be on a link of elem of the side
08464           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
08465           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
08466           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
08467           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
08468           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
08469         }
08470         insertMapIt = insertMap.find( elem );
08471         bool notFound = ( insertMapIt == insertMap.end() );
08472         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
08473         if ( otherLink ) {
08474           // insert into another link of the same element:
08475           // 1. perform insertion into the other link of the elem
08476           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
08477           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
08478           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
08479           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
08480           // 2. perform insertion into the link of adjacent faces
08481           while (true) {
08482             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
08483             if ( adjElem )
08484               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
08485             else
08486               break;
08487           }
08488           if (toCreatePolyedrs) {
08489             // perform insertion into the links of adjacent volumes
08490             UpdateVolumes(n12, n22, nodeList);
08491           }
08492           // 3. find an element appeared on n1 and n2 after the insertion
08493           insertMap.erase( elem );
08494           elem = findAdjacentFace( n1, n2, 0 );
08495         }
08496         if ( notFound || otherLink ) {
08497           // add element and nodes of the side into the insertMap
08498           insertMapIt = insertMap.insert
08499             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
08500           (*insertMapIt).second.push_back( n1 );
08501           (*insertMapIt).second.push_back( n2 );
08502         }
08503         // add node to be inserted into elem
08504         (*insertMapIt).second.push_back( nIns );
08505         next[ 1 - intoBord ] = true;
08506       }
08507 
08508       // go to the next segment
08509       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
08510         if ( next[ iBord ] ) {
08511           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
08512             eIt[ iBord ]++;
08513           nPrev[ iBord ] = *nIt[ iBord ];
08514           nIt[ iBord ]++; i[ iBord ]++;
08515         }
08516       }
08517     }
08518     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
08519 
08520     // perform insertion of nodes into elements
08521 
08522     for (insertMapIt = insertMap.begin();
08523          insertMapIt != insertMap.end();
08524          insertMapIt++ )
08525     {
08526       const SMDS_MeshElement* elem = (*insertMapIt).first;
08527       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
08528       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
08529       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
08530 
08531       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
08532 
08533       if ( !theSideIsFreeBorder ) {
08534         // look for and insert nodes into the faces adjacent to elem
08535         while (true) {
08536           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
08537           if ( adjElem )
08538             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
08539           else
08540             break;
08541         }
08542       }
08543       if (toCreatePolyedrs) {
08544         // perform insertion into the links of adjacent volumes
08545         UpdateVolumes(n1, n2, nodeList);
08546       }
08547     }
08548 
08549     delete param[0];
08550     delete param[1];
08551   } // end: insert new nodes
08552 
08553   MergeNodes ( nodeGroupsToMerge );
08554 
08555   return aResult;
08556 }
08557 
08558 //=======================================================================
08559 //function : InsertNodesIntoLink
08560 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
08561 //           and theBetweenNode2 and split theElement
08562 //=======================================================================
08563 
08564 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
08565                                            const SMDS_MeshNode*        theBetweenNode1,
08566                                            const SMDS_MeshNode*        theBetweenNode2,
08567                                            list<const SMDS_MeshNode*>& theNodesToInsert,
08568                                            const bool                  toCreatePoly)
08569 {
08570   if ( theFace->GetType() != SMDSAbs_Face ) return;
08571 
08572   // find indices of 2 link nodes and of the rest nodes
08573   int iNode = 0, il1, il2, i3, i4;
08574   il1 = il2 = i3 = i4 = -1;
08575   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
08576   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
08577 
08578   if(theFace->IsQuadratic()) {
08579     const SMDS_VtkFace* F =
08580       dynamic_cast<const SMDS_VtkFace*>(theFace);
08581     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
08582     // use special nodes iterator
08583     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
08584     while( anIter->more() ) {
08585       const SMDS_MeshNode* n = cast2Node(anIter->next());
08586       if ( n == theBetweenNode1 )
08587         il1 = iNode;
08588       else if ( n == theBetweenNode2 )
08589         il2 = iNode;
08590       else if ( i3 < 0 )
08591         i3 = iNode;
08592       else
08593         i4 = iNode;
08594       nodes[ iNode++ ] = n;
08595     }
08596   }
08597   else {
08598     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
08599     while ( nodeIt->more() ) {
08600       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
08601       if ( n == theBetweenNode1 )
08602         il1 = iNode;
08603       else if ( n == theBetweenNode2 )
08604         il2 = iNode;
08605       else if ( i3 < 0 )
08606         i3 = iNode;
08607       else
08608         i4 = iNode;
08609       nodes[ iNode++ ] = n;
08610     }
08611   }
08612   if ( il1 < 0 || il2 < 0 || i3 < 0 )
08613     return ;
08614 
08615   // arrange link nodes to go one after another regarding the face orientation
08616   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
08617   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
08618   if ( reverse ) {
08619     iNode = il1;
08620     il1 = il2;
08621     il2 = iNode;
08622     aNodesToInsert.reverse();
08623   }
08624   // check that not link nodes of a quadrangles are in good order
08625   int nbFaceNodes = theFace->NbNodes();
08626   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
08627     iNode = i3;
08628     i3 = i4;
08629     i4 = iNode;
08630   }
08631 
08632   if (toCreatePoly || theFace->IsPoly()) {
08633 
08634     iNode = 0;
08635     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
08636 
08637     // add nodes of face up to first node of link
08638     bool isFLN = false;
08639 
08640     if(theFace->IsQuadratic()) {
08641       const SMDS_VtkFace* F =
08642         dynamic_cast<const SMDS_VtkFace*>(theFace);
08643       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
08644       // use special nodes iterator
08645       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
08646       while( anIter->more()  && !isFLN ) {
08647         const SMDS_MeshNode* n = cast2Node(anIter->next());
08648         poly_nodes[iNode++] = n;
08649         if (n == nodes[il1]) {
08650           isFLN = true;
08651         }
08652       }
08653       // add nodes to insert
08654       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
08655       for (; nIt != aNodesToInsert.end(); nIt++) {
08656         poly_nodes[iNode++] = *nIt;
08657       }
08658       // add nodes of face starting from last node of link
08659       while ( anIter->more() ) {
08660         poly_nodes[iNode++] = cast2Node(anIter->next());
08661       }
08662     }
08663     else {
08664       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
08665       while ( nodeIt->more() && !isFLN ) {
08666         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
08667         poly_nodes[iNode++] = n;
08668         if (n == nodes[il1]) {
08669           isFLN = true;
08670         }
08671       }
08672       // add nodes to insert
08673       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
08674       for (; nIt != aNodesToInsert.end(); nIt++) {
08675         poly_nodes[iNode++] = *nIt;
08676       }
08677       // add nodes of face starting from last node of link
08678       while ( nodeIt->more() ) {
08679         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
08680         poly_nodes[iNode++] = n;
08681       }
08682     }
08683 
08684     // edit or replace the face
08685     SMESHDS_Mesh *aMesh = GetMeshDS();
08686 
08687     if (theFace->IsPoly()) {
08688       aMesh->ChangePolygonNodes(theFace, poly_nodes);
08689     }
08690     else {
08691       int aShapeId = FindShape( theFace );
08692 
08693       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
08694       myLastCreatedElems.Append(newElem);
08695       if ( aShapeId && newElem )
08696         aMesh->SetMeshElementOnShape( newElem, aShapeId );
08697 
08698       aMesh->RemoveElement(theFace);
08699     }
08700     return;
08701   }
08702 
08703   SMESHDS_Mesh *aMesh = GetMeshDS();
08704   if( !theFace->IsQuadratic() ) {
08705 
08706     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
08707     int nbLinkNodes = 2 + aNodesToInsert.size();
08708     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
08709     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
08710     linkNodes[ 0 ] = nodes[ il1 ];
08711     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
08712     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
08713     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
08714       linkNodes[ iNode++ ] = *nIt;
08715     }
08716     // decide how to split a quadrangle: compare possible variants
08717     // and choose which of splits to be a quadrangle
08718     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
08719     if ( nbFaceNodes == 3 ) {
08720       iBestQuad = nbSplits;
08721       i4 = i3;
08722     }
08723     else if ( nbFaceNodes == 4 ) {
08724       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
08725       double aBestRate = DBL_MAX;
08726       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
08727         i1 = 0; i2 = 1;
08728         double aBadRate = 0;
08729         // evaluate elements quality
08730         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
08731           if ( iSplit == iQuad ) {
08732             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
08733                                    linkNodes[ i2++ ],
08734                                    nodes[ i3 ],
08735                                    nodes[ i4 ]);
08736             aBadRate += getBadRate( &quad, aCrit );
08737           }
08738           else {
08739             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
08740                                    linkNodes[ i2++ ],
08741                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
08742             aBadRate += getBadRate( &tria, aCrit );
08743           }
08744         }
08745         // choice
08746         if ( aBadRate < aBestRate ) {
08747           iBestQuad = iQuad;
08748           aBestRate = aBadRate;
08749         }
08750       }
08751     }
08752 
08753     // create new elements
08754     int aShapeId = FindShape( theFace );
08755 
08756     i1 = 0; i2 = 1;
08757     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
08758       SMDS_MeshElement* newElem = 0;
08759       if ( iSplit == iBestQuad )
08760         newElem = aMesh->AddFace (linkNodes[ i1++ ],
08761                                   linkNodes[ i2++ ],
08762                                   nodes[ i3 ],
08763                                   nodes[ i4 ]);
08764       else
08765         newElem = aMesh->AddFace (linkNodes[ i1++ ],
08766                                   linkNodes[ i2++ ],
08767                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
08768       myLastCreatedElems.Append(newElem);
08769       if ( aShapeId && newElem )
08770         aMesh->SetMeshElementOnShape( newElem, aShapeId );
08771     }
08772 
08773     // change nodes of theFace
08774     const SMDS_MeshNode* newNodes[ 4 ];
08775     newNodes[ 0 ] = linkNodes[ i1 ];
08776     newNodes[ 1 ] = linkNodes[ i2 ];
08777     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
08778     newNodes[ 3 ] = nodes[ i4 ];
08779     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
08780     const SMDS_MeshElement* newElem = 0;
08781     if (iSplit == iBestQuad)
08782       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
08783     else
08784       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
08785     myLastCreatedElems.Append(newElem);
08786     if ( aShapeId && newElem )
08787       aMesh->SetMeshElementOnShape( newElem, aShapeId );
08788 } // end if(!theFace->IsQuadratic())
08789   else { // theFace is quadratic
08790     // we have to split theFace on simple triangles and one simple quadrangle
08791     int tmp = il1/2;
08792     int nbshift = tmp*2;
08793     // shift nodes in nodes[] by nbshift
08794     int i,j;
08795     for(i=0; i<nbshift; i++) {
08796       const SMDS_MeshNode* n = nodes[0];
08797       for(j=0; j<nbFaceNodes-1; j++) {
08798         nodes[j] = nodes[j+1];
08799       }
08800       nodes[nbFaceNodes-1] = n;
08801     }
08802     il1 = il1 - nbshift;
08803     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
08804     //   n0      n1     n2    n0      n1     n2
08805     //     +-----+-----+        +-----+-----+
08806     //      \         /         |           |
08807     //       \       /          |           |
08808     //      n5+     +n3       n7+           +n3
08809     //         \   /            |           |
08810     //          \ /             |           |
08811     //           +              +-----+-----+
08812     //           n4           n6      n5     n4
08813 
08814     // create new elements
08815     int aShapeId = FindShape( theFace );
08816 
08817     int n1,n2,n3;
08818     if(nbFaceNodes==6) { // quadratic triangle
08819       SMDS_MeshElement* newElem =
08820         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
08821       myLastCreatedElems.Append(newElem);
08822       if ( aShapeId && newElem )
08823         aMesh->SetMeshElementOnShape( newElem, aShapeId );
08824       if(theFace->IsMediumNode(nodes[il1])) {
08825         // create quadrangle
08826         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
08827         myLastCreatedElems.Append(newElem);
08828         if ( aShapeId && newElem )
08829           aMesh->SetMeshElementOnShape( newElem, aShapeId );
08830         n1 = 1;
08831         n2 = 2;
08832         n3 = 3;
08833       }
08834       else {
08835         // create quadrangle
08836         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
08837         myLastCreatedElems.Append(newElem);
08838         if ( aShapeId && newElem )
08839           aMesh->SetMeshElementOnShape( newElem, aShapeId );
08840         n1 = 0;
08841         n2 = 1;
08842         n3 = 5;
08843       }
08844     }
08845     else { // nbFaceNodes==8 - quadratic quadrangle
08846       SMDS_MeshElement* newElem =
08847         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
08848       myLastCreatedElems.Append(newElem);
08849       if ( aShapeId && newElem )
08850         aMesh->SetMeshElementOnShape( newElem, aShapeId );
08851       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
08852       myLastCreatedElems.Append(newElem);
08853       if ( aShapeId && newElem )
08854         aMesh->SetMeshElementOnShape( newElem, aShapeId );
08855       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
08856       myLastCreatedElems.Append(newElem);
08857       if ( aShapeId && newElem )
08858         aMesh->SetMeshElementOnShape( newElem, aShapeId );
08859       if(theFace->IsMediumNode(nodes[il1])) {
08860         // create quadrangle
08861         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
08862         myLastCreatedElems.Append(newElem);
08863         if ( aShapeId && newElem )
08864           aMesh->SetMeshElementOnShape( newElem, aShapeId );
08865         n1 = 1;
08866         n2 = 2;
08867         n3 = 3;
08868       }
08869       else {
08870         // create quadrangle
08871         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
08872         myLastCreatedElems.Append(newElem);
08873         if ( aShapeId && newElem )
08874           aMesh->SetMeshElementOnShape( newElem, aShapeId );
08875         n1 = 0;
08876         n2 = 1;
08877         n3 = 7;
08878       }
08879     }
08880     // create needed triangles using n1,n2,n3 and inserted nodes
08881     int nbn = 2 + aNodesToInsert.size();
08882     //const SMDS_MeshNode* aNodes[nbn];
08883     vector<const SMDS_MeshNode*> aNodes(nbn);
08884     aNodes[0] = nodes[n1];
08885     aNodes[nbn-1] = nodes[n2];
08886     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
08887     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
08888       aNodes[iNode++] = *nIt;
08889     }
08890     for(i=1; i<nbn; i++) {
08891       SMDS_MeshElement* newElem =
08892         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
08893       myLastCreatedElems.Append(newElem);
08894       if ( aShapeId && newElem )
08895         aMesh->SetMeshElementOnShape( newElem, aShapeId );
08896     }
08897   }
08898   // remove old face
08899   aMesh->RemoveElement(theFace);
08900 }
08901 
08902 //=======================================================================
08903 //function : UpdateVolumes
08904 //purpose  :
08905 //=======================================================================
08906 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
08907                                       const SMDS_MeshNode*        theBetweenNode2,
08908                                       list<const SMDS_MeshNode*>& theNodesToInsert)
08909 {
08910   myLastCreatedElems.Clear();
08911   myLastCreatedNodes.Clear();
08912 
08913   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
08914   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
08915     const SMDS_MeshElement* elem = invElemIt->next();
08916 
08917     // check, if current volume has link theBetweenNode1 - theBetweenNode2
08918     SMDS_VolumeTool aVolume (elem);
08919     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
08920       continue;
08921 
08922     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
08923     int iface, nbFaces = aVolume.NbFaces();
08924     vector<const SMDS_MeshNode *> poly_nodes;
08925     vector<int> quantities (nbFaces);
08926 
08927     for (iface = 0; iface < nbFaces; iface++) {
08928       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
08929       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
08930       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
08931 
08932       for (int inode = 0; inode < nbFaceNodes; inode++) {
08933         poly_nodes.push_back(faceNodes[inode]);
08934 
08935         if (nbInserted == 0) {
08936           if (faceNodes[inode] == theBetweenNode1) {
08937             if (faceNodes[inode + 1] == theBetweenNode2) {
08938               nbInserted = theNodesToInsert.size();
08939 
08940               // add nodes to insert
08941               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
08942               for (; nIt != theNodesToInsert.end(); nIt++) {
08943                 poly_nodes.push_back(*nIt);
08944               }
08945             }
08946           }
08947           else if (faceNodes[inode] == theBetweenNode2) {
08948             if (faceNodes[inode + 1] == theBetweenNode1) {
08949               nbInserted = theNodesToInsert.size();
08950 
08951               // add nodes to insert in reversed order
08952               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
08953               nIt--;
08954               for (; nIt != theNodesToInsert.begin(); nIt--) {
08955                 poly_nodes.push_back(*nIt);
08956               }
08957               poly_nodes.push_back(*nIt);
08958             }
08959           }
08960           else {
08961           }
08962         }
08963       }
08964       quantities[iface] = nbFaceNodes + nbInserted;
08965     }
08966 
08967     // Replace or update the volume
08968     SMESHDS_Mesh *aMesh = GetMeshDS();
08969 
08970     if (elem->IsPoly()) {
08971       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
08972 
08973     }
08974     else {
08975       int aShapeId = FindShape( elem );
08976 
08977       SMDS_MeshElement* newElem =
08978         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
08979       myLastCreatedElems.Append(newElem);
08980       if (aShapeId && newElem)
08981         aMesh->SetMeshElementOnShape(newElem, aShapeId);
08982 
08983       aMesh->RemoveElement(elem);
08984     }
08985   }
08986 }
08987 
08988 namespace
08989 {
08990   //================================================================================
08994   //================================================================================
08995 
08996   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
08997                            vector<const SMDS_MeshNode *> & nodes,
08998                            vector<int> &                   nbNodeInFaces )
08999   {
09000     nodes.clear();
09001     nbNodeInFaces.clear();
09002     SMDS_VolumeTool vTool ( elem );
09003     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
09004     {
09005       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
09006       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
09007       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
09008     }
09009   }
09010 }
09011 
09012 //=======================================================================
09017 //=======================================================================
09018 
09019 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
09020                                              SMESH_MesherHelper& theHelper,
09021                                              const bool          theForce3d)
09022 {
09023   int nbElem = 0;
09024   if( !theSm ) return nbElem;
09025 
09026   vector<int> nbNodeInFaces;
09027   vector<const SMDS_MeshNode *> nodes;
09028   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
09029   while(ElemItr->more())
09030   {
09031     nbElem++;
09032     const SMDS_MeshElement* elem = ElemItr->next();
09033     if( !elem || elem->IsQuadratic() ) continue;
09034 
09035     // get elem data needed to re-create it
09036     //
09037     const int id                        = elem->GetID();
09038     const int nbNodes                   = elem->NbNodes();
09039     const SMDSAbs_ElementType aType     = elem->GetType();
09040     const SMDSAbs_EntityType  aGeomType = elem->GetEntityType();
09041     nodes.assign(elem->begin_nodes(), elem->end_nodes());
09042     if ( aGeomType == SMDSEntity_Polyhedra )
09043       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
09044     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
09045       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
09046 
09047     // remove a linear element
09048     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
09049 
09050     const SMDS_MeshElement* NewElem = 0;
09051 
09052     switch( aType )
09053     {
09054     case SMDSAbs_Edge :
09055       {
09056         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
09057         break;
09058       }
09059     case SMDSAbs_Face :
09060       {
09061         switch(nbNodes)
09062         {
09063         case 3:
09064           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
09065           break;
09066         case 4:
09067           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09068           break;
09069         default:
09070           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
09071           continue;
09072         }
09073         break;
09074       }
09075     case SMDSAbs_Volume :
09076       {
09077         switch( aGeomType )
09078         {
09079         case SMDSEntity_Tetra:
09080           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09081           break;
09082         case SMDSEntity_Pyramid:
09083           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
09084           break;
09085         case SMDSEntity_Penta:
09086           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
09087           break;
09088         case SMDSEntity_Hexa:
09089           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09090                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
09091           break;
09092         case SMDSEntity_Hexagonal_Prism:
09093         default:
09094           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
09095         }
09096         break;
09097       }
09098     default :
09099       continue;
09100     }
09101     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
09102     if( NewElem )
09103       theSm->AddElement( NewElem );
09104   }
09105   return nbElem;
09106 }
09107 
09108 //=======================================================================
09109 //function : ConvertToQuadratic
09110 //purpose  :
09111 //=======================================================================
09112 
09113 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
09114 {
09115   SMESHDS_Mesh* meshDS = GetMeshDS();
09116 
09117   SMESH_MesherHelper aHelper(*myMesh);
09118   aHelper.SetIsQuadratic( true );
09119 
09120   int nbCheckedElems = 0;
09121   if ( myMesh->HasShapeToMesh() )
09122   {
09123     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
09124     {
09125       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
09126       while ( smIt->more() ) {
09127         SMESH_subMesh* sm = smIt->next();
09128         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
09129           aHelper.SetSubShape( sm->GetSubShape() );
09130           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
09131         }
09132       }
09133     }
09134   }
09135   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
09136   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
09137   {
09138     SMESHDS_SubMesh *smDS = 0;
09139     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
09140     while(aEdgeItr->more())
09141     {
09142       const SMDS_MeshEdge* edge = aEdgeItr->next();
09143       if(edge && !edge->IsQuadratic())
09144       {
09145         int id = edge->GetID();
09146         //MESSAGE("edge->GetID() " << id);
09147         const SMDS_MeshNode* n1 = edge->GetNode(0);
09148         const SMDS_MeshNode* n2 = edge->GetNode(1);
09149 
09150         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
09151 
09152         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
09153         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
09154       }
09155     }
09156     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
09157     while(aFaceItr->more())
09158     {
09159       const SMDS_MeshFace* face = aFaceItr->next();
09160       if(!face || face->IsQuadratic() ) continue;
09161 
09162       const int id = face->GetID();
09163       const SMDSAbs_EntityType type = face->GetEntityType();
09164       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
09165 
09166       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
09167 
09168       SMDS_MeshFace * NewFace = 0;
09169       switch( type )
09170       {
09171       case SMDSEntity_Triangle:
09172         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
09173         break;
09174       case SMDSEntity_Quadrangle:
09175         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09176         break;
09177       default:
09178         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
09179       }
09180       ReplaceElemInGroups( face, NewFace, GetMeshDS());
09181     }
09182     vector<int> nbNodeInFaces;
09183     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
09184     while(aVolumeItr->more())
09185     {
09186       const SMDS_MeshVolume* volume = aVolumeItr->next();
09187       if(!volume || volume->IsQuadratic() ) continue;
09188 
09189       const int id = volume->GetID();
09190       const SMDSAbs_EntityType type = volume->GetEntityType();
09191       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
09192       if ( type == SMDSEntity_Polyhedra )
09193         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
09194       else if ( type == SMDSEntity_Hexagonal_Prism )
09195         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
09196 
09197       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
09198 
09199       SMDS_MeshVolume * NewVolume = 0;
09200       switch ( type )
09201       {
09202       case SMDSEntity_Tetra:
09203         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
09204         break;
09205       case SMDSEntity_Hexa:
09206         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09207                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
09208         break;
09209       case SMDSEntity_Pyramid:
09210         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
09211                                       nodes[3], nodes[4], id, theForce3d);
09212         break;
09213       case SMDSEntity_Penta:
09214         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
09215                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
09216         break;
09217       case SMDSEntity_Hexagonal_Prism:
09218       default:
09219         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
09220       }
09221       ReplaceElemInGroups(volume, NewVolume, meshDS);
09222     }
09223   }
09224 
09225   if ( !theForce3d )
09226   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
09227     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
09228     aHelper.FixQuadraticElements();
09229   }
09230 }
09231 
09232 //================================================================================
09238 //================================================================================
09239 
09240 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
09241                                           TIDSortedElemSet& theElements)
09242 {
09243   if ( theElements.empty() ) return;
09244 
09245   // we believe that all theElements are of the same type
09246   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
09247   
09248   // get all nodes shared by theElements
09249   TIDSortedNodeSet allNodes;
09250   TIDSortedElemSet::iterator eIt = theElements.begin();
09251   for ( ; eIt != theElements.end(); ++eIt )
09252     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
09253 
09254   // complete theElements with elements of lower dim whose all nodes are in allNodes
09255 
09256   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
09257   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
09258   TIDSortedNodeSet::iterator nIt = allNodes.begin();
09259   for ( ; nIt != allNodes.end(); ++nIt )
09260   {
09261     const SMDS_MeshNode* n = *nIt;
09262     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
09263     while ( invIt->more() )
09264     {
09265       const SMDS_MeshElement* e = invIt->next();
09266       if ( e->IsQuadratic() )
09267       {
09268         quadAdjacentElems[ e->GetType() ].insert( e );
09269         continue;
09270       }
09271       if ( e->GetType() >= elemType )
09272       {
09273         continue; // same type of more complex linear element
09274       }
09275 
09276       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
09277         continue; // e is already checked
09278 
09279       // check nodes
09280       bool allIn = true;
09281       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
09282       while ( nodeIt->more() && allIn )
09283         allIn = allNodes.count( cast2Node( nodeIt->next() ));
09284       if ( allIn )
09285         theElements.insert(e );
09286     }
09287   }
09288 
09289   SMESH_MesherHelper helper(*myMesh);
09290   helper.SetIsQuadratic( true );
09291 
09292   // add links of quadratic adjacent elements to the helper
09293 
09294   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
09295     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
09296           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
09297     {
09298       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
09299     }
09300   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
09301     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
09302           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
09303     {
09304       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
09305     }
09306   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
09307     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
09308           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
09309     {
09310       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
09311     }
09312 
09313   // make quadratic elements instead of linear ones
09314 
09315   SMESHDS_Mesh* meshDS = GetMeshDS();
09316   SMESHDS_SubMesh* smDS = 0;
09317   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
09318   {
09319     const SMDS_MeshElement* elem = *eIt;
09320     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
09321       continue;
09322 
09323     const int id                   = elem->GetID();
09324     const SMDSAbs_ElementType type = elem->GetType();
09325     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
09326 
09327     if ( !smDS || !smDS->Contains( elem ))
09328       smDS = meshDS->MeshElements( elem->getshapeId() );
09329     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
09330 
09331     SMDS_MeshElement * newElem = 0;
09332     switch( nodes.size() )
09333     {
09334     case 4: // cases for most frequently used element types go first (for optimization)
09335       if ( type == SMDSAbs_Volume )
09336         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09337       else
09338         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
09339       break;
09340     case 8:
09341       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09342                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
09343       break;
09344     case 3:
09345       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
09346       break;
09347     case 2:
09348       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
09349       break;
09350     case 5:
09351       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09352                                  nodes[4], id, theForce3d);
09353       break;
09354     case 6:
09355       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
09356                                  nodes[4], nodes[5], id, theForce3d);
09357       break;
09358     default:;
09359     }
09360     ReplaceElemInGroups( elem, newElem, meshDS);
09361     if( newElem && smDS )
09362       smDS->AddElement( newElem );
09363   }
09364 
09365   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
09366   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
09367     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
09368     helper.FixQuadraticElements();
09369   }
09370 }
09371 
09372 //=======================================================================
09377 //=======================================================================
09378 
09379 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
09380                                      SMDS_ElemIteratorPtr theItr,
09381                                      const int            theShapeID)
09382 {
09383   int nbElem = 0;
09384   SMESHDS_Mesh* meshDS = GetMeshDS();
09385 
09386   while( theItr->more() )
09387   {
09388     const SMDS_MeshElement* elem = theItr->next();
09389     nbElem++;
09390     if( elem && elem->IsQuadratic())
09391     {
09392       int id                    = elem->GetID();
09393       int nbCornerNodes         = elem->NbCornerNodes();
09394       SMDSAbs_ElementType aType = elem->GetType();
09395 
09396       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
09397 
09398       //remove a quadratic element
09399       if ( !theSm || !theSm->Contains( elem ))
09400         theSm = meshDS->MeshElements( elem->getshapeId() );
09401       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
09402 
09403       // remove medium nodes
09404       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
09405         if ( nodes[i]->NbInverseElements() == 0 )
09406           meshDS->RemoveFreeNode( nodes[i], theSm );
09407 
09408       // add a linear element
09409       nodes.resize( nbCornerNodes );
09410       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
09411       ReplaceElemInGroups(elem, newElem, meshDS);
09412       if( theSm && newElem )
09413         theSm->AddElement( newElem );
09414     }
09415   }
09416   return nbElem;
09417 }
09418 
09419 //=======================================================================
09420 //function : ConvertFromQuadratic
09421 //purpose  :
09422 //=======================================================================
09423 
09424 bool SMESH_MeshEditor::ConvertFromQuadratic()
09425 {
09426   int nbCheckedElems = 0;
09427   if ( myMesh->HasShapeToMesh() )
09428   {
09429     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
09430     {
09431       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
09432       while ( smIt->more() ) {
09433         SMESH_subMesh* sm = smIt->next();
09434         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
09435           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
09436       }
09437     }
09438   }
09439 
09440   int totalNbElems =
09441     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
09442   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
09443   {
09444     SMESHDS_SubMesh *aSM = 0;
09445     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
09446   }
09447 
09448   return true;
09449 }
09450 
09451 namespace
09452 {
09453   //================================================================================
09457   //================================================================================
09458 
09459   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
09460   {
09461     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
09462       if ( !nodeSet.count( elem->GetNode(i) ))
09463         return false;
09464     return true;
09465   }
09466 }
09467 
09468 //================================================================================
09472 //================================================================================
09473 
09474 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
09475 {
09476   if ( theElements.empty() ) return;
09477 
09478   // collect IDs of medium nodes of theElements; some of these nodes will be removed
09479   set<int> mediumNodeIDs;
09480   TIDSortedElemSet::iterator eIt = theElements.begin();
09481   for ( ; eIt != theElements.end(); ++eIt )
09482   {
09483     const SMDS_MeshElement* e = *eIt;
09484     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
09485       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
09486   }
09487 
09488   // replace given elements by linear ones
09489   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
09490   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
09491   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
09492 
09493   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
09494   // except those elements sharing medium nodes of quadratic element whose medium nodes
09495   // are not all in mediumNodeIDs
09496 
09497   // get remaining medium nodes
09498   TIDSortedNodeSet mediumNodes;
09499   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
09500   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
09501     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
09502       mediumNodes.insert( mediumNodes.end(), n );
09503 
09504   // find more quadratic elements to convert
09505   TIDSortedElemSet moreElemsToConvert;
09506   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
09507   for ( ; nIt != mediumNodes.end(); ++nIt )
09508   {
09509     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
09510     while ( invIt->more() )
09511     {
09512       const SMDS_MeshElement* e = invIt->next();
09513       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
09514       {
09515         // find a more complex element including e and
09516         // whose medium nodes are not in mediumNodes
09517         bool complexFound = false;
09518         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
09519         {
09520           SMDS_ElemIteratorPtr invIt2 =
09521             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
09522           while ( invIt2->more() )
09523           {
09524             const SMDS_MeshElement* eComplex = invIt2->next();
09525             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
09526             {
09527               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
09528               if ( nbCommonNodes == e->NbNodes())
09529               {
09530                 complexFound = true;
09531                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
09532                 break;
09533               }
09534             }
09535           }
09536         }
09537         if ( !complexFound )
09538           moreElemsToConvert.insert( e );
09539       }
09540     }
09541   }
09542   elemIt = SMDS_ElemIteratorPtr
09543     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
09544   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
09545 }
09546 
09547 //=======================================================================
09548 //function : SewSideElements
09549 //purpose  :
09550 //=======================================================================
09551 
09552 SMESH_MeshEditor::Sew_Error
09553 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
09554                                    TIDSortedElemSet&    theSide2,
09555                                    const SMDS_MeshNode* theFirstNode1,
09556                                    const SMDS_MeshNode* theFirstNode2,
09557                                    const SMDS_MeshNode* theSecondNode1,
09558                                    const SMDS_MeshNode* theSecondNode2)
09559 {
09560   myLastCreatedElems.Clear();
09561   myLastCreatedNodes.Clear();
09562 
09563   MESSAGE ("::::SewSideElements()");
09564   if ( theSide1.size() != theSide2.size() )
09565     return SEW_DIFF_NB_OF_ELEMENTS;
09566 
09567   Sew_Error aResult = SEW_OK;
09568   // Algo:
09569   // 1. Build set of faces representing each side
09570   // 2. Find which nodes of the side 1 to merge with ones on the side 2
09571   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
09572 
09573   // =======================================================================
09574   // 1. Build set of faces representing each side:
09575   // =======================================================================
09576   // a. build set of nodes belonging to faces
09577   // b. complete set of faces: find missing faces whose nodes are in set of nodes
09578   // c. create temporary faces representing side of volumes if correspondent
09579   //    face does not exist
09580 
09581   SMESHDS_Mesh* aMesh = GetMeshDS();
09582   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
09583   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
09584   TIDSortedElemSet             faceSet1, faceSet2;
09585   set<const SMDS_MeshElement*> volSet1,  volSet2;
09586   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
09587   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
09588   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
09589   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
09590   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
09591   int iSide, iFace, iNode;
09592 
09593   list<const SMDS_MeshElement* > tempFaceList;
09594   for ( iSide = 0; iSide < 2; iSide++ ) {
09595     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
09596     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
09597     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
09598     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
09599     set<const SMDS_MeshElement*>::iterator vIt;
09600     TIDSortedElemSet::iterator eIt;
09601     set<const SMDS_MeshNode*>::iterator    nIt;
09602 
09603     // check that given nodes belong to given elements
09604     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
09605     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
09606     int firstIndex = -1, secondIndex = -1;
09607     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
09608       const SMDS_MeshElement* elem = *eIt;
09609       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
09610       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
09611       if ( firstIndex > -1 && secondIndex > -1 ) break;
09612     }
09613     if ( firstIndex < 0 || secondIndex < 0 ) {
09614       // we can simply return until temporary faces created
09615       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
09616     }
09617 
09618     // -----------------------------------------------------------
09619     // 1a. Collect nodes of existing faces
09620     //     and build set of face nodes in order to detect missing
09621     //     faces corresponding to sides of volumes
09622     // -----------------------------------------------------------
09623 
09624     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
09625 
09626     // loop on the given element of a side
09627     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
09628       //const SMDS_MeshElement* elem = *eIt;
09629       const SMDS_MeshElement* elem = *eIt;
09630       if ( elem->GetType() == SMDSAbs_Face ) {
09631         faceSet->insert( elem );
09632         set <const SMDS_MeshNode*> faceNodeSet;
09633         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
09634         while ( nodeIt->more() ) {
09635           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09636           nodeSet->insert( n );
09637           faceNodeSet.insert( n );
09638         }
09639         setOfFaceNodeSet.insert( faceNodeSet );
09640       }
09641       else if ( elem->GetType() == SMDSAbs_Volume )
09642         volSet->insert( elem );
09643     }
09644     // ------------------------------------------------------------------------------
09645     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
09646     // ------------------------------------------------------------------------------
09647 
09648     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
09649       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
09650       while ( fIt->more() ) { // loop on faces sharing a node
09651         const SMDS_MeshElement* f = fIt->next();
09652         if ( faceSet->find( f ) == faceSet->end() ) {
09653           // check if all nodes are in nodeSet and
09654           // complete setOfFaceNodeSet if they are
09655           set <const SMDS_MeshNode*> faceNodeSet;
09656           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
09657           bool allInSet = true;
09658           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
09659             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09660             if ( nodeSet->find( n ) == nodeSet->end() )
09661               allInSet = false;
09662             else
09663               faceNodeSet.insert( n );
09664           }
09665           if ( allInSet ) {
09666             faceSet->insert( f );
09667             setOfFaceNodeSet.insert( faceNodeSet );
09668           }
09669         }
09670       }
09671     }
09672 
09673     // -------------------------------------------------------------------------
09674     // 1c. Create temporary faces representing sides of volumes if correspondent
09675     //     face does not exist
09676     // -------------------------------------------------------------------------
09677 
09678     if ( !volSet->empty() ) {
09679       //int nodeSetSize = nodeSet->size();
09680 
09681       // loop on given volumes
09682       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
09683         SMDS_VolumeTool vol (*vIt);
09684         // loop on volume faces: find free faces
09685         // --------------------------------------
09686         list<const SMDS_MeshElement* > freeFaceList;
09687         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
09688           if ( !vol.IsFreeFace( iFace ))
09689             continue;
09690           // check if there is already a face with same nodes in a face set
09691           const SMDS_MeshElement* aFreeFace = 0;
09692           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
09693           int nbNodes = vol.NbFaceNodes( iFace );
09694           set <const SMDS_MeshNode*> faceNodeSet;
09695           vol.GetFaceNodes( iFace, faceNodeSet );
09696           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
09697           if ( isNewFace ) {
09698             // no such a face is given but it still can exist, check it
09699             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
09700             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
09701           }
09702           if ( !aFreeFace ) {
09703             // create a temporary face
09704             if ( nbNodes == 3 ) {
09705               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
09706               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
09707             }
09708             else if ( nbNodes == 4 ) {
09709               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
09710               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
09711             }
09712             else {
09713               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
09714               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
09715               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
09716             }
09717             if ( aFreeFace )
09718               tempFaceList.push_back( aFreeFace );
09719           }
09720 
09721           if ( aFreeFace )
09722             freeFaceList.push_back( aFreeFace );
09723 
09724         } // loop on faces of a volume
09725 
09726         // choose one of several free faces of a volume
09727         // --------------------------------------------
09728         if ( freeFaceList.size() > 1 ) {
09729           // choose a face having max nb of nodes shared by other elems of a side
09730           int maxNbNodes = -1;
09731           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
09732           while ( fIt != freeFaceList.end() ) { // loop on free faces
09733             int nbSharedNodes = 0;
09734             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
09735             while ( nodeIt->more() ) { // loop on free face nodes
09736               const SMDS_MeshNode* n =
09737                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09738               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
09739               while ( invElemIt->more() ) {
09740                 const SMDS_MeshElement* e = invElemIt->next();
09741                 nbSharedNodes += faceSet->count( e );
09742                 nbSharedNodes += elemSet->count( e );
09743               }
09744             }
09745             if ( nbSharedNodes > maxNbNodes ) {
09746               maxNbNodes = nbSharedNodes;
09747               freeFaceList.erase( freeFaceList.begin(), fIt++ );
09748             }
09749             else if ( nbSharedNodes == maxNbNodes ) {
09750               fIt++;
09751             }
09752             else {
09753               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
09754             }
09755           }
09756           if ( freeFaceList.size() > 1 )
09757           {
09758             // could not choose one face, use another way
09759             // choose a face most close to the bary center of the opposite side
09760             gp_XYZ aBC( 0., 0., 0. );
09761             set <const SMDS_MeshNode*> addedNodes;
09762             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
09763             eIt = elemSet2->begin();
09764             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
09765               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
09766               while ( nodeIt->more() ) { // loop on free face nodes
09767                 const SMDS_MeshNode* n =
09768                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09769                 if ( addedNodes.insert( n ).second )
09770                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
09771               }
09772             }
09773             aBC /= addedNodes.size();
09774             double minDist = DBL_MAX;
09775             fIt = freeFaceList.begin();
09776             while ( fIt != freeFaceList.end() ) { // loop on free faces
09777               double dist = 0;
09778               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
09779               while ( nodeIt->more() ) { // loop on free face nodes
09780                 const SMDS_MeshNode* n =
09781                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09782                 gp_XYZ p( n->X(),n->Y(),n->Z() );
09783                 dist += ( aBC - p ).SquareModulus();
09784               }
09785               if ( dist < minDist ) {
09786                 minDist = dist;
09787                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
09788               }
09789               else
09790                 fIt = freeFaceList.erase( fIt++ );
09791             }
09792           }
09793         } // choose one of several free faces of a volume
09794 
09795         if ( freeFaceList.size() == 1 ) {
09796           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
09797           faceSet->insert( aFreeFace );
09798           // complete a node set with nodes of a found free face
09799           //           for ( iNode = 0; iNode < ; iNode++ )
09800           //             nodeSet->insert( fNodes[ iNode ] );
09801         }
09802 
09803       } // loop on volumes of a side
09804 
09805       //       // complete a set of faces if new nodes in a nodeSet appeared
09806       //       // ----------------------------------------------------------
09807       //       if ( nodeSetSize != nodeSet->size() ) {
09808       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
09809       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
09810       //           while ( fIt->more() ) { // loop on faces sharing a node
09811       //             const SMDS_MeshElement* f = fIt->next();
09812       //             if ( faceSet->find( f ) == faceSet->end() ) {
09813       //               // check if all nodes are in nodeSet and
09814       //               // complete setOfFaceNodeSet if they are
09815       //               set <const SMDS_MeshNode*> faceNodeSet;
09816       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
09817       //               bool allInSet = true;
09818       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
09819       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
09820       //                 if ( nodeSet->find( n ) == nodeSet->end() )
09821       //                   allInSet = false;
09822       //                 else
09823       //                   faceNodeSet.insert( n );
09824       //               }
09825       //               if ( allInSet ) {
09826       //                 faceSet->insert( f );
09827       //                 setOfFaceNodeSet.insert( faceNodeSet );
09828       //               }
09829       //             }
09830       //           }
09831       //         }
09832       //       }
09833     } // Create temporary faces, if there are volumes given
09834   } // loop on sides
09835 
09836   if ( faceSet1.size() != faceSet2.size() ) {
09837     // delete temporary faces: they are in reverseElements of actual nodes
09838 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
09839 //    while ( tmpFaceIt->more() )
09840 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
09841 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
09842 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
09843 //      aMesh->RemoveElement(*tmpFaceIt);
09844     MESSAGE("Diff nb of faces");
09845     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
09846   }
09847 
09848   // ============================================================
09849   // 2. Find nodes to merge:
09850   //              bind a node to remove to a node to put instead
09851   // ============================================================
09852 
09853   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
09854   if ( theFirstNode1 != theFirstNode2 )
09855     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
09856   if ( theSecondNode1 != theSecondNode2 )
09857     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
09858 
09859   LinkID_Gen aLinkID_Gen( GetMeshDS() );
09860   set< long > linkIdSet; // links to process
09861   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
09862 
09863   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
09864   list< NLink > linkList[2];
09865   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
09866   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
09867   // loop on links in linkList; find faces by links and append links
09868   // of the found faces to linkList
09869   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
09870   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
09871   {
09872     NLink link[] = { *linkIt[0], *linkIt[1] };
09873     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
09874     if ( !linkIdSet.count( linkID ) )
09875       continue;
09876 
09877     // by links, find faces in the face sets,
09878     // and find indices of link nodes in the found faces;
09879     // in a face set, there is only one or no face sharing a link
09880     // ---------------------------------------------------------------
09881 
09882     const SMDS_MeshElement* face[] = { 0, 0 };
09883     vector<const SMDS_MeshNode*> fnodes[2];
09884     int iLinkNode[2][2];
09885     TIDSortedElemSet avoidSet;
09886     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
09887       const SMDS_MeshNode* n1 = link[iSide].first;
09888       const SMDS_MeshNode* n2 = link[iSide].second;
09889       //cout << "Side " << iSide << " ";
09890       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
09891       // find a face by two link nodes
09892       face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
09893                                      &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
09894       if ( face[ iSide ])
09895       {
09896         //cout << " F " << face[ iSide]->GetID() <<endl;
09897         faceSetPtr[ iSide ]->erase( face[ iSide ]);
09898         // put face nodes to fnodes
09899         if ( face[ iSide ]->IsQuadratic() )
09900         {
09901           // use interlaced nodes iterator
09902           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
09903           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
09904           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
09905           while ( nIter->more() )
09906             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
09907         }
09908         else
09909         {
09910           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
09911                                   face[ iSide ]->end_nodes() );
09912         }
09913         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
09914       }
09915     }
09916 
09917     // check similarity of elements of the sides
09918     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
09919       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
09920       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
09921         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
09922       }
09923       else {
09924         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
09925       }
09926       break; // do not return because it's necessary to remove tmp faces
09927     }
09928 
09929     // set nodes to merge
09930     // -------------------
09931 
09932     if ( face[0] && face[1] )  {
09933       const int nbNodes = face[0]->NbNodes();
09934       if ( nbNodes != face[1]->NbNodes() ) {
09935         MESSAGE("Diff nb of face nodes");
09936         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
09937         break; // do not return because it s necessary to remove tmp faces
09938       }
09939       bool reverse[] = { false, false }; // order of nodes in the link
09940       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
09941         // analyse link orientation in faces
09942         int i1 = iLinkNode[ iSide ][ 0 ];
09943         int i2 = iLinkNode[ iSide ][ 1 ];
09944         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
09945       }
09946       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
09947       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
09948       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
09949       {
09950         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
09951                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
09952       }
09953 
09954       // add other links of the faces to linkList
09955       // -----------------------------------------
09956 
09957       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
09958         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
09959         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
09960         if ( !iter_isnew.second ) { // already in a set: no need to process
09961           linkIdSet.erase( iter_isnew.first );
09962         }
09963         else // new in set == encountered for the first time: add
09964         {
09965           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
09966           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
09967           linkList[0].push_back ( NLink( n1, n2 ));
09968           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
09969         }
09970       }
09971     } // 2 faces found
09972 
09973     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
09974       break;
09975 
09976   } // loop on link lists
09977 
09978   if ( aResult == SEW_OK &&
09979        ( //linkIt[0] != linkList[0].end() ||
09980          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
09981     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
09982              " " << (faceSetPtr[1]->empty()));
09983     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
09984   }
09985 
09986   // ====================================================================
09987   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
09988   // ====================================================================
09989 
09990   // delete temporary faces
09991 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
09992 //  while ( tmpFaceIt->more() )
09993 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
09994   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
09995   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
09996     aMesh->RemoveElement(*tmpFaceIt);
09997 
09998   if ( aResult != SEW_OK)
09999     return aResult;
10000 
10001   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10002   // loop on nodes replacement map
10003   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10004   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10005     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10006       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10007       nodeIDsToRemove.push_back( nToRemove->GetID() );
10008       // loop on elements sharing nToRemove
10009       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10010       while ( invElemIt->more() ) {
10011         const SMDS_MeshElement* e = invElemIt->next();
10012         // get a new suite of nodes: make replacement
10013         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10014         vector< const SMDS_MeshNode*> nodes( nbNodes );
10015         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10016         while ( nIt->more() ) {
10017           const SMDS_MeshNode* n =
10018             static_cast<const SMDS_MeshNode*>( nIt->next() );
10019           nnIt = nReplaceMap.find( n );
10020           if ( nnIt != nReplaceMap.end() ) {
10021             nbReplaced++;
10022             n = (*nnIt).second;
10023           }
10024           nodes[ i++ ] = n;
10025         }
10026         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10027         //         elemIDsToRemove.push_back( e->GetID() );
10028         //       else
10029         if ( nbReplaced )
10030           {
10031             SMDSAbs_ElementType etyp = e->GetType();
10032             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10033             if (newElem)
10034               {
10035                 myLastCreatedElems.Append(newElem);
10036                 AddToSameGroups(newElem, e, aMesh);
10037                 int aShapeId = e->getshapeId();
10038                 if ( aShapeId )
10039                   {
10040                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10041                   }
10042               }
10043             aMesh->RemoveElement(e);
10044           }
10045       }
10046     }
10047 
10048   Remove( nodeIDsToRemove, true );
10049 
10050   return aResult;
10051 }
10052 
10053 //================================================================================
10065 //================================================================================
10066 
10067 #ifdef _DEBUG_
10068 //#define DEBUG_MATCHING_NODES
10069 #endif
10070 
10071 SMESH_MeshEditor::Sew_Error
10072 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10073                                     set<const SMDS_MeshElement*>& theSide2,
10074                                     const SMDS_MeshNode*          theFirstNode1,
10075                                     const SMDS_MeshNode*          theFirstNode2,
10076                                     const SMDS_MeshNode*          theSecondNode1,
10077                                     const SMDS_MeshNode*          theSecondNode2,
10078                                     TNodeNodeMap &                nReplaceMap)
10079 {
10080   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10081 
10082   nReplaceMap.clear();
10083   if ( theFirstNode1 != theFirstNode2 )
10084     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10085   if ( theSecondNode1 != theSecondNode2 )
10086     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10087 
10088   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10089   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10090 
10091   list< NLink > linkList[2];
10092   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10093   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10094 
10095   // loop on links in linkList; find faces by links and append links
10096   // of the found faces to linkList
10097   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10098   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10099     NLink link[] = { *linkIt[0], *linkIt[1] };
10100     if ( linkSet.find( link[0] ) == linkSet.end() )
10101       continue;
10102 
10103     // by links, find faces in the face sets,
10104     // and find indices of link nodes in the found faces;
10105     // in a face set, there is only one or no face sharing a link
10106     // ---------------------------------------------------------------
10107 
10108     const SMDS_MeshElement* face[] = { 0, 0 };
10109     list<const SMDS_MeshNode*> notLinkNodes[2];
10110     //bool reverse[] = { false, false }; // order of notLinkNodes
10111     int nbNodes[2];
10112     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10113     {
10114       const SMDS_MeshNode* n1 = link[iSide].first;
10115       const SMDS_MeshNode* n2 = link[iSide].second;
10116       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10117       set< const SMDS_MeshElement* > facesOfNode1;
10118       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10119       {
10120         // during a loop of the first node, we find all faces around n1,
10121         // during a loop of the second node, we find one face sharing both n1 and n2
10122         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10123         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10124         while ( fIt->more() ) { // loop on faces sharing a node
10125           const SMDS_MeshElement* f = fIt->next();
10126           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10127               ! facesOfNode1.insert( f ).second ) // f encounters twice
10128           {
10129             if ( face[ iSide ] ) {
10130               MESSAGE( "2 faces per link " );
10131               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10132             }
10133             face[ iSide ] = f;
10134             faceSet->erase( f );
10135 
10136             // get not link nodes
10137             int nbN = f->NbNodes();
10138             if ( f->IsQuadratic() )
10139               nbN /= 2;
10140             nbNodes[ iSide ] = nbN;
10141             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10142             int i1 = f->GetNodeIndex( n1 );
10143             int i2 = f->GetNodeIndex( n2 );
10144             int iEnd = nbN, iBeg = -1, iDelta = 1;
10145             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10146             if ( reverse ) {
10147               std::swap( iEnd, iBeg ); iDelta = -1;
10148             }
10149             int i = i2;
10150             while ( true ) {
10151               i += iDelta;
10152               if ( i == iEnd ) i = iBeg + iDelta;
10153               if ( i == i1 ) break;
10154               nodes.push_back ( f->GetNode( i ) );
10155             }
10156           }
10157         }
10158       }
10159     }
10160     // check similarity of elements of the sides
10161     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10162       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10163       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10164         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10165       }
10166       else {
10167         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10168       }
10169     }
10170 
10171     // set nodes to merge
10172     // -------------------
10173 
10174     if ( face[0] && face[1] )  {
10175       if ( nbNodes[0] != nbNodes[1] ) {
10176         MESSAGE("Diff nb of face nodes");
10177         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10178       }
10179 #ifdef DEBUG_MATCHING_NODES
10180       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10181                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10182                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10183 #endif
10184       int nbN = nbNodes[0];
10185       {
10186         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10187         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10188         for ( int i = 0 ; i < nbN - 2; ++i ) {
10189 #ifdef DEBUG_MATCHING_NODES
10190           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10191 #endif
10192           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10193         }
10194       }
10195 
10196       // add other links of the face 1 to linkList
10197       // -----------------------------------------
10198 
10199       const SMDS_MeshElement* f0 = face[0];
10200       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10201       for ( int i = 0; i < nbN; i++ )
10202       {
10203         const SMDS_MeshNode* n2 = f0->GetNode( i );
10204         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10205           linkSet.insert( SMESH_TLink( n1, n2 ));
10206         if ( !iter_isnew.second ) { // already in a set: no need to process
10207           linkSet.erase( iter_isnew.first );
10208         }
10209         else // new in set == encountered for the first time: add
10210         {
10211 #ifdef DEBUG_MATCHING_NODES
10212           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10213                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10214 #endif
10215           linkList[0].push_back ( NLink( n1, n2 ));
10216           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10217         }
10218         n1 = n2;
10219       }
10220     } // 2 faces found
10221   } // loop on link lists
10222 
10223   return SEW_OK;
10224 }
10225 
10226 //================================================================================
10236 //================================================================================
10237 
10238 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10239                                     const TIDSortedElemSet& theNodesNot,
10240                                     const TIDSortedElemSet& theAffectedElems )
10241 {
10242   myLastCreatedElems.Clear();
10243   myLastCreatedNodes.Clear();
10244 
10245   if ( theElems.size() == 0 )
10246     return false;
10247 
10248   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10249   if ( !aMeshDS )
10250     return false;
10251 
10252   bool res = false;
10253   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10254   // duplicate elements and nodes
10255   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10256   // replce nodes by duplications
10257   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10258   return res;
10259 }
10260 
10261 //================================================================================
10271 //================================================================================
10272 
10273 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10274                                     const TIDSortedElemSet& theElems,
10275                                     const TIDSortedElemSet& theNodesNot,
10276                                     std::map< const SMDS_MeshNode*,
10277                                     const SMDS_MeshNode* >& theNodeNodeMap,
10278                                     const bool theIsDoubleElem )
10279 {
10280   MESSAGE("doubleNodes");
10281   // iterate on through element and duplicate them (by nodes duplication)
10282   bool res = false;
10283   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10284   for ( ;  elemItr != theElems.end(); ++elemItr )
10285   {
10286     const SMDS_MeshElement* anElem = *elemItr;
10287     if (!anElem)
10288       continue;
10289 
10290     bool isDuplicate = false;
10291     // duplicate nodes to duplicate element
10292     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10293     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10294     int ind = 0;
10295     while ( anIter->more() ) 
10296     { 
10297 
10298       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10299       SMDS_MeshNode* aNewNode = aCurrNode;
10300       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10301         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10302       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10303       {
10304         // duplicate node
10305         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10306         theNodeNodeMap[ aCurrNode ] = aNewNode;
10307         myLastCreatedNodes.Append( aNewNode );
10308       }
10309       isDuplicate |= (aCurrNode != aNewNode);
10310       newNodes[ ind++ ] = aNewNode;
10311     }
10312     if ( !isDuplicate )
10313       continue;
10314 
10315     if ( theIsDoubleElem )
10316       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10317     else
10318       {
10319       MESSAGE("ChangeElementNodes");
10320       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10321       }
10322     res = true;
10323   }
10324   return res;
10325 }
10326 
10327 //================================================================================
10336 //================================================================================
10337 
10338 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10339                                     const std::list< int >& theListOfModifiedElems )
10340 {
10341   MESSAGE("DoubleNodes");
10342   myLastCreatedElems.Clear();
10343   myLastCreatedNodes.Clear();
10344 
10345   if ( theListOfNodes.size() == 0 )
10346     return false;
10347 
10348   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10349   if ( !aMeshDS )
10350     return false;
10351 
10352   // iterate through nodes and duplicate them
10353 
10354   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10355 
10356   std::list< int >::const_iterator aNodeIter;
10357   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10358   {
10359     int aCurr = *aNodeIter;
10360     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10361     if ( !aNode )
10362       continue;
10363 
10364     // duplicate node
10365 
10366     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10367     if ( aNewNode )
10368     {
10369       anOldNodeToNewNode[ aNode ] = aNewNode;
10370       myLastCreatedNodes.Append( aNewNode );
10371     }
10372   }
10373 
10374   // Create map of new nodes for modified elements
10375 
10376   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10377 
10378   std::list< int >::const_iterator anElemIter;
10379   for ( anElemIter = theListOfModifiedElems.begin(); 
10380         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10381   {
10382     int aCurr = *anElemIter;
10383     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10384     if ( !anElem )
10385       continue;
10386 
10387     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10388 
10389     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10390     int ind = 0;
10391     while ( anIter->more() ) 
10392     { 
10393       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10394       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10395       {
10396         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10397         aNodeArr[ ind++ ] = aNewNode;
10398       }
10399       else
10400         aNodeArr[ ind++ ] = aCurrNode;
10401     }
10402     anElemToNodes[ anElem ] = aNodeArr;
10403   }
10404 
10405   // Change nodes of elements  
10406 
10407   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10408     anElemToNodesIter = anElemToNodes.begin();
10409   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10410   {
10411     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10412     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10413     if ( anElem )
10414       {
10415       MESSAGE("ChangeElementNodes");
10416       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10417       }
10418   }
10419 
10420   return true;
10421 }
10422 
10423 namespace {
10424 
10425   //================================================================================
10430   //================================================================================
10431 
10432   template<class Classifier>
10433   bool isInside(const SMDS_MeshElement* theElem,
10434                 Classifier&             theClassifier,
10435                 const double            theTol)
10436   {
10437     gp_XYZ centerXYZ (0, 0, 0);
10438     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10439     while (aNodeItr->more())
10440       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10441 
10442     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10443     theClassifier.Perform(aPnt, theTol);
10444     TopAbs_State aState = theClassifier.State();
10445     return (aState == TopAbs_IN || aState == TopAbs_ON );
10446   }
10447 
10448   //================================================================================
10453   //================================================================================
10454 
10455   struct _FaceClassifier
10456   {
10457     Extrema_ExtPS       _extremum;
10458     BRepAdaptor_Surface _surface;
10459     TopAbs_State        _state;
10460 
10461     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10462     {
10463       _extremum.Initialize( _surface,
10464                             _surface.FirstUParameter(), _surface.LastUParameter(),
10465                             _surface.FirstVParameter(), _surface.LastVParameter(),
10466                             _surface.Tolerance(), _surface.Tolerance() );
10467     }
10468     void Perform(const gp_Pnt& aPnt, double theTol)
10469     {
10470       _state = TopAbs_OUT;
10471       _extremum.Perform(aPnt);
10472       if ( _extremum.IsDone() )
10473         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10474 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10475           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10476 #else
10477           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10478 #endif
10479     }
10480     TopAbs_State State() const
10481     {
10482       return _state;
10483     }
10484   };
10485 }
10486 
10487 //================================================================================
10497 //================================================================================
10498 
10499 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10500                                             const TIDSortedElemSet& theNodesNot,
10501                                             const TopoDS_Shape&     theShape )
10502 {
10503   if ( theShape.IsNull() )
10504     return false;
10505 
10506   const double aTol = Precision::Confusion();
10507   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10508   auto_ptr<_FaceClassifier>              aFaceClassifier;
10509   if ( theShape.ShapeType() == TopAbs_SOLID )
10510   {
10511     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10512     bsc3d->PerformInfinitePoint(aTol);
10513   }
10514   else if (theShape.ShapeType() == TopAbs_FACE )
10515   {
10516     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10517   }
10518 
10519   // iterates on indicated elements and get elements by back references from their nodes
10520   TIDSortedElemSet anAffected;
10521   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10522   for ( ;  elemItr != theElems.end(); ++elemItr )
10523   {
10524     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10525     if (!anElem)
10526       continue;
10527 
10528     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10529     while ( nodeItr->more() )
10530     {
10531       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10532       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10533         continue;
10534       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10535       while ( backElemItr->more() )
10536       {
10537         const SMDS_MeshElement* curElem = backElemItr->next();
10538         if ( curElem && theElems.find(curElem) == theElems.end() &&
10539              ( bsc3d.get() ?
10540                isInside( curElem, *bsc3d, aTol ) :
10541                isInside( curElem, *aFaceClassifier, aTol )))
10542           anAffected.insert( curElem );
10543       }
10544     }
10545   }
10546   return DoubleNodes( theElems, theNodesNot, anAffected );
10547 }
10548 
10557 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10558 {
10559 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10560 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10561 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10562 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10563   gp_Vec vref(p0, p1);
10564   gp_Vec v1(p0, g1);
10565   gp_Vec v2(p0, g2);
10566   gp_Vec n1 = vref.Crossed(v1);
10567   gp_Vec n2 = vref.Crossed(v2);
10568   return n2.AngleWithRef(n1, vref);
10569 }
10570 
10583 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10584                                                      bool createJointElems)
10585 {
10586   MESSAGE("----------------------------------------------");
10587   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10588   MESSAGE("----------------------------------------------");
10589 
10590   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10591   meshDS->BuildDownWardConnectivity(true);
10592   CHRONO(50);
10593   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10594 
10595   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10596   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10597   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10598 
10599   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10600   std::map<int,int>celldom; // cell vtkId --> domain
10601   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10602   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10603   faceDomains.clear();
10604   celldom.clear();
10605   cellDomains.clear();
10606   nodeDomains.clear();
10607   std::map<int,int> emptyMap;
10608   std::set<int> emptySet;
10609   emptyMap.clear();
10610 
10611   for (int idom = 0; idom < theElems.size(); idom++)
10612     {
10613 
10614       // --- build a map (face to duplicate --> volume to modify)
10615       //     with all the faces shared by 2 domains (group of elements)
10616       //     and corresponding volume of this domain, for each shared face.
10617       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10618 
10619       //MESSAGE("Domain " << idom);
10620       const TIDSortedElemSet& domain = theElems[idom];
10621       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10622       for (; elemItr != domain.end(); ++elemItr)
10623         {
10624           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10625           if (!anElem)
10626             continue;
10627           int vtkId = anElem->getVtkId();
10628           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
10629           int neighborsVtkIds[NBMAXNEIGHBORS];
10630           int downIds[NBMAXNEIGHBORS];
10631           unsigned char downTypes[NBMAXNEIGHBORS];
10632           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10633           for (int n = 0; n < nbNeighbors; n++)
10634             {
10635               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10636               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10637               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10638                 {
10639                   DownIdType face(downIds[n], downTypes[n]);
10640                   if (!faceDomains.count(face))
10641                     faceDomains[face] = emptyMap; // create an empty entry for face
10642                   if (!faceDomains[face].count(idom))
10643                     {
10644                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10645                       celldom[vtkId] = idom;
10646                       //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
10647                     }
10648                 }
10649             }
10650         }
10651     }
10652 
10653   //MESSAGE("Number of shared faces " << faceDomains.size());
10654   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10655 
10656   // --- explore the shared faces domain by domain,
10657   //     explore the nodes of the face and see if they belong to a cell in the domain,
10658   //     which has only a node or an edge on the border (not a shared face)
10659 
10660   for (int idomain = 0; idomain < theElems.size(); idomain++)
10661     {
10662       //MESSAGE("Domain " << idomain);
10663       const TIDSortedElemSet& domain = theElems[idomain];
10664       itface = faceDomains.begin();
10665       for (; itface != faceDomains.end(); ++itface)
10666         {
10667           std::map<int, int> domvol = itface->second;
10668           if (!domvol.count(idomain))
10669             continue;
10670           DownIdType face = itface->first;
10671           //MESSAGE(" --- face " << face.cellId);
10672           std::set<int> oldNodes;
10673           oldNodes.clear();
10674           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10675           std::set<int>::iterator itn = oldNodes.begin();
10676           for (; itn != oldNodes.end(); ++itn)
10677             {
10678               int oldId = *itn;
10679               //MESSAGE("     node " << oldId);
10680               std::set<int> cells;
10681               cells.clear();
10682               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10683               for (int i=0; i<l.ncells; i++)
10684                 {
10685                   int vtkId = l.cells[i];
10686                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10687                   if (!domain.count(anElem))
10688                     continue;
10689                   int vtkType = grid->GetCellType(vtkId);
10690                   int downId = grid->CellIdToDownId(vtkId);
10691                   if (downId < 0)
10692                     {
10693                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10694                       continue; // not OK at this stage of the algorithm:
10695                                 //no cells created after BuildDownWardConnectivity
10696                     }
10697                   DownIdType aCell(downId, vtkType);
10698                   if (celldom.count(vtkId))
10699                     continue;
10700                   cellDomains[aCell][idomain] = vtkId;
10701                   celldom[vtkId] = idomain;
10702                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
10703                 }
10704             }
10705         }
10706     }
10707 
10708   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10709   //     for each shared face, get the nodes
10710   //     for each node, for each domain of the face, create a clone of the node
10711 
10712   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10713   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10714   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10715 
10716   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10717   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10718   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10719 
10720   for (int idomain = 0; idomain < theElems.size(); idomain++)
10721     {
10722       itface = faceDomains.begin();
10723       for (; itface != faceDomains.end(); ++itface)
10724         {
10725           std::map<int, int> domvol = itface->second;
10726           if (!domvol.count(idomain))
10727             continue;
10728           DownIdType face = itface->first;
10729           //MESSAGE(" --- face " << face.cellId);
10730           std::set<int> oldNodes;
10731           oldNodes.clear();
10732           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10733           bool isMultipleDetected = false;
10734           std::set<int>::iterator itn = oldNodes.begin();
10735           for (; itn != oldNodes.end(); ++itn)
10736             {
10737               int oldId = *itn;
10738               //MESSAGE("     node " << oldId);
10739               if (!nodeDomains.count(oldId))
10740                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10741               if (nodeDomains[oldId].empty())
10742                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10743               std::map<int, int>::iterator itdom = domvol.begin();
10744               for (; itdom != domvol.end(); ++itdom)
10745                 {
10746                   int idom = itdom->first;
10747                   //MESSAGE("         domain " << idom);
10748                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10749                     {
10750                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10751                         {
10752                           vector<int> orderedDoms;
10753                           //MESSAGE("multiple node " << oldId);
10754                           isMultipleDetected =true;
10755                           if (mutipleNodes.count(oldId))
10756                             orderedDoms = mutipleNodes[oldId];
10757                           else
10758                             {
10759                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10760                               for (; it != nodeDomains[oldId].end(); ++it)
10761                                 orderedDoms.push_back(it->first);
10762                             }
10763                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10764                           //stringstream txt;
10765                           //for (int i=0; i<orderedDoms.size(); i++)
10766                           //  txt << orderedDoms[i] << " ";
10767                           //MESSAGE("orderedDoms " << txt.str());
10768                           mutipleNodes[oldId] = orderedDoms;
10769                         }
10770                       double *coords = grid->GetPoint(oldId);
10771                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10772                       int newId = newNode->getVtkId();
10773                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10774                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
10775                     }
10776                   if (nodeDomains[oldId].size() >= 3)
10777                     {
10778                       //MESSAGE("confirm multiple node " << oldId);
10779                       isMultipleDetected =true;
10780                     }
10781                 }
10782             }
10783           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
10784             {
10785               //MESSAGE("multiple Nodes detected on a shared face");
10786               int downId = itface->first.cellId;
10787               unsigned char cellType = itface->first.cellType;
10788               // --- shared edge or shared face ?
10789               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10790                 {
10791                   int nodes[3];
10792                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10793                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10794                     if (mutipleNodes.count(nodes[i]))
10795                       if (!mutipleNodesToFace.count(nodes[i]))
10796                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10797                }
10798               else // shared face (between two volumes)
10799                 {
10800                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10801                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10802                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10803                   for (int ie =0; ie < nbEdges; ie++)
10804                     {
10805                       int nodes[3];
10806                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10807                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10808                         {
10809                           vector<int> vn0 = mutipleNodes[nodes[0]];
10810                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10811                           sort( vn0.begin(), vn0.end() );
10812                           sort( vn1.begin(), vn1.end() );
10813                           if (vn0 == vn1)
10814                             {
10815                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10816                               double *coords = grid->GetPoint(nodes[0]);
10817                               gp_Pnt p0(coords[0], coords[1], coords[2]);
10818                               coords = grid->GetPoint(nodes[nbNodes - 1]);
10819                               gp_Pnt p1(coords[0], coords[1], coords[2]);
10820                               gp_Pnt gref;
10821                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10822                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10823                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10824                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10825                               for (int id=0; id < vn0.size(); id++)
10826                                 {
10827                                   int idom = vn0[id];
10828                                   for (int ivol=0; ivol<nbvol; ivol++)
10829                                     {
10830                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10831                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10832                                       if (theElems[idom].count(elem))
10833                                         {
10834                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10835                                           domvol[idom] = svol;
10836                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
10837                                           double values[3];
10838                                           vtkIdType npts = 0;
10839                                           vtkIdType* pts = 0;
10840                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10841                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10842                                           if (id ==0)
10843                                             {
10844                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10845                                               angleDom[idom] = 0;
10846                                             }
10847                                           else
10848                                             {
10849                                               gp_Pnt g(values[0], values[1], values[2]);
10850                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10851                                               //MESSAGE("  angle=" << angleDom[idom]);
10852                                             }
10853                                           break;
10854                                         }
10855                                     }
10856                                 }
10857                               map<double, int> sortedDom; // sort domains by angle
10858                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10859                                 sortedDom[ia->second] = ia->first;
10860                               vector<int> vnodes;
10861                               vector<int> vdom;
10862                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10863                                 {
10864                                   vdom.push_back(ib->second);
10865                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
10866                                 }
10867                               for (int ino = 0; ino < nbNodes; ino++)
10868                                 vnodes.push_back(nodes[ino]);
10869                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10870                             }
10871                         }
10872                     }
10873                 }
10874             }
10875         }
10876     }
10877 
10878   // --- iterate on shared faces (volumes to modify, face to extrude)
10879   //     get node id's of the face (id SMDS = id VTK)
10880   //     create flat element with old and new nodes if requested
10881 
10882   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10883   //     (domain1 X domain2) = domain1 + MAXINT*domain2
10884 
10885   std::map<int, std::map<long,int> > nodeQuadDomains;
10886   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10887 
10888   if (createJointElems)
10889     {
10890       itface = faceDomains.begin();
10891       for (; itface != faceDomains.end(); ++itface)
10892         {
10893           DownIdType face = itface->first;
10894           std::set<int> oldNodes;
10895           std::set<int>::iterator itn;
10896           oldNodes.clear();
10897           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10898 
10899           std::map<int, int> domvol = itface->second;
10900           std::map<int, int>::iterator itdom = domvol.begin();
10901           int dom1 = itdom->first;
10902           int vtkVolId = itdom->second;
10903           itdom++;
10904           int dom2 = itdom->first;
10905           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
10906