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