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