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