]> SALOME platform Git repositories - modules/smesh.git/blob - src/SMESH/SMESH_MeshEditor.cxx
Salome HOME
Implement ConvertFromQuadratic()
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
21 //
22 //
23 //
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27
28
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 #include "SMDS_QuadraticFaceOfNodes.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_subMesh.hxx"
43 #include "SMESH_ControlsDef.hxx"
44
45 #include "utilities.h"
46
47 #include <TopTools_ListIteratorOfListOfShape.hxx>
48 #include <TopTools_ListOfShape.hxx>
49 #include <math.h>
50 #include <gp_Dir.hxx>
51 #include <gp_Vec.hxx>
52 #include <gp_Ax1.hxx>
53 #include <gp_Trsf.hxx>
54 #include <gp_Lin.hxx>
55 #include <gp_XYZ.hxx>
56 #include <gp_XY.hxx>
57 #include <gp.hxx>
58 #include <gp_Pln.hxx>
59 #include <BRep_Tool.hxx>
60 #include <Geom_Curve.hxx>
61 #include <Geom_Surface.hxx>
62 #include <Geom2d_Curve.hxx>
63 #include <Extrema_GenExtPS.hxx>
64 #include <Extrema_POnSurf.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <ElCLib.hxx>
67 #include <TColStd_ListOfInteger.hxx>
68
69 #include <map>
70
71 using namespace std;
72 using namespace SMESH::Controls;
73
74 typedef map<const SMDS_MeshNode*, const SMDS_MeshNode*>              TNodeNodeMap;
75 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
76 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
77 typedef map<const SMDS_MeshNode*, list<const SMDS_MeshNode*> >       TNodeOfNodeListMap;
78 typedef TNodeOfNodeListMap::iterator                                 TNodeOfNodeListMapItr;
79 //typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> >     TNodeOfNodeVecMap;
80 //typedef TNodeOfNodeVecMap::iterator                                  TNodeOfNodeVecMapItr;
81 typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeListMapItr> > TElemOfVecOfNnlmiMap;
82 //typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeVecMapItr> >  TElemOfVecOfMapNodesMap;
83
84 typedef pair<const SMDS_MeshNode*, const SMDS_MeshNode*> NLink;
85
86 //=======================================================================
87 //function : SMESH_MeshEditor
88 //purpose  :
89 //=======================================================================
90
91 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ):
92 myMesh( theMesh )
93 {
94 }
95
96 //=======================================================================
97 //function : Remove
98 //purpose  : Remove a node or an element.
99 //           Modify a compute state of sub-meshes which become empty
100 //=======================================================================
101
102 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
103                                const bool         isNodes )
104 {
105
106   SMESHDS_Mesh* aMesh = GetMeshDS();
107   set< SMESH_subMesh *> smmap;
108
109   list<int>::const_iterator it = theIDs.begin();
110   for ( ; it != theIDs.end(); it++ ) {
111     const SMDS_MeshElement * elem;
112     if ( isNodes )
113       elem = aMesh->FindNode( *it );
114     else
115       elem = aMesh->FindElement( *it );
116     if ( !elem )
117       continue;
118
119     // Find sub-meshes to notify about modification
120     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
121     while ( nodeIt->more() ) {
122       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
123       const SMDS_PositionPtr& aPosition = node->GetPosition();
124       if ( aPosition.get() ) {
125         if ( int aShapeID = aPosition->GetShapeId() ) {
126           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
127             smmap.insert( sm );
128         }
129       }
130     }
131
132     // Do remove
133     if ( isNodes )
134       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
135     else
136       aMesh->RemoveElement( elem );
137   }
138
139   // Notify sub-meshes about modification
140   if ( !smmap.empty() ) {
141     set< SMESH_subMesh *>::iterator smIt;
142     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
143       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
144   }
145
146   // Check if the whole mesh becomes empty
147   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
148     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
149
150   return true;
151 }
152
153 //=======================================================================
154 //function : FindShape
155 //purpose  : Return an index of the shape theElem is on
156 //           or zero if a shape not found
157 //=======================================================================
158
159 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
160 {
161   SMESHDS_Mesh * aMesh = GetMeshDS();
162   if ( aMesh->ShapeToMesh().IsNull() )
163     return 0;
164
165   if ( theElem->GetType() == SMDSAbs_Node ) {
166     const SMDS_PositionPtr& aPosition =
167       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
168     if ( aPosition.get() )
169       return aPosition->GetShapeId();
170     else
171       return 0;
172   }
173
174   TopoDS_Shape aShape; // the shape a node is on
175   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
176   while ( nodeIt->more() ) {
177     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
178     const SMDS_PositionPtr& aPosition = node->GetPosition();
179     if ( aPosition.get() ) {
180       int aShapeID = aPosition->GetShapeId();
181       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
182       if ( sm ) {
183         if ( sm->Contains( theElem ))
184           return aShapeID;
185         if ( aShape.IsNull() )
186           aShape = aMesh->IndexToShape( aShapeID );
187       }
188       else {
189         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
190       }
191     }
192   }
193
194   // None of nodes is on a proper shape,
195   // find the shape among ancestors of aShape on which a node is
196   if ( aShape.IsNull() ) {
197     //MESSAGE ("::FindShape() - NONE node is on shape")
198     return 0;
199   }
200   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
201   for ( ; ancIt.More(); ancIt.Next() ) {
202     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
203     if ( sm && sm->Contains( theElem ))
204       return aMesh->ShapeToIndex( ancIt.Value() );
205   }
206
207   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
208   return 0;
209 }
210
211 //=======================================================================
212 //function : IsMedium
213 //purpose  : 
214 //=======================================================================
215
216 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
217                                 const SMDSAbs_ElementType typeToCheck)
218 {
219   bool isMedium = false;
220   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
221   while (it->more()) {
222     const SMDS_MeshElement* elem = it->next();
223     isMedium = elem->IsMediumNode(node);
224     if ( typeToCheck == SMDSAbs_All || elem->GetType() == typeToCheck )
225       break;
226   }
227   return isMedium;
228 }
229
230 //=======================================================================
231 //function : ShiftNodesQuadTria
232 //purpose  : auxilary
233 //           Shift nodes in the array corresponded to quadratic triangle
234 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
235 //=======================================================================
236 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
237 {
238   const SMDS_MeshNode* nd1 = aNodes[0];
239   aNodes[0] = aNodes[1];
240   aNodes[1] = aNodes[2];
241   aNodes[2] = nd1;
242   const SMDS_MeshNode* nd2 = aNodes[3];
243   aNodes[3] = aNodes[4];
244   aNodes[4] = aNodes[5];
245   aNodes[5] = nd2;
246 }
247
248 //=======================================================================
249 //function : GetNodesFromTwoTria
250 //purpose  : auxilary
251 //           Shift nodes in the array corresponded to quadratic triangle
252 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
253 //=======================================================================
254 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
255                                 const SMDS_MeshElement * theTria2,
256                                 const SMDS_MeshNode* N1[],
257                                 const SMDS_MeshNode* N2[])
258 {
259   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
260   int i=0;
261   while(i<6) {
262     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
263     i++;
264   }
265   if(it->more()) return false;
266   it = theTria2->nodesIterator();
267   i=0;
268   while(i<6) {
269     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
270     i++;
271   }
272   if(it->more()) return false;
273
274   int sames[3] = {-1,-1,-1};
275   int nbsames = 0;
276   int j;
277   for(i=0; i<3; i++) {
278     for(j=0; j<3; j++) {
279       if(N1[i]==N2[j]) {
280         sames[i] = j;
281         nbsames++;
282         break;
283       }
284     }
285   }
286   if(nbsames!=2) return false;
287   if(sames[0]>-1) {
288     ShiftNodesQuadTria(N1);
289     if(sames[1]>-1) {
290       ShiftNodesQuadTria(N1);
291     }
292   }
293   i = sames[0] + sames[1] + sames[2];
294   for(; i<2; i++) {
295     ShiftNodesQuadTria(N2);
296   }
297   // now we receive following N1 and N2 (using numeration as above image)
298   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6) 
299   // i.e. first nodes from both arrays determ new diagonal
300   return true;
301 }
302
303 //=======================================================================
304 //function : InverseDiag
305 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
306 //           but having other common link.
307 //           Return False if args are improper
308 //=======================================================================
309
310 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
311                                     const SMDS_MeshElement * theTria2 )
312 {
313   if (!theTria1 || !theTria2)
314     return false;
315
316   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
317   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
318   if (F1 && F2) {
319
320     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
321     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
322     //    |/ |                                         | \|
323     //  B +--+ 2                                     B +--+ 2
324
325     // put nodes in array and find out indices of the same ones
326     const SMDS_MeshNode* aNodes [6];
327     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
328     int i = 0;
329     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
330     while ( it->more() ) {
331       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
332       
333       if ( i > 2 ) // theTria2
334         // find same node of theTria1
335         for ( int j = 0; j < 3; j++ )
336           if ( aNodes[ i ] == aNodes[ j ]) {
337             sameInd[ j ] = i;
338             sameInd[ i ] = j;
339             break;
340           }
341       // next
342       i++;
343       if ( i == 3 ) {
344         if ( it->more() )
345           return false; // theTria1 is not a triangle
346         it = theTria2->nodesIterator();
347       }
348       if ( i == 6 && it->more() )
349         return false; // theTria2 is not a triangle
350     }
351     
352     // find indices of 1,2 and of A,B in theTria1
353     int iA = 0, iB = 0, i1 = 0, i2 = 0;
354     for ( i = 0; i < 6; i++ ) {
355       if ( sameInd [ i ] == 0 )
356         if ( i < 3 ) i1 = i;
357         else         i2 = i;
358       else if (i < 3)
359         if ( iA ) iB = i;
360         else      iA = i;
361     }
362     // nodes 1 and 2 should not be the same
363     if ( aNodes[ i1 ] == aNodes[ i2 ] )
364       return false;
365
366     // theTria1: A->2
367     aNodes[ iA ] = aNodes[ i2 ];
368     // theTria2: B->1
369     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
370
371     //MESSAGE( theTria1 << theTria2 );
372     
373     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
374     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
375     
376     //MESSAGE( theTria1 << theTria2 );
377
378     return true;
379   
380   } // end if(F1 && F2)
381
382   // check case of quadratic faces
383   const SMDS_QuadraticFaceOfNodes* QF1 =
384     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
385   if(!QF1) return false;
386   const SMDS_QuadraticFaceOfNodes* QF2 =
387     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
388   if(!QF2) return false;
389
390   //       5
391   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
392   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
393   //    |   / |  
394   //  7 +  +  + 6
395   //    | /9  |
396   //    |/    |
397   //  4 +--+--+ 3  
398   //       8
399   
400   const SMDS_MeshNode* N1 [6];
401   const SMDS_MeshNode* N2 [6];
402   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
403     return false;
404   // now we receive following N1 and N2 (using numeration as above image)
405   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6) 
406   // i.e. first nodes from both arrays determ new diagonal
407
408   const SMDS_MeshNode* N1new [6];
409   const SMDS_MeshNode* N2new [6];
410   N1new[0] = N1[0];
411   N1new[1] = N2[0];
412   N1new[2] = N2[1];
413   N1new[3] = N1[4];
414   N1new[4] = N2[3];
415   N1new[5] = N1[5];
416   N2new[0] = N1[0];
417   N2new[1] = N1[1];
418   N2new[2] = N2[0];
419   N2new[3] = N1[3];
420   N2new[4] = N2[5];
421   N2new[5] = N1[4];
422   // replaces nodes in faces
423   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
424   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
425
426   return true;
427 }
428
429 //=======================================================================
430 //function : findTriangles
431 //purpose  : find triangles sharing theNode1-theNode2 link
432 //=======================================================================
433
434 static bool findTriangles(const SMDS_MeshNode *    theNode1,
435                           const SMDS_MeshNode *    theNode2,
436                           const SMDS_MeshElement*& theTria1,
437                           const SMDS_MeshElement*& theTria2)
438 {
439   if ( !theNode1 || !theNode2 ) return false;
440
441   theTria1 = theTria2 = 0;
442
443   set< const SMDS_MeshElement* > emap;
444   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator();
445   while (it->more()) {
446     const SMDS_MeshElement* elem = it->next();
447     if ( elem->GetType() == SMDSAbs_Face && elem->NbNodes() == 3 )
448       emap.insert( elem );
449   }
450   it = theNode2->GetInverseElementIterator();
451   while (it->more()) {
452     const SMDS_MeshElement* elem = it->next();
453     if ( elem->GetType() == SMDSAbs_Face &&
454          emap.find( elem ) != emap.end() )
455       if ( theTria1 ) {
456         theTria2 = elem;
457         break;
458       }
459       else {
460         theTria1 = elem;
461       }
462   }
463   return ( theTria1 && theTria2 );
464 }
465
466 //=======================================================================
467 //function : InverseDiag
468 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
469 //           with ones built on the same 4 nodes but having other common link.
470 //           Return false if proper faces not found
471 //=======================================================================
472
473 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
474                                     const SMDS_MeshNode * theNode2)
475 {
476   MESSAGE( "::InverseDiag()" );
477
478   const SMDS_MeshElement *tr1, *tr2;
479   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
480     return false;
481
482   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
483   //if (!F1) return false;
484   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
485   //if (!F2) return false;
486   if (F1 && F2) {
487
488     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
489     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
490     //    |/ |                                    | \|
491     //  B +--+ 2                                B +--+ 2
492
493     // put nodes in array
494     // and find indices of 1,2 and of A in tr1 and of B in tr2
495     int i, iA1 = 0, i1 = 0;
496     const SMDS_MeshNode* aNodes1 [3];
497     SMDS_ElemIteratorPtr it;
498     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
499       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
500       if ( aNodes1[ i ] == theNode1 )
501         iA1 = i; // node A in tr1
502       else if ( aNodes1[ i ] != theNode2 )
503         i1 = i;  // node 1
504     }
505     int iB2 = 0, i2 = 0;
506     const SMDS_MeshNode* aNodes2 [3];
507     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
508       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
509       if ( aNodes2[ i ] == theNode2 )
510         iB2 = i; // node B in tr2
511       else if ( aNodes2[ i ] != theNode1 )
512         i2 = i;  // node 2
513     }
514     
515     // nodes 1 and 2 should not be the same
516     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
517       return false;
518
519     // tr1: A->2
520     aNodes1[ iA1 ] = aNodes2[ i2 ];
521     // tr2: B->1
522     aNodes2[ iB2 ] = aNodes1[ i1 ];
523
524     //MESSAGE( tr1 << tr2 );
525
526     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
527     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
528
529     //MESSAGE( tr1 << tr2 );
530     
531     return true;
532   }
533
534   // check case of quadratic faces
535   const SMDS_QuadraticFaceOfNodes* QF1 =
536     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
537   if(!QF1) return false;
538   const SMDS_QuadraticFaceOfNodes* QF2 =
539     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
540   if(!QF2) return false;
541   return InverseDiag(tr1,tr2);
542 }
543
544 //=======================================================================
545 //function : getQuadrangleNodes
546 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
547 //           fusion of triangles tr1 and tr2 having shared link on
548 //           theNode1 and theNode2
549 //=======================================================================
550
551 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
552                         const SMDS_MeshNode *    theNode1,
553                         const SMDS_MeshNode *    theNode2,
554                         const SMDS_MeshElement * tr1,
555                         const SMDS_MeshElement * tr2 )
556 {
557   if( tr1->NbNodes() != tr2->NbNodes() )
558     return false;
559   // find the 4-th node to insert into tr1
560   const SMDS_MeshNode* n4 = 0;
561   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
562   int i=0;
563   //while ( !n4 && it->more() ) {
564   while ( !n4 && i<3 ) {
565     const SMDS_MeshNode * n = static_cast<const SMDS_MeshNode*>( it->next() );
566     i++;
567     bool isDiag = ( n == theNode1 || n == theNode2 );
568     if ( !isDiag )
569       n4 = n;
570   }
571   // Make an array of nodes to be in a quadrangle
572   int iNode = 0, iFirstDiag = -1;
573   it = tr1->nodesIterator();
574   i=0;
575   //while ( it->more() ) {
576   while ( i<3 ) {
577     const SMDS_MeshNode * n = static_cast<const SMDS_MeshNode*>( it->next() );
578     i++;
579     bool isDiag = ( n == theNode1 || n == theNode2 );
580     if ( isDiag ) {
581       if ( iFirstDiag < 0 )
582         iFirstDiag = iNode;
583       else if ( iNode - iFirstDiag == 1 )
584         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
585     }
586     else if ( n == n4 ) {
587       return false; // tr1 and tr2 should not have all the same nodes
588     }
589     theQuadNodes[ iNode++ ] = n;
590   }
591   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
592     theQuadNodes[ iNode ] = n4;
593
594   return true;
595 }
596
597 //=======================================================================
598 //function : DeleteDiag
599 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
600 //           with a quadrangle built on the same 4 nodes.
601 //           Return false if proper faces not found
602 //=======================================================================
603
604 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
605                                    const SMDS_MeshNode * theNode2)
606 {
607   MESSAGE( "::DeleteDiag()" );
608
609   const SMDS_MeshElement *tr1, *tr2;
610   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
611     return false;
612
613   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
614   //if (!F1) return false;
615   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
616   //if (!F2) return false;
617   if (F1 && F2) {
618
619     const SMDS_MeshNode* aNodes [ 4 ];
620     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
621       return false;
622
623     //MESSAGE( endl << tr1 << tr2 );
624
625     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
626     GetMeshDS()->RemoveElement( tr2 );
627
628     //MESSAGE( endl << tr1 );
629
630     return true;
631   }
632
633   // check case of quadratic faces
634   const SMDS_QuadraticFaceOfNodes* QF1 =
635     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
636   if(!QF1) return false;
637   const SMDS_QuadraticFaceOfNodes* QF2 =
638     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
639   if(!QF2) return false;
640
641   //       5
642   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
643   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
644   //    |   / |  
645   //  7 +  +  + 6
646   //    | /9  |
647   //    |/    |
648   //  4 +--+--+ 3  
649   //       8
650   
651   const SMDS_MeshNode* N1 [6];
652   const SMDS_MeshNode* N2 [6];
653   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
654     return false;
655   // now we receive following N1 and N2 (using numeration as above image)
656   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6) 
657   // i.e. first nodes from both arrays determ new diagonal
658
659   const SMDS_MeshNode* aNodes[8];
660   aNodes[0] = N1[0];
661   aNodes[1] = N1[1];
662   aNodes[2] = N2[0];
663   aNodes[3] = N2[1];
664   aNodes[4] = N1[3];
665   aNodes[5] = N2[5];
666   aNodes[6] = N2[3];
667   aNodes[7] = N1[5];
668
669   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
670   GetMeshDS()->RemoveElement( tr2 );
671
672   // remove middle node (9)
673   GetMeshDS()->RemoveNode( N1[4] );
674
675   return true;
676 }
677
678 //=======================================================================
679 //function : Reorient
680 //purpose  : Reverse theElement orientation
681 //=======================================================================
682
683 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
684 {
685   if (!theElem)
686     return false;
687   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
688   if ( !it || !it->more() )
689     return false;
690
691   switch ( theElem->GetType() ) {
692
693   case SMDSAbs_Edge:
694   case SMDSAbs_Face: {
695     if(!theElem->IsQuadratic()) {
696       int i = theElem->NbNodes();
697       vector<const SMDS_MeshNode*> aNodes( i );
698       while ( it->more() )
699         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
700       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
701     }
702     else {
703       // quadratic elements
704       if(theElem->GetType()==SMDSAbs_Edge) {
705         vector<const SMDS_MeshNode*> aNodes(3);
706         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
707         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
708         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
709         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
710       }
711       else {
712         int nbn = theElem->NbNodes();
713         vector<const SMDS_MeshNode*> aNodes(nbn);
714         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
715         int i=1;
716         for(; i<nbn/2; i++) {
717           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
718         }
719         for(i=0; i<nbn/2; i++) {
720           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
721         }
722         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
723       }
724     }
725   }
726   case SMDSAbs_Volume: {
727     if (theElem->IsPoly()) {
728       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
729         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
730       if (!aPolyedre) {
731         MESSAGE("Warning: bad volumic element");
732         return false;
733       }
734
735       int nbFaces = aPolyedre->NbFaces();
736       vector<const SMDS_MeshNode *> poly_nodes;
737       vector<int> quantities (nbFaces);
738
739       // reverse each face of the polyedre
740       for (int iface = 1; iface <= nbFaces; iface++) {
741         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
742         quantities[iface - 1] = nbFaceNodes;
743         
744         for (inode = nbFaceNodes; inode >= 1; inode--) {
745           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
746           poly_nodes.push_back(curNode);
747         }
748       }
749       
750       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
751
752     }
753     else {
754       SMDS_VolumeTool vTool;
755       if ( !vTool.Set( theElem ))
756         return false;
757       vTool.Inverse();
758       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
759     }
760   }
761   default:;
762   }
763
764   return false;
765 }
766
767 //=======================================================================
768 //function : getBadRate
769 //purpose  :
770 //=======================================================================
771
772 static double getBadRate (const SMDS_MeshElement*               theElem,
773                           SMESH::Controls::NumericalFunctorPtr& theCrit)
774 {
775   SMESH::Controls::TSequenceOfXYZ P;
776   if ( !theElem || !theCrit->GetPoints( theElem, P ))
777     return 1e100;
778   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
779   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
780 }
781
782 //=======================================================================
783 //function : QuadToTri
784 //purpose  : Cut quadrangles into triangles.
785 //           theCrit is used to select a diagonal to cut
786 //=======================================================================
787
788 bool SMESH_MeshEditor::QuadToTri (set<const SMDS_MeshElement*> &       theElems,
789                                   SMESH::Controls::NumericalFunctorPtr theCrit)
790 {
791   MESSAGE( "::QuadToTri()" );
792
793   if ( !theCrit.get() )
794     return false;
795
796   SMESHDS_Mesh * aMesh = GetMeshDS();
797
798   set< const SMDS_MeshElement * >::iterator itElem;
799   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
800     const SMDS_MeshElement* elem = (*itElem);
801     if ( !elem || elem->GetType() != SMDSAbs_Face )
802       continue;
803
804     if(elem->NbNodes()==4) {
805
806       // retrieve element nodes
807       const SMDS_MeshNode* aNodes [4];
808       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
809       int i = 0;
810       while ( itN->more() )
811         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
812
813       // compare two sets of possible triangles
814       double aBadRate1, aBadRate2; // to what extent a set is bad
815       SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
816       SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
817       aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
818       
819       SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
820       SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
821       aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
822
823       int aShapeId = FindShape( elem );
824       //MESSAGE( "aBadRate1 = " << aBadRate1 << "; aBadRate2 = " << aBadRate2
825       //      << " ShapeID = " << aShapeId << endl << elem );
826
827       if ( aBadRate1 <= aBadRate2 ) {
828         // tr1 + tr2 is better
829         aMesh->ChangeElementNodes( elem, aNodes, 3 );
830         //MESSAGE( endl << elem );
831
832         elem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
833       }
834       else {
835         // tr3 + tr4 is better
836         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
837         //MESSAGE( endl << elem );
838         
839         elem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
840       }
841       //MESSAGE( endl << elem );
842
843       // put a new triangle on the same shape
844       if ( aShapeId )
845         aMesh->SetMeshElementOnShape( elem, aShapeId );
846     }
847
848     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
849       const SMDS_MeshNode* aNodes [8];
850       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
851       int i = 0;
852       while ( itN->more() ) {
853         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
854       }
855
856       // compare two sets of possible triangles
857       // use for comparing simple triangles (not quadratic)
858       double aBadRate1, aBadRate2; // to what extent a set is bad
859       SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
860       SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
861       aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
862
863       SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
864       SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
865       aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
866
867       int aShapeId = FindShape( elem );
868       
869       // find middle point for (0,1,2,3)
870       // and create node in this point;
871       double x=0., y=0., z=0.;
872       for(i=0; i<4; i++) {
873         x += aNodes[i]->X();
874         y += aNodes[i]->Y();
875         z += aNodes[i]->Z();
876       }
877       const SMDS_MeshNode* newN = aMesh->AddNode(x/4, y/4, z/4);
878
879       if ( aBadRate1 <= aBadRate2 ) {
880         // tr1 + tr2 is better
881         const SMDS_MeshNode* N[6];
882         N[0] = aNodes[0];
883         N[1] = aNodes[1];
884         N[2] = aNodes[2];
885         N[3] = aNodes[4];
886         N[4] = aNodes[5];
887         N[5] = newN;
888         aMesh->ChangeElementNodes( elem, N, 6 );
889         elem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
890                               aNodes[6], aNodes[7], newN );
891       }
892       else {
893         // tr3 + tr4 is better
894         const SMDS_MeshNode* N[6];
895         N[0] = aNodes[1];
896         N[1] = aNodes[2];
897         N[2] = aNodes[3];
898         N[3] = aNodes[5];
899         N[4] = aNodes[6];
900         N[5] = newN;
901         aMesh->ChangeElementNodes( elem, N, 6 );
902         elem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
903                               aNodes[7], aNodes[4], newN );
904       }
905       // put a new triangle on the same shape
906       if ( aShapeId ) {
907         aMesh->SetMeshElementOnShape( elem, aShapeId );
908       }
909     }
910
911   }
912   return true;
913 }
914
915 //=======================================================================
916 //function : BestSplit
917 //purpose  : Find better diagonal for cutting.
918 //=======================================================================
919 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
920                                  SMESH::Controls::NumericalFunctorPtr theCrit)
921 {
922   if (!theCrit.get())
923     return -1;
924
925   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
926     return -1;
927
928   if( theQuad->NbNodes()==4 ||
929       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
930
931     // retrieve element nodes
932     const SMDS_MeshNode* aNodes [4];
933     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
934     int i = 0;
935     //while (itN->more())
936     while (i<4) {
937       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
938     }
939     // compare two sets of possible triangles
940     double aBadRate1, aBadRate2; // to what extent a set is bad
941     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
942     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
943     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
944
945     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
946     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
947     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
948
949     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
950       return 1; // diagonal 1-3
951
952     return 2; // diagonal 2-4
953   }
954   return -1;
955 }
956
957
958 //=======================================================================
959 //function : AddToSameGroups
960 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
961 //=======================================================================
962
963 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
964                                         const SMDS_MeshElement* elemInGroups,
965                                         SMESHDS_Mesh *          aMesh)
966 {
967   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
968   set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
969   for ( ; grIt != groups.end(); grIt++ ) {
970     SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
971     if ( group && group->SMDSGroup().Contains( elemInGroups ))
972       group->SMDSGroup().Add( elemToAdd );
973   }
974 }
975
976 //=======================================================================
977 //function : RemoveElemFromGroups
978 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
979 //=======================================================================
980 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
981                                              SMESHDS_Mesh *          aMesh)
982 {
983   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
984   if (!groups.empty()) 
985   {
986     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
987     for (; GrIt != groups.end(); GrIt++) 
988     {
989       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
990       if (!grp || grp->IsEmpty()) continue;
991       grp->SMDSGroup().Remove(removeelem);
992     }
993   }
994 }
995 //=======================================================================
996 //function : QuadToTri
997 //purpose  : Cut quadrangles into triangles.
998 //           theCrit is used to select a diagonal to cut
999 //=======================================================================
1000
1001 bool SMESH_MeshEditor::QuadToTri (std::set<const SMDS_MeshElement*> & theElems,
1002                                   const bool                          the13Diag)
1003 {
1004   MESSAGE( "::QuadToTri()" );
1005
1006   SMESHDS_Mesh * aMesh = GetMeshDS();
1007
1008   set< const SMDS_MeshElement * >::iterator itElem;
1009   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1010     const SMDS_MeshElement* elem = (*itElem);
1011     if ( !elem || elem->GetType() != SMDSAbs_Face )
1012       continue;
1013     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1014     if(!isquad) continue;
1015
1016     if(elem->NbNodes()==4) {
1017       // retrieve element nodes
1018       const SMDS_MeshNode* aNodes [4];
1019       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1020       int i = 0;
1021       while ( itN->more() )
1022         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1023
1024       int aShapeId = FindShape( elem );
1025       const SMDS_MeshElement* newElem = 0;
1026       if ( the13Diag ) {
1027         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1028         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1029       }
1030       else {
1031         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1032         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1033       }
1034       // put a new triangle on the same shape and add to the same groups
1035       if ( aShapeId )
1036         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1037       AddToSameGroups( newElem, elem, aMesh );
1038     }
1039
1040     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1041       const SMDS_MeshNode* aNodes [8];
1042       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1043       int i = 0;
1044       while ( itN->more() ) {
1045         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1046       }
1047
1048       // find middle point for (0,1,2,3)
1049       // and create node in this point;
1050       double x=0., y=0., z=0.;
1051       for(i=0; i<4; i++) {
1052         x += aNodes[i]->X();
1053         y += aNodes[i]->Y();
1054         z += aNodes[i]->Z();
1055       }
1056       const SMDS_MeshNode* newN = aMesh->AddNode(x/4, y/4, z/4);
1057
1058       int aShapeId = FindShape( elem );
1059       const SMDS_MeshElement* newElem = 0;
1060       if ( the13Diag ) {
1061         const SMDS_MeshNode* N[6];
1062         N[0] = aNodes[0];
1063         N[1] = aNodes[1];
1064         N[2] = aNodes[2];
1065         N[3] = aNodes[4];
1066         N[4] = aNodes[5];
1067         N[5] = newN;
1068         aMesh->ChangeElementNodes( elem, N, 6 );
1069         elem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1070                               aNodes[6], aNodes[7], newN );
1071       }
1072       else {
1073         const SMDS_MeshNode* N[6];
1074         N[0] = aNodes[1];
1075         N[1] = aNodes[2];
1076         N[2] = aNodes[3];
1077         N[3] = aNodes[5];
1078         N[4] = aNodes[6];
1079         N[5] = newN;
1080         aMesh->ChangeElementNodes( elem, N, 6 );
1081         elem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1082                               aNodes[7], aNodes[4], newN );
1083       }
1084       // put a new triangle on the same shape and add to the same groups
1085       if ( aShapeId )
1086         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1087       AddToSameGroups( newElem, elem, aMesh );
1088     }
1089   }
1090
1091   return true;
1092 }
1093
1094 //=======================================================================
1095 //function : getAngle
1096 //purpose  :
1097 //=======================================================================
1098
1099 double getAngle(const SMDS_MeshElement * tr1,
1100                 const SMDS_MeshElement * tr2,
1101                 const SMDS_MeshNode *    n1,
1102                 const SMDS_MeshNode *    n2)
1103 {
1104   double angle = 2*PI; // bad angle
1105
1106   // get normals
1107   SMESH::Controls::TSequenceOfXYZ P1, P2;
1108   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1109        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1110     return angle;
1111   gp_Vec N1,N2;
1112   if(!tr1->IsQuadratic())
1113     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1114   else
1115     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1116   if ( N1.SquareMagnitude() <= gp::Resolution() )
1117     return angle;
1118   if(!tr2->IsQuadratic())
1119     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1120   else
1121     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1122   if ( N2.SquareMagnitude() <= gp::Resolution() )
1123     return angle;
1124
1125   // find the first diagonal node n1 in the triangles:
1126   // take in account a diagonal link orientation
1127   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1128   for ( int t = 0; t < 2; t++ ) {
1129     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1130     int i = 0, iDiag = -1;
1131     while ( it->more()) {
1132       const SMDS_MeshElement *n = it->next();
1133       if ( n == n1 || n == n2 )
1134         if ( iDiag < 0)
1135           iDiag = i;
1136         else {
1137           if ( i - iDiag == 1 )
1138             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1139           else
1140             nFirst[ t ] = n;
1141           break;
1142         }
1143       i++;
1144     }
1145   }
1146   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1147     N2.Reverse();
1148
1149   angle = N1.Angle( N2 );
1150   //SCRUTE( angle );
1151   return angle;
1152 }
1153
1154 // =================================================
1155 // class generating a unique ID for a pair of nodes
1156 // and able to return nodes by that ID
1157 // =================================================
1158 class LinkID_Gen {
1159  public:
1160
1161   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1162     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1163   {}
1164
1165   long GetLinkID (const SMDS_MeshNode * n1,
1166                   const SMDS_MeshNode * n2) const
1167   {
1168     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1169   }
1170
1171   bool GetNodes (const long             theLinkID,
1172                  const SMDS_MeshNode* & theNode1,
1173                  const SMDS_MeshNode* & theNode2) const
1174   {
1175     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1176     if ( !theNode1 ) return false;
1177     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1178     if ( !theNode2 ) return false;
1179     return true;
1180   }
1181
1182  private:
1183   LinkID_Gen();
1184   const SMESHDS_Mesh* myMesh;
1185   long                myMaxID;
1186 };
1187
1188
1189 //=======================================================================
1190 //function : TriToQuad
1191 //purpose  : Fuse neighbour triangles into quadrangles.
1192 //           theCrit is used to select a neighbour to fuse with.
1193 //           theMaxAngle is a max angle between element normals at which
1194 //           fusion is still performed.
1195 //=======================================================================
1196
1197 bool SMESH_MeshEditor::TriToQuad (set<const SMDS_MeshElement*> &       theElems,
1198                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1199                                   const double                         theMaxAngle)
1200 {
1201   MESSAGE( "::TriToQuad()" );
1202
1203   if ( !theCrit.get() )
1204     return false;
1205
1206   SMESHDS_Mesh * aMesh = GetMeshDS();
1207   //LinkID_Gen aLinkID_Gen( aMesh );
1208
1209   // Prepare data for algo: build
1210   // 1. map of elements with their linkIDs
1211   // 2. map of linkIDs with their elements
1212
1213   //map< long, list< const SMDS_MeshElement* > > mapLi_listEl;
1214   //map< long, list< const SMDS_MeshElement* > >::iterator itLE;
1215   //map< const SMDS_MeshElement*, set< long > >  mapEl_setLi;
1216   //map< const SMDS_MeshElement*, set< long > >::iterator itEL;
1217
1218   map< NLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1219   map< NLink, list< const SMDS_MeshElement* > >::iterator itLE;
1220   map< const SMDS_MeshElement*, set< NLink > >  mapEl_setLi;
1221   map< const SMDS_MeshElement*, set< NLink > >::iterator itEL;
1222
1223   set<const SMDS_MeshElement*>::iterator itElem;
1224   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1225     const SMDS_MeshElement* elem = (*itElem);
1226     //if ( !elem || elem->NbNodes() != 3 )
1227     //  continue;
1228     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1229     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1230     if(!IsTria) continue;
1231
1232     // retrieve element nodes
1233     const SMDS_MeshNode* aNodes [4];
1234     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1235     int i = 0;
1236     //while ( itN->more() )
1237     while ( i<3 )
1238       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1239     ASSERT( i == 3 );
1240     aNodes[ 3 ] = aNodes[ 0 ];
1241
1242     // fill maps
1243     for ( i = 0; i < 3; i++ ) {
1244       //long linkID = aLinkID_Gen.GetLinkID( aNodes[ i ], aNodes[ i+1 ] );
1245       NLink link(( aNodes[i] < aNodes[i+1] ? aNodes[i] : aNodes[i+1] ),
1246                  ( aNodes[i] < aNodes[i+1] ? aNodes[i+1] : aNodes[i] ));
1247       // check if elements sharing a link can be fused
1248       //itLE = mapLi_listEl.find( linkID );
1249       itLE = mapLi_listEl.find( link );
1250       if ( itLE != mapLi_listEl.end() ) {
1251         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1252           continue;
1253         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1254         //if ( FindShape( elem ) != FindShape( elem2 ))
1255         //  continue; // do not fuse triangles laying on different shapes
1256         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1257           continue; // avoid making badly shaped quads
1258         (*itLE).second.push_back( elem );
1259       }
1260       else {
1261         //mapLi_listEl[ linkID ].push_back( elem );
1262         mapLi_listEl[ link ].push_back( elem );
1263       }
1264       //mapEl_setLi [ elem ].insert( linkID );
1265       mapEl_setLi [ elem ].insert( link );
1266     }
1267   }
1268   // Clean the maps from the links shared by a sole element, ie
1269   // links to which only one element is bound in mapLi_listEl
1270
1271   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1272     int nbElems = (*itLE).second.size();
1273     if ( nbElems < 2  ) {
1274       const SMDS_MeshElement* elem = (*itLE).second.front();
1275       //long link = (*itLE).first;
1276       NLink link = (*itLE).first;
1277       mapEl_setLi[ elem ].erase( link );
1278       if ( mapEl_setLi[ elem ].empty() )
1279         mapEl_setLi.erase( elem );
1280     }
1281   }
1282
1283   // Algo: fuse triangles into quadrangles
1284
1285   while ( ! mapEl_setLi.empty() ) {
1286     // Look for the start element:
1287     // the element having the least nb of shared links
1288
1289     const SMDS_MeshElement* startElem = 0;
1290     int minNbLinks = 4;
1291     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1292       int nbLinks = (*itEL).second.size();
1293       if ( nbLinks < minNbLinks ) {
1294         startElem = (*itEL).first;
1295         minNbLinks = nbLinks;
1296         if ( minNbLinks == 1 )
1297           break;
1298       }
1299     }
1300
1301     // search elements to fuse starting from startElem or links of elements
1302     // fused earlyer - startLinks
1303     //list< long > startLinks;
1304     list< NLink > startLinks;
1305     while ( startElem || !startLinks.empty() ) {
1306       while ( !startElem && !startLinks.empty() ) {
1307         // Get an element to start, by a link
1308         //long linkId = startLinks.front();
1309         NLink linkId = startLinks.front();
1310         startLinks.pop_front();
1311         itLE = mapLi_listEl.find( linkId );
1312         if ( itLE != mapLi_listEl.end() ) {
1313           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1314           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1315           for ( ; itE != listElem.end() ; itE++ )
1316             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1317               startElem = (*itE);
1318           mapLi_listEl.erase( itLE );
1319         }
1320       }
1321
1322       if ( startElem ) {
1323         // Get candidates to be fused
1324         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1325         //long link12, link13;
1326         NLink link12, link13;
1327         startElem = 0;
1328         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1329         //set< long >& setLi = mapEl_setLi[ tr1 ];
1330         set< NLink >& setLi = mapEl_setLi[ tr1 ];
1331         ASSERT( !setLi.empty() );
1332         //set< long >::iterator itLi;
1333         set< NLink >::iterator itLi;
1334         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ ) {
1335           //long linkID = (*itLi);
1336           NLink linkID = (*itLi);
1337           itLE = mapLi_listEl.find( linkID );
1338           if ( itLE == mapLi_listEl.end() )
1339             continue;
1340
1341           const SMDS_MeshElement* elem = (*itLE).second.front();
1342           if ( elem == tr1 )
1343             elem = (*itLE).second.back();
1344           mapLi_listEl.erase( itLE );
1345           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1346             continue;
1347           if ( tr2 ) {
1348             tr3 = elem;
1349             link13 = linkID;
1350           }
1351           else {
1352             tr2 = elem;
1353             link12 = linkID;
1354           }
1355
1356           // add other links of elem to list of links to re-start from
1357           //set< long >& links = mapEl_setLi[ elem ];
1358           //set< long >::iterator it;
1359           set< NLink >& links = mapEl_setLi[ elem ];
1360           set< NLink >::iterator it;
1361           for ( it = links.begin(); it != links.end(); it++ ) {
1362             //long linkID2 = (*it);
1363             NLink linkID2 = (*it);
1364             if ( linkID2 != linkID )
1365               startLinks.push_back( linkID2 );
1366           }
1367         }
1368
1369         // Get nodes of possible quadrangles
1370         const SMDS_MeshNode *n12 [4], *n13 [4];
1371         bool Ok12 = false, Ok13 = false;
1372         //const SMDS_MeshNode *linkNode1, *linkNode2;
1373         const SMDS_MeshNode *linkNode1, *linkNode2;
1374         if(tr2) {
1375           //const SMDS_MeshNode *linkNode1 = link12.first;
1376           //const SMDS_MeshNode *linkNode2 = link12.second;
1377           linkNode1 = link12.first;
1378           linkNode2 = link12.second;
1379           //if ( tr2 &&
1380           //     aLinkID_Gen.GetNodes( link12, linkNode1, linkNode2 ) &&
1381           //     getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1382           //  Ok12 = true;
1383           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1384             Ok12 = true;
1385         }
1386         if(tr3) {
1387           linkNode1 = link13.first;
1388           linkNode2 = link13.second;
1389           //if ( tr3 &&
1390           //     aLinkID_Gen.GetNodes( link13, linkNode1, linkNode2 ) &&
1391           //     getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1392           //  Ok13 = true;
1393           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1394             Ok13 = true;
1395         }
1396
1397         // Choose a pair to fuse
1398         if ( Ok12 && Ok13 ) {
1399           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1400           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1401           double aBadRate12 = getBadRate( &quad12, theCrit );
1402           double aBadRate13 = getBadRate( &quad13, theCrit );
1403           if (  aBadRate13 < aBadRate12 )
1404             Ok12 = false;
1405           else
1406             Ok13 = false;
1407         }
1408
1409         // Make quadrangles
1410         // and remove fused elems and removed links from the maps
1411         mapEl_setLi.erase( tr1 );
1412         if ( Ok12 ) {
1413           mapEl_setLi.erase( tr2 );
1414           mapLi_listEl.erase( link12 );
1415           if(tr1->NbNodes()==3) {
1416             aMesh->ChangeElementNodes( tr1, n12, 4 );
1417             aMesh->RemoveElement( tr2 );
1418           }
1419           else {
1420             const SMDS_MeshNode* N1 [6];
1421             const SMDS_MeshNode* N2 [6];
1422             GetNodesFromTwoTria(tr1,tr2,N1,N2);
1423             // now we receive following N1 and N2 (using numeration as above image)
1424             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6) 
1425             // i.e. first nodes from both arrays determ new diagonal
1426             const SMDS_MeshNode* aNodes[8];
1427             aNodes[0] = N1[0];
1428             aNodes[1] = N1[1];
1429             aNodes[2] = N2[0];
1430             aNodes[3] = N2[1];
1431             aNodes[4] = N1[3];
1432             aNodes[5] = N2[5];
1433             aNodes[6] = N2[3];
1434             aNodes[7] = N1[5];
1435             GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1436             GetMeshDS()->RemoveElement( tr2 );
1437             // remove middle node (9)
1438             GetMeshDS()->RemoveNode( N1[4] );
1439           }
1440         }
1441         else if ( Ok13 ) {
1442           mapEl_setLi.erase( tr3 );
1443           mapLi_listEl.erase( link13 );
1444           if(tr1->NbNodes()==3) {
1445             aMesh->ChangeElementNodes( tr1, n13, 4 );
1446             aMesh->RemoveElement( tr3 );
1447           }
1448           else {
1449             const SMDS_MeshNode* N1 [6];
1450             const SMDS_MeshNode* N2 [6];
1451             GetNodesFromTwoTria(tr1,tr3,N1,N2);
1452             // now we receive following N1 and N2 (using numeration as above image)
1453             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6) 
1454             // i.e. first nodes from both arrays determ new diagonal
1455             const SMDS_MeshNode* aNodes[8];
1456             aNodes[0] = N1[0];
1457             aNodes[1] = N1[1];
1458             aNodes[2] = N2[0];
1459             aNodes[3] = N2[1];
1460             aNodes[4] = N1[3];
1461             aNodes[5] = N2[5];
1462             aNodes[6] = N2[3];
1463             aNodes[7] = N1[5];
1464             GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1465             GetMeshDS()->RemoveElement( tr3 );
1466             // remove middle node (9)
1467             GetMeshDS()->RemoveNode( N1[4] );
1468           }
1469         }
1470
1471         // Next element to fuse: the rejected one
1472         if ( tr3 )
1473           startElem = Ok12 ? tr3 : tr2;
1474
1475       } // if ( startElem )
1476     } // while ( startElem || !startLinks.empty() )
1477   } // while ( ! mapEl_setLi.empty() )
1478
1479   return true;
1480 }
1481
1482
1483 /*#define DUMPSO(txt) \
1484 //  cout << txt << endl;
1485 //=============================================================================
1486 //
1487 //
1488 //
1489 //=============================================================================
1490 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1491 {
1492   if ( i1 == i2 )
1493     return;
1494   int tmp = idNodes[ i1 ];
1495   idNodes[ i1 ] = idNodes[ i2 ];
1496   idNodes[ i2 ] = tmp;
1497   gp_Pnt Ptmp = P[ i1 ];
1498   P[ i1 ] = P[ i2 ];
1499   P[ i2 ] = Ptmp;
1500   DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1501 }
1502
1503 //=======================================================================
1504 //function : SortQuadNodes
1505 //purpose  : Set 4 nodes of a quadrangle face in a good order.
1506 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
1507 //           1 or 2 else 0.
1508 //=======================================================================
1509
1510 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1511                                      int               idNodes[] )
1512 {
1513   gp_Pnt P[4];
1514   int i;
1515   for ( i = 0; i < 4; i++ ) {
1516     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1517     if ( !n ) return 0;
1518     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1519   }
1520
1521   gp_Vec V1(P[0], P[1]);
1522   gp_Vec V2(P[0], P[2]);
1523   gp_Vec V3(P[0], P[3]);
1524
1525   gp_Vec Cross1 = V1 ^ V2;
1526   gp_Vec Cross2 = V2 ^ V3;
1527
1528   i = 0;
1529   if (Cross1.Dot(Cross2) < 0)
1530   {
1531     Cross1 = V2 ^ V1;
1532     Cross2 = V1 ^ V3;
1533
1534     if (Cross1.Dot(Cross2) < 0)
1535       i = 2;
1536     else
1537       i = 1;
1538     swap ( i, i + 1, idNodes, P );
1539
1540 //     for ( int ii = 0; ii < 4; ii++ ) {
1541 //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1542 //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1543 //     }
1544   }
1545   return i;
1546 }
1547
1548 //=======================================================================
1549 //function : SortHexaNodes
1550 //purpose  : Set 8 nodes of a hexahedron in a good order.
1551 //           Return success status
1552 //=======================================================================
1553
1554 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1555                                       int               idNodes[] )
1556 {
1557   gp_Pnt P[8];
1558   int i;
1559   DUMPSO( "INPUT: ========================================");
1560   for ( i = 0; i < 8; i++ ) {
1561     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1562     if ( !n ) return false;
1563     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1564     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1565   }
1566   DUMPSO( "========================================");
1567
1568
1569   set<int> faceNodes;  // ids of bottom face nodes, to be found
1570   set<int> checkedId1; // ids of tried 2-nd nodes
1571   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1572   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
1573   int iMin, iLoop1 = 0;
1574
1575   // Loop to try the 2-nd nodes
1576
1577   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1578   {
1579     // Find not checked 2-nd node
1580     for ( i = 1; i < 8; i++ )
1581       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1582         int id1 = idNodes[i];
1583         swap ( 1, i, idNodes, P );
1584         checkedId1.insert ( id1 );
1585         break;
1586       }
1587
1588     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
1589     // ie that all but meybe one (id3 which is on the same face) nodes
1590     // lay on the same side from the triangle plane.
1591
1592     bool manyInPlane = false; // more than 4 nodes lay in plane
1593     int iLoop2 = 0;
1594     while ( ++iLoop2 < 6 ) {
1595
1596       // get 1-2-3 plane coeffs
1597       Standard_Real A, B, C, D;
1598       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1599       if ( N.SquareMagnitude() > gp::Resolution() )
1600       {
1601         gp_Pln pln ( P[0], N );
1602         pln.Coefficients( A, B, C, D );
1603
1604         // find the node (iMin) closest to pln
1605         Standard_Real dist[ 8 ], minDist = DBL_MAX;
1606         set<int> idInPln;
1607         for ( i = 3; i < 8; i++ ) {
1608           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
1609           if ( fabs( dist[i] ) < minDist ) {
1610             minDist = fabs( dist[i] );
1611             iMin = i;
1612           }
1613           if ( fabs( dist[i] ) <= tol )
1614             idInPln.insert( idNodes[i] );
1615         }
1616
1617         // there should not be more than 4 nodes in bottom plane
1618         if ( idInPln.size() > 1 )
1619         {
1620           DUMPSO( "### idInPln.size() = " << idInPln.size());
1621           // idInPlane does not contain the first 3 nodes
1622           if ( manyInPlane || idInPln.size() == 5)
1623             return false; // all nodes in one plane
1624           manyInPlane = true;
1625
1626           // set the 1-st node to be not in plane
1627           for ( i = 3; i < 8; i++ ) {
1628             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
1629               DUMPSO( "### Reset 0-th node");
1630               swap( 0, i, idNodes, P );
1631               break;
1632             }
1633           }
1634
1635           // reset to re-check second nodes
1636           leastDist = DBL_MAX;
1637           faceNodes.clear();
1638           checkedId1.clear();
1639           iLoop1 = 0;
1640           break; // from iLoop2;
1641         }
1642
1643         // check that the other 4 nodes are on the same side
1644         bool sameSide = true;
1645         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
1646         for ( i = 3; sameSide && i < 8; i++ ) {
1647           if ( i != iMin )
1648             sameSide = ( isNeg == dist[i] <= 0.);
1649         }
1650
1651         // keep best solution
1652         if ( sameSide && minDist < leastDist ) {
1653           leastDist = minDist;
1654           faceNodes.clear();
1655           faceNodes.insert( idNodes[ 1 ] );
1656           faceNodes.insert( idNodes[ 2 ] );
1657           faceNodes.insert( idNodes[ iMin ] );
1658           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
1659             << " leastDist = " << leastDist);
1660           if ( leastDist <= DBL_MIN )
1661             break;
1662         }
1663       }
1664
1665       // set next 3-d node to check
1666       int iNext = 2 + iLoop2;
1667       if ( iNext < 8 ) {
1668         DUMPSO( "Try 2-nd");
1669         swap ( 2, iNext, idNodes, P );
1670       }
1671     } // while ( iLoop2 < 6 )
1672   } // iLoop1
1673
1674   if ( faceNodes.empty() ) return false;
1675
1676   // Put the faceNodes in proper places
1677   for ( i = 4; i < 8; i++ ) {
1678     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
1679       // find a place to put
1680       int iTo = 1;
1681       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
1682         iTo++;
1683       DUMPSO( "Set faceNodes");
1684       swap ( iTo, i, idNodes, P );
1685     }
1686   }
1687
1688
1689   // Set nodes of the found bottom face in good order
1690   DUMPSO( " Found bottom face: ");
1691   i = SortQuadNodes( theMesh, idNodes );
1692   if ( i ) {
1693     gp_Pnt Ptmp = P[ i ];
1694     P[ i ] = P[ i+1 ];
1695     P[ i+1 ] = Ptmp;
1696   }
1697 //   else
1698 //     for ( int ii = 0; ii < 4; ii++ ) {
1699 //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1700 //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1701 //    }
1702
1703   // Gravity center of the top and bottom faces
1704   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
1705   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
1706
1707   // Get direction from the bottom to the top face
1708   gp_Vec upDir ( aGCb, aGCt );
1709   Standard_Real upDirSize = upDir.Magnitude();
1710   if ( upDirSize <= gp::Resolution() ) return false;
1711   upDir / upDirSize;
1712
1713   // Assure that the bottom face normal points up
1714   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1715   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
1716   if ( Nb.Dot( upDir ) < 0 ) {
1717     DUMPSO( "Reverse bottom face");
1718     swap( 1, 3, idNodes, P );
1719   }
1720
1721   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
1722   Standard_Real minDist = DBL_MAX;
1723   for ( i = 4; i < 8; i++ ) {
1724     // projection of P[i] to the plane defined by P[0] and upDir
1725     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
1726     Standard_Real sqDist = P[0].SquareDistance( Pp );
1727     if ( sqDist < minDist ) {
1728       minDist = sqDist;
1729       iMin = i;
1730     }
1731   }
1732   DUMPSO( "Set 4-th");
1733   swap ( 4, iMin, idNodes, P );
1734
1735   // Set nodes of the top face in good order
1736   DUMPSO( "Sort top face");
1737   i = SortQuadNodes( theMesh, &idNodes[4] );
1738   if ( i ) {
1739     i += 4;
1740     gp_Pnt Ptmp = P[ i ];
1741     P[ i ] = P[ i+1 ];
1742     P[ i+1 ] = Ptmp;
1743   }
1744
1745   // Assure that direction of the top face normal is from the bottom face
1746   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
1747   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
1748   if ( Nt.Dot( upDir ) < 0 ) {
1749     DUMPSO( "Reverse top face");
1750     swap( 5, 7, idNodes, P );
1751   }
1752
1753 //   DUMPSO( "OUTPUT: ========================================");
1754 //   for ( i = 0; i < 8; i++ ) {
1755 //     float *p = ugrid->GetPoint(idNodes[i]);
1756 //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
1757 //   }
1758
1759   return true;
1760 }*/
1761
1762 //=======================================================================
1763 //function : laplacianSmooth
1764 //purpose  : pulls theNode toward the center of surrounding nodes directly
1765 //           connected to that node along an element edge
1766 //=======================================================================
1767
1768 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
1769                      const Handle(Geom_Surface)&          theSurface,
1770                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
1771 {
1772   // find surrounding nodes
1773
1774   set< const SMDS_MeshNode* > nodeSet;
1775   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
1776   while ( elemIt->more() )
1777   {
1778     const SMDS_MeshElement* elem = elemIt->next();
1779     if ( elem->GetType() != SMDSAbs_Face )
1780       continue;
1781
1782     for ( int i = 0; i < elem->NbNodes(); ++i ) {
1783       if ( elem->GetNode( i ) == theNode ) {
1784         // add linked nodes
1785         int iBefore = i - 1;
1786         int iAfter = i + 1;
1787         if ( elem->IsQuadratic() ) {
1788           int nbCorners = elem->NbNodes() / 2;
1789           if ( iAfter >= nbCorners )
1790             iAfter = 0; // elem->GetNode() wraps index
1791           if ( iBefore == -1 )
1792             iBefore = nbCorners - 1;
1793         }
1794         nodeSet.insert( elem->GetNode( iAfter ));
1795         nodeSet.insert( elem->GetNode( iBefore ));
1796         break;
1797       }
1798     }
1799   }
1800
1801   // compute new coodrs
1802
1803   double coord[] = { 0., 0., 0. };
1804   set< const SMDS_MeshNode* >::iterator nodeSetIt = nodeSet.begin();
1805   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
1806     const SMDS_MeshNode* node = (*nodeSetIt);
1807     if ( theSurface.IsNull() ) { // smooth in 3D
1808       coord[0] += node->X();
1809       coord[1] += node->Y();
1810       coord[2] += node->Z();
1811     }
1812     else { // smooth in 2D
1813       ASSERT( theUVMap.find( node ) != theUVMap.end() );
1814       gp_XY* uv = theUVMap[ node ];
1815       coord[0] += uv->X();
1816       coord[1] += uv->Y();
1817     }
1818   }
1819   int nbNodes = nodeSet.size();
1820   if ( !nbNodes )
1821     return;
1822   coord[0] /= nbNodes;
1823   coord[1] /= nbNodes;
1824
1825   if ( !theSurface.IsNull() ) {
1826     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
1827     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
1828     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
1829     coord[0] = p3d.X();
1830     coord[1] = p3d.Y();
1831     coord[2] = p3d.Z();
1832   }
1833   else
1834     coord[2] /= nbNodes;
1835
1836   // move node
1837
1838   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
1839 }
1840
1841 //=======================================================================
1842 //function : centroidalSmooth
1843 //purpose  : pulls theNode toward the element-area-weighted centroid of the
1844 //           surrounding elements
1845 //=======================================================================
1846
1847 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
1848                       const Handle(Geom_Surface)&          theSurface,
1849                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
1850 {
1851   gp_XYZ aNewXYZ(0.,0.,0.);
1852   SMESH::Controls::Area anAreaFunc;
1853   double totalArea = 0.;
1854   int nbElems = 0;
1855
1856   // compute new XYZ
1857
1858   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
1859   while ( elemIt->more() )
1860   {
1861     const SMDS_MeshElement* elem = elemIt->next();
1862     if ( elem->GetType() != SMDSAbs_Face )
1863       continue;
1864     nbElems++;
1865
1866     gp_XYZ elemCenter(0.,0.,0.);
1867     SMESH::Controls::TSequenceOfXYZ aNodePoints;
1868     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1869     int nn = elem->NbNodes();
1870     if(elem->IsQuadratic()) nn = nn/2;
1871     int i=0;
1872     //while ( itN->more() ) {
1873     while ( i<nn ) {
1874       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
1875       i++;
1876       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
1877       aNodePoints.push_back( aP );
1878       if ( !theSurface.IsNull() ) { // smooth in 2D
1879         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
1880         gp_XY* uv = theUVMap[ aNode ];
1881         aP.SetCoord( uv->X(), uv->Y(), 0. );
1882       }
1883       elemCenter += aP;
1884     }
1885     double elemArea = anAreaFunc.GetValue( aNodePoints );
1886     totalArea += elemArea;
1887     elemCenter /= nn;
1888     aNewXYZ += elemCenter * elemArea;
1889   }
1890   aNewXYZ /= totalArea;
1891   if ( !theSurface.IsNull() ) {
1892     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
1893     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
1894   }
1895
1896   // move node
1897
1898   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
1899 }
1900
1901 //=======================================================================
1902 //function : getClosestUV
1903 //purpose  : return UV of closest projection
1904 //=======================================================================
1905
1906 static bool getClosestUV (Extrema_GenExtPS& projector,
1907                           const gp_Pnt&     point,
1908                           gp_XY &           result)
1909 {
1910   projector.Perform( point );
1911   if ( projector.IsDone() ) {
1912     double u, v, minVal = DBL_MAX;
1913     for ( int i = projector.NbExt(); i > 0; i-- )
1914       if ( projector.Value( i ) < minVal ) {
1915         minVal = projector.Value( i );
1916         projector.Point( i ).Parameter( u, v );
1917       }
1918     result.SetCoord( u, v );
1919     return true;
1920   }
1921   return false;
1922 }
1923
1924 //=======================================================================
1925 //function : Smooth
1926 //purpose  : Smooth theElements during theNbIterations or until a worst
1927 //           element has aspect ratio <= theTgtAspectRatio.
1928 //           Aspect Ratio varies in range [1.0, inf].
1929 //           If theElements is empty, the whole mesh is smoothed.
1930 //           theFixedNodes contains additionally fixed nodes. Nodes built
1931 //           on edges and boundary nodes are always fixed.
1932 //=======================================================================
1933
1934 void SMESH_MeshEditor::Smooth (set<const SMDS_MeshElement*> & theElems,
1935                                set<const SMDS_MeshNode*> &    theFixedNodes,
1936                                const SmoothMethod             theSmoothMethod,
1937                                const int                      theNbIterations,
1938                                double                         theTgtAspectRatio,
1939                                const bool                     the2D)
1940 {
1941   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
1942
1943   if ( theTgtAspectRatio < 1.0 )
1944     theTgtAspectRatio = 1.0;
1945
1946   const double disttol = 1.e-16;
1947
1948   SMESH::Controls::AspectRatio aQualityFunc;
1949
1950   SMESHDS_Mesh* aMesh = GetMeshDS();
1951
1952   if ( theElems.empty() ) {
1953     // add all faces to theElems
1954     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
1955     while ( fIt->more() )
1956       theElems.insert( fIt->next() );
1957   }
1958   // get all face ids theElems are on
1959   set< int > faceIdSet;
1960   set< const SMDS_MeshElement* >::iterator itElem;
1961   if ( the2D )
1962     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1963       int fId = FindShape( *itElem );
1964       // check that corresponding submesh exists and a shape is face
1965       if (fId &&
1966           faceIdSet.find( fId ) == faceIdSet.end() &&
1967           aMesh->MeshElements( fId )) {
1968         TopoDS_Shape F = aMesh->IndexToShape( fId );
1969         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
1970           faceIdSet.insert( fId );
1971       }
1972     }
1973   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
1974
1975   // ===============================================
1976   // smooth elements on each TopoDS_Face separately
1977   // ===============================================
1978
1979   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
1980   for ( ; fId != faceIdSet.rend(); ++fId ) {
1981     // get face surface and submesh
1982     Handle(Geom_Surface) surface;
1983     SMESHDS_SubMesh* faceSubMesh = 0;
1984     TopoDS_Face face;
1985     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
1986     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
1987     bool isUPeriodic = false, isVPeriodic = false;
1988     if ( *fId ) {
1989       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
1990       surface = BRep_Tool::Surface( face );
1991       faceSubMesh = aMesh->MeshElements( *fId );
1992       fToler2 = BRep_Tool::Tolerance( face );
1993       fToler2 *= fToler2 * 10.;
1994       isUPeriodic = surface->IsUPeriodic();
1995       if ( isUPeriodic )
1996         vPeriod = surface->UPeriod();
1997       isVPeriodic = surface->IsVPeriodic();
1998       if ( isVPeriodic )
1999         uPeriod = surface->VPeriod();
2000       surface->Bounds( u1, u2, v1, v2 );
2001     }
2002     // ---------------------------------------------------------
2003     // for elements on a face, find movable and fixed nodes and
2004     // compute UV for them
2005     // ---------------------------------------------------------
2006     bool checkBoundaryNodes = false;
2007     bool isQuadratic = false;
2008     set<const SMDS_MeshNode*> setMovableNodes;
2009     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2010     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2011     list< const SMDS_MeshElement* > elemsOnFace;
2012
2013     Extrema_GenExtPS projector;
2014     GeomAdaptor_Surface surfAdaptor;
2015     if ( !surface.IsNull() ) {
2016       surfAdaptor.Load( surface );
2017       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2018     }
2019     int nbElemOnFace = 0;
2020     itElem = theElems.begin();
2021      // loop on not yet smoothed elements: look for elems on a face
2022     while ( itElem != theElems.end() ) {
2023       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2024         break; // all elements found
2025
2026       const SMDS_MeshElement* elem = (*itElem);
2027       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2028           ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2029         ++itElem;
2030         continue;
2031       }
2032       elemsOnFace.push_back( elem );
2033       theElems.erase( itElem++ );
2034       nbElemOnFace++;
2035
2036       if ( !isQuadratic )
2037         isQuadratic = elem->IsQuadratic();
2038
2039       // get movable nodes of elem
2040       const SMDS_MeshNode* node;
2041       SMDS_TypeOfPosition posType;
2042       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2043       int nn = 0, nbn =  elem->NbNodes();
2044       if(elem->IsQuadratic())
2045         nbn = nbn/2;
2046       while ( nn++ < nbn ) {
2047         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2048         const SMDS_PositionPtr& pos = node->GetPosition();
2049         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2050         if (posType != SMDS_TOP_EDGE &&
2051             posType != SMDS_TOP_VERTEX &&
2052             theFixedNodes.find( node ) == theFixedNodes.end())
2053         {
2054           // check if all faces around the node are on faceSubMesh
2055           // because a node on edge may be bound to face
2056           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
2057           bool all = true;
2058           if ( faceSubMesh ) {
2059             while ( eIt->more() && all ) {
2060               const SMDS_MeshElement* e = eIt->next();
2061               if ( e->GetType() == SMDSAbs_Face )
2062                 all = faceSubMesh->Contains( e );
2063             }
2064           }
2065           if ( all )
2066             setMovableNodes.insert( node );
2067           else
2068             checkBoundaryNodes = true;
2069         }
2070         if ( posType == SMDS_TOP_3DSPACE )
2071           checkBoundaryNodes = true;
2072       }
2073
2074       if ( surface.IsNull() )
2075         continue;
2076
2077       // get nodes to check UV
2078       list< const SMDS_MeshNode* > uvCheckNodes;
2079       itN = elem->nodesIterator();
2080       nn = 0; nbn =  elem->NbNodes();
2081       if(elem->IsQuadratic())
2082         nbn = nbn/2;
2083       while ( nn++ < nbn ) {
2084         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2085         if ( uvMap.find( node ) == uvMap.end() )
2086           uvCheckNodes.push_back( node );
2087         // add nodes of elems sharing node
2088 //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
2089 //         while ( eIt->more() ) {
2090 //           const SMDS_MeshElement* e = eIt->next();
2091 //           if ( e != elem && e->GetType() == SMDSAbs_Face ) {
2092 //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2093 //             while ( nIt->more() ) {
2094 //               const SMDS_MeshNode* n =
2095 //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2096 //               if ( uvMap.find( n ) == uvMap.end() )
2097 //                 uvCheckNodes.push_back( n );
2098 //             }
2099 //           }
2100 //         }
2101       }
2102       // check UV on face
2103       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2104       for ( ; n != uvCheckNodes.end(); ++n ) {
2105         node = *n;
2106         gp_XY uv( 0, 0 );
2107         const SMDS_PositionPtr& pos = node->GetPosition();
2108         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2109         // get existing UV
2110         switch ( posType ) {
2111         case SMDS_TOP_FACE: {
2112           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2113           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2114           break;
2115         }
2116         case SMDS_TOP_EDGE: {
2117           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2118           Handle(Geom2d_Curve) pcurve;
2119           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2120             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2121           if ( !pcurve.IsNull() ) {
2122             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2123             uv = pcurve->Value( u ).XY();
2124           }
2125           break;
2126         }
2127         case SMDS_TOP_VERTEX: {
2128           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2129           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2130             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2131           break;
2132         }
2133         default:;
2134         }
2135         // check existing UV
2136         bool project = true;
2137         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2138         double dist1 = DBL_MAX, dist2 = 0;
2139         if ( posType != SMDS_TOP_3DSPACE ) {
2140           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2141           project = dist1 > fToler2;
2142         }
2143         if ( project ) { // compute new UV
2144           gp_XY newUV;
2145           if ( !getClosestUV( projector, pNode, newUV )) {
2146             MESSAGE("Node Projection Failed " << node);
2147           }
2148           else {
2149             if ( isUPeriodic )
2150               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2151             if ( isVPeriodic )
2152               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2153             // check new UV
2154             if ( posType != SMDS_TOP_3DSPACE )
2155               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2156             if ( dist2 < dist1 )
2157               uv = newUV;
2158           }
2159         }
2160         // store UV in the map
2161         listUV.push_back( uv );
2162         uvMap.insert( make_pair( node, &listUV.back() ));
2163       }
2164     } // loop on not yet smoothed elements
2165
2166     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2167       checkBoundaryNodes = true;
2168
2169     // fix nodes on mesh boundary
2170
2171     if ( checkBoundaryNodes ) {
2172       typedef pair<const SMDS_MeshNode*, const SMDS_MeshNode*> TLink;
2173       map< TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2174       map< TLink, int >::iterator link_nb;
2175       // put all elements links to linkNbMap
2176       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2177       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2178         const SMDS_MeshElement* elem = (*elemIt);
2179         int nbn =  elem->NbNodes();
2180         if(elem->IsQuadratic())
2181           nbn = nbn/2;
2182         // loop on elem links: insert them in linkNbMap
2183         const SMDS_MeshNode* curNode, *prevNode = elem->GetNode( nbn );
2184         for ( int iN = 0; iN < nbn; ++iN ) {
2185           curNode = elem->GetNode( iN );
2186           TLink link;
2187           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2188           else                      link = make_pair( prevNode , curNode );
2189           prevNode = curNode;
2190           link_nb = linkNbMap.find( link );
2191           if ( link_nb == linkNbMap.end() )
2192             linkNbMap.insert( make_pair ( link, 1 ));
2193           else
2194             link_nb->second++;
2195         }
2196       }
2197       // remove nodes that are in links encountered only once from setMovableNodes
2198       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2199         if ( link_nb->second == 1 ) {
2200           setMovableNodes.erase( link_nb->first.first );
2201           setMovableNodes.erase( link_nb->first.second );
2202         }
2203       }
2204     }
2205
2206     // -----------------------------------------------------
2207     // for nodes on seam edge, compute one more UV ( uvMap2 );
2208     // find movable nodes linked to nodes on seam and which
2209     // are to be smoothed using the second UV ( uvMap2 )
2210     // -----------------------------------------------------
2211
2212     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2213     if ( !surface.IsNull() ) {
2214       TopExp_Explorer eExp( face, TopAbs_EDGE );
2215       for ( ; eExp.More(); eExp.Next() ) {
2216         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2217         if ( !BRep_Tool::IsClosed( edge, face ))
2218           continue;
2219         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2220         if ( !sm ) continue;
2221         // find out which parameter varies for a node on seam
2222         double f,l;
2223         gp_Pnt2d uv1, uv2;
2224         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2225         if ( pcurve.IsNull() ) continue;
2226         uv1 = pcurve->Value( f );
2227         edge.Reverse();
2228         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2229         if ( pcurve.IsNull() ) continue;
2230         uv2 = pcurve->Value( f );
2231         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2232         // assure uv1 < uv2
2233         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2234           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2235         }
2236         // get nodes on seam and its vertices
2237         list< const SMDS_MeshNode* > seamNodes;
2238         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2239         while ( nSeamIt->more() ) {
2240           const SMDS_MeshNode* node = nSeamIt->next();
2241           if ( !isQuadratic || !IsMedium( node ))
2242             seamNodes.push_back( node );
2243         }
2244         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2245         for ( ; vExp.More(); vExp.Next() ) {
2246           sm = aMesh->MeshElements( vExp.Current() );
2247           if ( sm ) {
2248             nSeamIt = sm->GetNodes();
2249             while ( nSeamIt->more() )
2250               seamNodes.push_back( nSeamIt->next() );
2251           }
2252         }
2253         // loop on nodes on seam
2254         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2255         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2256           const SMDS_MeshNode* nSeam = *noSeIt;
2257           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2258           if ( n_uv == uvMap.end() )
2259             continue;
2260           // set the first UV
2261           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2262           // set the second UV
2263           listUV.push_back( *n_uv->second );
2264           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2265           if ( uvMap2.empty() )
2266             uvMap2 = uvMap; // copy the uvMap contents
2267           uvMap2[ nSeam ] = &listUV.back();
2268
2269           // collect movable nodes linked to ones on seam in nodesNearSeam
2270           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator();
2271           while ( eIt->more() ) {
2272             const SMDS_MeshElement* e = eIt->next();
2273             if ( e->GetType() != SMDSAbs_Face )
2274               continue;
2275             int nbUseMap1 = 0, nbUseMap2 = 0;
2276             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2277             int nn = 0, nbn =  e->NbNodes();
2278             if(e->IsQuadratic()) nbn = nbn/2;
2279             while ( nn++ < nbn )
2280             {
2281               const SMDS_MeshNode* n =
2282                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2283               if (n == nSeam ||
2284                   setMovableNodes.find( n ) == setMovableNodes.end() )
2285                 continue;
2286               // add only nodes being closer to uv2 than to uv1
2287               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2288                            0.5 * ( n->Y() + nSeam->Y() ),
2289                            0.5 * ( n->Z() + nSeam->Z() ));
2290               gp_XY uv;
2291               getClosestUV( projector, pMid, uv );
2292               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2293                 nodesNearSeam.insert( n );
2294                 nbUseMap2++;
2295               }
2296               else
2297                 nbUseMap1++;
2298             }
2299             // for centroidalSmooth all element nodes must
2300             // be on one side of a seam
2301             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2302               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2303               nn = 0;
2304               while ( nn++ < nbn ) {
2305                 const SMDS_MeshNode* n =
2306                   static_cast<const SMDS_MeshNode*>( nIt->next() );
2307                 setMovableNodes.erase( n );
2308               }
2309             }
2310           }
2311         } // loop on nodes on seam
2312       } // loop on edge of a face
2313     } // if ( !face.IsNull() )
2314
2315     if ( setMovableNodes.empty() ) {
2316       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2317       continue; // goto next face
2318     }
2319
2320     // -------------
2321     // SMOOTHING //
2322     // -------------
2323
2324     int it = -1;
2325     double maxRatio = -1., maxDisplacement = -1.;
2326     set<const SMDS_MeshNode*>::iterator nodeToMove;
2327     for ( it = 0; it < theNbIterations; it++ ) {
2328       maxDisplacement = 0.;
2329       nodeToMove = setMovableNodes.begin();
2330       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2331         const SMDS_MeshNode* node = (*nodeToMove);
2332         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2333
2334         // smooth
2335         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2336         if ( theSmoothMethod == LAPLACIAN )
2337           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2338         else
2339           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2340
2341         // node displacement
2342         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2343         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2344         if ( aDispl > maxDisplacement )
2345           maxDisplacement = aDispl;
2346       }
2347       // no node movement => exit
2348       //if ( maxDisplacement < 1.e-16 ) {
2349       if ( maxDisplacement < disttol ) {
2350         MESSAGE("-- no node movement --");
2351         break;
2352       }
2353
2354       // check elements quality
2355       maxRatio  = 0;
2356       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2357       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2358         const SMDS_MeshElement* elem = (*elemIt);
2359         if ( !elem || elem->GetType() != SMDSAbs_Face )
2360           continue;
2361         SMESH::Controls::TSequenceOfXYZ aPoints;
2362         if ( aQualityFunc.GetPoints( elem, aPoints )) {
2363           double aValue = aQualityFunc.GetValue( aPoints );
2364           if ( aValue > maxRatio )
2365             maxRatio = aValue;
2366         }
2367       }
2368       if ( maxRatio <= theTgtAspectRatio ) {
2369         MESSAGE("-- quality achived --");
2370         break;
2371       }
2372       if (it+1 == theNbIterations) {
2373         MESSAGE("-- Iteration limit exceeded --");
2374       }
2375     } // smoothing iterations
2376
2377     MESSAGE(" Face id: " << *fId <<
2378             " Nb iterstions: " << it <<
2379             " Displacement: " << maxDisplacement <<
2380             " Aspect Ratio " << maxRatio);
2381
2382     // ---------------------------------------
2383     // new nodes positions are computed,
2384     // record movement in DS and set new UV
2385     // ---------------------------------------
2386     nodeToMove = setMovableNodes.begin();
2387     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2388       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2389       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2390       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2391       if ( node_uv != uvMap.end() ) {
2392         gp_XY* uv = node_uv->second;
2393         node->SetPosition
2394           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2395       }
2396     }
2397
2398     // move medium nodes of quadratic elements
2399     if ( isQuadratic )
2400     {
2401       SMESH_MesherHelper helper( *GetMesh() );
2402       if ( !face.IsNull() )
2403         helper.SetSubShape( face );
2404       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2405       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2406         const SMDS_QuadraticFaceOfNodes* QF =
2407           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2408         if(QF) {
2409           vector<const SMDS_MeshNode*> Ns;
2410           Ns.reserve(QF->NbNodes()+1);
2411           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2412           while ( anIter->more() )
2413             Ns.push_back( anIter->next() );
2414           Ns.push_back( Ns[0] );
2415           double x, y, z;
2416           for ( int i=0; i<QF->NbNodes(); i=i+2 ) {
2417             if ( !surface.IsNull() ) {
2418               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2419               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2420               gp_XY uv = ( uv1 + uv2 ) / 2.;
2421               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2422               x = xyz.X(); y = xyz.Y(); z = xyz.Z(); 
2423             }
2424             else {
2425               x = (Ns[i]->X() + Ns[i+2]->X())/2;
2426               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2427               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2428             }
2429             if( fabs( Ns[i+1]->X() - x ) > disttol ||
2430                 fabs( Ns[i+1]->Y() - y ) > disttol ||
2431                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2432               // we have to move i+1 node
2433               aMesh->MoveNode( Ns[i+1], x, y, z );
2434             }
2435           }
2436         }
2437       }
2438     }
2439     
2440   } // loop on face ids
2441
2442 }
2443
2444 //=======================================================================
2445 //function : isReverse
2446 //purpose  : Return true if normal of prevNodes is not co-directied with
2447 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2448 //           iNotSame is where prevNodes and nextNodes are different
2449 //=======================================================================
2450
2451 static bool isReverse(const SMDS_MeshNode* prevNodes[],
2452                       const SMDS_MeshNode* nextNodes[],
2453                       const int            nbNodes,
2454                       const int            iNotSame)
2455 {
2456   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2457   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2458
2459   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2460   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2461   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2462   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2463
2464   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2465   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2466   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2467   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2468
2469   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2470
2471   return (vA ^ vB) * vN < 0.0;
2472 }
2473
2474 //=======================================================================
2475 //function : sweepElement
2476 //purpose  :
2477 //=======================================================================
2478
2479 static void sweepElement(SMESHDS_Mesh*                         aMesh,
2480                          const SMDS_MeshElement*               elem,
2481                          const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2482                          list<const SMDS_MeshElement*>&        newElems,
2483                          const int nbSteps)
2484 {
2485   // Loop on elem nodes:
2486   // find new nodes and detect same nodes indices
2487   int nbNodes = elem->NbNodes();
2488   list<const SMDS_MeshNode*>::const_iterator itNN[ nbNodes ];
2489   const SMDS_MeshNode* prevNod[ nbNodes ], *nextNod[ nbNodes ], *midlNod[ nbNodes ];
2490   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2491   vector<int> sames(nbNodes);
2492
2493   bool issimple[nbNodes];
2494
2495   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2496     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2497     const SMDS_MeshNode*                 node         = nnIt->first;
2498     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2499     if ( listNewNodes.empty() )
2500       return;
2501
2502     if(listNewNodes.size()==nbSteps) {
2503       issimple[iNode] = true;
2504     }
2505     else {
2506       issimple[iNode] = false;
2507     }
2508
2509     itNN[ iNode ] = listNewNodes.begin();
2510     prevNod[ iNode ] = node;
2511     nextNod[ iNode ] = listNewNodes.front();
2512 //cout<<"iNode="<<iNode<<endl;
2513 //cout<<" prevNod[iNode]="<< prevNod[iNode]<<" nextNod[iNode]="<< nextNod[iNode]<<endl;
2514     if ( prevNod[ iNode ] != nextNod [ iNode ])
2515       iNotSameNode = iNode;
2516     else {
2517       iSameNode = iNode;
2518       //nbSame++;
2519       sames[nbSame++] = iNode;
2520     }
2521   }
2522 //cout<<"1 nbSame="<<nbSame<<endl;
2523   if ( nbSame == nbNodes || nbSame > 2) {
2524     MESSAGE( " Too many same nodes of element " << elem->GetID() );
2525     return;
2526   }
2527
2528 //  if( elem->IsQuadratic() && nbSame>0 ) {
2529 //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2530 //    return;
2531 //  }
2532
2533   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2534   if ( nbSame > 0 ) {
2535     iBeforeSame = ( iSameNode == 0 ? nbNodes - 1 : iSameNode - 1 );
2536     iAfterSame  = ( iSameNode + 1 == nbNodes ? 0 : iSameNode + 1 );
2537     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
2538   }
2539
2540 //if(nbNodes==8)
2541 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2542 //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2543 //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2544 //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2545
2546   // check element orientation
2547   int i0 = 0, i2 = 2;
2548   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2549     //MESSAGE("Reversed elem " << elem );
2550     i0 = 2;
2551     i2 = 0;
2552     if ( nbSame > 0 ) {
2553       int iAB = iAfterSame + iBeforeSame;
2554       iBeforeSame = iAB - iBeforeSame;
2555       iAfterSame  = iAB - iAfterSame;
2556     }
2557   }
2558
2559   // make new elements
2560   int iStep;//, nbSteps = newNodesItVec[ 0 ]->second.size();
2561   for (iStep = 0; iStep < nbSteps; iStep++ ) {
2562     // get next nodes
2563     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2564       if(issimple[iNode]) {
2565         nextNod[ iNode ] = *itNN[ iNode ];
2566         itNN[ iNode ]++;
2567       }
2568       else {
2569         if( elem->GetType()==SMDSAbs_Node ) {
2570           // we have to use two nodes
2571           midlNod[ iNode ] = *itNN[ iNode ];
2572           itNN[ iNode ]++;
2573           nextNod[ iNode ] = *itNN[ iNode ];
2574           itNN[ iNode ]++;
2575         }
2576         else if(!elem->IsQuadratic() ||
2577            elem->IsQuadratic() && elem->IsMediumNode(prevNod[iNode]) ) {
2578           // we have to use each second node
2579           itNN[ iNode ]++;
2580           nextNod[ iNode ] = *itNN[ iNode ];
2581           itNN[ iNode ]++;
2582         }
2583         else {
2584           // we have to use two nodes
2585           midlNod[ iNode ] = *itNN[ iNode ];
2586           itNN[ iNode ]++;
2587           nextNod[ iNode ] = *itNN[ iNode ];
2588           itNN[ iNode ]++;
2589         }
2590       }
2591     }
2592     SMDS_MeshElement* aNewElem = 0;
2593     if(!elem->IsPoly()) {
2594       switch ( nbNodes ) {
2595       case 0:
2596         return;
2597       case 1: { // NODE
2598         if ( nbSame == 0 ) {
2599           if(issimple[0])
2600             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2601           else
2602             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2603         }
2604         break;
2605       }
2606       case 2: { // EDGE
2607         if ( nbSame == 0 )
2608           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2609                                     nextNod[ 1 ], nextNod[ 0 ] );
2610         else
2611           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2612                                     nextNod[ iNotSameNode ] );
2613         break;
2614       }
2615
2616       case 3: { // TRIANGLE or quadratic edge
2617         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2618
2619           if ( nbSame == 0 )       // --- pentahedron
2620             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2621                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2622
2623           else if ( nbSame == 1 )  // --- pyramid
2624             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
2625                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2626                                          nextNod[ iSameNode ]);
2627
2628           else // 2 same nodes:      --- tetrahedron
2629             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2630                                          nextNod[ iNotSameNode ]);
2631         }
2632         else { // quadratic edge
2633           if(nbSame==0) {     // quadratic quadrangle
2634             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2635                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2636           }
2637           else if(nbSame==1) { // quadratic triangle
2638             if(sames[0]==2)
2639               return; // medium node on axis
2640             else if(sames[0]==0) {
2641               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2642                                         nextNod[2], midlNod[1], prevNod[2]);
2643             }
2644             else { // sames[0]==1
2645               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2646                                         midlNod[0], nextNod[2], prevNod[2]);
2647             }
2648           }
2649           else
2650             return;
2651         }
2652         break;
2653       }
2654       case 4: { // QUADRANGLE
2655
2656         if ( nbSame == 0 )       // --- hexahedron
2657           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2658                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2659         
2660         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2661           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
2662                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2663                                        nextNod[ iSameNode ]);
2664           newElems.push_back( aNewElem );
2665           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2666                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
2667                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
2668         }
2669         else if ( nbSame == 2 ) { // pentahedron
2670           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2671             // iBeforeSame is same too
2672             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2673                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
2674                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
2675           else
2676             // iAfterSame is same too
2677             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2678                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2679                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
2680         }
2681         break;
2682       }
2683       case 6: { // quadratic triangle
2684         // create pentahedron with 15 nodes
2685         if(i0>0) { // reversed case
2686           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2687                                        nextNod[0], nextNod[2], nextNod[1],
2688                                        prevNod[5], prevNod[4], prevNod[3],
2689                                        nextNod[5], nextNod[4], nextNod[3],
2690                                        midlNod[0], midlNod[2], midlNod[1]);
2691         }
2692         else { // not reversed case
2693           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2694                                        nextNod[0], nextNod[1], nextNod[2],
2695                                        prevNod[3], prevNod[4], prevNod[5],
2696                                        nextNod[3], nextNod[4], nextNod[5],
2697                                        midlNod[0], midlNod[1], midlNod[2]);
2698         }
2699         break;
2700       }
2701       case 8: { // quadratic quadrangle
2702         // create hexahedron with 20 nodes
2703         if(i0>0) { // reversed case
2704           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
2705                                        nextNod[0], nextNod[3], nextNod[2], nextNod[1],
2706                                        prevNod[7], prevNod[6], prevNod[5], prevNod[4],
2707                                        nextNod[7], nextNod[6], nextNod[5], nextNod[4],
2708                                        midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
2709         }
2710         else { // not reversed case
2711           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
2712                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
2713                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
2714                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
2715                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
2716         }
2717         break;
2718       }
2719       default: {
2720         // realized for extrusion only
2721         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
2722         //vector<int> quantities (nbNodes + 2);
2723         
2724         //quantities[0] = nbNodes; // bottom of prism
2725         //for (int inode = 0; inode < nbNodes; inode++) {
2726         //  polyedre_nodes[inode] = prevNod[inode];
2727         //}
2728
2729         //quantities[1] = nbNodes; // top of prism
2730         //for (int inode = 0; inode < nbNodes; inode++) {
2731         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
2732         //}
2733         
2734         //for (int iface = 0; iface < nbNodes; iface++) {
2735         //  quantities[iface + 2] = 4;
2736         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
2737         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
2738         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
2739         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
2740         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
2741         //}
2742         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
2743         break;
2744       }
2745       }
2746     }
2747
2748     if(!aNewElem) {
2749       // realized for extrusion only
2750       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
2751       vector<int> quantities (nbNodes + 2);
2752
2753       quantities[0] = nbNodes; // bottom of prism
2754       for (int inode = 0; inode < nbNodes; inode++) {
2755         polyedre_nodes[inode] = prevNod[inode];
2756       }
2757
2758       quantities[1] = nbNodes; // top of prism
2759       for (int inode = 0; inode < nbNodes; inode++) {
2760         polyedre_nodes[nbNodes + inode] = nextNod[inode];
2761       }
2762
2763       for (int iface = 0; iface < nbNodes; iface++) {
2764         quantities[iface + 2] = 4;
2765         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
2766         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
2767         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
2768         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
2769         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
2770       }
2771       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
2772     }
2773
2774     if ( aNewElem ) {
2775       newElems.push_back( aNewElem );
2776     }
2777
2778     // set new prev nodes
2779     for ( iNode = 0; iNode < nbNodes; iNode++ )
2780       prevNod[ iNode ] = nextNod[ iNode ];
2781
2782   } // for steps
2783 }
2784
2785 //=======================================================================
2786 //function : makeWalls
2787 //purpose  : create 1D and 2D elements around swept elements
2788 //=======================================================================
2789
2790 static void makeWalls (SMESHDS_Mesh*                 aMesh,
2791                        TNodeOfNodeListMap &          mapNewNodes,
2792                        TElemOfElemListMap &          newElemsMap,
2793                        TElemOfVecOfNnlmiMap &        elemNewNodesMap,
2794                        set<const SMDS_MeshElement*>& elemSet,
2795                        const int nbSteps)
2796 {
2797   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
2798
2799   // Find nodes belonging to only one initial element - sweep them to get edges.
2800
2801   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
2802   for ( ; nList != mapNewNodes.end(); nList++ ) {
2803     const SMDS_MeshNode* node =
2804       static_cast<const SMDS_MeshNode*>( nList->first );
2805     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
2806     int nbInitElems = 0;
2807     const SMDS_MeshElement* el;
2808     while ( eIt->more() && nbInitElems < 2 ) {
2809       el = eIt->next();
2810       //if ( elemSet.find( eIt->next() ) != elemSet.end() )
2811       if ( elemSet.find(el) != elemSet.end() )
2812         nbInitElems++;
2813     }
2814     if ( nbInitElems < 2 ) {
2815       bool NotCreateEdge = el->IsQuadratic() && el->IsMediumNode(node);
2816       if(!NotCreateEdge) {
2817         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
2818         list<const SMDS_MeshElement*> newEdges;
2819         sweepElement( aMesh, node, newNodesItVec, newEdges, nbSteps );
2820       }
2821     }
2822   }
2823
2824   // Make a ceiling for each element ie an equal element of last new nodes.
2825   // Find free links of faces - make edges and sweep them into faces.
2826
2827   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
2828   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
2829   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
2830     const SMDS_MeshElement* elem = itElem->first;
2831     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
2832
2833     if ( elem->GetType() == SMDSAbs_Edge ) {
2834       if(!elem->IsQuadratic()) {
2835         // create a ceiling edge
2836         aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
2837                        vecNewNodes[ 1 ]->second.back() );
2838       }
2839       else {
2840         // create a ceiling edge
2841         aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
2842                        vecNewNodes[ 1 ]->second.back(),
2843                        vecNewNodes[ 2 ]->second.back());
2844       }
2845     }
2846     if ( elem->GetType() != SMDSAbs_Face )
2847       continue;
2848
2849     bool hasFreeLinks = false;
2850
2851     set<const SMDS_MeshElement*> avoidSet;
2852     avoidSet.insert( elem );
2853
2854     set<const SMDS_MeshNode*> aFaceLastNodes;
2855     int iNode, nbNodes = vecNewNodes.size();
2856     if(!elem->IsQuadratic()) {
2857       // loop on a face nodes
2858       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2859         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
2860         // look for free links of a face
2861         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
2862         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
2863         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
2864         // check if a link is free
2865         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
2866           hasFreeLinks = true;
2867           // make an edge and a ceiling for a new edge
2868           if ( !aMesh->FindEdge( n1, n2 )) {
2869             aMesh->AddEdge( n1, n2 );
2870           }
2871           n1 = vecNewNodes[ iNode ]->second.back();
2872           n2 = vecNewNodes[ iNext ]->second.back();
2873           if ( !aMesh->FindEdge( n1, n2 )) {
2874             aMesh->AddEdge( n1, n2 );
2875           }
2876         }
2877       }
2878     }
2879     else { // elem is quadratic face
2880       int nbn = nbNodes/2;
2881       for ( iNode = 0; iNode < nbn; iNode++ ) {
2882         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
2883         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
2884         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
2885         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
2886         // check if a link is free
2887         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
2888           hasFreeLinks = true;
2889           // make an edge and a ceiling for a new edge
2890           // find medium node
2891           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
2892           if ( !aMesh->FindEdge( n1, n2, n3 )) {
2893             aMesh->AddEdge( n1, n2, n3 );
2894           }
2895           n1 = vecNewNodes[ iNode ]->second.back();
2896           n2 = vecNewNodes[ iNext ]->second.back();
2897           n3 = vecNewNodes[ iNode+nbn ]->second.back();
2898           if ( !aMesh->FindEdge( n1, n2, n3 )) {
2899             aMesh->AddEdge( n1, n2, n3 );
2900           }
2901         }
2902       }
2903       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
2904         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
2905       }
2906     }
2907
2908     // sweep free links into faces
2909
2910     if ( hasFreeLinks )  {
2911       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
2912       int iStep; //, nbSteps = vecNewNodes[0]->second.size();
2913       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
2914
2915       set<const SMDS_MeshNode*> initNodeSet, faceNodeSet;
2916       for ( iNode = 0; iNode < nbNodes; iNode++ )
2917         initNodeSet.insert( vecNewNodes[ iNode ]->first );
2918
2919       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
2920         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
2921         iVol = 0;
2922         while ( iVol++ < volNb ) v++;
2923         // find indices of free faces of a volume
2924         list< int > fInd;
2925         SMDS_VolumeTool vTool( *v );
2926         int iF, nbF = vTool.NbFaces();
2927         for ( iF = 0; iF < nbF; iF ++ ) {
2928           if (vTool.IsFreeFace( iF ) &&
2929               vTool.GetFaceNodes( iF, faceNodeSet ) &&
2930               initNodeSet != faceNodeSet) // except an initial face
2931             fInd.push_back( iF );
2932         }
2933         if ( fInd.empty() )
2934           continue;
2935
2936         // create faces for all steps
2937         for ( iStep = 0; iStep < nbSteps; iStep++ )  {
2938           vTool.Set( *v );
2939           vTool.SetExternalNormal();
2940           list< int >::iterator ind = fInd.begin();
2941           for ( ; ind != fInd.end(); ind++ ) {
2942             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
2943             int nbn = vTool.NbFaceNodes( *ind );
2944             //switch ( vTool.NbFaceNodes( *ind ) ) {
2945             switch ( nbn ) {
2946             case 3:
2947               aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ); break;
2948             case 4:
2949               aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ); break;
2950             default:
2951               {
2952                 if( (*v)->IsQuadratic() ) {
2953                   if(nbn==6) {
2954                     aMesh->AddFace(nodes[0], nodes[2], nodes[4],
2955                                    nodes[1], nodes[3], nodes[5]); break;
2956                   }
2957                   else {
2958                       aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
2959                                      nodes[1], nodes[3], nodes[5], nodes[7]);
2960                       break;
2961                   }
2962                 }
2963                 else {
2964                   int nbPolygonNodes = vTool.NbFaceNodes( *ind );
2965                   vector<const SMDS_MeshNode*> polygon_nodes (nbPolygonNodes);
2966                   for (int inode = 0; inode < nbPolygonNodes; inode++) {
2967                     polygon_nodes[inode] = nodes[inode];
2968                   }
2969                   aMesh->AddPolygonalFace(polygon_nodes);
2970                 }
2971                 break;
2972               }
2973             }
2974           }
2975           // go to the next volume
2976           iVol = 0;
2977           while ( iVol++ < nbVolumesByStep ) v++;
2978         }
2979       }
2980     } // sweep free links into faces
2981
2982     // make a ceiling face with a normal external to a volume
2983
2984     SMDS_VolumeTool lastVol( itElem->second.back() );
2985
2986     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
2987     if ( iF >= 0 ) {
2988       lastVol.SetExternalNormal();
2989       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
2990       int nbn = lastVol.NbFaceNodes( iF );
2991       switch ( nbn ) {
2992       case 3:
2993         if (!hasFreeLinks ||
2994             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
2995           aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] );
2996         break;
2997       case 4:
2998         if (!hasFreeLinks ||
2999             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3000           aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] );
3001         break;
3002       default:
3003         {
3004           if(itElem->second.back()->IsQuadratic()) {
3005             if(nbn==6) {
3006               if (!hasFreeLinks ||
3007                   !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3008                                    nodes[1], nodes[3], nodes[5]) ) {
3009                 aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3010                                nodes[1], nodes[3], nodes[5]); break;
3011               }
3012             }
3013             else { // nbn==8
3014               if (!hasFreeLinks ||
3015                   !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3016                                    nodes[1], nodes[3], nodes[5], nodes[7]) )
3017                 aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3018                                nodes[1], nodes[3], nodes[5], nodes[7]);
3019             }
3020           }
3021           else {
3022             int nbPolygonNodes = lastVol.NbFaceNodes( iF );
3023             vector<const SMDS_MeshNode*> polygon_nodes (nbPolygonNodes);
3024             for (int inode = 0; inode < nbPolygonNodes; inode++) {
3025               polygon_nodes[inode] = nodes[inode];
3026             }
3027             if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3028               aMesh->AddPolygonalFace(polygon_nodes);
3029           }
3030         }
3031         break;
3032       }
3033     }
3034   } // loop on swept elements
3035 }
3036
3037 //=======================================================================
3038 //function : RotationSweep
3039 //purpose  :
3040 //=======================================================================
3041
3042 void SMESH_MeshEditor::RotationSweep(set<const SMDS_MeshElement*> & theElems,
3043                                      const gp_Ax1&                  theAxis,
3044                                      const double                   theAngle,
3045                                      const int                      theNbSteps,
3046                                      const double                   theTol)
3047 {
3048   MESSAGE( "RotationSweep()");
3049   gp_Trsf aTrsf;
3050   aTrsf.SetRotation( theAxis, theAngle );
3051   gp_Trsf aTrsf2;
3052   aTrsf2.SetRotation( theAxis, theAngle/2. );
3053
3054   gp_Lin aLine( theAxis );
3055   double aSqTol = theTol * theTol;
3056
3057   SMESHDS_Mesh* aMesh = GetMeshDS();
3058
3059   TNodeOfNodeListMap mapNewNodes;
3060   TElemOfVecOfNnlmiMap mapElemNewNodes;
3061   TElemOfElemListMap newElemsMap;
3062
3063   // loop on theElems
3064   set< const SMDS_MeshElement* >::iterator itElem;
3065   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3066     const SMDS_MeshElement* elem = (*itElem);
3067     if ( !elem )
3068       continue;
3069     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3070     newNodesItVec.reserve( elem->NbNodes() );
3071
3072     // loop on elem nodes
3073     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3074     while ( itN->more() ) {
3075
3076       // check if a node has been already sweeped
3077       const SMDS_MeshNode* node =
3078         static_cast<const SMDS_MeshNode*>( itN->next() );
3079       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3080       if ( nIt == mapNewNodes.end() ) {
3081         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3082         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3083
3084         // make new nodes
3085         gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3086         double coord[3];
3087         aXYZ.Coord( coord[0], coord[1], coord[2] );
3088         bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3089         const SMDS_MeshNode * newNode = node;
3090         for ( int i = 0; i < theNbSteps; i++ ) {
3091           if ( !isOnAxis ) {
3092             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3093               // create two nodes
3094               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3095               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3096               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3097               listNewNodes.push_back( newNode );
3098               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3099               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3100             }
3101             else {
3102               aTrsf.Transforms( coord[0], coord[1], coord[2] );
3103             }
3104             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3105           }
3106           listNewNodes.push_back( newNode );
3107         }
3108       }
3109       else {
3110         // if current elem is quadratic and current node is not medium
3111         // we have to check - may be it is needed to insert additional nodes
3112         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3113           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3114           if(listNewNodes.size()==theNbSteps) {
3115             listNewNodes.clear();
3116             // make new nodes
3117             gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3118             double coord[3];
3119             aXYZ.Coord( coord[0], coord[1], coord[2] );
3120             const SMDS_MeshNode * newNode = node;
3121             for(int i = 0; i<theNbSteps; i++) {
3122               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3123               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3124               listNewNodes.push_back( newNode );
3125               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3126               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3127               listNewNodes.push_back( newNode );
3128             }
3129           }
3130         }
3131       }
3132       newNodesItVec.push_back( nIt );
3133     }
3134     // make new elements
3135     sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], theNbSteps );
3136   }
3137
3138   makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps );
3139
3140 }
3141
3142
3143 //=======================================================================
3144 //function : CreateNode
3145 //purpose  : 
3146 //=======================================================================
3147 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3148                                                   const double y,
3149                                                   const double z,
3150                                                   const double tolnode,
3151                                                   SMESH_SequenceOfNode& aNodes)
3152 {
3153   gp_Pnt P1(x,y,z);
3154   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3155
3156   // try to search in sequence of existing nodes
3157   // if aNodes.Length()>0 we 'nave to use given sequence
3158   // else - use all nodes of mesh
3159   if(aNodes.Length()>0) {
3160     int i;
3161     for(i=1; i<=aNodes.Length(); i++) {
3162       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3163       if(P1.Distance(P2)<tolnode)
3164         return aNodes.Value(i);
3165     }
3166   }
3167   else {
3168     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3169     while(itn->more()) {
3170       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3171       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3172       if(P1.Distance(P2)<tolnode)
3173         return aN;
3174     }    
3175   }
3176
3177   // create new node and return it
3178   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3179   return NewNode;
3180 }
3181
3182
3183 //=======================================================================
3184 //function : ExtrusionSweep
3185 //purpose  :
3186 //=======================================================================
3187
3188 void SMESH_MeshEditor::ExtrusionSweep
3189                     (set<const SMDS_MeshElement*> & theElems,
3190                      const gp_Vec&                  theStep,
3191                      const int                      theNbSteps,
3192                      TElemOfElemListMap&            newElemsMap,
3193                      const int                      theFlags,
3194                      const double                   theTolerance)
3195 {
3196   ExtrusParam aParams;
3197   aParams.myDir = gp_Dir(theStep);
3198   aParams.myNodes.Clear();
3199   aParams.mySteps = new TColStd_HSequenceOfReal;
3200   int i;
3201   for(i=1; i<=theNbSteps; i++)
3202     aParams.mySteps->Append(theStep.Magnitude());
3203
3204   ExtrusionSweep(theElems,aParams,newElemsMap,theFlags,theTolerance);
3205
3206 }
3207
3208
3209 //=======================================================================
3210 //function : ExtrusionSweep
3211 //purpose  :
3212 //=======================================================================
3213
3214 void SMESH_MeshEditor::ExtrusionSweep
3215                     (set<const SMDS_MeshElement*> & theElems,
3216                      ExtrusParam&                   theParams,
3217                      TElemOfElemListMap&            newElemsMap,
3218                      const int                      theFlags,
3219                      const double                   theTolerance)
3220 {
3221   SMESHDS_Mesh* aMesh = GetMeshDS();
3222
3223   int nbsteps = theParams.mySteps->Length();
3224
3225   TNodeOfNodeListMap mapNewNodes;
3226   //TNodeOfNodeVecMap mapNewNodes;
3227   TElemOfVecOfNnlmiMap mapElemNewNodes;
3228   //TElemOfVecOfMapNodesMap mapElemNewNodes;
3229
3230   // loop on theElems
3231   set< const SMDS_MeshElement* >::iterator itElem;
3232   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3233     // check element type
3234     const SMDS_MeshElement* elem = (*itElem);
3235     if ( !elem )
3236       continue;
3237
3238     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3239     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3240     newNodesItVec.reserve( elem->NbNodes() );
3241
3242     // loop on elem nodes
3243     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3244     while ( itN->more() ) {
3245
3246       // check if a node has been already sweeped
3247       const SMDS_MeshNode* node =
3248         static_cast<const SMDS_MeshNode*>( itN->next() );
3249       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3250       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3251       if ( nIt == mapNewNodes.end() ) {
3252         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3253         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3254         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3255         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3256         //vecNewNodes.reserve(nbsteps);
3257
3258         // make new nodes
3259         double coord[] = { node->X(), node->Y(), node->Z() };
3260         //int nbsteps = theParams.mySteps->Length();
3261         for ( int i = 0; i < nbsteps; i++ ) {
3262           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3263             // create additional node
3264             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3265             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3266             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3267             if( theFlags & EXTRUSION_FLAG_SEW ) {
3268               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3269                                                          theTolerance, theParams.myNodes);
3270               listNewNodes.push_back( newNode );
3271             }
3272             else {
3273               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3274               listNewNodes.push_back( newNode );
3275             }
3276           }
3277           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3278           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3279           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3280           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3281           if( theFlags & EXTRUSION_FLAG_SEW ) {
3282             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3283                                                        theTolerance, theParams.myNodes);
3284             listNewNodes.push_back( newNode );
3285             //vecNewNodes[i]=newNode;
3286           }
3287           else {
3288             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3289             listNewNodes.push_back( newNode );
3290             //vecNewNodes[i]=newNode;
3291           }
3292         }
3293       }
3294       else {
3295         // if current elem is quadratic and current node is not medium
3296         // we have to check - may be it is needed to insert additional nodes
3297         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3298           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3299           if(listNewNodes.size()==nbsteps) {
3300             listNewNodes.clear();
3301             double coord[] = { node->X(), node->Y(), node->Z() };
3302             for ( int i = 0; i < nbsteps; i++ ) {
3303               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3304               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3305               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3306               if( theFlags & EXTRUSION_FLAG_SEW ) {
3307                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3308                                                            theTolerance, theParams.myNodes);
3309                 listNewNodes.push_back( newNode );
3310               }
3311               else {
3312                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3313                 listNewNodes.push_back( newNode );
3314               }
3315               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3316               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3317               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3318               if( theFlags & EXTRUSION_FLAG_SEW ) {
3319                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3320                                                            theTolerance, theParams.myNodes);
3321                 listNewNodes.push_back( newNode );
3322               }
3323               else {
3324                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3325                 listNewNodes.push_back( newNode );
3326               }
3327             }
3328           }
3329         }
3330       }
3331       newNodesItVec.push_back( nIt );
3332     }
3333     // make new elements
3334     sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], nbsteps );
3335   }
3336   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3337     makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps );
3338   }
3339 }
3340
3341
3342 //=======================================================================
3343 //class    : SMESH_MeshEditor_PathPoint
3344 //purpose  : auxiliary class
3345 //=======================================================================
3346 class SMESH_MeshEditor_PathPoint {
3347 public:
3348   SMESH_MeshEditor_PathPoint() {
3349     myPnt.SetCoord(99., 99., 99.);
3350     myTgt.SetCoord(1.,0.,0.);
3351     myAngle=0.;
3352     myPrm=0.;
3353   }
3354   void SetPnt(const gp_Pnt& aP3D){
3355     myPnt=aP3D;
3356   }
3357   void SetTangent(const gp_Dir& aTgt){
3358     myTgt=aTgt;
3359   }
3360   void SetAngle(const double& aBeta){
3361     myAngle=aBeta;
3362   }
3363   void SetParameter(const double& aPrm){
3364     myPrm=aPrm;
3365   }
3366   const gp_Pnt& Pnt()const{
3367     return myPnt;
3368   }
3369   const gp_Dir& Tangent()const{
3370     return myTgt;
3371   }
3372   double Angle()const{
3373     return myAngle;
3374   }
3375   double Parameter()const{
3376     return myPrm;
3377   }
3378
3379 protected:
3380   gp_Pnt myPnt;
3381   gp_Dir myTgt;
3382   double myAngle;
3383   double myPrm;
3384 };
3385
3386 //=======================================================================
3387 //function : ExtrusionAlongTrack
3388 //purpose  :
3389 //=======================================================================
3390 SMESH_MeshEditor::Extrusion_Error
3391   SMESH_MeshEditor::ExtrusionAlongTrack (std::set<const SMDS_MeshElement*> & theElements,
3392                                          SMESH_subMesh* theTrack,
3393                                          const SMDS_MeshNode* theN1,
3394                                          const bool theHasAngles,
3395                                          std::list<double>& theAngles,
3396                                          const bool theHasRefPoint,
3397                                          const gp_Pnt& theRefPoint)
3398 {
3399   MESSAGE("SMESH_MeshEditor::ExtrusionAlongTrack")
3400   int j, aNbTP, aNbE, aNb;
3401   double aT1, aT2, aT, aAngle, aX, aY, aZ;
3402   std::list<double> aPrms;
3403   std::list<double>::iterator aItD;
3404   std::set< const SMDS_MeshElement* >::iterator itElem;
3405
3406   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
3407   gp_Pnt aP3D, aV0;
3408   gp_Vec aVec;
3409   gp_XYZ aGC;
3410   Handle(Geom_Curve) aC3D;
3411   TopoDS_Edge aTrackEdge;
3412   TopoDS_Vertex aV1, aV2;
3413
3414   SMDS_ElemIteratorPtr aItE;
3415   SMDS_NodeIteratorPtr aItN;
3416   SMDSAbs_ElementType aTypeE;
3417
3418   TNodeOfNodeListMap mapNewNodes;
3419   TElemOfVecOfNnlmiMap mapElemNewNodes;
3420   TElemOfElemListMap newElemsMap;
3421
3422   aTolVec=1.e-7;
3423   aTolVec2=aTolVec*aTolVec;
3424
3425   // 1. Check data
3426   aNbE = theElements.size();
3427   // nothing to do
3428   if ( !aNbE )
3429     return EXTR_NO_ELEMENTS;
3430
3431   // 1.1 Track Pattern
3432   ASSERT( theTrack );
3433
3434   SMESHDS_SubMesh* pSubMeshDS=theTrack->GetSubMeshDS();
3435
3436   aItE = pSubMeshDS->GetElements();
3437   while ( aItE->more() ) {
3438     const SMDS_MeshElement* pE = aItE->next();
3439     aTypeE = pE->GetType();
3440     // Pattern must contain links only
3441     if ( aTypeE != SMDSAbs_Edge )
3442       return EXTR_PATH_NOT_EDGE;
3443   }
3444
3445   const TopoDS_Shape& aS = theTrack->GetSubShape();
3446   // Sub shape for the Pattern must be an Edge
3447   if ( aS.ShapeType() != TopAbs_EDGE )
3448     return EXTR_BAD_PATH_SHAPE;
3449
3450   aTrackEdge = TopoDS::Edge( aS );
3451   // the Edge must not be degenerated
3452   if ( BRep_Tool::Degenerated( aTrackEdge ) )
3453     return EXTR_BAD_PATH_SHAPE;
3454
3455   TopExp::Vertices( aTrackEdge, aV1, aV2 );
3456   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
3457   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
3458
3459   aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
3460   const SMDS_MeshNode* aN1 = aItN->next();
3461
3462   aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
3463   const SMDS_MeshNode* aN2 = aItN->next();
3464
3465   // starting node must be aN1 or aN2
3466   if ( !( aN1 == theN1 || aN2 == theN1 ) )
3467     return EXTR_BAD_STARTING_NODE;
3468
3469   aNbTP = pSubMeshDS->NbNodes() + 2;
3470
3471   // 1.2. Angles
3472   vector<double> aAngles( aNbTP );
3473
3474   for ( j=0; j < aNbTP; ++j ) {
3475     aAngles[j] = 0.;
3476   }
3477
3478   if ( theHasAngles ) {
3479     aItD = theAngles.begin();
3480     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
3481       aAngle = *aItD;
3482       aAngles[j] = aAngle;
3483     }
3484   }
3485
3486   // 2. Collect parameters on the track edge
3487   aPrms.push_back( aT1 );
3488   aPrms.push_back( aT2 );
3489
3490   aItN = pSubMeshDS->GetNodes();
3491   while ( aItN->more() ) {
3492     const SMDS_MeshNode* pNode = aItN->next();
3493     const SMDS_EdgePosition* pEPos =
3494       static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
3495     aT = pEPos->GetUParameter();
3496     aPrms.push_back( aT );
3497   }
3498
3499   // sort parameters
3500   aPrms.sort();
3501   if ( aN1 == theN1 ) {
3502     if ( aT1 > aT2 ) {
3503       aPrms.reverse();
3504     }
3505   }
3506   else {
3507     if ( aT2 > aT1 ) {
3508       aPrms.reverse();
3509     }
3510   }
3511
3512   // 3. Path Points
3513   SMESH_MeshEditor_PathPoint aPP;
3514   vector<SMESH_MeshEditor_PathPoint> aPPs( aNbTP );
3515   //
3516   aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
3517   //
3518   aItD = aPrms.begin();
3519   for ( j=0; aItD != aPrms.end(); ++aItD, ++j ) {
3520     aT = *aItD;
3521     aC3D->D1( aT, aP3D, aVec );
3522     aL2 = aVec.SquareMagnitude();
3523     if ( aL2 < aTolVec2 )
3524       return EXTR_CANT_GET_TANGENT;
3525
3526     gp_Dir aTgt( aVec );
3527     aAngle = aAngles[j];
3528
3529     aPP.SetPnt( aP3D );
3530     aPP.SetTangent( aTgt );
3531     aPP.SetAngle( aAngle );
3532     aPP.SetParameter( aT );
3533     aPPs[j]=aPP;
3534   }
3535
3536   // 3. Center of rotation aV0
3537   aV0 = theRefPoint;
3538   if ( !theHasRefPoint ) {
3539     aNb = 0;
3540     aGC.SetCoord( 0.,0.,0. );
3541
3542     itElem = theElements.begin();
3543     for ( ; itElem != theElements.end(); itElem++ ) {
3544       const SMDS_MeshElement* elem = (*itElem);
3545
3546       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3547       while ( itN->more() ) {
3548         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
3549         aX = node->X();
3550         aY = node->Y();
3551         aZ = node->Z();
3552
3553         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
3554           list<const SMDS_MeshNode*> aLNx;
3555           mapNewNodes[node] = aLNx;
3556           //
3557           gp_XYZ aXYZ( aX, aY, aZ );
3558           aGC += aXYZ;
3559           ++aNb;
3560         }
3561       }
3562     }
3563     aGC /= aNb;
3564     aV0.SetXYZ( aGC );
3565   } // if (!theHasRefPoint) {
3566   mapNewNodes.clear();
3567
3568   // 4. Processing the elements
3569   SMESHDS_Mesh* aMesh = GetMeshDS();
3570
3571   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
3572     // check element type
3573     const SMDS_MeshElement* elem = (*itElem);
3574     aTypeE = elem->GetType();
3575     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
3576       continue;
3577
3578     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3579     newNodesItVec.reserve( elem->NbNodes() );
3580
3581     // loop on elem nodes
3582     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3583     while ( itN->more() ) {
3584
3585       // check if a node has been already processed
3586       const SMDS_MeshNode* node =
3587         static_cast<const SMDS_MeshNode*>( itN->next() );
3588       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3589       if ( nIt == mapNewNodes.end() ) {
3590         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3591         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3592
3593         // make new nodes
3594         aX = node->X();  aY = node->Y(); aZ = node->Z();
3595
3596         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
3597         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
3598         gp_Ax1 anAx1, anAxT1T0;
3599         gp_Dir aDT1x, aDT0x, aDT1T0;
3600
3601         aTolAng=1.e-4;
3602
3603         aV0x = aV0;
3604         aPN0.SetCoord(aX, aY, aZ);
3605
3606         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
3607         aP0x = aPP0.Pnt();
3608         aDT0x= aPP0.Tangent();
3609
3610         for ( j = 1; j < aNbTP; ++j ) {
3611           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
3612           aP1x = aPP1.Pnt();
3613           aDT1x = aPP1.Tangent();
3614           aAngle1x = aPP1.Angle();
3615
3616           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
3617           // Translation
3618           gp_Vec aV01x( aP0x, aP1x );
3619           aTrsf.SetTranslation( aV01x );
3620
3621           // traslated point
3622           aV1x = aV0x.Transformed( aTrsf );
3623           aPN1 = aPN0.Transformed( aTrsf );
3624
3625           // rotation 1 [ T1,T0 ]
3626           aAngleT1T0=-aDT1x.Angle( aDT0x );
3627           if (fabs(aAngleT1T0) > aTolAng) {
3628             aDT1T0=aDT1x^aDT0x;
3629             anAxT1T0.SetLocation( aV1x );
3630             anAxT1T0.SetDirection( aDT1T0 );
3631             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
3632
3633             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
3634           }
3635
3636           // rotation 2
3637           if ( theHasAngles ) {
3638             anAx1.SetLocation( aV1x );
3639             anAx1.SetDirection( aDT1x );
3640             aTrsfRot.SetRotation( anAx1, aAngle1x );
3641
3642             aPN1 = aPN1.Transformed( aTrsfRot );
3643           }
3644
3645           // make new node
3646           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3647             // create additional node
3648             double x = ( aPN1.X() + aPN0.X() )/2.;
3649             double y = ( aPN1.Y() + aPN0.Y() )/2.;
3650             double z = ( aPN1.Z() + aPN0.Z() )/2.;
3651             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
3652             listNewNodes.push_back( newNode );
3653           }
3654           aX = aPN1.X();
3655           aY = aPN1.Y();
3656           aZ = aPN1.Z();
3657           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
3658           listNewNodes.push_back( newNode );
3659
3660           aPN0 = aPN1;
3661           aP0x = aP1x;
3662           aV0x = aV1x;
3663           aDT0x = aDT1x;
3664         }
3665       }
3666
3667       else {
3668         // if current elem is quadratic and current node is not medium
3669         // we have to check - may be it is needed to insert additional nodes
3670         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3671           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3672           if(listNewNodes.size()==aNbTP-1) {
3673             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
3674             gp_XYZ P(node->X(), node->Y(), node->Z());
3675             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
3676             int i;
3677             for(i=0; i<aNbTP-1; i++) {
3678               const SMDS_MeshNode* N = *it;
3679               double x = ( N->X() + P.X() )/2.;
3680               double y = ( N->Y() + P.Y() )/2.;
3681               double z = ( N->Z() + P.Z() )/2.;
3682               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
3683               aNodes[2*i] = newN;
3684               aNodes[2*i+1] = N;
3685               P = gp_XYZ(N->X(),N->Y(),N->Z());
3686             }
3687             listNewNodes.clear();
3688             for(i=0; i<2*(aNbTP-1); i++) {
3689               listNewNodes.push_back(aNodes[i]);
3690             }
3691           }
3692         }
3693       }
3694
3695       newNodesItVec.push_back( nIt );
3696     }
3697     // make new elements
3698     sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
3699                   newNodesItVec[0]->second.size() );
3700   }
3701
3702   makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElements,
3703             aNbTP-1 );
3704
3705   return EXTR_OK;
3706 }
3707
3708 //=======================================================================
3709 //function : Transform
3710 //purpose  :
3711 //=======================================================================
3712
3713 void SMESH_MeshEditor::Transform (set<const SMDS_MeshElement*> & theElems,
3714                                   const gp_Trsf&                 theTrsf,
3715                                   const bool                     theCopy)
3716 {
3717   bool needReverse;
3718   switch ( theTrsf.Form() ) {
3719   case gp_PntMirror:
3720   case gp_Ax2Mirror:
3721     needReverse = true;
3722     break;
3723   default:
3724     needReverse = false;
3725   }
3726
3727   SMESHDS_Mesh* aMesh = GetMeshDS();
3728
3729   // map old node to new one
3730   TNodeNodeMap nodeMap;
3731
3732   // elements sharing moved nodes; those of them which have all
3733   // nodes mirrored but are not in theElems are to be reversed
3734   set<const SMDS_MeshElement*> inverseElemSet;
3735
3736   // loop on theElems
3737   set< const SMDS_MeshElement* >::iterator itElem;
3738   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3739     const SMDS_MeshElement* elem = (*itElem);
3740     if ( !elem )
3741       continue;
3742
3743     // loop on elem nodes
3744     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3745     while ( itN->more() ) {
3746
3747       // check if a node has been already transformed
3748       const SMDS_MeshNode* node =
3749         static_cast<const SMDS_MeshNode*>( itN->next() );
3750       if (nodeMap.find( node ) != nodeMap.end() )
3751         continue;
3752
3753       double coord[3];
3754       coord[0] = node->X();
3755       coord[1] = node->Y();
3756       coord[2] = node->Z();
3757       theTrsf.Transforms( coord[0], coord[1], coord[2] );
3758       const SMDS_MeshNode * newNode = node;
3759       if ( theCopy )
3760         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3761       else {
3762         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
3763         // node position on shape becomes invalid
3764         const_cast< SMDS_MeshNode* > ( node )->SetPosition
3765           ( SMDS_SpacePosition::originSpacePosition() );
3766       }
3767       nodeMap.insert( TNodeNodeMap::value_type( node, newNode ));
3768
3769       // keep inverse elements
3770       if ( !theCopy && needReverse ) {
3771         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
3772         while ( invElemIt->more() )
3773           inverseElemSet.insert( invElemIt->next() );
3774       }
3775     }
3776   }
3777
3778   // either new elements are to be created
3779   // or a mirrored element are to be reversed
3780   if ( !theCopy && !needReverse)
3781     return;
3782
3783   if ( !inverseElemSet.empty()) {
3784     set<const SMDS_MeshElement*>::iterator invElemIt = inverseElemSet.begin();
3785     for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
3786       theElems.insert( *invElemIt );
3787   }
3788
3789   // replicate or reverse elements
3790
3791   enum {
3792     REV_TETRA   = 0,  //  = nbNodes - 4
3793     REV_PYRAMID = 1,  //  = nbNodes - 4
3794     REV_PENTA   = 2,  //  = nbNodes - 4
3795     REV_FACE    = 3,
3796     REV_HEXA    = 4,  //  = nbNodes - 4
3797     FORWARD     = 5
3798     };
3799   int index[][8] = {
3800     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
3801     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
3802     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
3803     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
3804     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
3805     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
3806   };
3807
3808   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3809     const SMDS_MeshElement* elem = (*itElem);
3810     if ( !elem || elem->GetType() == SMDSAbs_Node )
3811       continue;
3812
3813     int nbNodes = elem->NbNodes();
3814     int elemType = elem->GetType();
3815
3816     if (elem->IsPoly()) {
3817       // Polygon or Polyhedral Volume
3818       switch ( elemType ) {
3819       case SMDSAbs_Face:
3820         {
3821           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
3822           int iNode = 0;
3823           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3824           while (itN->more()) {
3825             const SMDS_MeshNode* node =
3826               static_cast<const SMDS_MeshNode*>(itN->next());
3827             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
3828             if (nodeMapIt == nodeMap.end())
3829               break; // not all nodes transformed
3830             if (needReverse) {
3831               // reverse mirrored faces and volumes
3832               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
3833             } else {
3834               poly_nodes[iNode] = (*nodeMapIt).second;
3835             }
3836             iNode++;
3837           }
3838           if ( iNode != nbNodes )
3839             continue; // not all nodes transformed
3840
3841           if ( theCopy ) {
3842             aMesh->AddPolygonalFace(poly_nodes);
3843           } else {
3844             aMesh->ChangePolygonNodes(elem, poly_nodes);
3845           }
3846         }
3847         break;
3848       case SMDSAbs_Volume:
3849         {
3850           // ATTENTION: Reversing is not yet done!!!
3851           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
3852             (const SMDS_PolyhedralVolumeOfNodes*) elem;
3853           if (!aPolyedre) {
3854             MESSAGE("Warning: bad volumic element");
3855             continue;
3856           }
3857
3858           vector<const SMDS_MeshNode*> poly_nodes;
3859           vector<int> quantities;
3860
3861           bool allTransformed = true;
3862           int nbFaces = aPolyedre->NbFaces();
3863           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
3864             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
3865             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
3866               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
3867               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
3868               if (nodeMapIt == nodeMap.end()) {
3869                 allTransformed = false; // not all nodes transformed
3870               } else {
3871                 poly_nodes.push_back((*nodeMapIt).second);
3872               }
3873             }
3874             quantities.push_back(nbFaceNodes);
3875           }
3876           if ( !allTransformed )
3877             continue; // not all nodes transformed
3878
3879           if ( theCopy ) {
3880             aMesh->AddPolyhedralVolume(poly_nodes, quantities);
3881           } else {
3882             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
3883           }
3884         }
3885         break;
3886       default:;
3887       }
3888       continue;
3889     }
3890
3891     // Regular elements
3892     int* i = index[ FORWARD ];
3893     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
3894       if ( elemType == SMDSAbs_Face )
3895         i = index[ REV_FACE ];
3896       else
3897         i = index[ nbNodes - 4 ];
3898
3899     if(elem->IsQuadratic()) {
3900       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
3901       i = anIds;
3902       if(needReverse) {
3903         if(nbNodes==3) { // quadratic edge
3904           static int anIds[] = {1,0,2};
3905           i = anIds;
3906         }
3907         else if(nbNodes==6) { // quadratic triangle
3908           static int anIds[] = {0,2,1,5,4,3};
3909           i = anIds;
3910         }
3911         else if(nbNodes==8) { // quadratic quadrangle
3912           static int anIds[] = {0,3,2,1,7,6,5,4};
3913           i = anIds;
3914         }
3915         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
3916           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
3917           i = anIds;
3918         }
3919         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
3920           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
3921           i = anIds;
3922         }
3923         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
3924           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
3925           i = anIds;
3926         }
3927         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
3928           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
3929           i = anIds;
3930         }
3931       }
3932     }
3933
3934     // find transformed nodes
3935     const SMDS_MeshNode* nodes[8];
3936     int iNode = 0;
3937     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3938     while ( itN->more() ) {
3939       const SMDS_MeshNode* node =
3940         static_cast<const SMDS_MeshNode*>( itN->next() );
3941       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
3942       if ( nodeMapIt == nodeMap.end() )
3943         break; // not all nodes transformed
3944       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
3945     }
3946     if ( iNode != nbNodes )
3947       continue; // not all nodes transformed
3948
3949     if ( theCopy ) {
3950       // add a new element
3951       switch ( elemType ) {
3952       case SMDSAbs_Edge:
3953         if ( nbNodes == 2 )
3954           aMesh->AddEdge( nodes[ 0 ], nodes[ 1 ] );
3955         else
3956           aMesh->AddEdge( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] );
3957         break;
3958       case SMDSAbs_Face:
3959         if ( nbNodes == 3 )
3960           aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] );
3961         else if(nbNodes==4)
3962           aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ]);
3963         else if(nbNodes==6)
3964           aMesh->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
3965                          nodes[4], nodes[5]);
3966         else // nbNodes==8
3967           aMesh->AddFace(nodes[0], nodes[1], nodes[2], nodes[3],
3968                          nodes[4], nodes[5], nodes[6], nodes[7]);
3969         break;
3970       case SMDSAbs_Volume:
3971         if ( nbNodes == 4 )
3972           aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ] );
3973         else if ( nbNodes == 8 )
3974           aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ],
3975                             nodes[ 4 ], nodes[ 5 ], nodes[ 6 ] , nodes[ 7 ]);
3976         else if ( nbNodes == 6 )
3977           aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ],
3978                             nodes[ 4 ], nodes[ 5 ]);
3979         else if ( nbNodes == 5 )
3980           aMesh->AddVolume( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] , nodes[ 3 ],
3981                             nodes[ 4 ]);
3982         else if(nbNodes==10)
3983           aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4],
3984                            nodes[5], nodes[6], nodes[7], nodes[8], nodes[9]);
3985         else if(nbNodes==13)
3986           aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4],
3987                            nodes[5], nodes[6], nodes[7], nodes[8], nodes[9],
3988                            nodes[10], nodes[11], nodes[12]);
3989         else if(nbNodes==15)
3990           aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4],
3991                            nodes[5], nodes[6], nodes[7], nodes[8], nodes[9],
3992                            nodes[10], nodes[11], nodes[12], nodes[13], nodes[14]);
3993         else // nbNodes==20
3994           aMesh->AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4],
3995                            nodes[5], nodes[6], nodes[7], nodes[8], nodes[9],
3996                            nodes[10], nodes[11], nodes[12], nodes[13], nodes[14],
3997                            nodes[15], nodes[16], nodes[17], nodes[18], nodes[19]);
3998         break;
3999       default:;
4000       }
4001     }
4002     else
4003     {
4004       // reverse element as it was reversed by transformation
4005       if ( nbNodes > 2 )
4006         aMesh->ChangeElementNodes( elem, nodes, nbNodes );
4007     }
4008   }
4009 }
4010
4011 //=======================================================================
4012 //function : FindCoincidentNodes
4013 //purpose  : Return list of group of nodes close to each other within theTolerance
4014 //           Search among theNodes or in the whole mesh if theNodes is empty.
4015 //=======================================================================
4016
4017 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
4018                                             const double                theTolerance,
4019                                             TListOfListOfNodes &        theGroupsOfNodes)
4020 {
4021   double tol2 = theTolerance * theTolerance;
4022
4023   list<const SMDS_MeshNode*> nodes;
4024   if ( theNodes.empty() )
4025   { // get all nodes in the mesh
4026     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
4027     while ( nIt->more() )
4028       nodes.push_back( nIt->next() );
4029   }
4030   else
4031   {
4032     nodes.insert( nodes.end(), theNodes.begin(), theNodes.end() );
4033   }
4034
4035   list<const SMDS_MeshNode*>::iterator it2, it1 = nodes.begin();
4036   for ( ; it1 != nodes.end(); it1++ )
4037   {
4038     const SMDS_MeshNode* n1 = *it1;
4039     gp_Pnt p1( n1->X(), n1->Y(), n1->Z() );
4040
4041     list<const SMDS_MeshNode*> * groupPtr = 0;
4042     it2 = it1;
4043     for ( it2++; it2 != nodes.end(); it2++ )
4044     {
4045       const SMDS_MeshNode* n2 = *it2;
4046       gp_Pnt p2( n2->X(), n2->Y(), n2->Z() );
4047       if ( p1.SquareDistance( p2 ) <= tol2 )
4048       {
4049         if ( !groupPtr ) {
4050           theGroupsOfNodes.push_back( list<const SMDS_MeshNode*>() );
4051           groupPtr = & theGroupsOfNodes.back();
4052           groupPtr->push_back( n1 );
4053         }
4054         groupPtr->push_back( n2 );
4055         it2 = nodes.erase( it2 );
4056         it2--;
4057       }
4058     }
4059   }
4060 }
4061
4062 //=======================================================================
4063 //function : SimplifyFace
4064 //purpose  :
4065 //=======================================================================
4066 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
4067                                     vector<const SMDS_MeshNode *>&      poly_nodes,
4068                                     vector<int>&                        quantities) const
4069 {
4070   int nbNodes = faceNodes.size();
4071
4072   if (nbNodes < 3)
4073     return 0;
4074
4075   set<const SMDS_MeshNode*> nodeSet;
4076
4077   // get simple seq of nodes
4078   const SMDS_MeshNode* simpleNodes[ nbNodes ];
4079   int iSimple = 0, nbUnique = 0;
4080
4081   simpleNodes[iSimple++] = faceNodes[0];
4082   nbUnique++;
4083   for (int iCur = 1; iCur < nbNodes; iCur++) {
4084     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
4085       simpleNodes[iSimple++] = faceNodes[iCur];
4086       if (nodeSet.insert( faceNodes[iCur] ).second)
4087         nbUnique++;
4088     }
4089   }
4090   int nbSimple = iSimple;
4091   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
4092     nbSimple--;
4093     iSimple--;
4094   }
4095
4096   if (nbUnique < 3)
4097     return 0;
4098
4099   // separate loops
4100   int nbNew = 0;
4101   bool foundLoop = (nbSimple > nbUnique);
4102   while (foundLoop) {
4103     foundLoop = false;
4104     set<const SMDS_MeshNode*> loopSet;
4105     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
4106       const SMDS_MeshNode* n = simpleNodes[iSimple];
4107       if (!loopSet.insert( n ).second) {
4108         foundLoop = true;
4109
4110         // separate loop
4111         int iC = 0, curLast = iSimple;
4112         for (; iC < curLast; iC++) {
4113           if (simpleNodes[iC] == n) break;
4114         }
4115         int loopLen = curLast - iC;
4116         if (loopLen > 2) {
4117           // create sub-element
4118           nbNew++;
4119           quantities.push_back(loopLen);
4120           for (; iC < curLast; iC++) {
4121             poly_nodes.push_back(simpleNodes[iC]);
4122           }
4123         }
4124         // shift the rest nodes (place from the first loop position)
4125         for (iC = curLast + 1; iC < nbSimple; iC++) {
4126           simpleNodes[iC - loopLen] = simpleNodes[iC];
4127         }
4128         nbSimple -= loopLen;
4129         iSimple -= loopLen;
4130       }
4131     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
4132   } // while (foundLoop)
4133
4134   if (iSimple > 2) {
4135     nbNew++;
4136     quantities.push_back(iSimple);
4137     for (int i = 0; i < iSimple; i++)
4138       poly_nodes.push_back(simpleNodes[i]);
4139   }
4140
4141   return nbNew;
4142 }
4143
4144 //=======================================================================
4145 //function : MergeNodes
4146 //purpose  : In each group, the cdr of nodes are substituted by the first one
4147 //           in all elements.
4148 //=======================================================================
4149
4150 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
4151 {
4152   SMESHDS_Mesh* aMesh = GetMeshDS();
4153
4154   TNodeNodeMap nodeNodeMap; // node to replace - new node
4155   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
4156   list< int > rmElemIds, rmNodeIds;
4157
4158   // Fill nodeNodeMap and elems
4159
4160   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
4161   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
4162     list<const SMDS_MeshNode*>& nodes = *grIt;
4163     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
4164     const SMDS_MeshNode* nToKeep = *nIt;
4165     for ( ; nIt != nodes.end(); nIt++ ) {
4166       const SMDS_MeshNode* nToRemove = *nIt;
4167       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
4168       if ( nToRemove != nToKeep ) {
4169         rmNodeIds.push_back( nToRemove->GetID() );
4170         AddToSameGroups( nToKeep, nToRemove, aMesh );
4171       }
4172
4173       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
4174       while ( invElemIt->more() ) {
4175         const SMDS_MeshElement* elem = invElemIt->next();
4176           elems.insert(elem);
4177       }
4178     }
4179   }
4180   // Change element nodes or remove an element
4181
4182   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
4183   for ( ; eIt != elems.end(); eIt++ ) {
4184     const SMDS_MeshElement* elem = *eIt;
4185     int nbNodes = elem->NbNodes();
4186     int aShapeId = FindShape( elem );
4187
4188     set<const SMDS_MeshNode*> nodeSet;
4189     const SMDS_MeshNode* curNodes[ nbNodes ], *uniqueNodes[ nbNodes ];
4190     int iUnique = 0, iCur = 0, nbRepl = 0, iRepl [ nbNodes ];
4191
4192     // get new seq of nodes
4193     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4194     while ( itN->more() ) {
4195       const SMDS_MeshNode* n =
4196         static_cast<const SMDS_MeshNode*>( itN->next() );
4197
4198       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
4199       if ( nnIt != nodeNodeMap.end() ) { // n sticks
4200         n = (*nnIt).second;
4201         iRepl[ nbRepl++ ] = iCur;
4202       }
4203       curNodes[ iCur ] = n;
4204       bool isUnique = nodeSet.insert( n ).second;
4205       if ( isUnique )
4206         uniqueNodes[ iUnique++ ] = n;
4207       iCur++;
4208     }
4209
4210     // Analyse element topology after replacement
4211
4212     bool isOk = true;
4213     int nbUniqueNodes = nodeSet.size();
4214     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
4215       // Polygons and Polyhedral volumes
4216       if (elem->IsPoly()) {
4217
4218         if (elem->GetType() == SMDSAbs_Face) {
4219           // Polygon
4220           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
4221           int inode = 0;
4222           for (; inode < nbNodes; inode++) {
4223             face_nodes[inode] = curNodes[inode];
4224           }
4225
4226           vector<const SMDS_MeshNode *> polygons_nodes;
4227           vector<int> quantities;
4228           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
4229
4230           if (nbNew > 0) {
4231             inode = 0;
4232             for (int iface = 0; iface < nbNew - 1; iface++) {
4233               int nbNodes = quantities[iface];
4234               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
4235               for (int ii = 0; ii < nbNodes; ii++, inode++) {
4236                 poly_nodes[ii] = polygons_nodes[inode];
4237               }
4238               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
4239               if (aShapeId)
4240                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
4241             }
4242             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
4243           }
4244           else {
4245             rmElemIds.push_back(elem->GetID());
4246           }
4247
4248         }
4249         else if (elem->GetType() == SMDSAbs_Volume) {
4250           // Polyhedral volume
4251           if (nbUniqueNodes < 4) {
4252             rmElemIds.push_back(elem->GetID());
4253           }
4254           else {
4255             // each face has to be analized in order to check volume validity
4256             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4257               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4258             if (aPolyedre) {
4259               int nbFaces = aPolyedre->NbFaces();
4260
4261               vector<const SMDS_MeshNode *> poly_nodes;
4262               vector<int> quantities;
4263
4264               for (int iface = 1; iface <= nbFaces; iface++) {
4265                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4266                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
4267
4268                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
4269                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
4270                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
4271                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
4272                     faceNode = (*nnIt).second;
4273                   }
4274                   faceNodes[inode - 1] = faceNode;
4275                 }
4276
4277                 SimplifyFace(faceNodes, poly_nodes, quantities);
4278               }
4279
4280               if (quantities.size() > 3) {
4281                 // to be done: remove coincident faces
4282               }
4283
4284               if (quantities.size() > 3)
4285                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4286               else
4287                 rmElemIds.push_back(elem->GetID());
4288
4289             }
4290             else {
4291               rmElemIds.push_back(elem->GetID());
4292             }
4293           }
4294         }
4295         else {
4296         }
4297
4298         continue;
4299       }
4300
4301       // Regular elements
4302       switch ( nbNodes ) {
4303       case 2: ///////////////////////////////////// EDGE
4304         isOk = false; break;
4305       case 3: ///////////////////////////////////// TRIANGLE
4306         isOk = false; break;
4307       case 4:
4308         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
4309           isOk = false;
4310         else { //////////////////////////////////// QUADRANGLE
4311           if ( nbUniqueNodes < 3 )
4312             isOk = false;
4313           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
4314             isOk = false; // opposite nodes stick
4315         }
4316         break;
4317       case 6: ///////////////////////////////////// PENTAHEDRON
4318         if ( nbUniqueNodes == 4 ) {
4319           // ---------------------------------> tetrahedron
4320           if (nbRepl == 3 &&
4321               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
4322             // all top nodes stick: reverse a bottom
4323             uniqueNodes[ 0 ] = curNodes [ 1 ];
4324             uniqueNodes[ 1 ] = curNodes [ 0 ];
4325           }
4326           else if (nbRepl == 3 &&
4327                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
4328             // all bottom nodes stick: set a top before
4329             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
4330             uniqueNodes[ 0 ] = curNodes [ 3 ];
4331             uniqueNodes[ 1 ] = curNodes [ 4 ];
4332             uniqueNodes[ 2 ] = curNodes [ 5 ];
4333           }
4334           else if (nbRepl == 4 &&
4335                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
4336             // a lateral face turns into a line: reverse a bottom
4337             uniqueNodes[ 0 ] = curNodes [ 1 ];
4338             uniqueNodes[ 1 ] = curNodes [ 0 ];
4339           }
4340           else
4341             isOk = false;
4342         }
4343         else if ( nbUniqueNodes == 5 ) {
4344           // PENTAHEDRON --------------------> 2 tetrahedrons
4345           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
4346             // a bottom node sticks with a linked top one
4347             // 1.
4348             SMDS_MeshElement* newElem =
4349               aMesh->AddVolume(curNodes[ 3 ],
4350                                curNodes[ 4 ],
4351                                curNodes[ 5 ],
4352                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
4353             if ( aShapeId )
4354               aMesh->SetMeshElementOnShape( newElem, aShapeId );
4355             // 2. : reverse a bottom
4356             uniqueNodes[ 0 ] = curNodes [ 1 ];
4357             uniqueNodes[ 1 ] = curNodes [ 0 ];
4358             nbUniqueNodes = 4;
4359           }
4360           else
4361             isOk = false;
4362         }
4363         else
4364           isOk = false;
4365         break;
4366       case 8: { 
4367         if(elem->IsQuadratic()) { // Quadratic quadrangle
4368           //   1    5    2
4369           //    +---+---+
4370           //    |       |
4371           //    |       |
4372           //   4+       +6
4373           //    |       |
4374           //    |       |
4375           //    +---+---+
4376           //   0    7    3
4377           isOk = false;
4378           if(nbRepl==3) {
4379             nbUniqueNodes = 6;
4380             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
4381               uniqueNodes[0] = curNodes[0];
4382               uniqueNodes[1] = curNodes[2];
4383               uniqueNodes[2] = curNodes[3];
4384               uniqueNodes[3] = curNodes[5];
4385               uniqueNodes[4] = curNodes[6];
4386               uniqueNodes[5] = curNodes[7];
4387               isOk = true;
4388             }
4389             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
4390               uniqueNodes[0] = curNodes[0];
4391               uniqueNodes[1] = curNodes[1];
4392               uniqueNodes[2] = curNodes[2];
4393               uniqueNodes[3] = curNodes[4];
4394               uniqueNodes[4] = curNodes[5];
4395               uniqueNodes[5] = curNodes[6];
4396               isOk = true;
4397             }
4398             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
4399               uniqueNodes[0] = curNodes[1];
4400               uniqueNodes[1] = curNodes[2];
4401               uniqueNodes[2] = curNodes[3];
4402               uniqueNodes[3] = curNodes[5];
4403               uniqueNodes[4] = curNodes[6];
4404               uniqueNodes[5] = curNodes[0];
4405               isOk = true;
4406             }
4407             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
4408               uniqueNodes[0] = curNodes[0];
4409               uniqueNodes[1] = curNodes[1];
4410               uniqueNodes[2] = curNodes[3];
4411               uniqueNodes[3] = curNodes[4];
4412               uniqueNodes[4] = curNodes[6];
4413               uniqueNodes[5] = curNodes[7];
4414               isOk = true;
4415             }
4416             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
4417               uniqueNodes[0] = curNodes[0];
4418               uniqueNodes[1] = curNodes[2];
4419               uniqueNodes[2] = curNodes[3];
4420               uniqueNodes[3] = curNodes[1];
4421               uniqueNodes[4] = curNodes[6];
4422               uniqueNodes[5] = curNodes[7];
4423               isOk = true;
4424             }
4425             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
4426               uniqueNodes[0] = curNodes[0];
4427               uniqueNodes[1] = curNodes[1];
4428               uniqueNodes[2] = curNodes[2];
4429               uniqueNodes[3] = curNodes[4];
4430               uniqueNodes[4] = curNodes[5];
4431               uniqueNodes[5] = curNodes[7];
4432               isOk = true;
4433             }
4434             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
4435               uniqueNodes[0] = curNodes[0];
4436               uniqueNodes[1] = curNodes[1];
4437               uniqueNodes[2] = curNodes[3];
4438               uniqueNodes[3] = curNodes[4];
4439               uniqueNodes[4] = curNodes[2];
4440               uniqueNodes[5] = curNodes[7];
4441               isOk = true;
4442             }
4443             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
4444               uniqueNodes[0] = curNodes[0];
4445               uniqueNodes[1] = curNodes[1];
4446               uniqueNodes[2] = curNodes[2];
4447               uniqueNodes[3] = curNodes[4];
4448               uniqueNodes[4] = curNodes[5];
4449               uniqueNodes[5] = curNodes[3];
4450               isOk = true;
4451             }
4452           }
4453           break;
4454         }
4455         //////////////////////////////////// HEXAHEDRON
4456         isOk = false;
4457         SMDS_VolumeTool hexa (elem);
4458         hexa.SetExternalNormal();
4459         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
4460           //////////////////////// ---> tetrahedron
4461           for ( int iFace = 0; iFace < 6; iFace++ ) {
4462             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
4463             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
4464                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
4465                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
4466               // one face turns into a point ...
4467               int iOppFace = hexa.GetOppFaceIndex( iFace );
4468               ind = hexa.GetFaceNodesIndices( iOppFace );
4469               int nbStick = 0;
4470               iUnique = 2; // reverse a tetrahedron bottom
4471               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
4472                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
4473                   nbStick++;
4474                 else if ( iUnique >= 0 )
4475                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
4476               }
4477               if ( nbStick == 1 ) {
4478                 // ... and the opposite one - into a triangle.
4479                 // set a top node
4480                 ind = hexa.GetFaceNodesIndices( iFace );
4481                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
4482                 isOk = true;
4483               }
4484               break;
4485             }
4486           }
4487         }
4488         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
4489           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
4490           for ( int iFace = 0; iFace < 6; iFace++ ) {
4491             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
4492             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
4493                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
4494                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
4495               // one face turns into a point ...
4496               int iOppFace = hexa.GetOppFaceIndex( iFace );
4497               ind = hexa.GetFaceNodesIndices( iOppFace );
4498               int nbStick = 0;
4499               iUnique = 2;  // reverse a tetrahedron 1 bottom
4500               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
4501                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
4502                   nbStick++;
4503                 else if ( iUnique >= 0 )
4504                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
4505               }
4506               if ( nbStick == 0 ) {
4507                 // ... and the opposite one is a quadrangle
4508                 // set a top node
4509                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
4510                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
4511                 nbUniqueNodes = 4;
4512                 // tetrahedron 2
4513                 SMDS_MeshElement* newElem =
4514                   aMesh->AddVolume(curNodes[ind[ 0 ]],
4515                                    curNodes[ind[ 3 ]],
4516                                    curNodes[ind[ 2 ]],
4517                                    curNodes[indTop[ 0 ]]);
4518                 if ( aShapeId )
4519                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
4520                 isOk = true;
4521               }
4522               break;
4523             }
4524           }
4525         }
4526         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
4527           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
4528           // find indices of quad and tri faces
4529           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
4530           for ( iFace = 0; iFace < 6; iFace++ ) {
4531             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
4532             nodeSet.clear();
4533             for ( iCur = 0; iCur < 4; iCur++ )
4534               nodeSet.insert( curNodes[ind[ iCur ]] );
4535             nbUniqueNodes = nodeSet.size();
4536             if ( nbUniqueNodes == 3 )
4537               iTriFace[ nbTri++ ] = iFace;
4538             else if ( nbUniqueNodes == 4 )
4539               iQuadFace[ nbQuad++ ] = iFace;
4540           }
4541           if (nbQuad == 2 && nbTri == 4 &&
4542               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
4543             // 2 opposite quadrangles stuck with a diagonal;
4544             // sample groups of merged indices: (0-4)(2-6)
4545             // --------------------------------------------> 2 tetrahedrons
4546             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
4547             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
4548             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
4549             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
4550                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
4551               // stuck with 0-2 diagonal
4552               i0  = ind1[ 3 ];
4553               i1d = ind1[ 0 ];
4554               i2  = ind1[ 1 ];
4555               i3d = ind1[ 2 ];
4556               i0t = ind2[ 1 ];
4557               i2t = ind2[ 3 ];
4558             }
4559             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
4560                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
4561               // stuck with 1-3 diagonal
4562               i0  = ind1[ 0 ];
4563               i1d = ind1[ 1 ];
4564               i2  = ind1[ 2 ];
4565               i3d = ind1[ 3 ];
4566               i0t = ind2[ 0 ];
4567               i2t = ind2[ 1 ];
4568             }
4569             else {
4570               ASSERT(0);
4571             }
4572             // tetrahedron 1
4573             uniqueNodes[ 0 ] = curNodes [ i0 ];
4574             uniqueNodes[ 1 ] = curNodes [ i1d ];
4575             uniqueNodes[ 2 ] = curNodes [ i3d ];
4576             uniqueNodes[ 3 ] = curNodes [ i0t ];
4577             nbUniqueNodes = 4;
4578             // tetrahedron 2
4579             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
4580                                                          curNodes[ i2 ],
4581                                                          curNodes[ i3d ],
4582                                                          curNodes[ i2t ]);
4583             if ( aShapeId )
4584               aMesh->SetMeshElementOnShape( newElem, aShapeId );
4585             isOk = true;
4586           }
4587           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
4588                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
4589             // --------------------------------------------> prism
4590             // find 2 opposite triangles
4591             nbUniqueNodes = 6;
4592             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
4593               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
4594                 // find indices of kept and replaced nodes
4595                 // and fill unique nodes of 2 opposite triangles
4596                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
4597                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
4598                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
4599                 // fill unique nodes
4600                 iUnique = 0;
4601                 isOk = true;
4602                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
4603                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
4604                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
4605                   if ( n == nInit ) {
4606                     // iCur of a linked node of the opposite face (make normals co-directed):
4607                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
4608                     // check that correspondent corners of triangles are linked
4609                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
4610                       isOk = false;
4611                     else {
4612                       uniqueNodes[ iUnique ] = n;
4613                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
4614                       iUnique++;
4615                     }
4616                   }
4617                 }
4618                 break;
4619               }
4620             }
4621           }
4622         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
4623         break;
4624       } // HEXAHEDRON
4625
4626       default:
4627         isOk = false;
4628       } // switch ( nbNodes )
4629
4630     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
4631
4632     if ( isOk ) {
4633       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
4634         // Change nodes of polyedre
4635         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4636           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4637         if (aPolyedre) {
4638           int nbFaces = aPolyedre->NbFaces();
4639
4640           vector<const SMDS_MeshNode *> poly_nodes;
4641           vector<int> quantities (nbFaces);
4642
4643           for (int iface = 1; iface <= nbFaces; iface++) {
4644             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4645             quantities[iface - 1] = nbFaceNodes;
4646
4647             for (inode = 1; inode <= nbFaceNodes; inode++) {
4648               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
4649
4650               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
4651               if (nnIt != nodeNodeMap.end()) { // curNode sticks
4652                 curNode = (*nnIt).second;
4653               }
4654               poly_nodes.push_back(curNode);
4655             }
4656           }
4657           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
4658         }
4659       }
4660       else {
4661         // Change regular element or polygon
4662         aMesh->ChangeElementNodes( elem, uniqueNodes, nbUniqueNodes );
4663       }
4664     }
4665     else {
4666       // Remove invalid regular element or invalid polygon
4667       rmElemIds.push_back( elem->GetID() );
4668     }
4669
4670   } // loop on elements
4671
4672   // Remove equal nodes and bad elements
4673
4674   Remove( rmNodeIds, true );
4675   Remove( rmElemIds, false );
4676
4677 }
4678
4679 //=======================================================================
4680 //function : MergeEqualElements
4681 //purpose  : Remove all but one of elements built on the same nodes.
4682 //=======================================================================
4683
4684 void SMESH_MeshEditor::MergeEqualElements()
4685 {
4686   SMESHDS_Mesh* aMesh = GetMeshDS();
4687
4688   SMDS_EdgeIteratorPtr   eIt = aMesh->edgesIterator();
4689   SMDS_FaceIteratorPtr   fIt = aMesh->facesIterator();
4690   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
4691
4692   list< int > rmElemIds; // IDs of elems to remove
4693
4694   for ( int iDim = 1; iDim <= 3; iDim++ ) {
4695
4696     set< set <const SMDS_MeshElement*> > setOfNodeSet;
4697
4698     while ( 1 ) {
4699       // get next element
4700       const SMDS_MeshElement* elem = 0;
4701       if ( iDim == 1 ) {
4702         if ( eIt->more() ) elem = eIt->next();
4703       } else if ( iDim == 2 ) {
4704         if ( fIt->more() ) elem = fIt->next();
4705       } else {
4706         if ( vIt->more() ) elem = vIt->next();
4707       }
4708       if ( !elem ) break;
4709
4710       // get elem nodes
4711       set <const SMDS_MeshElement*> nodeSet;
4712       SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
4713       while ( nodeIt->more() )
4714         nodeSet.insert( nodeIt->next() );
4715
4716       // check uniqueness
4717       bool isUnique = setOfNodeSet.insert( nodeSet ).second;
4718       if ( !isUnique )
4719         rmElemIds.push_back( elem->GetID() );
4720     }
4721   }
4722
4723   Remove( rmElemIds, false );
4724 }
4725
4726 //=======================================================================
4727 //function : FindFaceInSet
4728 //purpose  : Return a face having linked nodes n1 and n2 and which is
4729 //           - not in avoidSet,
4730 //           - in elemSet provided that !elemSet.empty()
4731 //=======================================================================
4732
4733 const SMDS_MeshElement*
4734   SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*                n1,
4735                                   const SMDS_MeshNode*                n2,
4736                                   const set<const SMDS_MeshElement*>& elemSet,
4737                                   const set<const SMDS_MeshElement*>& avoidSet)
4738
4739 {
4740   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator();
4741   while ( invElemIt->more() ) { // loop on inverse elements of n1
4742     const SMDS_MeshElement* elem = invElemIt->next();
4743     if (elem->GetType() != SMDSAbs_Face ||
4744         avoidSet.find( elem ) != avoidSet.end() )
4745       continue;
4746     if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
4747       continue;
4748     // get face nodes and find index of n1
4749     int i1, nbN = elem->NbNodes(), iNode = 0;
4750     const SMDS_MeshNode* faceNodes[ nbN ], *n;
4751     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
4752     while ( nIt->more() ) {
4753       faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
4754       if ( faceNodes[ iNode++ ] == n1 )
4755         i1 = iNode - 1;
4756     }
4757     // find a n2 linked to n1
4758     if(!elem->IsQuadratic()) {
4759       for ( iNode = 0; iNode < 2; iNode++ ) {
4760         if ( iNode ) // node before n1
4761           n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
4762         else         // node after n1
4763           n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
4764         if ( n == n2 )
4765           return elem;
4766       }
4767     }
4768     else { // analysis for quadratic elements
4769       bool IsFind = false;
4770       // check using only corner nodes
4771       for ( iNode = 0; iNode < 2; iNode++ ) {
4772         if ( iNode ) // node before n1
4773           n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
4774         else         // node after n1
4775           n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
4776         if ( n == n2 )
4777           IsFind = true;
4778       }
4779       if(IsFind) {
4780         return elem;
4781       }
4782       else {
4783         // check using all nodes
4784         const SMDS_QuadraticFaceOfNodes* F =
4785           static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
4786         // use special nodes iterator
4787         iNode = 0;
4788         SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
4789         while ( anIter->more() ) {
4790           faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
4791           if ( faceNodes[ iNode++ ] == n1 )
4792             i1 = iNode - 1;
4793         }
4794         for ( iNode = 0; iNode < 2; iNode++ ) {
4795           if ( iNode ) // node before n1
4796             n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
4797           else         // node after n1
4798             n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
4799           if ( n == n2 ) {
4800             return elem;
4801           }
4802         }
4803       }
4804     } // end analysis for quadratic elements
4805   }
4806   return 0;
4807 }
4808
4809 //=======================================================================
4810 //function : findAdjacentFace
4811 //purpose  :
4812 //=======================================================================
4813
4814 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
4815                                                 const SMDS_MeshNode* n2,
4816                                                 const SMDS_MeshElement* elem)
4817 {
4818   set<const SMDS_MeshElement*> elemSet, avoidSet;
4819   if ( elem )
4820     avoidSet.insert ( elem );
4821   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
4822 }
4823
4824 //=======================================================================
4825 //function : findFreeBorder
4826 //purpose  :
4827 //=======================================================================
4828
4829 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
4830
4831 static bool findFreeBorder (const SMDS_MeshNode*                theFirstNode,
4832                             const SMDS_MeshNode*                theSecondNode,
4833                             const SMDS_MeshNode*                theLastNode,
4834                             list< const SMDS_MeshNode* > &      theNodes,
4835                             list< const SMDS_MeshElement* > &   theFaces)
4836 {
4837   if ( !theFirstNode || !theSecondNode )
4838     return false;
4839   // find border face between theFirstNode and theSecondNode
4840   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
4841   if ( !curElem )
4842     return false;
4843
4844   theFaces.push_back( curElem );
4845   theNodes.push_back( theFirstNode );
4846   theNodes.push_back( theSecondNode );
4847
4848   //vector<const SMDS_MeshNode*> nodes;
4849   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
4850   set < const SMDS_MeshElement* > foundElems;
4851   bool needTheLast = ( theLastNode != 0 );
4852
4853   while ( nStart != theLastNode ) {
4854     if ( nStart == theFirstNode )
4855       return !needTheLast;
4856
4857     // find all free border faces sharing form nStart
4858
4859     list< const SMDS_MeshElement* > curElemList;
4860     list< const SMDS_MeshNode* > nStartList;
4861     SMDS_ElemIteratorPtr invElemIt = nStart->facesIterator();
4862     while ( invElemIt->more() ) {
4863       const SMDS_MeshElement* e = invElemIt->next();
4864       if ( e == curElem || foundElems.insert( e ).second ) {
4865         // get nodes
4866         int iNode = 0, nbNodes = e->NbNodes();
4867         const SMDS_MeshNode* nodes[nbNodes+1];
4868         if(e->IsQuadratic()) {
4869           const SMDS_QuadraticFaceOfNodes* F =
4870             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
4871           // use special nodes iterator
4872           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
4873           while( anIter->more() ) {
4874             nodes[ iNode++ ] = anIter->next();
4875           }
4876         }
4877         else {
4878           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
4879           while ( nIt->more() )
4880             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
4881         }
4882         nodes[ iNode ] = nodes[ 0 ];
4883         // check 2 links
4884         for ( iNode = 0; iNode < nbNodes; iNode++ )
4885           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
4886                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
4887               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
4888           {
4889             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
4890             curElemList.push_back( e );
4891           }
4892       }
4893     }
4894     // analyse the found
4895
4896     int nbNewBorders = curElemList.size();
4897     if ( nbNewBorders == 0 ) {
4898       // no free border furthermore
4899       return !needTheLast;
4900     }
4901     else if ( nbNewBorders == 1 ) {
4902       // one more element found
4903       nIgnore = nStart;
4904       nStart = nStartList.front();
4905       curElem = curElemList.front();
4906       theFaces.push_back( curElem );
4907       theNodes.push_back( nStart );
4908     }
4909     else {
4910       // several continuations found
4911       list< const SMDS_MeshElement* >::iterator curElemIt;
4912       list< const SMDS_MeshNode* >::iterator nStartIt;
4913       // check if one of them reached the last node
4914       if ( needTheLast ) {
4915         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
4916              curElemIt!= curElemList.end();
4917              curElemIt++, nStartIt++ )
4918           if ( *nStartIt == theLastNode ) {
4919             theFaces.push_back( *curElemIt );
4920             theNodes.push_back( *nStartIt );
4921             return true;
4922           }
4923       }
4924       // find the best free border by the continuations
4925       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
4926       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
4927       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
4928            curElemIt!= curElemList.end();
4929            curElemIt++, nStartIt++ )
4930       {
4931         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
4932         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
4933         // find one more free border
4934         if ( ! findFreeBorder( nIgnore, nStart, theLastNode, *cNL, *cFL )) {
4935           cNL->clear();
4936           cFL->clear();
4937         }
4938         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
4939           // choice: clear a worse one
4940           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
4941           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
4942           contNodes[ iWorse ].clear();
4943           contFaces[ iWorse ].clear();
4944         }
4945       }
4946       if ( contNodes[0].empty() && contNodes[1].empty() )
4947         return false;
4948
4949       // append the best free border
4950       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
4951       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
4952       theNodes.pop_back(); // remove nIgnore
4953       theNodes.pop_back(); // remove nStart
4954       theFaces.pop_back(); // remove curElem
4955       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
4956       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
4957       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
4958       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
4959       return true;
4960
4961     } // several continuations found
4962   } // while ( nStart != theLastNode )
4963
4964   return true;
4965 }
4966
4967 //=======================================================================
4968 //function : CheckFreeBorderNodes
4969 //purpose  : Return true if the tree nodes are on a free border
4970 //=======================================================================
4971
4972 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
4973                                             const SMDS_MeshNode* theNode2,
4974                                             const SMDS_MeshNode* theNode3)
4975 {
4976   list< const SMDS_MeshNode* > nodes;
4977   list< const SMDS_MeshElement* > faces;
4978   return findFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
4979 }
4980
4981 //=======================================================================
4982 //function : SewFreeBorder
4983 //purpose  :
4984 //=======================================================================
4985
4986 SMESH_MeshEditor::Sew_Error
4987   SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
4988                                    const SMDS_MeshNode* theBordSecondNode,
4989                                    const SMDS_MeshNode* theBordLastNode,
4990                                    const SMDS_MeshNode* theSideFirstNode,
4991                                    const SMDS_MeshNode* theSideSecondNode,
4992                                    const SMDS_MeshNode* theSideThirdNode,
4993                                    const bool           theSideIsFreeBorder,
4994                                    const bool           toCreatePolygons,
4995                                    const bool           toCreatePolyedrs)
4996 {
4997   MESSAGE("::SewFreeBorder()");
4998   Sew_Error aResult = SEW_OK;
4999
5000   // ====================================
5001   //    find side nodes and elements
5002   // ====================================
5003
5004   list< const SMDS_MeshNode* > nSide[ 2 ];
5005   list< const SMDS_MeshElement* > eSide[ 2 ];
5006   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
5007   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
5008
5009   // Free border 1
5010   // --------------
5011   if (!findFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
5012                       nSide[0], eSide[0])) {
5013     MESSAGE(" Free Border 1 not found " );
5014     aResult = SEW_BORDER1_NOT_FOUND;
5015   }
5016   if (theSideIsFreeBorder) {
5017     // Free border 2
5018     // --------------
5019     if (!findFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
5020                         nSide[1], eSide[1])) {
5021       MESSAGE(" Free Border 2 not found " );
5022       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
5023     }
5024   }
5025   if ( aResult != SEW_OK )
5026     return aResult;
5027
5028   if (!theSideIsFreeBorder) {
5029     // Side 2
5030     // --------------
5031
5032     // -------------------------------------------------------------------------
5033     // Algo:
5034     // 1. If nodes to merge are not coincident, move nodes of the free border
5035     //    from the coord sys defined by the direction from the first to last
5036     //    nodes of the border to the correspondent sys of the side 2
5037     // 2. On the side 2, find the links most co-directed with the correspondent
5038     //    links of the free border
5039     // -------------------------------------------------------------------------
5040
5041     // 1. Since sewing may brake if there are volumes to split on the side 2,
5042     //    we wont move nodes but just compute new coordinates for them
5043     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
5044     TNodeXYZMap nBordXYZ;
5045     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
5046     list< const SMDS_MeshNode* >::iterator nBordIt;
5047
5048     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
5049     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
5050     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
5051     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
5052     double tol2 = 1.e-8;
5053     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
5054     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
5055       // Need node movement.
5056
5057       // find X and Z axes to create trsf
5058       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
5059       gp_Vec X = Zs ^ Zb;
5060       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
5061         // Zb || Zs
5062         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
5063
5064       // coord systems
5065       gp_Ax3 toBordAx( Pb1, Zb, X );
5066       gp_Ax3 fromSideAx( Ps1, Zs, X );
5067       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
5068       // set trsf
5069       gp_Trsf toBordSys, fromSide2Sys;
5070       toBordSys.SetTransformation( toBordAx );
5071       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
5072       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
5073
5074       // move
5075       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
5076         const SMDS_MeshNode* n = *nBordIt;
5077         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
5078         toBordSys.Transforms( xyz );
5079         fromSide2Sys.Transforms( xyz );
5080         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
5081       }
5082     }
5083     else {
5084       // just insert nodes XYZ in the nBordXYZ map
5085       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
5086         const SMDS_MeshNode* n = *nBordIt;
5087         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
5088       }
5089     }
5090
5091     // 2. On the side 2, find the links most co-directed with the correspondent
5092     //    links of the free border
5093
5094     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
5095     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
5096     sideNodes.push_back( theSideFirstNode );
5097
5098     bool hasVolumes = false;
5099     LinkID_Gen aLinkID_Gen( GetMeshDS() );
5100     set<long> foundSideLinkIDs, checkedLinkIDs;
5101     SMDS_VolumeTool volume;
5102     //const SMDS_MeshNode* faceNodes[ 4 ];
5103
5104     const SMDS_MeshNode*    sideNode;
5105     const SMDS_MeshElement* sideElem;
5106     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
5107     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
5108     nBordIt = bordNodes.begin();
5109     nBordIt++;
5110     // border node position and border link direction to compare with
5111     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
5112     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
5113     // choose next side node by link direction or by closeness to
5114     // the current border node:
5115     bool searchByDir = ( *nBordIt != theBordLastNode );
5116     do {
5117       // find the next node on the Side 2
5118       sideNode = 0;
5119       double maxDot = -DBL_MAX, minDist = DBL_MAX;
5120       long linkID;
5121       checkedLinkIDs.clear();
5122       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
5123
5124       SMDS_ElemIteratorPtr invElemIt
5125         = prevSideNode->GetInverseElementIterator();
5126       while ( invElemIt->more() ) { // loop on inverse elements on the Side 2
5127         const SMDS_MeshElement* elem = invElemIt->next();
5128         // prepare data for a loop on links, of a face or a volume
5129         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
5130         const SMDS_MeshNode* faceNodes[ nbNodes ];
5131         bool isVolume = volume.Set( elem );
5132         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : faceNodes;
5133         if ( isVolume ) // --volume
5134           hasVolumes = true;
5135         //else if ( nbNodes > 2 ) { // --face
5136         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
5137           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
5138           if(elem->IsQuadratic()) {
5139             const SMDS_QuadraticFaceOfNodes* F =
5140               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
5141             // use special nodes iterator
5142             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5143             while( anIter->more() ) {
5144               nodes[ iNode ] = anIter->next();
5145               if ( nodes[ iNode++ ] == prevSideNode )
5146                 iPrevNode = iNode - 1;
5147             }
5148           }
5149           else {
5150             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5151             while ( nIt->more() ) {
5152               nodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5153               if ( nodes[ iNode++ ] == prevSideNode )
5154                 iPrevNode = iNode - 1;
5155             }
5156           }
5157           // there are 2 links to check
5158           nbNodes = 2;
5159         }
5160         else // --edge
5161           continue;
5162         // loop on links, to be precise, on the second node of links
5163         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
5164           const SMDS_MeshNode* n = nodes[ iNode ];
5165           if ( isVolume ) {
5166             if ( !volume.IsLinked( n, prevSideNode ))
5167               continue;
5168           }
5169           else {
5170             if ( iNode ) // a node before prevSideNode
5171               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
5172             else         // a node after prevSideNode
5173               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
5174           }
5175           // check if this link was already used
5176           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
5177           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
5178           if (!isJustChecked &&
5179               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() ) {
5180             // test a link geometrically
5181             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
5182             bool linkIsBetter = false;
5183             double dot, dist;
5184             if ( searchByDir ) { // choose most co-directed link
5185               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
5186               linkIsBetter = ( dot > maxDot );
5187             }
5188             else { // choose link with the node closest to bordPos
5189               dist = ( nextXYZ - bordPos ).SquareModulus();
5190               linkIsBetter = ( dist < minDist );
5191             }
5192             if ( linkIsBetter ) {
5193               maxDot = dot;
5194               minDist = dist;
5195               linkID = iLink;
5196               sideNode = n;
5197               sideElem = elem;
5198             }
5199           }
5200         }
5201       } // loop on inverse elements of prevSideNode
5202
5203       if ( !sideNode ) {
5204         MESSAGE(" Cant find path by links of the Side 2 ");
5205         return SEW_BAD_SIDE_NODES;
5206       }
5207       sideNodes.push_back( sideNode );
5208       sideElems.push_back( sideElem );
5209       foundSideLinkIDs.insert ( linkID );
5210       prevSideNode = sideNode;
5211
5212       if ( *nBordIt == theBordLastNode )
5213         searchByDir = false;
5214       else {
5215         // find the next border link to compare with
5216         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
5217         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
5218         while ( *nBordIt != theBordLastNode && !searchByDir ) {
5219           prevBordNode = *nBordIt;
5220           nBordIt++;
5221           bordPos = nBordXYZ[ *nBordIt ];
5222           bordDir = bordPos - nBordXYZ[ prevBordNode ];
5223           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
5224         }
5225       }
5226     }
5227     while ( sideNode != theSideSecondNode );
5228
5229     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
5230       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
5231       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
5232     }
5233   } // end nodes search on the side 2
5234
5235   // ============================
5236   // sew the border to the side 2
5237   // ============================
5238
5239   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
5240   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
5241
5242   TListOfListOfNodes nodeGroupsToMerge;
5243   if ( nbNodes[0] == nbNodes[1] ||
5244       ( theSideIsFreeBorder && !theSideThirdNode)) {
5245
5246     // all nodes are to be merged
5247
5248     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
5249          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
5250          nIt[0]++, nIt[1]++ )
5251     {
5252       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
5253       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
5254       nodeGroupsToMerge.back().push_back( *nIt[0] ); // tp remove
5255     }
5256   }
5257   else {
5258
5259     // insert new nodes into the border and the side to get equal nb of segments
5260
5261     // get normalized parameters of nodes on the borders
5262     double param[ 2 ][ maxNbNodes ];
5263     int iNode, iBord;
5264     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
5265       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
5266       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
5267       const SMDS_MeshNode* nPrev = *nIt;
5268       double bordLength = 0;
5269       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
5270         const SMDS_MeshNode* nCur = *nIt;
5271         gp_XYZ segment (nCur->X() - nPrev->X(),
5272                         nCur->Y() - nPrev->Y(),
5273                         nCur->Z() - nPrev->Z());
5274         double segmentLen = segment.Modulus();
5275         bordLength += segmentLen;
5276         param[ iBord ][ iNode ] = bordLength;
5277         nPrev = nCur;
5278       }
5279       // normalize within [0,1]
5280       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
5281         param[ iBord ][ iNode ] /= bordLength;
5282       }
5283     }
5284
5285     // loop on border segments
5286     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
5287     int i[ 2 ] = { 0, 0 };
5288     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
5289     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
5290
5291     TElemOfNodeListMap insertMap;
5292     TElemOfNodeListMap::iterator insertMapIt;
5293     // insertMap is
5294     // key:   elem to insert nodes into
5295     // value: 2 nodes to insert between + nodes to be inserted
5296     do {
5297       bool next[ 2 ] = { false, false };
5298
5299       // find min adjacent segment length after sewing
5300       double nextParam = 10., prevParam = 0;
5301       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
5302         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
5303           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
5304         if ( i[ iBord ] > 0 )
5305           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
5306       }
5307       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
5308       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
5309       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
5310
5311       // choose to insert or to merge nodes
5312       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
5313       if ( Abs( du ) <= minSegLen * 0.2 ) {
5314         // merge
5315         // ------
5316         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
5317         const SMDS_MeshNode* n0 = *nIt[0];
5318         const SMDS_MeshNode* n1 = *nIt[1];
5319         nodeGroupsToMerge.back().push_back( n1 );
5320         nodeGroupsToMerge.back().push_back( n0 );
5321         // position of node of the border changes due to merge
5322         param[ 0 ][ i[0] ] += du;
5323         // move n1 for the sake of elem shape evaluation during insertion.
5324         // n1 will be removed by MergeNodes() anyway
5325         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
5326         next[0] = next[1] = true;
5327       }
5328       else {
5329         // insert
5330         // ------
5331         int intoBord = ( du < 0 ) ? 0 : 1;
5332         const SMDS_MeshElement* elem = *eIt[ intoBord ];
5333         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
5334         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
5335         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
5336         if ( intoBord == 1 ) {
5337           // move node of the border to be on a link of elem of the side
5338           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
5339           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
5340           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
5341           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
5342           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
5343         }
5344         insertMapIt = insertMap.find( elem );
5345         bool notFound = ( insertMapIt == insertMap.end() );
5346         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
5347         if ( otherLink ) {
5348           // insert into another link of the same element:
5349           // 1. perform insertion into the other link of the elem
5350           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
5351           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
5352           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
5353           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
5354           // 2. perform insertion into the link of adjacent faces
5355           while (true) {
5356             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
5357             if ( adjElem )
5358               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
5359             else
5360               break;
5361           }
5362           if (toCreatePolyedrs) {
5363             // perform insertion into the links of adjacent volumes
5364             UpdateVolumes(n12, n22, nodeList);
5365           }
5366           // 3. find an element appeared on n1 and n2 after the insertion
5367           insertMap.erase( elem );
5368           elem = findAdjacentFace( n1, n2, 0 );
5369         }
5370         if ( notFound || otherLink ) {
5371           // add element and nodes of the side into the insertMap
5372           insertMapIt = insertMap.insert
5373             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
5374           (*insertMapIt).second.push_back( n1 );
5375           (*insertMapIt).second.push_back( n2 );
5376         }
5377         // add node to be inserted into elem
5378         (*insertMapIt).second.push_back( nIns );
5379         next[ 1 - intoBord ] = true;
5380       }
5381
5382       // go to the next segment
5383       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
5384         if ( next[ iBord ] ) {
5385           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
5386             eIt[ iBord ]++;
5387           nPrev[ iBord ] = *nIt[ iBord ];
5388           nIt[ iBord ]++; i[ iBord ]++;
5389         }
5390       }
5391     }
5392     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
5393
5394     // perform insertion of nodes into elements
5395
5396     for (insertMapIt = insertMap.begin();
5397          insertMapIt != insertMap.end();
5398          insertMapIt++ )
5399     {
5400       const SMDS_MeshElement* elem = (*insertMapIt).first;
5401       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
5402       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
5403       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
5404
5405       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
5406
5407       if ( !theSideIsFreeBorder ) {
5408         // look for and insert nodes into the faces adjacent to elem
5409         while (true) {
5410           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
5411           if ( adjElem )
5412             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
5413           else
5414             break;
5415         }
5416       }
5417       if (toCreatePolyedrs) {
5418         // perform insertion into the links of adjacent volumes
5419         UpdateVolumes(n1, n2, nodeList);
5420       }
5421     }
5422
5423   } // end: insert new nodes
5424
5425   MergeNodes ( nodeGroupsToMerge );
5426
5427   return aResult;
5428 }
5429
5430 //=======================================================================
5431 //function : InsertNodesIntoLink
5432 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
5433 //           and theBetweenNode2 and split theElement
5434 //=======================================================================
5435
5436 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
5437                                            const SMDS_MeshNode*        theBetweenNode1,
5438                                            const SMDS_MeshNode*        theBetweenNode2,
5439                                            list<const SMDS_MeshNode*>& theNodesToInsert,
5440                                            const bool                  toCreatePoly)
5441 {
5442   if ( theFace->GetType() != SMDSAbs_Face ) return;
5443
5444   // find indices of 2 link nodes and of the rest nodes
5445   int iNode = 0, il1, il2, i3, i4;
5446   il1 = il2 = i3 = i4 = -1;
5447   const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
5448
5449   if(theFace->IsQuadratic()) {
5450     const SMDS_QuadraticFaceOfNodes* F =
5451       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
5452     // use special nodes iterator
5453     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5454     while( anIter->more() ) {
5455       const SMDS_MeshNode* n = anIter->next();
5456       if ( n == theBetweenNode1 )
5457         il1 = iNode;
5458       else if ( n == theBetweenNode2 )
5459         il2 = iNode;
5460       else if ( i3 < 0 )
5461         i3 = iNode;
5462       else
5463         i4 = iNode;
5464       nodes[ iNode++ ] = n;
5465     }
5466   }
5467   else {
5468     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
5469     while ( nodeIt->more() ) {
5470       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
5471       if ( n == theBetweenNode1 )
5472         il1 = iNode;
5473       else if ( n == theBetweenNode2 )
5474         il2 = iNode;
5475       else if ( i3 < 0 )
5476         i3 = iNode;
5477       else
5478         i4 = iNode;
5479       nodes[ iNode++ ] = n;
5480     }
5481   }
5482   if ( il1 < 0 || il2 < 0 || i3 < 0 )
5483     return ;
5484
5485   // arrange link nodes to go one after another regarding the face orientation
5486   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
5487   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
5488   if ( reverse ) {
5489     iNode = il1;
5490     il1 = il2;
5491     il2 = iNode;
5492     aNodesToInsert.reverse();
5493   }
5494   // check that not link nodes of a quadrangles are in good order
5495   int nbFaceNodes = theFace->NbNodes();
5496   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
5497     iNode = i3;
5498     i3 = i4;
5499     i4 = iNode;
5500   }
5501
5502   if (toCreatePoly || theFace->IsPoly()) {
5503
5504     iNode = 0;
5505     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
5506
5507     // add nodes of face up to first node of link
5508     bool isFLN = false;
5509
5510     if(theFace->IsQuadratic()) {
5511       const SMDS_QuadraticFaceOfNodes* F =
5512         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
5513       // use special nodes iterator
5514       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5515       while( anIter->more()  && !isFLN ) {
5516         const SMDS_MeshNode* n = anIter->next();
5517         poly_nodes[iNode++] = n;
5518         if (n == nodes[il1]) {
5519           isFLN = true;
5520         }
5521       }
5522       // add nodes to insert
5523       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
5524       for (; nIt != aNodesToInsert.end(); nIt++) {
5525         poly_nodes[iNode++] = *nIt;
5526       }
5527       // add nodes of face starting from last node of link
5528       while ( anIter->more() ) {
5529         poly_nodes[iNode++] = anIter->next();
5530       }
5531     }
5532     else {
5533       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
5534       while ( nodeIt->more() && !isFLN ) {
5535         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
5536         poly_nodes[iNode++] = n;
5537         if (n == nodes[il1]) {
5538           isFLN = true;
5539         }
5540       }
5541       // add nodes to insert
5542       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
5543       for (; nIt != aNodesToInsert.end(); nIt++) {
5544         poly_nodes[iNode++] = *nIt;
5545       }
5546       // add nodes of face starting from last node of link
5547       while ( nodeIt->more() ) {
5548         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
5549         poly_nodes[iNode++] = n;
5550       }
5551     }
5552
5553     // edit or replace the face
5554     SMESHDS_Mesh *aMesh = GetMeshDS();
5555
5556     if (theFace->IsPoly()) {
5557       aMesh->ChangePolygonNodes(theFace, poly_nodes);
5558     }
5559     else {
5560       int aShapeId = FindShape( theFace );
5561
5562       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5563       if ( aShapeId && newElem )
5564         aMesh->SetMeshElementOnShape( newElem, aShapeId );
5565
5566       aMesh->RemoveElement(theFace);
5567     }
5568     return;
5569   }
5570
5571   if( !theFace->IsQuadratic() ) {
5572
5573     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
5574     int nbLinkNodes = 2 + aNodesToInsert.size();
5575     const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
5576     linkNodes[ 0 ] = nodes[ il1 ];
5577     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
5578     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
5579     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
5580       linkNodes[ iNode++ ] = *nIt;
5581     }
5582     // decide how to split a quadrangle: compare possible variants
5583     // and choose which of splits to be a quadrangle
5584     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
5585     if ( nbFaceNodes == 3 ) {
5586       iBestQuad = nbSplits;
5587       i4 = i3;
5588     }
5589     else if ( nbFaceNodes == 4 ) {
5590       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
5591       double aBestRate = DBL_MAX;
5592       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
5593         i1 = 0; i2 = 1;
5594         double aBadRate = 0;
5595         // evaluate elements quality
5596         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
5597           if ( iSplit == iQuad ) {
5598             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
5599                                    linkNodes[ i2++ ],
5600                                    nodes[ i3 ],
5601                                    nodes[ i4 ]);
5602             aBadRate += getBadRate( &quad, aCrit );
5603           }
5604           else {
5605             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
5606                                    linkNodes[ i2++ ],
5607                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
5608             aBadRate += getBadRate( &tria, aCrit );
5609           }
5610         }
5611         // choice
5612         if ( aBadRate < aBestRate ) {
5613           iBestQuad = iQuad;
5614           aBestRate = aBadRate;
5615         }
5616       }
5617     }
5618     
5619     // create new elements
5620     SMESHDS_Mesh *aMesh = GetMeshDS();
5621     int aShapeId = FindShape( theFace );
5622     
5623     i1 = 0; i2 = 1;
5624     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
5625       SMDS_MeshElement* newElem = 0;
5626       if ( iSplit == iBestQuad )
5627         newElem = aMesh->AddFace (linkNodes[ i1++ ],
5628                                   linkNodes[ i2++ ],
5629                                   nodes[ i3 ],
5630                                   nodes[ i4 ]);
5631       else
5632         newElem = aMesh->AddFace (linkNodes[ i1++ ],
5633                                   linkNodes[ i2++ ],
5634                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
5635       if ( aShapeId && newElem )
5636         aMesh->SetMeshElementOnShape( newElem, aShapeId );
5637     }
5638     
5639     // change nodes of theFace
5640     const SMDS_MeshNode* newNodes[ 4 ];
5641     newNodes[ 0 ] = linkNodes[ i1 ];
5642     newNodes[ 1 ] = linkNodes[ i2 ];
5643     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
5644     newNodes[ 3 ] = nodes[ i4 ];
5645     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
5646   } // end if(!theFace->IsQuadratic())
5647   else { // theFace is quadratic
5648     // we have to split theFace on simple triangles and one simple quadrangle
5649     int tmp = il1/2;
5650     int nbshift = tmp*2;
5651     // shift nodes in nodes[] by nbshift
5652     int i,j;
5653     for(i=0; i<nbshift; i++) {
5654       const SMDS_MeshNode* n = nodes[0];
5655       for(j=0; j<nbFaceNodes-1; j++) {
5656         nodes[j] = nodes[j+1];
5657       }
5658       nodes[nbFaceNodes-1] = n;
5659     }
5660     il1 = il1 - nbshift;
5661     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
5662     //   n0      n1     n2    n0      n1     n2
5663     //     +-----+-----+        +-----+-----+ 
5664     //      \         /         |           |
5665     //       \       /          |           |
5666     //      n5+     +n3       n7+           +n3
5667     //         \   /            |           |
5668     //          \ /             |           |
5669     //           +              +-----+-----+
5670     //           n4           n6      n5     n4
5671
5672     // create new elements
5673     SMESHDS_Mesh *aMesh = GetMeshDS();
5674     int aShapeId = FindShape( theFace );
5675
5676     int n1,n2,n3;
5677     if(nbFaceNodes==6) { // quadratic triangle
5678       SMDS_MeshElement* newElem =
5679         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
5680       if ( aShapeId && newElem )
5681         aMesh->SetMeshElementOnShape( newElem, aShapeId );
5682       if(theFace->IsMediumNode(nodes[il1])) {
5683         // create quadrangle
5684         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
5685         if ( aShapeId && newElem )
5686           aMesh->SetMeshElementOnShape( newElem, aShapeId );
5687         n1 = 1;
5688         n2 = 2;
5689         n3 = 3;
5690       }
5691       else {
5692         // create quadrangle
5693         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
5694         if ( aShapeId && newElem )
5695           aMesh->SetMeshElementOnShape( newElem, aShapeId );
5696         n1 = 0;
5697         n2 = 1;
5698         n3 = 5;
5699       }
5700     }
5701     else { // nbFaceNodes==8 - quadratic quadrangle
5702       SMDS_MeshElement* newElem =
5703         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
5704       if ( aShapeId && newElem )
5705         aMesh->SetMeshElementOnShape( newElem, aShapeId );
5706       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
5707       if ( aShapeId && newElem )
5708         aMesh->SetMeshElementOnShape( newElem, aShapeId );
5709       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
5710       if ( aShapeId && newElem )
5711         aMesh->SetMeshElementOnShape( newElem, aShapeId );
5712       if(theFace->IsMediumNode(nodes[il1])) {
5713         // create quadrangle
5714         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
5715         if ( aShapeId && newElem )
5716           aMesh->SetMeshElementOnShape( newElem, aShapeId );
5717         n1 = 1;
5718         n2 = 2;
5719         n3 = 3;
5720       }
5721       else {
5722         // create quadrangle
5723         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
5724         if ( aShapeId && newElem )
5725           aMesh->SetMeshElementOnShape( newElem, aShapeId );
5726         n1 = 0;
5727         n2 = 1;
5728         n3 = 7;
5729       }
5730     }
5731     // create needed triangles using n1,n2,n3 and inserted nodes
5732     int nbn = 2 + aNodesToInsert.size();
5733     const SMDS_MeshNode* aNodes[nbn];
5734     aNodes[0] = nodes[n1];
5735     aNodes[nbn-1] = nodes[n2];
5736     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
5737     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
5738       aNodes[iNode++] = *nIt;
5739     }
5740     for(i=1; i<nbn; i++) {
5741       SMDS_MeshElement* newElem =
5742         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
5743       if ( aShapeId && newElem )
5744         aMesh->SetMeshElementOnShape( newElem, aShapeId );
5745     }
5746     // remove old quadratic face
5747     aMesh->RemoveElement(theFace);
5748   }
5749 }
5750
5751 //=======================================================================
5752 //function : UpdateVolumes
5753 //purpose  :
5754 //=======================================================================
5755 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
5756                                       const SMDS_MeshNode*        theBetweenNode2,
5757                                       list<const SMDS_MeshNode*>& theNodesToInsert)
5758 {
5759   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator();
5760   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
5761     const SMDS_MeshElement* elem = invElemIt->next();
5762     if (elem->GetType() != SMDSAbs_Volume)
5763       continue;
5764
5765     // check, if current volume has link theBetweenNode1 - theBetweenNode2
5766     SMDS_VolumeTool aVolume (elem);
5767     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
5768       continue;
5769
5770     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
5771     int iface, nbFaces = aVolume.NbFaces();
5772     vector<const SMDS_MeshNode *> poly_nodes;
5773     vector<int> quantities (nbFaces);
5774
5775     for (iface = 0; iface < nbFaces; iface++) {
5776       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
5777       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
5778       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
5779
5780       for (int inode = 0; inode < nbFaceNodes; inode++) {
5781         poly_nodes.push_back(faceNodes[inode]);
5782
5783         if (nbInserted == 0) {
5784           if (faceNodes[inode] == theBetweenNode1) {
5785             if (faceNodes[inode + 1] == theBetweenNode2) {
5786               nbInserted = theNodesToInsert.size();
5787
5788               // add nodes to insert
5789               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
5790               for (; nIt != theNodesToInsert.end(); nIt++) {
5791                 poly_nodes.push_back(*nIt);
5792               }
5793             }
5794           }
5795           else if (faceNodes[inode] == theBetweenNode2) {
5796             if (faceNodes[inode + 1] == theBetweenNode1) {
5797               nbInserted = theNodesToInsert.size();
5798
5799               // add nodes to insert in reversed order
5800               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
5801               nIt--;
5802               for (; nIt != theNodesToInsert.begin(); nIt--) {
5803                 poly_nodes.push_back(*nIt);
5804               }
5805               poly_nodes.push_back(*nIt);
5806             }
5807           }
5808           else {
5809           }
5810         }
5811       }
5812       quantities[iface] = nbFaceNodes + nbInserted;
5813     }
5814
5815     // Replace or update the volume
5816     SMESHDS_Mesh *aMesh = GetMeshDS();
5817
5818     if (elem->IsPoly()) {
5819       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5820
5821     }
5822     else {
5823       int aShapeId = FindShape( elem );
5824
5825       SMDS_MeshElement* newElem =
5826         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
5827       if (aShapeId && newElem)
5828         aMesh->SetMeshElementOnShape(newElem, aShapeId);
5829
5830       aMesh->RemoveElement(elem);
5831     }
5832   }
5833 }
5834
5835 //=======================================================================
5836 //function : ConvertElemToQuadratic
5837 //purpose  :
5838 //=======================================================================
5839 void SMESH_MeshEditor::ConvertElemToQuadratic(SMESHDS_SubMesh *theSm,
5840                                               SMESH_MesherHelper* theHelper,
5841                                               const bool theForce3d)
5842 {
5843   if( !theSm ) return;
5844   SMESHDS_Mesh* meshDS = GetMeshDS();
5845   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
5846   while(ElemItr->more())
5847   {
5848     const SMDS_MeshElement* elem = ElemItr->next();
5849     if( !elem ) continue;
5850
5851     int id = elem->GetID();
5852     int nbNodes = elem->NbNodes();
5853     vector<const SMDS_MeshNode *> aNds (nbNodes);
5854     
5855     for(int i = 0; i < nbNodes; i++)
5856     {
5857       aNds[i] = elem->GetNode(i);
5858     }
5859
5860     SMDSAbs_ElementType aType = elem->GetType();
5861     const SMDS_MeshElement* NewElem = 0;
5862
5863     switch( aType )
5864     {
5865     case SMDSAbs_Edge :
5866     {
5867       meshDS->RemoveFreeElement(elem, theSm);   
5868       NewElem = theHelper->AddQuadraticEdge(aNds[0], aNds[1], id, theForce3d);
5869       break;
5870     }
5871     case SMDSAbs_Face :
5872     {
5873       if(elem->IsQuadratic()) continue;
5874
5875       meshDS->RemoveFreeElement(elem, theSm);
5876       switch(nbNodes)
5877       {
5878       case 3:
5879         NewElem = theHelper->AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
5880         break;
5881       case 4:
5882         NewElem = theHelper->AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
5883         break;
5884       default:
5885         continue;
5886       }
5887       break;  
5888     }
5889     case SMDSAbs_Volume :
5890     {
5891       if( elem->IsQuadratic() ) continue;
5892
5893       meshDS->RemoveFreeElement(elem, theSm);
5894       switch(nbNodes)
5895       {
5896       case 4:
5897         NewElem = theHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, true);
5898         break;
5899       case 6:
5900         NewElem = theHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, true);
5901         break;
5902       case 8:
5903         NewElem = theHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
5904                                        aNds[4], aNds[5], aNds[6], aNds[7], id, true);
5905         break;
5906       default:
5907         continue;
5908       }
5909       break;  
5910     }
5911     default :
5912       continue;
5913     }
5914     if( NewElem )
5915     {
5916       AddToSameGroups( NewElem, elem, meshDS);
5917       theSm->AddElement( NewElem );
5918     }
5919   }
5920 }
5921
5922 //=======================================================================
5923 //function : ConvertToQuadratic
5924 //purpose  :
5925 //=======================================================================
5926 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
5927 {
5928   SMESHDS_Mesh* meshDS = GetMeshDS();
5929
5930   SMESH_MesherHelper* aHelper = new SMESH_MesherHelper(*myMesh);
5931   const TopoDS_Shape& aShape = meshDS->ShapeToMesh();
5932
5933   if ( !aShape.IsNull() && GetMesh()->GetSubMeshContaining(aShape) )
5934   {
5935     SMESH_subMesh *aSubMesh = GetMesh()->GetSubMeshContaining(aShape);
5936     
5937     const map < int, SMESH_subMesh * >& aMapSM = aSubMesh->DependsOn();
5938     map < int, SMESH_subMesh * >::const_iterator itsub;
5939     for (itsub = aMapSM.begin(); itsub != aMapSM.end(); itsub++)
5940     {
5941       SMESHDS_SubMesh *sm = ((*itsub).second)->GetSubMeshDS();
5942       aHelper->SetSubShape( (*itsub).second->GetSubShape() );
5943       ConvertElemToQuadratic(sm, aHelper, theForce3d);
5944     }
5945     aHelper->SetSubShape( aSubMesh->GetSubShape() );
5946     ConvertElemToQuadratic(aSubMesh->GetSubMeshDS(), aHelper, theForce3d);
5947   }
5948   else
5949   {
5950     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
5951     while(aEdgeItr->more())
5952     {
5953       const SMDS_MeshEdge* edge = aEdgeItr->next();
5954       if(edge)
5955       {
5956         int id = edge->GetID();
5957         const SMDS_MeshNode* n1 = edge->GetNode(0);
5958         const SMDS_MeshNode* n2 = edge->GetNode(1);
5959
5960         RemoveElemFromGroups (edge, meshDS);
5961         meshDS->SMDS_Mesh::RemoveFreeElement(edge);
5962
5963         const SMDS_QuadraticEdge* NewEdge = aHelper->AddQuadraticEdge(n1, n2, id, theForce3d);
5964         AddToSameGroups(NewEdge, edge, meshDS);
5965       }
5966     }
5967     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
5968     while(aFaceItr->more())
5969     {
5970       const SMDS_MeshFace* face = aFaceItr->next();
5971       if(!face || face->IsQuadratic() ) continue;
5972       
5973       int id = face->GetID();
5974       int nbNodes = face->NbNodes();
5975       vector<const SMDS_MeshNode *> aNds (nbNodes);
5976
5977       for(int i = 0; i < nbNodes; i++)
5978       {
5979         aNds[i] = face->GetNode(i);
5980       }
5981
5982       RemoveElemFromGroups (face, meshDS); 
5983       meshDS->SMDS_Mesh::RemoveFreeElement(face);
5984
5985       SMDS_MeshFace * NewFace = 0;
5986       switch(nbNodes)
5987       {
5988       case 3:
5989         NewFace = aHelper->AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
5990         break;
5991       case 4:
5992         NewFace = aHelper->AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
5993         break;
5994       default:
5995         continue;
5996       }
5997       AddToSameGroups(NewFace, face, meshDS);
5998     }
5999     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
6000     while(aVolumeItr->more())
6001     {
6002       const SMDS_MeshVolume* volume = aVolumeItr->next();
6003       if(!volume || volume->IsQuadratic() ) continue;
6004       
6005       int id = volume->GetID();
6006       int nbNodes = volume->NbNodes();
6007       vector<const SMDS_MeshNode *> aNds (nbNodes);
6008
6009       for(int i = 0; i < nbNodes; i++)
6010       {
6011         aNds[i] = volume->GetNode(i);
6012       }
6013
6014       RemoveElemFromGroups (volume, meshDS);
6015       meshDS->SMDS_Mesh::RemoveFreeElement(volume);
6016
6017       SMDS_MeshVolume * NewVolume = 0;
6018       switch(nbNodes)
6019       {
6020       case 4:
6021         NewVolume = aHelper->AddVolume(aNds[0], aNds[1], aNds[2],
6022                                        aNds[3], id, true );
6023         break;
6024       case 6:
6025         NewVolume = aHelper->AddVolume(aNds[0], aNds[1], aNds[2],
6026                                        aNds[3], aNds[4], aNds[5], id, true);
6027         break;
6028       case 8:
6029         NewVolume = aHelper->AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
6030                                        aNds[4], aNds[5], aNds[6], aNds[7], id, true);
6031         break;
6032       default:
6033         continue;
6034       }
6035       AddToSameGroups(NewVolume, volume, meshDS);
6036     }
6037   }
6038   delete aHelper;
6039 }
6040
6041 //=======================================================================
6042 //function : RemoveQuadElem
6043 //purpose  :
6044 //=======================================================================
6045 void SMESH_MeshEditor::RemoveQuadElem(SMESHDS_SubMesh *theSm, 
6046                                       SMDS_ElemIteratorPtr theItr)
6047 {
6048   SMESHDS_Mesh* meshDS = GetMeshDS();
6049   while( theItr->more() )
6050   {
6051     const SMDS_MeshElement* elem = theItr->next();
6052     if( elem )
6053     {
6054       if( !elem->IsQuadratic() )
6055         continue;
6056       
6057       int id = elem->GetID();
6058
6059       int nbNodes = elem->NbNodes(), idx = 0;
6060       vector<const SMDS_MeshNode *> aNds; 
6061       vector<const SMDS_MeshNode *> aQuadNds; 
6062
6063       //remove all quadratic nodes 
6064       for(int i = 0; i < nbNodes; i++)
6065       {
6066         const SMDS_MeshNode* n = elem->GetNode(i);
6067
6068         if( elem->IsMediumNode( n ) )
6069         {
6070           aQuadNds.push_back( n );
6071           /*  ItRemoveQuadNodeMap itRNM = myRemoveNodeMap.find( n );
6072             if( itRNM == myRemoveNodeMap.end() )
6073             {
6074               aQuadNds.push_back( n );
6075               myRemoveNodeMap.insert(RemoveQuadNodeMap::value_type( n,theSm ));
6076               }*/
6077         }
6078         else 
6079           aNds.push_back( n );
6080       }
6081
6082       idx = aNds.size();
6083       if( !idx ) continue;
6084       SMDSAbs_ElementType aType = elem->GetType();      
6085
6086       //remove old quadratic elements
6087       meshDS->RemoveFreeElement( elem, theSm );
6088
6089       for( int j = 0; j < aQuadNds.size(); j++ )
6090       {
6091         meshDS->RemoveFreeNode( aQuadNds[j], theSm );   
6092       }
6093       SMDS_MeshElement * NewElem = 0;
6094       switch(aType)
6095       {
6096         case SMDSAbs_Edge:
6097           NewElem = meshDS->AddEdgeWithID( aNds[0], aNds[1] ,id );
6098           break;
6099         case SMDSAbs_Face:
6100           if( idx==3 ) NewElem = meshDS->AddFaceWithID( aNds[0],
6101                                    aNds[1], aNds[2], id );
6102           if( idx==4 ) NewElem = meshDS->AddFaceWithID( aNds[0],
6103                                    aNds[1], aNds[2], aNds[3],id );
6104           break;
6105         case SMDSAbs_Volume:
6106           if( idx==4 ) NewElem = meshDS->AddVolumeWithID( aNds[0],
6107                                    aNds[1], aNds[2], aNds[3], id );
6108           if( idx==6 ) NewElem = meshDS->AddVolumeWithID( aNds[0],
6109                                    aNds[1], aNds[2], aNds[3],
6110                                    aNds[4], aNds[5], id );
6111           if( idx==8 ) NewElem = meshDS->AddVolumeWithID(aNds[0],
6112                                    aNds[1], aNds[2], aNds[3],
6113                                    aNds[4], aNds[5], aNds[6],
6114                                    aNds[7] ,id );
6115           break;
6116         default:
6117           break;
6118       }
6119
6120       AddToSameGroups(NewElem, elem, meshDS);
6121       if( theSm )
6122         theSm->AddElement( NewElem );
6123     }
6124   }
6125 }
6126 //=======================================================================
6127 //function : ConvertFromQuadratic
6128 //purpose  :
6129 //=======================================================================
6130 bool  SMESH_MeshEditor::ConvertFromQuadratic()
6131 {
6132   SMESHDS_Mesh* meshDS = GetMeshDS();
6133   //  myRemoveNodeMap.clear();
6134
6135   const TopoDS_Shape& aShape = meshDS->ShapeToMesh();
6136
6137   if ( !aShape.IsNull() && GetMesh()->GetSubMeshContaining(aShape) )
6138   {
6139     SMESH_subMesh *aSubMesh = GetMesh()->GetSubMeshContaining(aShape);
6140     
6141     const map < int, SMESH_subMesh * >& aMapSM = aSubMesh->DependsOn();
6142     map < int, SMESH_subMesh * >::const_iterator itsub;
6143     for (itsub = aMapSM.begin(); itsub != aMapSM.end(); itsub++)
6144     {
6145       SMESHDS_SubMesh *sm = ((*itsub).second)->GetSubMeshDS();
6146       if( sm )
6147         RemoveQuadElem( sm, sm->GetElements() );
6148     }
6149     SMESHDS_SubMesh *Sm = aSubMesh->GetSubMeshDS();
6150     if( Sm )
6151       RemoveQuadElem( Sm, Sm->GetElements() );
6152   }
6153   else
6154   {
6155     SMESHDS_SubMesh *aSM = 0;
6156     RemoveQuadElem( aSM, meshDS->elementsIterator() );
6157   }
6158
6159   /*  ItRemoveQuadNodeMap itRNM = myRemoveNodeMap.begin();
6160   for ( ; itRNM != myRemoveNodeMap.end(); itRNM++ ) {
6161   {
6162     meshDS->RemoveFreeNode( (*itRNM), (*itRNM).second  );       
6163     }*/
6164
6165   return true;
6166 }
6167
6168 //=======================================================================
6169 //function : SewSideElements
6170 //purpose  :
6171 //=======================================================================
6172
6173 SMESH_MeshEditor::Sew_Error
6174   SMESH_MeshEditor::SewSideElements (set<const SMDS_MeshElement*>& theSide1,
6175                                      set<const SMDS_MeshElement*>& theSide2,
6176                                      const SMDS_MeshNode*          theFirstNode1,
6177                                      const SMDS_MeshNode*          theFirstNode2,
6178                                      const SMDS_MeshNode*          theSecondNode1,
6179                                      const SMDS_MeshNode*          theSecondNode2)
6180 {
6181   MESSAGE ("::::SewSideElements()");
6182   if ( theSide1.size() != theSide2.size() )
6183     return SEW_DIFF_NB_OF_ELEMENTS;
6184
6185   Sew_Error aResult = SEW_OK;
6186   // Algo:
6187   // 1. Build set of faces representing each side
6188   // 2. Find which nodes of the side 1 to merge with ones on the side 2
6189   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
6190
6191   // =======================================================================
6192   // 1. Build set of faces representing each side:
6193   // =======================================================================
6194   // a. build set of nodes belonging to faces
6195   // b. complete set of faces: find missing fices whose nodes are in set of nodes
6196   // c. create temporary faces representing side of volumes if correspondent
6197   //    face does not exist
6198
6199   SMESHDS_Mesh* aMesh = GetMeshDS();
6200   SMDS_Mesh aTmpFacesMesh;
6201   set<const SMDS_MeshElement*> faceSet1, faceSet2;
6202   set<const SMDS_MeshElement*> volSet1,  volSet2;
6203   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
6204   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
6205   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
6206   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
6207   set<const SMDS_MeshElement*> * elemSetPtr[] = { &theSide1, &theSide2 };
6208   int iSide, iFace, iNode;
6209
6210   for ( iSide = 0; iSide < 2; iSide++ ) {
6211     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
6212     set<const SMDS_MeshElement*> * elemSet = elemSetPtr[ iSide ];
6213     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
6214     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
6215     set<const SMDS_MeshElement*>::iterator vIt, eIt;
6216     set<const SMDS_MeshNode*>::iterator    nIt;
6217
6218     // check that given nodes belong to given elements
6219     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
6220     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
6221     int firstIndex = -1, secondIndex = -1;
6222     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
6223       const SMDS_MeshElement* elem = *eIt;
6224       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
6225       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
6226       if ( firstIndex > -1 && secondIndex > -1 ) break;
6227     }
6228     if ( firstIndex < 0 || secondIndex < 0 ) {
6229       // we can simply return until temporary faces created
6230       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
6231     }
6232
6233     // -----------------------------------------------------------
6234     // 1a. Collect nodes of existing faces
6235     //     and build set of face nodes in order to detect missing
6236     //     faces corresponing to sides of volumes
6237     // -----------------------------------------------------------
6238
6239     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
6240
6241     // loop on the given element of a side
6242     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
6243       const SMDS_MeshElement* elem = *eIt;
6244       if ( elem->GetType() == SMDSAbs_Face ) {
6245         faceSet->insert( elem );
6246         set <const SMDS_MeshNode*> faceNodeSet;
6247         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6248         while ( nodeIt->more() ) {
6249           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6250           nodeSet->insert( n );
6251           faceNodeSet.insert( n );
6252         }
6253         setOfFaceNodeSet.insert( faceNodeSet );
6254       }
6255       else if ( elem->GetType() == SMDSAbs_Volume )
6256         volSet->insert( elem );
6257     }
6258     // ------------------------------------------------------------------------------
6259     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
6260     // ------------------------------------------------------------------------------
6261
6262     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
6263       SMDS_ElemIteratorPtr fIt = (*nIt)->facesIterator();
6264       while ( fIt->more() ) { // loop on faces sharing a node
6265         const SMDS_MeshElement* f = fIt->next();
6266         if ( faceSet->find( f ) == faceSet->end() ) {
6267           // check if all nodes are in nodeSet and
6268           // complete setOfFaceNodeSet if they are
6269           set <const SMDS_MeshNode*> faceNodeSet;
6270           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
6271           bool allInSet = true;
6272           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
6273             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6274             if ( nodeSet->find( n ) == nodeSet->end() )
6275               allInSet = false;
6276             else
6277               faceNodeSet.insert( n );
6278           }
6279           if ( allInSet ) {
6280             faceSet->insert( f );
6281             setOfFaceNodeSet.insert( faceNodeSet );
6282           }
6283         }
6284       }
6285     }
6286
6287     // -------------------------------------------------------------------------
6288     // 1c. Create temporary faces representing sides of volumes if correspondent
6289     //     face does not exist
6290     // -------------------------------------------------------------------------
6291
6292     if ( !volSet->empty() ) {
6293       //int nodeSetSize = nodeSet->size();
6294
6295       // loop on given volumes
6296       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
6297         SMDS_VolumeTool vol (*vIt);
6298         // loop on volume faces: find free faces
6299         // --------------------------------------
6300         list<const SMDS_MeshElement* > freeFaceList;
6301         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
6302           if ( !vol.IsFreeFace( iFace ))
6303             continue;
6304           // check if there is already a face with same nodes in a face set
6305           const SMDS_MeshElement* aFreeFace = 0;
6306           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
6307           int nbNodes = vol.NbFaceNodes( iFace );
6308           set <const SMDS_MeshNode*> faceNodeSet;
6309           vol.GetFaceNodes( iFace, faceNodeSet );
6310           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
6311           if ( isNewFace ) {
6312             // no such a face is given but it still can exist, check it
6313             if ( nbNodes == 3 ) {
6314               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
6315             }
6316             else if ( nbNodes == 4 ) {
6317               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
6318             }
6319             else {
6320               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
6321               aFreeFace = aMesh->FindFace(poly_nodes);
6322             }
6323           }
6324           if ( !aFreeFace ) {
6325             // create a temporary face
6326             if ( nbNodes == 3 ) {
6327               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
6328             }
6329             else if ( nbNodes == 4 ) {
6330               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
6331             }
6332             else {
6333               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
6334               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
6335             }
6336           }
6337           if ( aFreeFace )
6338             freeFaceList.push_back( aFreeFace );
6339
6340         } // loop on faces of a volume
6341
6342         // choose one of several free faces
6343         // --------------------------------------
6344         if ( freeFaceList.size() > 1 ) {
6345           // choose a face having max nb of nodes shared by other elems of a side
6346           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
6347           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
6348           while ( fIt != freeFaceList.end() ) { // loop on free faces
6349             int nbSharedNodes = 0;
6350             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
6351             while ( nodeIt->more() ) { // loop on free face nodes
6352               const SMDS_MeshNode* n =
6353                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6354               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
6355               while ( invElemIt->more() ) {
6356                 const SMDS_MeshElement* e = invElemIt->next();
6357                 if ( faceSet->find( e ) != faceSet->end() )
6358                   nbSharedNodes++;
6359                 if ( elemSet->find( e ) != elemSet->end() )
6360                   nbSharedNodes++;
6361               }
6362             }
6363             if ( nbSharedNodes >= maxNbNodes ) {
6364               maxNbNodes = nbSharedNodes;
6365               fIt++;
6366             }
6367             else
6368               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
6369           }
6370           if ( freeFaceList.size() > 1 )
6371           {
6372             // could not choose one face, use another way
6373             // choose a face most close to the bary center of the opposite side
6374             gp_XYZ aBC( 0., 0., 0. );
6375             set <const SMDS_MeshNode*> addedNodes;
6376             set<const SMDS_MeshElement*> * elemSet2 = elemSetPtr[ 1 - iSide ];
6377             eIt = elemSet2->begin();
6378             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
6379               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
6380               while ( nodeIt->more() ) { // loop on free face nodes
6381                 const SMDS_MeshNode* n =
6382                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6383                 if ( addedNodes.insert( n ).second )
6384                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
6385               }
6386             }
6387             aBC /= addedNodes.size();
6388             double minDist = DBL_MAX;
6389             fIt = freeFaceList.begin();
6390             while ( fIt != freeFaceList.end() ) { // loop on free faces
6391               double dist = 0;
6392               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
6393               while ( nodeIt->more() ) { // loop on free face nodes
6394                 const SMDS_MeshNode* n =
6395                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6396                 gp_XYZ p( n->X(),n->Y(),n->Z() );
6397                 dist += ( aBC - p ).SquareModulus();
6398               }
6399               if ( dist < minDist ) {
6400                 minDist = dist;
6401                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
6402               }
6403               else
6404                 fIt = freeFaceList.erase( fIt++ );
6405             }
6406           }
6407         } // choose one of several free faces of a volume
6408
6409         if ( freeFaceList.size() == 1 ) {
6410           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
6411           faceSet->insert( aFreeFace );
6412           // complete a node set with nodes of a found free face
6413 //           for ( iNode = 0; iNode < ; iNode++ )
6414 //             nodeSet->insert( fNodes[ iNode ] );
6415         }
6416
6417       } // loop on volumes of a side
6418
6419 //       // complete a set of faces if new nodes in a nodeSet appeared
6420 //       // ----------------------------------------------------------
6421 //       if ( nodeSetSize != nodeSet->size() ) {
6422 //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
6423 //           SMDS_ElemIteratorPtr fIt = (*nIt)->facesIterator();
6424 //           while ( fIt->more() ) { // loop on faces sharing a node
6425 //             const SMDS_MeshElement* f = fIt->next();
6426 //             if ( faceSet->find( f ) == faceSet->end() ) {
6427 //               // check if all nodes are in nodeSet and
6428 //               // complete setOfFaceNodeSet if they are
6429 //               set <const SMDS_MeshNode*> faceNodeSet;
6430 //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
6431 //               bool allInSet = true;
6432 //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
6433 //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6434 //                 if ( nodeSet->find( n ) == nodeSet->end() )
6435 //                   allInSet = false;
6436 //                 else
6437 //                   faceNodeSet.insert( n );
6438 //               }
6439 //               if ( allInSet ) {
6440 //                 faceSet->insert( f );
6441 //                 setOfFaceNodeSet.insert( faceNodeSet );
6442 //               }
6443 //             }
6444 //           }
6445 //         }
6446 //       }
6447     } // Create temporary faces, if there are volumes given
6448   } // loop on sides
6449
6450   if ( faceSet1.size() != faceSet2.size() ) {
6451     // delete temporary faces: they are in reverseElements of actual nodes
6452     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
6453     while ( tmpFaceIt->more() )
6454       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
6455     MESSAGE("Diff nb of faces");
6456     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
6457   }
6458
6459   // ============================================================
6460   // 2. Find nodes to merge:
6461   //              bind a node to remove to a node to put instead
6462   // ============================================================
6463
6464   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
6465   if ( theFirstNode1 != theFirstNode2 )
6466     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
6467   if ( theSecondNode1 != theSecondNode2 )
6468     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
6469
6470   LinkID_Gen aLinkID_Gen( GetMeshDS() );
6471   set< long > linkIdSet; // links to process
6472   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
6473
6474   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > TPairOfNodes;
6475   list< TPairOfNodes > linkList[2];
6476   linkList[0].push_back( TPairOfNodes( theFirstNode1, theSecondNode1 ));
6477   linkList[1].push_back( TPairOfNodes( theFirstNode2, theSecondNode2 ));
6478   // loop on links in linkList; find faces by links and append links
6479   // of the found faces to linkList
6480   list< TPairOfNodes >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
6481   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
6482     TPairOfNodes link[] = { *linkIt[0], *linkIt[1] };
6483     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
6484     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
6485       continue;
6486
6487     // by links, find faces in the face sets,
6488     // and find indices of link nodes in the found faces;
6489     // in a face set, there is only one or no face sharing a link
6490     // ---------------------------------------------------------------
6491
6492     const SMDS_MeshElement* face[] = { 0, 0 };
6493     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
6494     vector<const SMDS_MeshNode*> fnodes1(9);
6495     vector<const SMDS_MeshNode*> fnodes2(9);
6496     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
6497     vector<const SMDS_MeshNode*> notLinkNodes1(6);
6498     vector<const SMDS_MeshNode*> notLinkNodes2(6);
6499     int iLinkNode[2][2];
6500     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
6501       const SMDS_MeshNode* n1 = link[iSide].first;
6502       const SMDS_MeshNode* n2 = link[iSide].second;
6503       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
6504       set< const SMDS_MeshElement* > fMap;
6505       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
6506         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
6507         SMDS_ElemIteratorPtr fIt = n->facesIterator();
6508         while ( fIt->more() ) { // loop on faces sharing a node
6509           const SMDS_MeshElement* f = fIt->next();
6510           if (faceSet->find( f ) != faceSet->end() && // f is in face set
6511               ! fMap.insert( f ).second ) // f encounters twice
6512           {
6513             if ( face[ iSide ] ) {
6514               MESSAGE( "2 faces per link " );
6515               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
6516               break;
6517             }
6518             face[ iSide ] = f;
6519             faceSet->erase( f );
6520             // get face nodes and find ones of a link
6521             iNode = 0;
6522             int nbl = -1;
6523             if(f->IsPoly()) {
6524               if(iSide==0) {
6525                 fnodes1.resize(f->NbNodes()+1);
6526                 notLinkNodes1.resize(f->NbNodes()-2);
6527               }
6528               else {
6529                 fnodes2.resize(f->NbNodes()+1);
6530                 notLinkNodes2.resize(f->NbNodes()-2);
6531               }
6532             }
6533             if(!f->IsQuadratic()) {
6534               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
6535               while ( nIt->more() ) {
6536                 const SMDS_MeshNode* n =
6537                   static_cast<const SMDS_MeshNode*>( nIt->next() );
6538                 if ( n == n1 ) {
6539                   iLinkNode[ iSide ][ 0 ] = iNode;
6540                 }
6541                 else if ( n == n2 ) {
6542                   iLinkNode[ iSide ][ 1 ] = iNode;
6543                 }
6544                 //else if ( notLinkNodes[ iSide ][ 0 ] )
6545                 //  notLinkNodes[ iSide ][ 1 ] = n;
6546                 //else
6547                 //  notLinkNodes[ iSide ][ 0 ] = n;
6548                 else {
6549                   nbl++;
6550                   if(iSide==0)
6551                     notLinkNodes1[nbl] = n;
6552                     //notLinkNodes1.push_back(n);
6553                   else
6554                     notLinkNodes2[nbl] = n;
6555                     //notLinkNodes2.push_back(n);
6556                 }
6557                 //faceNodes[ iSide ][ iNode++ ] = n;
6558                 if(iSide==0) {
6559                   fnodes1[iNode++] = n;
6560                 }
6561                 else {
6562                   fnodes2[iNode++] = n;
6563                 }
6564               }
6565             }
6566             else { // f->IsQuadratic()
6567               const SMDS_QuadraticFaceOfNodes* F =
6568                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
6569               // use special nodes iterator
6570               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6571               while ( anIter->more() ) {
6572                 const SMDS_MeshNode* n =
6573                   static_cast<const SMDS_MeshNode*>( anIter->next() );
6574                 if ( n == n1 ) {
6575                   iLinkNode[ iSide ][ 0 ] = iNode;
6576                 }
6577                 else if ( n == n2 ) {
6578                   iLinkNode[ iSide ][ 1 ] = iNode;
6579                 }
6580                 else {
6581                   nbl++;
6582                   if(iSide==0) {
6583                     notLinkNodes1[nbl] = n;
6584                   }
6585                   else {
6586                     notLinkNodes2[nbl] = n;
6587                   }
6588                 }
6589                 if(iSide==0) {
6590                   fnodes1[iNode++] = n;
6591                 }
6592                 else {
6593                   fnodes2[iNode++] = n;
6594                 }
6595               }
6596             }
6597             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
6598             if(iSide==0) {
6599               fnodes1[iNode] = fnodes1[0];
6600             }
6601             else {
6602               fnodes2[iNode] = fnodes1[0];
6603             }
6604           }
6605         }
6606       }
6607     }
6608
6609     // check similarity of elements of the sides
6610     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
6611       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
6612       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
6613         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
6614       }
6615       else {
6616         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
6617       }
6618       break; // do not return because it s necessary to remove tmp faces
6619     }
6620
6621     // set nodes to merge
6622     // -------------------
6623
6624     if ( face[0] && face[1] )  {
6625       int nbNodes = face[0]->NbNodes();
6626       if ( nbNodes != face[1]->NbNodes() ) {
6627         MESSAGE("Diff nb of face nodes");
6628         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
6629         break; // do not return because it s necessary to remove tmp faces
6630       }
6631       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
6632       if ( nbNodes == 3 ) {
6633         //nReplaceMap.insert( TNodeNodeMap::value_type
6634         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
6635         nReplaceMap.insert( TNodeNodeMap::value_type
6636                            ( notLinkNodes1[0], notLinkNodes2[0] ));
6637       }
6638       else {
6639         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
6640           // analyse link orientation in faces
6641           int i1 = iLinkNode[ iSide ][ 0 ];
6642           int i2 = iLinkNode[ iSide ][ 1 ];
6643           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
6644           // if notLinkNodes are the first and the last ones, then
6645           // their order does not correspond to the link orientation
6646           if (( i1 == 1 && i2 == 2 ) ||
6647               ( i1 == 2 && i2 == 1 ))
6648             reverse[ iSide ] = !reverse[ iSide ];
6649         }
6650         if ( reverse[0] == reverse[1] ) {
6651           //nReplaceMap.insert( TNodeNodeMap::value_type
6652           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
6653           //nReplaceMap.insert( TNodeNodeMap::value_type
6654           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
6655           for(int nn=0; nn<nbNodes-2; nn++) {
6656             nReplaceMap.insert( TNodeNodeMap::value_type
6657                              ( notLinkNodes1[nn], notLinkNodes2[nn] ));
6658           }
6659         }
6660         else {
6661           //nReplaceMap.insert( TNodeNodeMap::value_type
6662           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
6663           //nReplaceMap.insert( TNodeNodeMap::value_type
6664           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
6665           for(int nn=0; nn<nbNodes-2; nn++) {
6666             nReplaceMap.insert( TNodeNodeMap::value_type
6667                              ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
6668           }
6669         }
6670       }
6671
6672       // add other links of the faces to linkList
6673       // -----------------------------------------
6674
6675       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
6676       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
6677         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
6678         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
6679         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
6680         if ( !iter_isnew.second ) { // already in a set: no need to process
6681           linkIdSet.erase( iter_isnew.first );
6682         }
6683         else // new in set == encountered for the first time: add
6684         {
6685           //const SMDS_MeshNode* n1 = nodes[ iNode ];
6686           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
6687           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
6688           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
6689           linkList[0].push_back ( TPairOfNodes( n1, n2 ));
6690           linkList[1].push_back ( TPairOfNodes( nReplaceMap[n1], nReplaceMap[n2] ));
6691         }
6692       }
6693     } // 2 faces found
6694   } // loop on link lists
6695
6696   if ( aResult == SEW_OK &&
6697       ( linkIt[0] != linkList[0].end() ||
6698        !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
6699     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
6700             " " << (faceSetPtr[1]->empty()));
6701     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
6702   }
6703
6704   // ====================================================================
6705   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
6706   // ====================================================================
6707
6708   // delete temporary faces: they are in reverseElements of actual nodes
6709   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
6710   while ( tmpFaceIt->more() )
6711     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
6712
6713   if ( aResult != SEW_OK)
6714     return aResult;
6715
6716   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
6717   // loop on nodes replacement map
6718   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
6719   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
6720     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
6721       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
6722       nodeIDsToRemove.push_back( nToRemove->GetID() );
6723       // loop on elements sharing nToRemove
6724       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6725       while ( invElemIt->more() ) {
6726         const SMDS_MeshElement* e = invElemIt->next();
6727         // get a new suite of nodes: make replacement
6728         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
6729         vector< const SMDS_MeshNode*> nodes( nbNodes );
6730         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6731         while ( nIt->more() ) {
6732           const SMDS_MeshNode* n =
6733             static_cast<const SMDS_MeshNode*>( nIt->next() );
6734           nnIt = nReplaceMap.find( n );
6735           if ( nnIt != nReplaceMap.end() ) {
6736             nbReplaced++;
6737             n = (*nnIt).second;
6738           }
6739           nodes[ i++ ] = n;
6740         }
6741         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
6742         //         elemIDsToRemove.push_back( e->GetID() );
6743         //       else
6744         if ( nbReplaced )
6745           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
6746       }
6747     }
6748
6749   Remove( nodeIDsToRemove, true );
6750
6751   return aResult;
6752 }