Salome HOME
Implememtation of evaluation for improvement 0019296.
[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 =
3860       MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
3861   }
3862   else if( aS.ShapeType() == TopAbs_WIRE ) {
3863     list< SMESH_subMesh* > LSM;
3864     TopTools_SequenceOfShape Edges;
3865     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
3866     while(itSM->more()) {
3867       SMESH_subMesh* SM = itSM->next();
3868       LSM.push_back(SM);
3869       const TopoDS_Shape& aS = SM->GetSubShape();
3870       Edges.Append(aS);
3871     }
3872     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
3873     int startNid = theN1->GetID();
3874     TColStd_MapOfInteger UsedNums;
3875     int NbEdges = Edges.Length();
3876     int i = 1;
3877     for(; i<=NbEdges; i++) {
3878       int k = 0;
3879       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
3880       for(; itLSM!=LSM.end(); itLSM++) {
3881         k++;
3882         if(UsedNums.Contains(k)) continue;
3883         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
3884         SMESH_subMesh* locTrack = *itLSM;
3885         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
3886         TopExp::Vertices( aTrackEdge, aV1, aV2 );
3887         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
3888         const SMDS_MeshNode* aN1 = aItN->next();
3889         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
3890         const SMDS_MeshNode* aN2 = aItN->next();
3891         // starting node must be aN1 or aN2
3892         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
3893         // 2. Collect parameters on the track edge
3894         aPrms.clear();
3895         aItN = locMeshDS->GetNodes();
3896         while ( aItN->more() ) {
3897           const SMDS_MeshNode* pNode = aItN->next();
3898           const SMDS_EdgePosition* pEPos =
3899             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
3900           double aT = pEPos->GetUParameter();
3901           aPrms.push_back( aT );
3902         }
3903         list<SMESH_MeshEditor_PathPoint> LPP;
3904         //Extrusion_Error err =
3905           MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
3906         LLPPs.push_back(LPP);
3907         UsedNums.Add(k);
3908         // update startN for search following egde
3909         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
3910         else startNid = aN1->GetID();
3911         break;
3912       }
3913     }
3914     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
3915     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
3916     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
3917     for(; itPP!=firstList.end(); itPP++) {
3918       fullList.push_back( *itPP );
3919     }
3920     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
3921     fullList.pop_back();
3922     itLLPP++;
3923     for(; itLLPP!=LLPPs.end(); itLLPP++) {
3924       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
3925       itPP = currList.begin();
3926       SMESH_MeshEditor_PathPoint PP2 = currList.front();
3927       gp_Dir D1 = PP1.Tangent();
3928       gp_Dir D2 = PP2.Tangent();
3929       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
3930                            (D1.Z()+D2.Z())/2 ) );
3931       PP1.SetTangent(Dnew);
3932       fullList.push_back(PP1);
3933       itPP++;
3934       for(; itPP!=firstList.end(); itPP++) {
3935         fullList.push_back( *itPP );
3936       }
3937       PP1 = fullList.back();
3938       fullList.pop_back();
3939     }
3940     // if wire not closed
3941     fullList.push_back(PP1);
3942     // else ???
3943   }
3944   else {
3945     return EXTR_BAD_PATH_SHAPE;
3946   }
3947
3948   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
3949                           theHasRefPoint, theRefPoint, theMakeGroups);
3950 }
3951
3952
3953 //=======================================================================
3954 //function : ExtrusionAlongTrack
3955 //purpose  :
3956 //=======================================================================
3957 SMESH_MeshEditor::Extrusion_Error
3958   SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
3959                                          SMESH_Mesh*          theTrack,
3960                                          const SMDS_MeshNode* theN1,
3961                                          const bool           theHasAngles,
3962                                          list<double>&        theAngles,
3963                                          const bool           theLinearVariation,
3964                                          const bool           theHasRefPoint,
3965                                          const gp_Pnt&        theRefPoint,
3966                                          const bool           theMakeGroups)
3967 {
3968   myLastCreatedElems.Clear();
3969   myLastCreatedNodes.Clear();
3970
3971   int aNbE;
3972   std::list<double> aPrms;
3973   TIDSortedElemSet::iterator itElem;
3974
3975   gp_XYZ aGC;
3976   TopoDS_Edge aTrackEdge;
3977   TopoDS_Vertex aV1, aV2;
3978
3979   SMDS_ElemIteratorPtr aItE;
3980   SMDS_NodeIteratorPtr aItN;
3981   SMDSAbs_ElementType aTypeE;
3982
3983   TNodeOfNodeListMap mapNewNodes;
3984
3985   // 1. Check data
3986   aNbE = theElements.size();
3987   // nothing to do
3988   if ( !aNbE )
3989     return EXTR_NO_ELEMENTS;
3990
3991   // 1.1 Track Pattern
3992   ASSERT( theTrack );
3993
3994   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
3995
3996   aItE = pMeshDS->elementsIterator();
3997   while ( aItE->more() ) {
3998     const SMDS_MeshElement* pE = aItE->next();
3999     aTypeE = pE->GetType();
4000     // Pattern must contain links only
4001     if ( aTypeE != SMDSAbs_Edge )
4002       return EXTR_PATH_NOT_EDGE;
4003   }
4004
4005   list<SMESH_MeshEditor_PathPoint> fullList;
4006
4007   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4008   // Sub shape for the Pattern must be an Edge or Wire
4009   if( aS.ShapeType() == TopAbs_EDGE ) {
4010     aTrackEdge = TopoDS::Edge( aS );
4011     // the Edge must not be degenerated
4012     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4013       return EXTR_BAD_PATH_SHAPE;
4014     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4015     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4016     const SMDS_MeshNode* aN1 = aItN->next();
4017     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4018     const SMDS_MeshNode* aN2 = aItN->next();
4019     // starting node must be aN1 or aN2
4020     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4021       return EXTR_BAD_STARTING_NODE;
4022     aItN = pMeshDS->nodesIterator();
4023     while ( aItN->more() ) {
4024       const SMDS_MeshNode* pNode = aItN->next();
4025       if( pNode==aN1 || pNode==aN2 ) continue;
4026       const SMDS_EdgePosition* pEPos =
4027         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4028       double aT = pEPos->GetUParameter();
4029       aPrms.push_back( aT );
4030     }
4031     //Extrusion_Error err =
4032       MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4033   }
4034   else if( aS.ShapeType() == TopAbs_WIRE ) {
4035     list< SMESH_subMesh* > LSM;
4036     TopTools_SequenceOfShape Edges;
4037     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4038     for(; eExp.More(); eExp.Next()) {
4039       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4040       if( BRep_Tool::Degenerated(E) ) continue;
4041       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4042       if(SM) {
4043         LSM.push_back(SM);
4044         Edges.Append(E);
4045       }
4046     }
4047     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4048     int startNid = theN1->GetID();
4049     TColStd_MapOfInteger UsedNums;
4050     int NbEdges = Edges.Length();
4051     int i = 1;
4052     for(; i<=NbEdges; i++) {
4053       int k = 0;
4054       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4055       for(; itLSM!=LSM.end(); itLSM++) {
4056         k++;
4057         if(UsedNums.Contains(k)) continue;
4058         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4059         SMESH_subMesh* locTrack = *itLSM;
4060         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4061         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4062         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4063         const SMDS_MeshNode* aN1 = aItN->next();
4064         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4065         const SMDS_MeshNode* aN2 = aItN->next();
4066         // starting node must be aN1 or aN2
4067         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4068         // 2. Collect parameters on the track edge
4069         aPrms.clear();
4070         aItN = locMeshDS->GetNodes();
4071         while ( aItN->more() ) {
4072           const SMDS_MeshNode* pNode = aItN->next();
4073           const SMDS_EdgePosition* pEPos =
4074             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4075           double aT = pEPos->GetUParameter();
4076           aPrms.push_back( aT );
4077         }
4078         list<SMESH_MeshEditor_PathPoint> LPP;
4079         //Extrusion_Error err =
4080           MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4081         LLPPs.push_back(LPP);
4082         UsedNums.Add(k);
4083         // update startN for search following egde
4084         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4085         else startNid = aN1->GetID();
4086         break;
4087       }
4088     }
4089     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4090     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4091     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4092     for(; itPP!=firstList.end(); itPP++) {
4093       fullList.push_back( *itPP );
4094     }
4095     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4096     fullList.pop_back();
4097     itLLPP++;
4098     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4099       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4100       itPP = currList.begin();
4101       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4102       gp_Pnt P1 = PP1.Pnt();
4103       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4104       gp_Pnt P2 = PP2.Pnt();
4105       gp_Dir D1 = PP1.Tangent();
4106       gp_Dir D2 = PP2.Tangent();
4107       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4108                            (D1.Z()+D2.Z())/2 ) );
4109       PP1.SetTangent(Dnew);
4110       fullList.push_back(PP1);
4111       itPP++;
4112       for(; itPP!=currList.end(); itPP++) {
4113         fullList.push_back( *itPP );
4114       }
4115       PP1 = fullList.back();
4116       fullList.pop_back();
4117     }
4118     // if wire not closed
4119     fullList.push_back(PP1);
4120     // else ???
4121   }
4122   else {
4123     return EXTR_BAD_PATH_SHAPE;
4124   }
4125
4126   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4127                           theHasRefPoint, theRefPoint, theMakeGroups);
4128 }
4129
4130
4131 //=======================================================================
4132 //function : MakeEdgePathPoints
4133 //purpose  : auxilary for ExtrusionAlongTrack
4134 //=======================================================================
4135 SMESH_MeshEditor::Extrusion_Error
4136 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4137                                      const TopoDS_Edge& aTrackEdge,
4138                                      bool FirstIsStart,
4139                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4140 {
4141   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4142   aTolVec=1.e-7;
4143   aTolVec2=aTolVec*aTolVec;
4144   double aT1, aT2;
4145   TopoDS_Vertex aV1, aV2;
4146   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4147   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4148   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4149   // 2. Collect parameters on the track edge
4150   aPrms.push_front( aT1 );
4151   aPrms.push_back( aT2 );
4152   // sort parameters
4153   aPrms.sort();
4154   if( FirstIsStart ) {
4155     if ( aT1 > aT2 ) {
4156       aPrms.reverse();
4157     }
4158   }
4159   else {
4160     if ( aT2 > aT1 ) {
4161       aPrms.reverse();
4162     }
4163   }
4164   // 3. Path Points
4165   SMESH_MeshEditor_PathPoint aPP;
4166   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4167   std::list<double>::iterator aItD = aPrms.begin();
4168   for(; aItD != aPrms.end(); ++aItD) {
4169     double aT = *aItD;
4170     gp_Pnt aP3D;
4171     gp_Vec aVec;
4172     aC3D->D1( aT, aP3D, aVec );
4173     aL2 = aVec.SquareMagnitude();
4174     if ( aL2 < aTolVec2 )
4175       return EXTR_CANT_GET_TANGENT;
4176     gp_Dir aTgt( aVec );
4177     aPP.SetPnt( aP3D );
4178     aPP.SetTangent( aTgt );
4179     aPP.SetParameter( aT );
4180     LPP.push_back(aPP);
4181   }
4182   return EXTR_OK;
4183 }
4184
4185
4186 //=======================================================================
4187 //function : MakeExtrElements
4188 //purpose  : auxilary for ExtrusionAlongTrack
4189 //=======================================================================
4190 SMESH_MeshEditor::Extrusion_Error
4191 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4192                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4193                                    const bool theHasAngles,
4194                                    list<double>& theAngles,
4195                                    const bool theLinearVariation,
4196                                    const bool theHasRefPoint,
4197                                    const gp_Pnt& theRefPoint,
4198                                    const bool theMakeGroups)
4199 {
4200   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4201   int aNbTP = fullList.size();
4202   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4203   // Angles
4204   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4205     LinearAngleVariation(aNbTP-1, theAngles);
4206   }
4207   vector<double> aAngles( aNbTP );
4208   int j = 0;
4209   for(; j<aNbTP; ++j) {
4210     aAngles[j] = 0.;
4211   }
4212   if ( theHasAngles ) {
4213     double anAngle;;
4214     std::list<double>::iterator aItD = theAngles.begin();
4215     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4216       anAngle = *aItD;
4217       aAngles[j] = anAngle;
4218     }
4219   }
4220   // fill vector of path points with angles
4221   //aPPs.resize(fullList.size());
4222   j = -1;
4223   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4224   for(; itPP!=fullList.end(); itPP++) {
4225     j++;
4226     SMESH_MeshEditor_PathPoint PP = *itPP;
4227     PP.SetAngle(aAngles[j]);
4228     aPPs[j] = PP;
4229   }
4230
4231   TNodeOfNodeListMap mapNewNodes;
4232   TElemOfVecOfNnlmiMap mapElemNewNodes;
4233   TElemOfElemListMap newElemsMap;
4234   TIDSortedElemSet::iterator itElem;
4235   double aX, aY, aZ;
4236   int aNb;
4237   SMDSAbs_ElementType aTypeE;
4238   // source elements for each generated one
4239   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4240
4241   // 3. Center of rotation aV0
4242   gp_Pnt aV0 = theRefPoint;
4243   gp_XYZ aGC;
4244   if ( !theHasRefPoint ) {
4245     aNb = 0;
4246     aGC.SetCoord( 0.,0.,0. );
4247     
4248     itElem = theElements.begin();
4249     for ( ; itElem != theElements.end(); itElem++ ) {
4250       const SMDS_MeshElement* elem = *itElem;
4251       
4252       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4253       while ( itN->more() ) {
4254         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4255         aX = node->X();
4256         aY = node->Y();
4257         aZ = node->Z();
4258         
4259         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4260           list<const SMDS_MeshNode*> aLNx;
4261           mapNewNodes[node] = aLNx;
4262           //
4263           gp_XYZ aXYZ( aX, aY, aZ );
4264           aGC += aXYZ;
4265           ++aNb;
4266         }
4267       }
4268     }
4269     aGC /= aNb;
4270     aV0.SetXYZ( aGC );
4271   } // if (!theHasRefPoint) {
4272   mapNewNodes.clear();
4273
4274   // 4. Processing the elements
4275   SMESHDS_Mesh* aMesh = GetMeshDS();
4276
4277   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4278     // check element type
4279     const SMDS_MeshElement* elem = *itElem;
4280     aTypeE = elem->GetType();
4281     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4282       continue;
4283
4284     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4285     newNodesItVec.reserve( elem->NbNodes() );
4286
4287     // loop on elem nodes
4288     int nodeIndex = -1;
4289     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4290     while ( itN->more() )
4291     {
4292       ++nodeIndex;
4293       // check if a node has been already processed
4294       const SMDS_MeshNode* node =
4295         static_cast<const SMDS_MeshNode*>( itN->next() );
4296       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4297       if ( nIt == mapNewNodes.end() ) {
4298         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4299         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4300
4301         // make new nodes
4302         aX = node->X();  aY = node->Y(); aZ = node->Z();
4303
4304         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4305         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4306         gp_Ax1 anAx1, anAxT1T0;
4307         gp_Dir aDT1x, aDT0x, aDT1T0;
4308
4309         aTolAng=1.e-4;
4310
4311         aV0x = aV0;
4312         aPN0.SetCoord(aX, aY, aZ);
4313
4314         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4315         aP0x = aPP0.Pnt();
4316         aDT0x= aPP0.Tangent();
4317         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4318
4319         for ( j = 1; j < aNbTP; ++j ) {
4320           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4321           aP1x = aPP1.Pnt();
4322           aDT1x = aPP1.Tangent();
4323           aAngle1x = aPP1.Angle();
4324
4325           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4326           // Translation
4327           gp_Vec aV01x( aP0x, aP1x );
4328           aTrsf.SetTranslation( aV01x );
4329
4330           // traslated point
4331           aV1x = aV0x.Transformed( aTrsf );
4332           aPN1 = aPN0.Transformed( aTrsf );
4333
4334           // rotation 1 [ T1,T0 ]
4335           aAngleT1T0=-aDT1x.Angle( aDT0x );
4336           if (fabs(aAngleT1T0) > aTolAng) {
4337             aDT1T0=aDT1x^aDT0x;
4338             anAxT1T0.SetLocation( aV1x );
4339             anAxT1T0.SetDirection( aDT1T0 );
4340             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4341
4342             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4343           }
4344
4345           // rotation 2
4346           if ( theHasAngles ) {
4347             anAx1.SetLocation( aV1x );
4348             anAx1.SetDirection( aDT1x );
4349             aTrsfRot.SetRotation( anAx1, aAngle1x );
4350
4351             aPN1 = aPN1.Transformed( aTrsfRot );
4352           }
4353
4354           // make new node
4355           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4356             // create additional node
4357             double x = ( aPN1.X() + aPN0.X() )/2.;
4358             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4359             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4360             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4361             myLastCreatedNodes.Append(newNode);
4362             srcNodes.Append( node );
4363             listNewNodes.push_back( newNode );
4364           }
4365           aX = aPN1.X();
4366           aY = aPN1.Y();
4367           aZ = aPN1.Z();
4368           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4369           myLastCreatedNodes.Append(newNode);
4370           srcNodes.Append( node );
4371           listNewNodes.push_back( newNode );
4372
4373           aPN0 = aPN1;
4374           aP0x = aP1x;
4375           aV0x = aV1x;
4376           aDT0x = aDT1x;
4377         }
4378       }
4379
4380       else {
4381         // if current elem is quadratic and current node is not medium
4382         // we have to check - may be it is needed to insert additional nodes
4383         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4384           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4385           if(listNewNodes.size()==aNbTP-1) {
4386             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4387             gp_XYZ P(node->X(), node->Y(), node->Z());
4388             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4389             int i;
4390             for(i=0; i<aNbTP-1; i++) {
4391               const SMDS_MeshNode* N = *it;
4392               double x = ( N->X() + P.X() )/2.;
4393               double y = ( N->Y() + P.Y() )/2.;
4394               double z = ( N->Z() + P.Z() )/2.;
4395               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4396               srcNodes.Append( node );
4397               myLastCreatedNodes.Append(newN);
4398               aNodes[2*i] = newN;
4399               aNodes[2*i+1] = N;
4400               P = gp_XYZ(N->X(),N->Y(),N->Z());
4401             }
4402             listNewNodes.clear();
4403             for(i=0; i<2*(aNbTP-1); i++) {
4404               listNewNodes.push_back(aNodes[i]);
4405             }
4406           }
4407         }
4408       }
4409
4410       newNodesItVec.push_back( nIt );
4411     }
4412     // make new elements
4413     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4414     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
4415     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4416   }
4417
4418   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4419
4420   if ( theMakeGroups )
4421     generateGroups( srcNodes, srcElems, "extruded");
4422
4423   return EXTR_OK;
4424 }
4425
4426
4427 //=======================================================================
4428 //function : LinearAngleVariation
4429 //purpose  : auxilary for ExtrusionAlongTrack
4430 //=======================================================================
4431 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4432                                             list<double>& Angles)
4433 {
4434   int nbAngles = Angles.size();
4435   if( nbSteps > nbAngles ) {
4436     vector<double> theAngles(nbAngles);
4437     list<double>::iterator it = Angles.begin();
4438     int i = -1;
4439     for(; it!=Angles.end(); it++) {
4440       i++;
4441       theAngles[i] = (*it);
4442     }
4443     list<double> res;
4444     double rAn2St = double( nbAngles ) / double( nbSteps );
4445     double angPrev = 0, angle;
4446     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4447       double angCur = rAn2St * ( iSt+1 );
4448       double angCurFloor  = floor( angCur );
4449       double angPrevFloor = floor( angPrev );
4450       if ( angPrevFloor == angCurFloor )
4451         angle = rAn2St * theAngles[ int( angCurFloor ) ];
4452       else {
4453         int iP = int( angPrevFloor );
4454         double angPrevCeil = ceil(angPrev);
4455         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4456           
4457         int iC = int( angCurFloor );
4458         if ( iC < nbAngles )
4459           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4460         
4461         iP = int( angPrevCeil );
4462         while ( iC-- > iP )
4463           angle += theAngles[ iC ];
4464       }
4465       res.push_back(angle);
4466       angPrev = angCur;
4467     }
4468     Angles.clear();
4469     it = res.begin();
4470     for(; it!=res.end(); it++)
4471       Angles.push_back( *it );
4472   }
4473 }
4474
4475
4476 //=======================================================================
4477 //function : Transform
4478 //purpose  :
4479 //=======================================================================
4480
4481 SMESH_MeshEditor::PGroupIDs
4482 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4483                              const gp_Trsf&     theTrsf,
4484                              const bool         theCopy,
4485                              const bool         theMakeGroups,
4486                              SMESH_Mesh*        theTargetMesh)
4487 {
4488   myLastCreatedElems.Clear();
4489   myLastCreatedNodes.Clear();
4490
4491   bool needReverse = false;
4492   string groupPostfix;
4493   switch ( theTrsf.Form() ) {
4494   case gp_PntMirror:
4495   case gp_Ax1Mirror:
4496   case gp_Ax2Mirror:
4497     needReverse = true;
4498     groupPostfix = "mirrored";
4499     break;
4500   case gp_Rotation:
4501     groupPostfix = "rotated";
4502     break;
4503   case gp_Translation:
4504     groupPostfix = "translated";
4505     break;
4506   case gp_Scale:
4507     groupPostfix = "scaled";
4508     break;
4509   default:
4510     needReverse = false;
4511     groupPostfix = "transformed";
4512   }
4513
4514   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4515   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4516   SMESHDS_Mesh* aMesh    = GetMeshDS();
4517   
4518
4519   // map old node to new one
4520   TNodeNodeMap nodeMap;
4521
4522   // elements sharing moved nodes; those of them which have all
4523   // nodes mirrored but are not in theElems are to be reversed
4524   TIDSortedElemSet inverseElemSet;
4525
4526   // source elements for each generated one
4527   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4528
4529   // loop on theElems
4530   TIDSortedElemSet::iterator itElem;
4531   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4532     const SMDS_MeshElement* elem = *itElem;
4533     if ( !elem )
4534       continue;
4535
4536     // loop on elem nodes
4537     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4538     while ( itN->more() ) {
4539
4540       // check if a node has been already transformed
4541       const SMDS_MeshNode* node = cast2Node( itN->next() );
4542       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4543         nodeMap.insert( make_pair ( node, node ));
4544       if ( !n2n_isnew.second )
4545         continue;
4546
4547       double coord[3];
4548       coord[0] = node->X();
4549       coord[1] = node->Y();
4550       coord[2] = node->Z();
4551       theTrsf.Transforms( coord[0], coord[1], coord[2] );
4552       if ( theTargetMesh ) {
4553         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4554         n2n_isnew.first->second = newNode;
4555         myLastCreatedNodes.Append(newNode);
4556         srcNodes.Append( node );
4557       }
4558       else if ( theCopy ) {
4559         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4560         n2n_isnew.first->second = newNode;
4561         myLastCreatedNodes.Append(newNode);
4562         srcNodes.Append( node );
4563       }
4564       else {
4565         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4566         // node position on shape becomes invalid
4567         const_cast< SMDS_MeshNode* > ( node )->SetPosition
4568           ( SMDS_SpacePosition::originSpacePosition() );
4569       }
4570
4571       // keep inverse elements
4572       if ( !theCopy && !theTargetMesh && needReverse ) {
4573         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4574         while ( invElemIt->more() ) {
4575           const SMDS_MeshElement* iel = invElemIt->next();
4576           inverseElemSet.insert( iel );
4577         }
4578       }
4579     }
4580   }
4581
4582   // either create new elements or reverse mirrored ones
4583   if ( !theCopy && !needReverse && !theTargetMesh )
4584     return PGroupIDs();
4585
4586   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4587   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4588     theElems.insert( *invElemIt );
4589
4590   // replicate or reverse elements
4591
4592   enum {
4593     REV_TETRA   = 0,  //  = nbNodes - 4
4594     REV_PYRAMID = 1,  //  = nbNodes - 4
4595     REV_PENTA   = 2,  //  = nbNodes - 4
4596     REV_FACE    = 3,
4597     REV_HEXA    = 4,  //  = nbNodes - 4
4598     FORWARD     = 5
4599     };
4600   int index[][8] = {
4601     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
4602     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
4603     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
4604     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
4605     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
4606     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
4607   };
4608
4609   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4610   {
4611     const SMDS_MeshElement* elem = *itElem;
4612     if ( !elem || elem->GetType() == SMDSAbs_Node )
4613       continue;
4614
4615     int nbNodes = elem->NbNodes();
4616     int elemType = elem->GetType();
4617
4618     if (elem->IsPoly()) {
4619       // Polygon or Polyhedral Volume
4620       switch ( elemType ) {
4621       case SMDSAbs_Face:
4622         {
4623           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4624           int iNode = 0;
4625           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4626           while (itN->more()) {
4627             const SMDS_MeshNode* node =
4628               static_cast<const SMDS_MeshNode*>(itN->next());
4629             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4630             if (nodeMapIt == nodeMap.end())
4631               break; // not all nodes transformed
4632             if (needReverse) {
4633               // reverse mirrored faces and volumes
4634               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4635             } else {
4636               poly_nodes[iNode] = (*nodeMapIt).second;
4637             }
4638             iNode++;
4639           }
4640           if ( iNode != nbNodes )
4641             continue; // not all nodes transformed
4642
4643           if ( theTargetMesh ) {
4644             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4645             srcElems.Append( elem );
4646           }
4647           else if ( theCopy ) {
4648             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4649             srcElems.Append( elem );
4650           }
4651           else {
4652             aMesh->ChangePolygonNodes(elem, poly_nodes);
4653           }
4654         }
4655         break;
4656       case SMDSAbs_Volume:
4657         {
4658           // ATTENTION: Reversing is not yet done!!!
4659           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4660             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4661           if (!aPolyedre) {
4662             MESSAGE("Warning: bad volumic element");
4663             continue;
4664           }
4665
4666           vector<const SMDS_MeshNode*> poly_nodes;
4667           vector<int> quantities;
4668
4669           bool allTransformed = true;
4670           int nbFaces = aPolyedre->NbFaces();
4671           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4672             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4673             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4674               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4675               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4676               if (nodeMapIt == nodeMap.end()) {
4677                 allTransformed = false; // not all nodes transformed
4678               } else {
4679                 poly_nodes.push_back((*nodeMapIt).second);
4680               }
4681             }
4682             quantities.push_back(nbFaceNodes);
4683           }
4684           if ( !allTransformed )
4685             continue; // not all nodes transformed
4686
4687           if ( theTargetMesh ) {
4688             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4689             srcElems.Append( elem );
4690           }
4691           else if ( theCopy ) {
4692             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4693             srcElems.Append( elem );
4694           }
4695           else {
4696             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4697           }
4698         }
4699         break;
4700     default:;
4701     }
4702     continue;
4703   }
4704
4705   // Regular elements
4706   int* i = index[ FORWARD ];
4707   if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4708     if ( elemType == SMDSAbs_Face )
4709       i = index[ REV_FACE ];
4710     else
4711       i = index[ nbNodes - 4 ];
4712
4713     if(elem->IsQuadratic()) {
4714       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4715       i = anIds;
4716       if(needReverse) {
4717         if(nbNodes==3) { // quadratic edge
4718           static int anIds[] = {1,0,2};
4719           i = anIds;
4720         }
4721         else if(nbNodes==6) { // quadratic triangle
4722           static int anIds[] = {0,2,1,5,4,3};
4723           i = anIds;
4724         }
4725         else if(nbNodes==8) { // quadratic quadrangle
4726           static int anIds[] = {0,3,2,1,7,6,5,4};
4727           i = anIds;
4728         }
4729         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4730           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4731           i = anIds;
4732         }
4733         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4734           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4735           i = anIds;
4736         }
4737         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4738           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4739           i = anIds;
4740         }
4741         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4742           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4743           i = anIds;
4744         }
4745       }
4746     }
4747
4748     // find transformed nodes
4749     vector<const SMDS_MeshNode*> nodes(nbNodes);
4750     int iNode = 0;
4751     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4752     while ( itN->more() ) {
4753       const SMDS_MeshNode* node =
4754         static_cast<const SMDS_MeshNode*>( itN->next() );
4755       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4756       if ( nodeMapIt == nodeMap.end() )
4757         break; // not all nodes transformed
4758       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4759     }
4760     if ( iNode != nbNodes )
4761       continue; // not all nodes transformed
4762
4763     if ( theTargetMesh ) {
4764       if ( SMDS_MeshElement* copy =
4765            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4766         myLastCreatedElems.Append( copy );
4767         srcElems.Append( elem );
4768       }
4769     }
4770     else if ( theCopy ) {
4771       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4772         myLastCreatedElems.Append( copy );
4773         srcElems.Append( elem );
4774       }
4775     }
4776     else {
4777       // reverse element as it was reversed by transformation
4778       if ( nbNodes > 2 )
4779         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4780     }
4781   }
4782
4783   PGroupIDs newGroupIDs;
4784
4785   if ( theMakeGroups && theCopy ||
4786        theMakeGroups && theTargetMesh )
4787     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4788
4789   return newGroupIDs;
4790 }
4791
4792 //=======================================================================
4793 /*!
4794  * \brief Create groups of elements made during transformation
4795  * \param nodeGens - nodes making corresponding myLastCreatedNodes
4796  * \param elemGens - elements making corresponding myLastCreatedElems
4797  * \param postfix - to append to names of new groups
4798  */
4799 //=======================================================================
4800
4801 SMESH_MeshEditor::PGroupIDs
4802 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4803                                  const SMESH_SequenceOfElemPtr& elemGens,
4804                                  const std::string&             postfix,
4805                                  SMESH_Mesh*                    targetMesh)
4806 {
4807   PGroupIDs newGroupIDs( new list<int> );
4808   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4809
4810   // Sort existing groups by types and collect their names
4811
4812   // to store an old group and a generated new one
4813   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4814   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4815   // group names
4816   set< string > groupNames;
4817   //
4818   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4819   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4820   while ( groupIt->more() ) {
4821     SMESH_Group * group = groupIt->next();
4822     if ( !group ) continue;
4823     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4824     if ( !groupDS || groupDS->IsEmpty() ) continue;
4825     groupNames.insert( group->GetName() );
4826     groupDS->SetStoreName( group->GetName() );
4827     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
4828   }
4829
4830   // Groups creation
4831
4832   // loop on nodes and elements
4833   for ( int isNodes = 0; isNodes < 2; ++isNodes )
4834   {
4835     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
4836     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
4837     if ( gens.Length() != elems.Length() )
4838       throw SALOME_Exception(LOCALIZED("invalid args"));
4839
4840     // loop on created elements
4841     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
4842     {
4843       const SMDS_MeshElement* sourceElem = gens( iElem );
4844       if ( !sourceElem ) {
4845         MESSAGE("generateGroups(): NULL source element");
4846         continue;
4847       }
4848       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
4849       if ( groupsOldNew.empty() ) {
4850         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
4851           ++iElem; // skip all elements made by sourceElem
4852         continue;
4853       }
4854       // collect all elements made by sourceElem
4855       list< const SMDS_MeshElement* > resultElems;
4856       if ( const SMDS_MeshElement* resElem = elems( iElem ))
4857         if ( resElem != sourceElem )
4858           resultElems.push_back( resElem );
4859       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
4860         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
4861           if ( resElem != sourceElem )
4862             resultElems.push_back( resElem );
4863       // do not generate element groups from node ones
4864       if ( sourceElem->GetType() == SMDSAbs_Node &&
4865            elems( iElem )->GetType() != SMDSAbs_Node )
4866         continue;
4867
4868       // add resultElems to groups made by ones the sourceElem belongs to
4869       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
4870       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
4871       {
4872         SMESHDS_GroupBase* oldGroup = gOldNew->first;
4873         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
4874         {
4875           SMDS_MeshGroup* & newGroup = gOldNew->second;
4876           if ( !newGroup )// create a new group
4877           {
4878             // make a name
4879             string name = oldGroup->GetStoreName();
4880             if ( !targetMesh ) {
4881               name += "_";
4882               name += postfix;
4883               int nb = 0;
4884               while ( !groupNames.insert( name ).second ) // name exists
4885               {
4886                 if ( nb == 0 ) {
4887                   name += "_1";
4888                 }
4889                 else {
4890                   TCollection_AsciiString nbStr(nb+1);
4891                   name.resize( name.rfind('_')+1 );
4892                   name += nbStr.ToCString();
4893                 }
4894                 ++nb;
4895               }
4896             }
4897             // make a group
4898             int id;
4899             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
4900                                                  name.c_str(), id );
4901             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
4902             newGroup = & groupDS->SMDSGroup();
4903             newGroupIDs->push_back( id );
4904           }
4905
4906           // fill in a new group
4907           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
4908           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
4909             newGroup->Add( *resElemIt );
4910         }
4911       }
4912     } // loop on created elements
4913   }// loop on nodes and elements
4914
4915   return newGroupIDs;
4916 }
4917
4918 //=======================================================================
4919 //function : FindCoincidentNodes
4920 //purpose  : Return list of group of nodes close to each other within theTolerance
4921 //           Search among theNodes or in the whole mesh if theNodes is empty using
4922 //           an Octree algorithm
4923 //=======================================================================
4924
4925 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
4926                                             const double                theTolerance,
4927                                             TListOfListOfNodes &        theGroupsOfNodes)
4928 {
4929   myLastCreatedElems.Clear();
4930   myLastCreatedNodes.Clear();
4931
4932   set<const SMDS_MeshNode*> nodes;
4933   if ( theNodes.empty() )
4934   { // get all nodes in the mesh
4935     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
4936     while ( nIt->more() )
4937       nodes.insert( nodes.end(),nIt->next());
4938   }
4939   else
4940     nodes=theNodes;
4941   SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
4942
4943 }
4944
4945 //=======================================================================
4946 /*!
4947  * \brief Implementation of search for the node closest to point
4948  */
4949 //=======================================================================
4950
4951 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
4952 {
4953   /*!
4954    * \brief Constructor
4955    */
4956   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
4957   {
4958     set<const SMDS_MeshNode*> nodes;
4959     if ( theMesh ) {
4960       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
4961       while ( nIt->more() )
4962         nodes.insert( nodes.end(), nIt->next() );
4963     }
4964     myOctreeNode = new SMESH_OctreeNode(nodes) ;
4965   }
4966   /*!
4967    * \brief Do it's job
4968    */
4969   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
4970   {
4971     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
4972     list<const SMDS_MeshNode*> nodes;
4973     const double precision = 1e-6;
4974     myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
4975
4976     double minSqDist = DBL_MAX;
4977     Bnd_B3d box;
4978     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
4979     {
4980       // sort leafs by their distance from thePnt
4981       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
4982       TDistTreeMap treeMap;
4983       list< SMESH_OctreeNode* > treeList;
4984       list< SMESH_OctreeNode* >::iterator trIt;
4985       treeList.push_back( myOctreeNode );
4986       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
4987       {
4988         SMESH_OctreeNode* tree = *trIt;
4989         if ( !tree->isLeaf() ) { // put children to the queue
4990           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
4991           while ( cIt->more() )
4992             treeList.push_back( cIt->next() );
4993         }
4994         else if ( tree->NbNodes() ) { // put tree to treeMap
4995           tree->getBox( box );
4996           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
4997           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
4998           if ( !it_in.second ) // not unique distance to box center
4999             treeMap.insert( it_in.first, make_pair( sqDist - 1e-13*treeMap.size(), tree ));
5000         }
5001       }
5002       // find distance after which there is no sense to check tree's
5003       double sqLimit = DBL_MAX;
5004       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5005       if ( treeMap.size() > 5 ) {
5006         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5007         closestTree->getBox( box );
5008         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5009         sqLimit = limit * limit;
5010       }
5011       // get all nodes from trees
5012       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5013         if ( sqDist_tree->first > sqLimit )
5014           break;
5015         SMESH_OctreeNode* tree = sqDist_tree->second;
5016         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5017       }
5018     }
5019     // find closest among nodes
5020     minSqDist = DBL_MAX;
5021     const SMDS_MeshNode* closestNode = 0;
5022     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5023     for ( ; nIt != nodes.end(); ++nIt ) {
5024       double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
5025       if ( minSqDist > sqDist ) {
5026         closestNode = *nIt;
5027         minSqDist = sqDist;
5028       }
5029     }
5030     return closestNode;
5031   }
5032   /*!
5033    * \brief Destructor
5034    */
5035   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5036 private:
5037   SMESH_OctreeNode* myOctreeNode;
5038 };
5039
5040 //=======================================================================
5041 /*!
5042  * \brief Return SMESH_NodeSearcher
5043  */
5044 //=======================================================================
5045
5046 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
5047 {
5048   return new SMESH_NodeSearcherImpl( GetMeshDS() );
5049 }
5050
5051 //=======================================================================
5052 //function : SimplifyFace
5053 //purpose  :
5054 //=======================================================================
5055 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5056                                     vector<const SMDS_MeshNode *>&      poly_nodes,
5057                                     vector<int>&                        quantities) const
5058 {
5059   int nbNodes = faceNodes.size();
5060
5061   if (nbNodes < 3)
5062     return 0;
5063
5064   set<const SMDS_MeshNode*> nodeSet;
5065
5066   // get simple seq of nodes
5067   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5068   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5069   int iSimple = 0, nbUnique = 0;
5070
5071   simpleNodes[iSimple++] = faceNodes[0];
5072   nbUnique++;
5073   for (int iCur = 1; iCur < nbNodes; iCur++) {
5074     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5075       simpleNodes[iSimple++] = faceNodes[iCur];
5076       if (nodeSet.insert( faceNodes[iCur] ).second)
5077         nbUnique++;
5078     }
5079   }
5080   int nbSimple = iSimple;
5081   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5082     nbSimple--;
5083     iSimple--;
5084   }
5085
5086   if (nbUnique < 3)
5087     return 0;
5088
5089   // separate loops
5090   int nbNew = 0;
5091   bool foundLoop = (nbSimple > nbUnique);
5092   while (foundLoop) {
5093     foundLoop = false;
5094     set<const SMDS_MeshNode*> loopSet;
5095     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5096       const SMDS_MeshNode* n = simpleNodes[iSimple];
5097       if (!loopSet.insert( n ).second) {
5098         foundLoop = true;
5099
5100         // separate loop
5101         int iC = 0, curLast = iSimple;
5102         for (; iC < curLast; iC++) {
5103           if (simpleNodes[iC] == n) break;
5104         }
5105         int loopLen = curLast - iC;
5106         if (loopLen > 2) {
5107           // create sub-element
5108           nbNew++;
5109           quantities.push_back(loopLen);
5110           for (; iC < curLast; iC++) {
5111             poly_nodes.push_back(simpleNodes[iC]);
5112           }
5113         }
5114         // shift the rest nodes (place from the first loop position)
5115         for (iC = curLast + 1; iC < nbSimple; iC++) {
5116           simpleNodes[iC - loopLen] = simpleNodes[iC];
5117         }
5118         nbSimple -= loopLen;
5119         iSimple -= loopLen;
5120       }
5121     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5122   } // while (foundLoop)
5123
5124   if (iSimple > 2) {
5125     nbNew++;
5126     quantities.push_back(iSimple);
5127     for (int i = 0; i < iSimple; i++)
5128       poly_nodes.push_back(simpleNodes[i]);
5129   }
5130
5131   return nbNew;
5132 }
5133
5134 //=======================================================================
5135 //function : MergeNodes
5136 //purpose  : In each group, the cdr of nodes are substituted by the first one
5137 //           in all elements.
5138 //=======================================================================
5139
5140 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5141 {
5142   myLastCreatedElems.Clear();
5143   myLastCreatedNodes.Clear();
5144
5145   SMESHDS_Mesh* aMesh = GetMeshDS();
5146
5147   TNodeNodeMap nodeNodeMap; // node to replace - new node
5148   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5149   list< int > rmElemIds, rmNodeIds;
5150
5151   // Fill nodeNodeMap and elems
5152
5153   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5154   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5155     list<const SMDS_MeshNode*>& nodes = *grIt;
5156     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5157     const SMDS_MeshNode* nToKeep = *nIt;
5158     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5159       const SMDS_MeshNode* nToRemove = *nIt;
5160       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5161       if ( nToRemove != nToKeep ) {
5162         rmNodeIds.push_back( nToRemove->GetID() );
5163         AddToSameGroups( nToKeep, nToRemove, aMesh );
5164       }
5165
5166       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5167       while ( invElemIt->more() ) {
5168         const SMDS_MeshElement* elem = invElemIt->next();
5169           elems.insert(elem);
5170       }
5171     }
5172   }
5173   // Change element nodes or remove an element
5174
5175   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5176   for ( ; eIt != elems.end(); eIt++ ) {
5177     const SMDS_MeshElement* elem = *eIt;
5178     int nbNodes = elem->NbNodes();
5179     int aShapeId = FindShape( elem );
5180
5181     set<const SMDS_MeshNode*> nodeSet;
5182     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5183     int iUnique = 0, iCur = 0, nbRepl = 0;
5184     vector<int> iRepl( nbNodes );
5185
5186     // get new seq of nodes
5187     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5188     while ( itN->more() ) {
5189       const SMDS_MeshNode* n =
5190         static_cast<const SMDS_MeshNode*>( itN->next() );
5191
5192       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5193       if ( nnIt != nodeNodeMap.end() ) { // n sticks
5194         n = (*nnIt).second;
5195         // BUG 0020185: begin
5196         {
5197           bool stopRecur = false;
5198           set<const SMDS_MeshNode*> nodesRecur;
5199           nodesRecur.insert(n);
5200           while (!stopRecur) {
5201             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5202             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5203               n = (*nnIt_i).second;
5204               if (!nodesRecur.insert(n).second) {
5205                 // error: recursive dependancy
5206                 stopRecur = true;
5207               }
5208             }
5209             else
5210               stopRecur = true;
5211           }
5212         }
5213         // BUG 0020185: end
5214         iRepl[ nbRepl++ ] = iCur;
5215       }
5216       curNodes[ iCur ] = n;
5217       bool isUnique = nodeSet.insert( n ).second;
5218       if ( isUnique )
5219         uniqueNodes[ iUnique++ ] = n;
5220       iCur++;
5221     }
5222
5223     // Analyse element topology after replacement
5224
5225     bool isOk = true;
5226     int nbUniqueNodes = nodeSet.size();
5227     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5228       // Polygons and Polyhedral volumes
5229       if (elem->IsPoly()) {
5230
5231         if (elem->GetType() == SMDSAbs_Face) {
5232           // Polygon
5233           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5234           int inode = 0;
5235           for (; inode < nbNodes; inode++) {
5236             face_nodes[inode] = curNodes[inode];
5237           }
5238
5239           vector<const SMDS_MeshNode *> polygons_nodes;
5240           vector<int> quantities;
5241           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5242
5243           if (nbNew > 0) {
5244             inode = 0;
5245             for (int iface = 0; iface < nbNew - 1; iface++) {
5246               int nbNodes = quantities[iface];
5247               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5248               for (int ii = 0; ii < nbNodes; ii++, inode++) {
5249                 poly_nodes[ii] = polygons_nodes[inode];
5250               }
5251               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5252               myLastCreatedElems.Append(newElem);
5253               if (aShapeId)
5254                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5255             }
5256             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5257           }
5258           else {
5259             rmElemIds.push_back(elem->GetID());
5260           }
5261
5262         }
5263         else if (elem->GetType() == SMDSAbs_Volume) {
5264           // Polyhedral volume
5265           if (nbUniqueNodes < 4) {
5266             rmElemIds.push_back(elem->GetID());
5267           }
5268           else {
5269             // each face has to be analized in order to check volume validity
5270             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5271               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5272             if (aPolyedre) {
5273               int nbFaces = aPolyedre->NbFaces();
5274
5275               vector<const SMDS_MeshNode *> poly_nodes;
5276               vector<int> quantities;
5277
5278               for (int iface = 1; iface <= nbFaces; iface++) {
5279                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5280                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5281
5282                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5283                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5284                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5285                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5286                     faceNode = (*nnIt).second;
5287                   }
5288                   faceNodes[inode - 1] = faceNode;
5289                 }
5290
5291                 SimplifyFace(faceNodes, poly_nodes, quantities);
5292               }
5293
5294               if (quantities.size() > 3) {
5295                 // to be done: remove coincident faces
5296               }
5297
5298               if (quantities.size() > 3)
5299                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5300               else
5301                 rmElemIds.push_back(elem->GetID());
5302
5303             }
5304             else {
5305               rmElemIds.push_back(elem->GetID());
5306             }
5307           }
5308         }
5309         else {
5310         }
5311
5312         continue;
5313       }
5314
5315       // Regular elements
5316       switch ( nbNodes ) {
5317       case 2: ///////////////////////////////////// EDGE
5318         isOk = false; break;
5319       case 3: ///////////////////////////////////// TRIANGLE
5320         isOk = false; break;
5321       case 4:
5322         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5323           isOk = false;
5324         else { //////////////////////////////////// QUADRANGLE
5325           if ( nbUniqueNodes < 3 )
5326             isOk = false;
5327           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5328             isOk = false; // opposite nodes stick
5329         }
5330         break;
5331       case 6: ///////////////////////////////////// PENTAHEDRON
5332         if ( nbUniqueNodes == 4 ) {
5333           // ---------------------------------> tetrahedron
5334           if (nbRepl == 3 &&
5335               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5336             // all top nodes stick: reverse a bottom
5337             uniqueNodes[ 0 ] = curNodes [ 1 ];
5338             uniqueNodes[ 1 ] = curNodes [ 0 ];
5339           }
5340           else if (nbRepl == 3 &&
5341                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
5342             // all bottom nodes stick: set a top before
5343             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
5344             uniqueNodes[ 0 ] = curNodes [ 3 ];
5345             uniqueNodes[ 1 ] = curNodes [ 4 ];
5346             uniqueNodes[ 2 ] = curNodes [ 5 ];
5347           }
5348           else if (nbRepl == 4 &&
5349                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
5350             // a lateral face turns into a line: reverse a bottom
5351             uniqueNodes[ 0 ] = curNodes [ 1 ];
5352             uniqueNodes[ 1 ] = curNodes [ 0 ];
5353           }
5354           else
5355             isOk = false;
5356         }
5357         else if ( nbUniqueNodes == 5 ) {
5358           // PENTAHEDRON --------------------> 2 tetrahedrons
5359           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
5360             // a bottom node sticks with a linked top one
5361             // 1.
5362             SMDS_MeshElement* newElem =
5363               aMesh->AddVolume(curNodes[ 3 ],
5364                                curNodes[ 4 ],
5365                                curNodes[ 5 ],
5366                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
5367             myLastCreatedElems.Append(newElem);
5368             if ( aShapeId )
5369               aMesh->SetMeshElementOnShape( newElem, aShapeId );
5370             // 2. : reverse a bottom
5371             uniqueNodes[ 0 ] = curNodes [ 1 ];
5372             uniqueNodes[ 1 ] = curNodes [ 0 ];
5373             nbUniqueNodes = 4;
5374           }
5375           else
5376             isOk = false;
5377         }
5378         else
5379           isOk = false;
5380         break;
5381       case 8: {
5382         if(elem->IsQuadratic()) { // Quadratic quadrangle
5383           //   1    5    2
5384           //    +---+---+
5385           //    |       |
5386           //    |       |
5387           //   4+       +6
5388           //    |       |
5389           //    |       |
5390           //    +---+---+
5391           //   0    7    3
5392           isOk = false;
5393           if(nbRepl==3) {
5394             nbUniqueNodes = 6;
5395             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
5396               uniqueNodes[0] = curNodes[0];
5397               uniqueNodes[1] = curNodes[2];
5398               uniqueNodes[2] = curNodes[3];
5399               uniqueNodes[3] = curNodes[5];
5400               uniqueNodes[4] = curNodes[6];
5401               uniqueNodes[5] = curNodes[7];
5402               isOk = true;
5403             }
5404             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
5405               uniqueNodes[0] = curNodes[0];
5406               uniqueNodes[1] = curNodes[1];
5407               uniqueNodes[2] = curNodes[2];
5408               uniqueNodes[3] = curNodes[4];
5409               uniqueNodes[4] = curNodes[5];
5410               uniqueNodes[5] = curNodes[6];
5411               isOk = true;
5412             }
5413             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
5414               uniqueNodes[0] = curNodes[1];
5415               uniqueNodes[1] = curNodes[2];
5416               uniqueNodes[2] = curNodes[3];
5417               uniqueNodes[3] = curNodes[5];
5418               uniqueNodes[4] = curNodes[6];
5419               uniqueNodes[5] = curNodes[0];
5420               isOk = true;
5421             }
5422             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
5423               uniqueNodes[0] = curNodes[0];
5424               uniqueNodes[1] = curNodes[1];
5425               uniqueNodes[2] = curNodes[3];
5426               uniqueNodes[3] = curNodes[4];
5427               uniqueNodes[4] = curNodes[6];
5428               uniqueNodes[5] = curNodes[7];
5429               isOk = true;
5430             }
5431             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
5432               uniqueNodes[0] = curNodes[0];
5433               uniqueNodes[1] = curNodes[2];
5434               uniqueNodes[2] = curNodes[3];
5435               uniqueNodes[3] = curNodes[1];
5436               uniqueNodes[4] = curNodes[6];
5437               uniqueNodes[5] = curNodes[7];
5438               isOk = true;
5439             }
5440             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
5441               uniqueNodes[0] = curNodes[0];
5442               uniqueNodes[1] = curNodes[1];
5443               uniqueNodes[2] = curNodes[2];
5444               uniqueNodes[3] = curNodes[4];
5445               uniqueNodes[4] = curNodes[5];
5446               uniqueNodes[5] = curNodes[7];
5447               isOk = true;
5448             }
5449             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
5450               uniqueNodes[0] = curNodes[0];
5451               uniqueNodes[1] = curNodes[1];
5452               uniqueNodes[2] = curNodes[3];
5453               uniqueNodes[3] = curNodes[4];
5454               uniqueNodes[4] = curNodes[2];
5455               uniqueNodes[5] = curNodes[7];
5456               isOk = true;
5457             }
5458             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
5459               uniqueNodes[0] = curNodes[0];
5460               uniqueNodes[1] = curNodes[1];
5461               uniqueNodes[2] = curNodes[2];
5462               uniqueNodes[3] = curNodes[4];
5463               uniqueNodes[4] = curNodes[5];
5464               uniqueNodes[5] = curNodes[3];
5465               isOk = true;
5466             }
5467           }
5468           break;
5469         }
5470         //////////////////////////////////// HEXAHEDRON
5471         isOk = false;
5472         SMDS_VolumeTool hexa (elem);
5473         hexa.SetExternalNormal();
5474         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
5475           //////////////////////// ---> tetrahedron
5476           for ( int iFace = 0; iFace < 6; iFace++ ) {
5477             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5478             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5479                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5480                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5481               // one face turns into a point ...
5482               int iOppFace = hexa.GetOppFaceIndex( iFace );
5483               ind = hexa.GetFaceNodesIndices( iOppFace );
5484               int nbStick = 0;
5485               iUnique = 2; // reverse a tetrahedron bottom
5486               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
5487                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5488                   nbStick++;
5489                 else if ( iUnique >= 0 )
5490                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5491               }
5492               if ( nbStick == 1 ) {
5493                 // ... and the opposite one - into a triangle.
5494                 // set a top node
5495                 ind = hexa.GetFaceNodesIndices( iFace );
5496                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
5497                 isOk = true;
5498               }
5499               break;
5500             }
5501           }
5502         }
5503         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
5504           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
5505           for ( int iFace = 0; iFace < 6; iFace++ ) {
5506             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5507             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5508                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5509                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5510               // one face turns into a point ...
5511               int iOppFace = hexa.GetOppFaceIndex( iFace );
5512               ind = hexa.GetFaceNodesIndices( iOppFace );
5513               int nbStick = 0;
5514               iUnique = 2;  // reverse a tetrahedron 1 bottom
5515               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
5516                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5517                   nbStick++;
5518                 else if ( iUnique >= 0 )
5519                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5520               }
5521               if ( nbStick == 0 ) {
5522                 // ... and the opposite one is a quadrangle
5523                 // set a top node
5524                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
5525                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
5526                 nbUniqueNodes = 4;
5527                 // tetrahedron 2
5528                 SMDS_MeshElement* newElem =
5529                   aMesh->AddVolume(curNodes[ind[ 0 ]],
5530                                    curNodes[ind[ 3 ]],
5531                                    curNodes[ind[ 2 ]],
5532                                    curNodes[indTop[ 0 ]]);
5533                 myLastCreatedElems.Append(newElem);
5534                 if ( aShapeId )
5535                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
5536                 isOk = true;
5537               }
5538               break;
5539             }
5540           }
5541         }
5542         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
5543           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
5544           // find indices of quad and tri faces
5545           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
5546           for ( iFace = 0; iFace < 6; iFace++ ) {
5547             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5548             nodeSet.clear();
5549             for ( iCur = 0; iCur < 4; iCur++ )
5550               nodeSet.insert( curNodes[ind[ iCur ]] );
5551             nbUniqueNodes = nodeSet.size();
5552             if ( nbUniqueNodes == 3 )
5553               iTriFace[ nbTri++ ] = iFace;
5554             else if ( nbUniqueNodes == 4 )
5555               iQuadFace[ nbQuad++ ] = iFace;
5556           }
5557           if (nbQuad == 2 && nbTri == 4 &&
5558               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
5559             // 2 opposite quadrangles stuck with a diagonal;
5560             // sample groups of merged indices: (0-4)(2-6)
5561             // --------------------------------------------> 2 tetrahedrons
5562             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
5563             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
5564             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
5565             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
5566                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
5567               // stuck with 0-2 diagonal
5568               i0  = ind1[ 3 ];
5569               i1d = ind1[ 0 ];
5570               i2  = ind1[ 1 ];
5571               i3d = ind1[ 2 ];
5572               i0t = ind2[ 1 ];
5573               i2t = ind2[ 3 ];
5574             }
5575             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
5576                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
5577               // stuck with 1-3 diagonal
5578               i0  = ind1[ 0 ];
5579               i1d = ind1[ 1 ];
5580               i2  = ind1[ 2 ];
5581               i3d = ind1[ 3 ];
5582               i0t = ind2[ 0 ];
5583               i2t = ind2[ 1 ];
5584             }
5585             else {
5586               ASSERT(0);
5587             }
5588             // tetrahedron 1
5589             uniqueNodes[ 0 ] = curNodes [ i0 ];
5590             uniqueNodes[ 1 ] = curNodes [ i1d ];
5591             uniqueNodes[ 2 ] = curNodes [ i3d ];
5592             uniqueNodes[ 3 ] = curNodes [ i0t ];
5593             nbUniqueNodes = 4;
5594             // tetrahedron 2
5595             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
5596                                                          curNodes[ i2 ],
5597                                                          curNodes[ i3d ],
5598                                                          curNodes[ i2t ]);
5599             myLastCreatedElems.Append(newElem);
5600             if ( aShapeId )
5601               aMesh->SetMeshElementOnShape( newElem, aShapeId );
5602             isOk = true;
5603           }
5604           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
5605                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
5606             // --------------------------------------------> prism
5607             // find 2 opposite triangles
5608             nbUniqueNodes = 6;
5609             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
5610               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
5611                 // find indices of kept and replaced nodes
5612                 // and fill unique nodes of 2 opposite triangles
5613                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
5614                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
5615                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
5616                 // fill unique nodes
5617                 iUnique = 0;
5618                 isOk = true;
5619                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
5620                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
5621                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
5622                   if ( n == nInit ) {
5623                     // iCur of a linked node of the opposite face (make normals co-directed):
5624                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
5625                     // check that correspondent corners of triangles are linked
5626                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
5627                       isOk = false;
5628                     else {
5629                       uniqueNodes[ iUnique ] = n;
5630                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
5631                       iUnique++;
5632                     }
5633                   }
5634                 }
5635                 break;
5636               }
5637             }
5638           }
5639         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
5640         break;
5641       } // HEXAHEDRON
5642
5643       default:
5644         isOk = false;
5645       } // switch ( nbNodes )
5646
5647     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
5648
5649     if ( isOk ) {
5650       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
5651         // Change nodes of polyedre
5652         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5653           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5654         if (aPolyedre) {
5655           int nbFaces = aPolyedre->NbFaces();
5656
5657           vector<const SMDS_MeshNode *> poly_nodes;
5658           vector<int> quantities (nbFaces);
5659
5660           for (int iface = 1; iface <= nbFaces; iface++) {
5661             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5662             quantities[iface - 1] = nbFaceNodes;
5663
5664             for (inode = 1; inode <= nbFaceNodes; inode++) {
5665               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
5666
5667               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
5668               if (nnIt != nodeNodeMap.end()) { // curNode sticks
5669                 curNode = (*nnIt).second;
5670               }
5671               poly_nodes.push_back(curNode);
5672             }
5673           }
5674           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
5675         }
5676       }
5677       else {
5678         // Change regular element or polygon
5679         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
5680       }
5681     }
5682     else {
5683       // Remove invalid regular element or invalid polygon
5684       rmElemIds.push_back( elem->GetID() );
5685     }
5686
5687   } // loop on elements
5688
5689   // Remove equal nodes and bad elements
5690
5691   Remove( rmNodeIds, true );
5692   Remove( rmElemIds, false );
5693
5694 }
5695
5696
5697 // ========================================================
5698 // class   : SortableElement
5699 // purpose : allow sorting elements basing on their nodes
5700 // ========================================================
5701 class SortableElement : public set <const SMDS_MeshElement*>
5702 {
5703  public:
5704
5705   SortableElement( const SMDS_MeshElement* theElem )
5706     {
5707       myElem = theElem;
5708       SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
5709       while ( nodeIt->more() )
5710         this->insert( nodeIt->next() );
5711     }
5712
5713   const SMDS_MeshElement* Get() const
5714     { return myElem; }
5715
5716   void Set(const SMDS_MeshElement* e) const
5717     { myElem = e; }
5718
5719
5720  private:
5721   mutable const SMDS_MeshElement* myElem;
5722 };
5723
5724 //=======================================================================
5725 //function : FindEqualElements
5726 //purpose  : Return list of group of elements built on the same nodes.
5727 //           Search among theElements or in the whole mesh if theElements is empty
5728 //=======================================================================
5729 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
5730                                          TListOfListOfElementsID &      theGroupsOfElementsID)
5731 {
5732   myLastCreatedElems.Clear();
5733   myLastCreatedNodes.Clear();
5734
5735   typedef set<const SMDS_MeshElement*> TElemsSet;
5736   typedef map< SortableElement, int > TMapOfNodeSet;
5737   typedef list<int> TGroupOfElems;
5738
5739   TElemsSet elems;
5740   if ( theElements.empty() )
5741   { // get all elements in the mesh
5742     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
5743     while ( eIt->more() )
5744       elems.insert( elems.end(), eIt->next());
5745   }
5746   else
5747     elems = theElements;
5748
5749   vector< TGroupOfElems > arrayOfGroups;
5750   TGroupOfElems groupOfElems;
5751   TMapOfNodeSet mapOfNodeSet;
5752
5753   TElemsSet::iterator elemIt = elems.begin();
5754   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
5755     const SMDS_MeshElement* curElem = *elemIt;
5756     SortableElement SE(curElem);
5757     int ind = -1;
5758     // check uniqueness
5759     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
5760     if( !(pp.second) ) {
5761       TMapOfNodeSet::iterator& itSE = pp.first;
5762       ind = (*itSE).second;
5763       arrayOfGroups[ind].push_back(curElem->GetID());
5764     }
5765     else {
5766       groupOfElems.clear();
5767       groupOfElems.push_back(curElem->GetID());
5768       arrayOfGroups.push_back(groupOfElems);
5769       i++;
5770     }
5771   }
5772
5773   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
5774   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
5775     groupOfElems = *groupIt;
5776     if ( groupOfElems.size() > 1 ) {
5777       groupOfElems.sort();
5778       theGroupsOfElementsID.push_back(groupOfElems);
5779     }
5780   }
5781 }
5782
5783 //=======================================================================
5784 //function : MergeElements
5785 //purpose  : In each given group, substitute all elements by the first one.
5786 //=======================================================================
5787
5788 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
5789 {
5790   myLastCreatedElems.Clear();
5791   myLastCreatedNodes.Clear();
5792
5793   typedef list<int> TListOfIDs;
5794   TListOfIDs rmElemIds; // IDs of elems to remove
5795
5796   SMESHDS_Mesh* aMesh = GetMeshDS();
5797
5798   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
5799   while ( groupsIt != theGroupsOfElementsID.end() ) {
5800     TListOfIDs& aGroupOfElemID = *groupsIt;
5801     aGroupOfElemID.sort();
5802     int elemIDToKeep = aGroupOfElemID.front();
5803     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
5804     aGroupOfElemID.pop_front();
5805     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
5806     while ( idIt != aGroupOfElemID.end() ) {
5807       int elemIDToRemove = *idIt;
5808       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
5809       // add the kept element in groups of removed one (PAL15188)
5810       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
5811       rmElemIds.push_back( elemIDToRemove );
5812       ++idIt;
5813     }
5814     ++groupsIt;
5815   }
5816
5817   Remove( rmElemIds, false );
5818 }
5819
5820 //=======================================================================
5821 //function : MergeEqualElements
5822 //purpose  : Remove all but one of elements built on the same nodes.
5823 //=======================================================================
5824
5825 void SMESH_MeshEditor::MergeEqualElements()
5826 {
5827   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
5828                                                  to merge equal elements in the whole mesh */
5829   TListOfListOfElementsID aGroupsOfElementsID;
5830   FindEqualElements(aMeshElements, aGroupsOfElementsID);
5831   MergeElements(aGroupsOfElementsID);
5832 }
5833
5834 //=======================================================================
5835 //function : FindFaceInSet
5836 //purpose  : Return a face having linked nodes n1 and n2 and which is
5837 //           - not in avoidSet,
5838 //           - in elemSet provided that !elemSet.empty()
5839 //=======================================================================
5840
5841 const SMDS_MeshElement*
5842   SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
5843                                   const SMDS_MeshNode*    n2,
5844                                   const TIDSortedElemSet& elemSet,
5845                                   const TIDSortedElemSet& avoidSet)
5846
5847 {
5848   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
5849   while ( invElemIt->more() ) { // loop on inverse elements of n1
5850     const SMDS_MeshElement* elem = invElemIt->next();
5851     if (avoidSet.find( elem ) != avoidSet.end() )
5852       continue;
5853     if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
5854       continue;
5855     // get face nodes and find index of n1
5856     int i1, nbN = elem->NbNodes(), iNode = 0;
5857     //const SMDS_MeshNode* faceNodes[ nbN ], *n;
5858     vector<const SMDS_MeshNode*> faceNodes( nbN );
5859     const SMDS_MeshNode* n;
5860     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5861     while ( nIt->more() ) {
5862       faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5863       if ( faceNodes[ iNode++ ] == n1 )
5864         i1 = iNode - 1;
5865     }
5866     // find a n2 linked to n1
5867     if(!elem->IsQuadratic()) {
5868       for ( iNode = 0; iNode < 2; iNode++ ) {
5869         if ( iNode ) // node before n1
5870           n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
5871         else         // node after n1
5872           n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
5873         if ( n == n2 )
5874           return elem;
5875       }
5876     }
5877     else { // analysis for quadratic elements
5878       bool IsFind = false;
5879       // check using only corner nodes
5880       for ( iNode = 0; iNode < 2; iNode++ ) {
5881         if ( iNode ) // node before n1
5882           n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
5883         else         // node after n1
5884           n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
5885         if ( n == n2 )
5886           IsFind = true;
5887       }
5888       if(IsFind) {
5889         return elem;
5890       }
5891       else {
5892         // check using all nodes
5893         const SMDS_QuadraticFaceOfNodes* F =
5894           static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
5895         // use special nodes iterator
5896         iNode = 0;
5897         SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5898         while ( anIter->more() ) {
5899           faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
5900           if ( faceNodes[ iNode++ ] == n1 )
5901             i1 = iNode - 1;
5902         }
5903         for ( iNode = 0; iNode < 2; iNode++ ) {
5904           if ( iNode ) // node before n1
5905             n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
5906           else         // node after n1
5907             n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
5908           if ( n == n2 ) {
5909             return elem;
5910           }
5911         }
5912       }
5913     } // end analysis for quadratic elements
5914   }
5915   return 0;
5916 }
5917
5918 //=======================================================================
5919 //function : findAdjacentFace
5920 //purpose  :
5921 //=======================================================================
5922
5923 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
5924                                                 const SMDS_MeshNode* n2,
5925                                                 const SMDS_MeshElement* elem)
5926 {
5927   TIDSortedElemSet elemSet, avoidSet;
5928   if ( elem )
5929     avoidSet.insert ( elem );
5930   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
5931 }
5932
5933 //=======================================================================
5934 //function : FindFreeBorder
5935 //purpose  :
5936 //=======================================================================
5937
5938 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
5939
5940 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
5941                                        const SMDS_MeshNode*             theSecondNode,
5942                                        const SMDS_MeshNode*             theLastNode,
5943                                        list< const SMDS_MeshNode* > &   theNodes,
5944                                        list< const SMDS_MeshElement* >& theFaces)
5945 {
5946   if ( !theFirstNode || !theSecondNode )
5947     return false;
5948   // find border face between theFirstNode and theSecondNode
5949   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
5950   if ( !curElem )
5951     return false;
5952
5953   theFaces.push_back( curElem );
5954   theNodes.push_back( theFirstNode );
5955   theNodes.push_back( theSecondNode );
5956
5957   //vector<const SMDS_MeshNode*> nodes;
5958   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
5959   set < const SMDS_MeshElement* > foundElems;
5960   bool needTheLast = ( theLastNode != 0 );
5961
5962   while ( nStart != theLastNode ) {
5963     if ( nStart == theFirstNode )
5964       return !needTheLast;
5965
5966     // find all free border faces sharing form nStart
5967
5968     list< const SMDS_MeshElement* > curElemList;
5969     list< const SMDS_MeshNode* > nStartList;
5970     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
5971     while ( invElemIt->more() ) {
5972       const SMDS_MeshElement* e = invElemIt->next();
5973       if ( e == curElem || foundElems.insert( e ).second ) {
5974         // get nodes
5975         int iNode = 0, nbNodes = e->NbNodes();
5976         //const SMDS_MeshNode* nodes[nbNodes+1];
5977         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
5978         
5979         if(e->IsQuadratic()) {
5980           const SMDS_QuadraticFaceOfNodes* F =
5981             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
5982           // use special nodes iterator
5983           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5984           while( anIter->more() ) {
5985             nodes[ iNode++ ] = anIter->next();
5986           }
5987         }
5988         else {
5989           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
5990           while ( nIt->more() )
5991             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5992         }
5993         nodes[ iNode ] = nodes[ 0 ];
5994         // check 2 links
5995         for ( iNode = 0; iNode < nbNodes; iNode++ )
5996           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
5997                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
5998               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
5999           {
6000             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6001             curElemList.push_back( e );
6002           }
6003       }
6004     }
6005     // analyse the found
6006
6007     int nbNewBorders = curElemList.size();
6008     if ( nbNewBorders == 0 ) {
6009       // no free border furthermore
6010       return !needTheLast;
6011     }
6012     else if ( nbNewBorders == 1 ) {
6013       // one more element found
6014       nIgnore = nStart;
6015       nStart = nStartList.front();
6016       curElem = curElemList.front();
6017       theFaces.push_back( curElem );
6018       theNodes.push_back( nStart );
6019     }
6020     else {
6021       // several continuations found
6022       list< const SMDS_MeshElement* >::iterator curElemIt;
6023       list< const SMDS_MeshNode* >::iterator nStartIt;
6024       // check if one of them reached the last node
6025       if ( needTheLast ) {
6026         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6027              curElemIt!= curElemList.end();
6028              curElemIt++, nStartIt++ )
6029           if ( *nStartIt == theLastNode ) {
6030             theFaces.push_back( *curElemIt );
6031             theNodes.push_back( *nStartIt );
6032             return true;
6033           }
6034       }
6035       // find the best free border by the continuations
6036       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
6037       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6038       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6039            curElemIt!= curElemList.end();
6040            curElemIt++, nStartIt++ )
6041       {
6042         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6043         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6044         // find one more free border
6045         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6046           cNL->clear();
6047           cFL->clear();
6048         }
6049         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6050           // choice: clear a worse one
6051           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6052           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6053           contNodes[ iWorse ].clear();
6054           contFaces[ iWorse ].clear();
6055         }
6056       }
6057       if ( contNodes[0].empty() && contNodes[1].empty() )
6058         return false;
6059
6060       // append the best free border
6061       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6062       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6063       theNodes.pop_back(); // remove nIgnore
6064       theNodes.pop_back(); // remove nStart
6065       theFaces.pop_back(); // remove curElem
6066       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6067       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6068       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6069       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6070       return true;
6071
6072     } // several continuations found
6073   } // while ( nStart != theLastNode )
6074
6075   return true;
6076 }
6077
6078 //=======================================================================
6079 //function : CheckFreeBorderNodes
6080 //purpose  : Return true if the tree nodes are on a free border
6081 //=======================================================================
6082
6083 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6084                                             const SMDS_MeshNode* theNode2,
6085                                             const SMDS_MeshNode* theNode3)
6086 {
6087   list< const SMDS_MeshNode* > nodes;
6088   list< const SMDS_MeshElement* > faces;
6089   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6090 }
6091
6092 //=======================================================================
6093 //function : SewFreeBorder
6094 //purpose  :
6095 //=======================================================================
6096
6097 SMESH_MeshEditor::Sew_Error
6098   SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6099                                    const SMDS_MeshNode* theBordSecondNode,
6100                                    const SMDS_MeshNode* theBordLastNode,
6101                                    const SMDS_MeshNode* theSideFirstNode,
6102                                    const SMDS_MeshNode* theSideSecondNode,
6103                                    const SMDS_MeshNode* theSideThirdNode,
6104                                    const bool           theSideIsFreeBorder,
6105                                    const bool           toCreatePolygons,
6106                                    const bool           toCreatePolyedrs)
6107 {
6108   myLastCreatedElems.Clear();
6109   myLastCreatedNodes.Clear();
6110
6111   MESSAGE("::SewFreeBorder()");
6112   Sew_Error aResult = SEW_OK;
6113
6114   // ====================================
6115   //    find side nodes and elements
6116   // ====================================
6117
6118   list< const SMDS_MeshNode* > nSide[ 2 ];
6119   list< const SMDS_MeshElement* > eSide[ 2 ];
6120   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6121   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6122
6123   // Free border 1
6124   // --------------
6125   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6126                       nSide[0], eSide[0])) {
6127     MESSAGE(" Free Border 1 not found " );
6128     aResult = SEW_BORDER1_NOT_FOUND;
6129   }
6130   if (theSideIsFreeBorder) {
6131     // Free border 2
6132     // --------------
6133     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6134                         nSide[1], eSide[1])) {
6135       MESSAGE(" Free Border 2 not found " );
6136       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6137     }
6138   }
6139   if ( aResult != SEW_OK )
6140     return aResult;
6141
6142   if (!theSideIsFreeBorder) {
6143     // Side 2
6144     // --------------
6145
6146     // -------------------------------------------------------------------------
6147     // Algo:
6148     // 1. If nodes to merge are not coincident, move nodes of the free border
6149     //    from the coord sys defined by the direction from the first to last
6150     //    nodes of the border to the correspondent sys of the side 2
6151     // 2. On the side 2, find the links most co-directed with the correspondent
6152     //    links of the free border
6153     // -------------------------------------------------------------------------
6154
6155     // 1. Since sewing may brake if there are volumes to split on the side 2,
6156     //    we wont move nodes but just compute new coordinates for them
6157     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6158     TNodeXYZMap nBordXYZ;
6159     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6160     list< const SMDS_MeshNode* >::iterator nBordIt;
6161
6162     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6163     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6164     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6165     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6166     double tol2 = 1.e-8;
6167     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6168     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6169       // Need node movement.
6170
6171       // find X and Z axes to create trsf
6172       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6173       gp_Vec X = Zs ^ Zb;
6174       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6175         // Zb || Zs
6176         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6177
6178       // coord systems
6179       gp_Ax3 toBordAx( Pb1, Zb, X );
6180       gp_Ax3 fromSideAx( Ps1, Zs, X );
6181       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6182       // set trsf
6183       gp_Trsf toBordSys, fromSide2Sys;
6184       toBordSys.SetTransformation( toBordAx );
6185       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6186       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6187
6188       // move
6189       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6190         const SMDS_MeshNode* n = *nBordIt;
6191         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6192         toBordSys.Transforms( xyz );
6193         fromSide2Sys.Transforms( xyz );
6194         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6195       }
6196     }
6197     else {
6198       // just insert nodes XYZ in the nBordXYZ map
6199       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6200         const SMDS_MeshNode* n = *nBordIt;
6201         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6202       }
6203     }
6204
6205     // 2. On the side 2, find the links most co-directed with the correspondent
6206     //    links of the free border
6207
6208     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6209     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6210     sideNodes.push_back( theSideFirstNode );
6211
6212     bool hasVolumes = false;
6213     LinkID_Gen aLinkID_Gen( GetMeshDS() );
6214     set<long> foundSideLinkIDs, checkedLinkIDs;
6215     SMDS_VolumeTool volume;
6216     //const SMDS_MeshNode* faceNodes[ 4 ];
6217
6218     const SMDS_MeshNode*    sideNode;
6219     const SMDS_MeshElement* sideElem;
6220     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6221     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6222     nBordIt = bordNodes.begin();
6223     nBordIt++;
6224     // border node position and border link direction to compare with
6225     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6226     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6227     // choose next side node by link direction or by closeness to
6228     // the current border node:
6229     bool searchByDir = ( *nBordIt != theBordLastNode );
6230     do {
6231       // find the next node on the Side 2
6232       sideNode = 0;
6233       double maxDot = -DBL_MAX, minDist = DBL_MAX;
6234       long linkID;
6235       checkedLinkIDs.clear();
6236       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6237
6238       // loop on inverse elements of current node (prevSideNode) on the Side 2
6239       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6240       while ( invElemIt->more() )
6241       {
6242         const SMDS_MeshElement* elem = invElemIt->next();
6243         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6244         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6245         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6246         bool isVolume = volume.Set( elem );
6247         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6248         if ( isVolume ) // --volume
6249           hasVolumes = true;
6250         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6251           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6252           if(elem->IsQuadratic()) {
6253             const SMDS_QuadraticFaceOfNodes* F =
6254               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6255             // use special nodes iterator
6256             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6257             while( anIter->more() ) {
6258               nodes[ iNode ] = anIter->next();
6259               if ( nodes[ iNode++ ] == prevSideNode )
6260                 iPrevNode = iNode - 1;
6261             }
6262           }
6263           else {
6264             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6265             while ( nIt->more() ) {
6266               nodes[ iNode ] = cast2Node( nIt->next() );
6267               if ( nodes[ iNode++ ] == prevSideNode )
6268                 iPrevNode = iNode - 1;
6269             }
6270           }
6271           // there are 2 links to check
6272           nbNodes = 2;
6273         }
6274         else // --edge
6275           continue;
6276         // loop on links, to be precise, on the second node of links
6277         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6278           const SMDS_MeshNode* n = nodes[ iNode ];
6279           if ( isVolume ) {
6280             if ( !volume.IsLinked( n, prevSideNode ))
6281               continue;
6282           }
6283           else {
6284             if ( iNode ) // a node before prevSideNode
6285               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6286             else         // a node after prevSideNode
6287               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6288           }
6289           // check if this link was already used
6290           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6291           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6292           if (!isJustChecked &&
6293               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6294           {
6295             // test a link geometrically
6296             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6297             bool linkIsBetter = false;
6298             double dot = 0.0, dist = 0.0;
6299             if ( searchByDir ) { // choose most co-directed link
6300               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6301               linkIsBetter = ( dot > maxDot );
6302             }
6303             else { // choose link with the node closest to bordPos
6304               dist = ( nextXYZ - bordPos ).SquareModulus();
6305               linkIsBetter = ( dist < minDist );
6306             }
6307             if ( linkIsBetter ) {
6308               maxDot = dot;
6309               minDist = dist;
6310               linkID = iLink;
6311               sideNode = n;
6312               sideElem = elem;
6313             }
6314           }
6315         }
6316       } // loop on inverse elements of prevSideNode
6317
6318       if ( !sideNode ) {
6319         MESSAGE(" Cant find path by links of the Side 2 ");
6320         return SEW_BAD_SIDE_NODES;
6321       }
6322       sideNodes.push_back( sideNode );
6323       sideElems.push_back( sideElem );
6324       foundSideLinkIDs.insert ( linkID );
6325       prevSideNode = sideNode;
6326
6327       if ( *nBordIt == theBordLastNode )
6328         searchByDir = false;
6329       else {
6330         // find the next border link to compare with
6331         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6332         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6333         // move to next border node if sideNode is before forward border node (bordPos)
6334         while ( *nBordIt != theBordLastNode && !searchByDir ) {
6335           prevBordNode = *nBordIt;
6336           nBordIt++;
6337           bordPos = nBordXYZ[ *nBordIt ];
6338           bordDir = bordPos - nBordXYZ[ prevBordNode ];
6339           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6340         }
6341       }
6342     }
6343     while ( sideNode != theSideSecondNode );
6344
6345     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
6346       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
6347       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
6348     }
6349   } // end nodes search on the side 2
6350
6351   // ============================
6352   // sew the border to the side 2
6353   // ============================
6354
6355   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
6356   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
6357
6358   TListOfListOfNodes nodeGroupsToMerge;
6359   if ( nbNodes[0] == nbNodes[1] ||
6360       ( theSideIsFreeBorder && !theSideThirdNode)) {
6361
6362     // all nodes are to be merged
6363
6364     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
6365          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
6366          nIt[0]++, nIt[1]++ )
6367     {
6368       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6369       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
6370       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
6371     }
6372   }
6373   else {
6374
6375     // insert new nodes into the border and the side to get equal nb of segments
6376
6377     // get normalized parameters of nodes on the borders
6378     //double param[ 2 ][ maxNbNodes ];
6379     double* param[ 2 ];
6380     param[0] = new double [ maxNbNodes ];
6381     param[1] = new double [ maxNbNodes ];
6382     int iNode, iBord;
6383     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6384       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
6385       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
6386       const SMDS_MeshNode* nPrev = *nIt;
6387       double bordLength = 0;
6388       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
6389         const SMDS_MeshNode* nCur = *nIt;
6390         gp_XYZ segment (nCur->X() - nPrev->X(),
6391                         nCur->Y() - nPrev->Y(),
6392                         nCur->Z() - nPrev->Z());
6393         double segmentLen = segment.Modulus();
6394         bordLength += segmentLen;
6395         param[ iBord ][ iNode ] = bordLength;
6396         nPrev = nCur;
6397       }
6398       // normalize within [0,1]
6399       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
6400         param[ iBord ][ iNode ] /= bordLength;
6401       }
6402     }
6403
6404     // loop on border segments
6405     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
6406     int i[ 2 ] = { 0, 0 };
6407     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
6408     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
6409
6410     TElemOfNodeListMap insertMap;
6411     TElemOfNodeListMap::iterator insertMapIt;
6412     // insertMap is
6413     // key:   elem to insert nodes into
6414     // value: 2 nodes to insert between + nodes to be inserted
6415     do {
6416       bool next[ 2 ] = { false, false };
6417
6418       // find min adjacent segment length after sewing
6419       double nextParam = 10., prevParam = 0;
6420       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6421         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
6422           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
6423         if ( i[ iBord ] > 0 )
6424           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
6425       }
6426       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6427       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6428       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
6429
6430       // choose to insert or to merge nodes
6431       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
6432       if ( Abs( du ) <= minSegLen * 0.2 ) {
6433         // merge
6434         // ------
6435         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6436         const SMDS_MeshNode* n0 = *nIt[0];
6437         const SMDS_MeshNode* n1 = *nIt[1];
6438         nodeGroupsToMerge.back().push_back( n1 );
6439         nodeGroupsToMerge.back().push_back( n0 );
6440         // position of node of the border changes due to merge
6441         param[ 0 ][ i[0] ] += du;
6442         // move n1 for the sake of elem shape evaluation during insertion.
6443         // n1 will be removed by MergeNodes() anyway
6444         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
6445         next[0] = next[1] = true;
6446       }
6447       else {
6448         // insert
6449         // ------
6450         int intoBord = ( du < 0 ) ? 0 : 1;
6451         const SMDS_MeshElement* elem = *eIt[ intoBord ];
6452         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
6453         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
6454         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
6455         if ( intoBord == 1 ) {
6456           // move node of the border to be on a link of elem of the side
6457           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
6458           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
6459           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
6460           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
6461           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
6462         }
6463         insertMapIt = insertMap.find( elem );
6464         bool notFound = ( insertMapIt == insertMap.end() );
6465         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
6466         if ( otherLink ) {
6467           // insert into another link of the same element:
6468           // 1. perform insertion into the other link of the elem
6469           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6470           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
6471           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
6472           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
6473           // 2. perform insertion into the link of adjacent faces
6474           while (true) {
6475             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
6476             if ( adjElem )
6477               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
6478             else
6479               break;
6480           }
6481           if (toCreatePolyedrs) {
6482             // perform insertion into the links of adjacent volumes
6483             UpdateVolumes(n12, n22, nodeList);
6484           }
6485           // 3. find an element appeared on n1 and n2 after the insertion
6486           insertMap.erase( elem );
6487           elem = findAdjacentFace( n1, n2, 0 );
6488         }
6489         if ( notFound || otherLink ) {
6490           // add element and nodes of the side into the insertMap
6491           insertMapIt = insertMap.insert
6492             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
6493           (*insertMapIt).second.push_back( n1 );
6494           (*insertMapIt).second.push_back( n2 );
6495         }
6496         // add node to be inserted into elem
6497         (*insertMapIt).second.push_back( nIns );
6498         next[ 1 - intoBord ] = true;
6499       }
6500
6501       // go to the next segment
6502       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6503         if ( next[ iBord ] ) {
6504           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
6505             eIt[ iBord ]++;
6506           nPrev[ iBord ] = *nIt[ iBord ];
6507           nIt[ iBord ]++; i[ iBord ]++;
6508         }
6509       }
6510     }
6511     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
6512
6513     // perform insertion of nodes into elements
6514
6515     for (insertMapIt = insertMap.begin();
6516          insertMapIt != insertMap.end();
6517          insertMapIt++ )
6518     {
6519       const SMDS_MeshElement* elem = (*insertMapIt).first;
6520       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6521       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
6522       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
6523
6524       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
6525
6526       if ( !theSideIsFreeBorder ) {
6527         // look for and insert nodes into the faces adjacent to elem
6528         while (true) {
6529           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
6530           if ( adjElem )
6531             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
6532           else
6533             break;
6534         }
6535       }
6536       if (toCreatePolyedrs) {
6537         // perform insertion into the links of adjacent volumes
6538         UpdateVolumes(n1, n2, nodeList);
6539       }
6540     }
6541
6542     delete param[0];
6543     delete param[1];
6544   } // end: insert new nodes
6545
6546   MergeNodes ( nodeGroupsToMerge );
6547
6548   return aResult;
6549 }
6550
6551 //=======================================================================
6552 //function : InsertNodesIntoLink
6553 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
6554 //           and theBetweenNode2 and split theElement
6555 //=======================================================================
6556
6557 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
6558                                            const SMDS_MeshNode*        theBetweenNode1,
6559                                            const SMDS_MeshNode*        theBetweenNode2,
6560                                            list<const SMDS_MeshNode*>& theNodesToInsert,
6561                                            const bool                  toCreatePoly)
6562 {
6563   if ( theFace->GetType() != SMDSAbs_Face ) return;
6564
6565   // find indices of 2 link nodes and of the rest nodes
6566   int iNode = 0, il1, il2, i3, i4;
6567   il1 = il2 = i3 = i4 = -1;
6568   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
6569   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
6570
6571   if(theFace->IsQuadratic()) {
6572     const SMDS_QuadraticFaceOfNodes* F =
6573       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6574     // use special nodes iterator
6575     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6576     while( anIter->more() ) {
6577       const SMDS_MeshNode* n = anIter->next();
6578       if ( n == theBetweenNode1 )
6579         il1 = iNode;
6580       else if ( n == theBetweenNode2 )
6581         il2 = iNode;
6582       else if ( i3 < 0 )
6583         i3 = iNode;
6584       else
6585         i4 = iNode;
6586       nodes[ iNode++ ] = n;
6587     }
6588   }
6589   else {
6590     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6591     while ( nodeIt->more() ) {
6592       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6593       if ( n == theBetweenNode1 )
6594         il1 = iNode;
6595       else if ( n == theBetweenNode2 )
6596         il2 = iNode;
6597       else if ( i3 < 0 )
6598         i3 = iNode;
6599       else
6600         i4 = iNode;
6601       nodes[ iNode++ ] = n;
6602     }
6603   }
6604   if ( il1 < 0 || il2 < 0 || i3 < 0 )
6605     return ;
6606
6607   // arrange link nodes to go one after another regarding the face orientation
6608   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
6609   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
6610   if ( reverse ) {
6611     iNode = il1;
6612     il1 = il2;
6613     il2 = iNode;
6614     aNodesToInsert.reverse();
6615   }
6616   // check that not link nodes of a quadrangles are in good order
6617   int nbFaceNodes = theFace->NbNodes();
6618   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
6619     iNode = i3;
6620     i3 = i4;
6621     i4 = iNode;
6622   }
6623
6624   if (toCreatePoly || theFace->IsPoly()) {
6625
6626     iNode = 0;
6627     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
6628
6629     // add nodes of face up to first node of link
6630     bool isFLN = false;
6631
6632     if(theFace->IsQuadratic()) {
6633       const SMDS_QuadraticFaceOfNodes* F =
6634         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6635       // use special nodes iterator
6636       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6637       while( anIter->more()  && !isFLN ) {
6638         const SMDS_MeshNode* n = anIter->next();
6639         poly_nodes[iNode++] = n;
6640         if (n == nodes[il1]) {
6641           isFLN = true;
6642         }
6643       }
6644       // add nodes to insert
6645       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6646       for (; nIt != aNodesToInsert.end(); nIt++) {
6647         poly_nodes[iNode++] = *nIt;
6648       }
6649       // add nodes of face starting from last node of link
6650       while ( anIter->more() ) {
6651         poly_nodes[iNode++] = anIter->next();
6652       }
6653     }
6654     else {
6655       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6656       while ( nodeIt->more() && !isFLN ) {
6657         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6658         poly_nodes[iNode++] = n;
6659         if (n == nodes[il1]) {
6660           isFLN = true;
6661         }
6662       }
6663       // add nodes to insert
6664       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6665       for (; nIt != aNodesToInsert.end(); nIt++) {
6666         poly_nodes[iNode++] = *nIt;
6667       }
6668       // add nodes of face starting from last node of link
6669       while ( nodeIt->more() ) {
6670         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6671         poly_nodes[iNode++] = n;
6672       }
6673     }
6674
6675     // edit or replace the face
6676     SMESHDS_Mesh *aMesh = GetMeshDS();
6677
6678     if (theFace->IsPoly()) {
6679       aMesh->ChangePolygonNodes(theFace, poly_nodes);
6680     }
6681     else {
6682       int aShapeId = FindShape( theFace );
6683
6684       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6685       myLastCreatedElems.Append(newElem);
6686       if ( aShapeId && newElem )
6687         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6688
6689       aMesh->RemoveElement(theFace);
6690     }
6691     return;
6692   }
6693
6694   if( !theFace->IsQuadratic() ) {
6695
6696     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
6697     int nbLinkNodes = 2 + aNodesToInsert.size();
6698     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
6699     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
6700     linkNodes[ 0 ] = nodes[ il1 ];
6701     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
6702     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6703     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6704       linkNodes[ iNode++ ] = *nIt;
6705     }
6706     // decide how to split a quadrangle: compare possible variants
6707     // and choose which of splits to be a quadrangle
6708     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
6709     if ( nbFaceNodes == 3 ) {
6710       iBestQuad = nbSplits;
6711       i4 = i3;
6712     }
6713     else if ( nbFaceNodes == 4 ) {
6714       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
6715       double aBestRate = DBL_MAX;
6716       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
6717         i1 = 0; i2 = 1;
6718         double aBadRate = 0;
6719         // evaluate elements quality
6720         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
6721           if ( iSplit == iQuad ) {
6722             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
6723                                    linkNodes[ i2++ ],
6724                                    nodes[ i3 ],
6725                                    nodes[ i4 ]);
6726             aBadRate += getBadRate( &quad, aCrit );
6727           }
6728           else {
6729             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
6730                                    linkNodes[ i2++ ],
6731                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
6732             aBadRate += getBadRate( &tria, aCrit );
6733           }
6734         }
6735         // choice
6736         if ( aBadRate < aBestRate ) {
6737           iBestQuad = iQuad;
6738           aBestRate = aBadRate;
6739         }
6740       }
6741     }
6742
6743     // create new elements
6744     SMESHDS_Mesh *aMesh = GetMeshDS();
6745     int aShapeId = FindShape( theFace );
6746
6747     i1 = 0; i2 = 1;
6748     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
6749       SMDS_MeshElement* newElem = 0;
6750       if ( iSplit == iBestQuad )
6751         newElem = aMesh->AddFace (linkNodes[ i1++ ],
6752                                   linkNodes[ i2++ ],
6753                                   nodes[ i3 ],
6754                                   nodes[ i4 ]);
6755       else
6756         newElem = aMesh->AddFace (linkNodes[ i1++ ],
6757                                   linkNodes[ i2++ ],
6758                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
6759       myLastCreatedElems.Append(newElem);
6760       if ( aShapeId && newElem )
6761         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6762     }
6763
6764     // change nodes of theFace
6765     const SMDS_MeshNode* newNodes[ 4 ];
6766     newNodes[ 0 ] = linkNodes[ i1 ];
6767     newNodes[ 1 ] = linkNodes[ i2 ];
6768     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
6769     newNodes[ 3 ] = nodes[ i4 ];
6770     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
6771   } // end if(!theFace->IsQuadratic())
6772   else { // theFace is quadratic
6773     // we have to split theFace on simple triangles and one simple quadrangle
6774     int tmp = il1/2;
6775     int nbshift = tmp*2;
6776     // shift nodes in nodes[] by nbshift
6777     int i,j;
6778     for(i=0; i<nbshift; i++) {
6779       const SMDS_MeshNode* n = nodes[0];
6780       for(j=0; j<nbFaceNodes-1; j++) {
6781         nodes[j] = nodes[j+1];
6782       }
6783       nodes[nbFaceNodes-1] = n;
6784     }
6785     il1 = il1 - nbshift;
6786     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
6787     //   n0      n1     n2    n0      n1     n2
6788     //     +-----+-----+        +-----+-----+
6789     //      \         /         |           |
6790     //       \       /          |           |
6791     //      n5+     +n3       n7+           +n3
6792     //         \   /            |           |
6793     //          \ /             |           |
6794     //           +              +-----+-----+
6795     //           n4           n6      n5     n4
6796
6797     // create new elements
6798     SMESHDS_Mesh *aMesh = GetMeshDS();
6799     int aShapeId = FindShape( theFace );
6800
6801     int n1,n2,n3;
6802     if(nbFaceNodes==6) { // quadratic triangle
6803       SMDS_MeshElement* newElem =
6804         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6805       myLastCreatedElems.Append(newElem);
6806       if ( aShapeId && newElem )
6807         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6808       if(theFace->IsMediumNode(nodes[il1])) {
6809         // create quadrangle
6810         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
6811         myLastCreatedElems.Append(newElem);
6812         if ( aShapeId && newElem )
6813           aMesh->SetMeshElementOnShape( newElem, aShapeId );
6814         n1 = 1;
6815         n2 = 2;
6816         n3 = 3;
6817       }
6818       else {
6819         // create quadrangle
6820         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
6821         myLastCreatedElems.Append(newElem);
6822         if ( aShapeId && newElem )
6823           aMesh->SetMeshElementOnShape( newElem, aShapeId );
6824         n1 = 0;
6825         n2 = 1;
6826         n3 = 5;
6827       }
6828     }
6829     else { // nbFaceNodes==8 - quadratic quadrangle
6830       SMDS_MeshElement* newElem =
6831         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6832       myLastCreatedElems.Append(newElem);
6833       if ( aShapeId && newElem )
6834         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6835       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
6836       myLastCreatedElems.Append(newElem);
6837       if ( aShapeId && newElem )
6838         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6839       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
6840       myLastCreatedElems.Append(newElem);
6841       if ( aShapeId && newElem )
6842         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6843       if(theFace->IsMediumNode(nodes[il1])) {
6844         // create quadrangle
6845         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
6846         myLastCreatedElems.Append(newElem);
6847         if ( aShapeId && newElem )
6848           aMesh->SetMeshElementOnShape( newElem, aShapeId );
6849         n1 = 1;
6850         n2 = 2;
6851         n3 = 3;
6852       }
6853       else {
6854         // create quadrangle
6855         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
6856         myLastCreatedElems.Append(newElem);
6857         if ( aShapeId && newElem )
6858           aMesh->SetMeshElementOnShape( newElem, aShapeId );
6859         n1 = 0;
6860         n2 = 1;
6861         n3 = 7;
6862       }
6863     }
6864     // create needed triangles using n1,n2,n3 and inserted nodes
6865     int nbn = 2 + aNodesToInsert.size();
6866     //const SMDS_MeshNode* aNodes[nbn];
6867     vector<const SMDS_MeshNode*> aNodes(nbn);
6868     aNodes[0] = nodes[n1];
6869     aNodes[nbn-1] = nodes[n2];
6870     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6871     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6872       aNodes[iNode++] = *nIt;
6873     }
6874     for(i=1; i<nbn; i++) {
6875       SMDS_MeshElement* newElem =
6876         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
6877       myLastCreatedElems.Append(newElem);
6878       if ( aShapeId && newElem )
6879         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6880     }
6881     // remove old quadratic face
6882     aMesh->RemoveElement(theFace);
6883   }
6884 }
6885
6886 //=======================================================================
6887 //function : UpdateVolumes
6888 //purpose  :
6889 //=======================================================================
6890 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
6891                                       const SMDS_MeshNode*        theBetweenNode2,
6892                                       list<const SMDS_MeshNode*>& theNodesToInsert)
6893 {
6894   myLastCreatedElems.Clear();
6895   myLastCreatedNodes.Clear();
6896
6897   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
6898   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
6899     const SMDS_MeshElement* elem = invElemIt->next();
6900
6901     // check, if current volume has link theBetweenNode1 - theBetweenNode2
6902     SMDS_VolumeTool aVolume (elem);
6903     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
6904       continue;
6905
6906     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
6907     int iface, nbFaces = aVolume.NbFaces();
6908     vector<const SMDS_MeshNode *> poly_nodes;
6909     vector<int> quantities (nbFaces);
6910
6911     for (iface = 0; iface < nbFaces; iface++) {
6912       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
6913       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
6914       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
6915
6916       for (int inode = 0; inode < nbFaceNodes; inode++) {
6917         poly_nodes.push_back(faceNodes[inode]);
6918
6919         if (nbInserted == 0) {
6920           if (faceNodes[inode] == theBetweenNode1) {
6921             if (faceNodes[inode + 1] == theBetweenNode2) {
6922               nbInserted = theNodesToInsert.size();
6923
6924               // add nodes to insert
6925               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
6926               for (; nIt != theNodesToInsert.end(); nIt++) {
6927                 poly_nodes.push_back(*nIt);
6928               }
6929             }
6930           }
6931           else if (faceNodes[inode] == theBetweenNode2) {
6932             if (faceNodes[inode + 1] == theBetweenNode1) {
6933               nbInserted = theNodesToInsert.size();
6934
6935               // add nodes to insert in reversed order
6936               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
6937               nIt--;
6938               for (; nIt != theNodesToInsert.begin(); nIt--) {
6939                 poly_nodes.push_back(*nIt);
6940               }
6941               poly_nodes.push_back(*nIt);
6942             }
6943           }
6944           else {
6945           }
6946         }
6947       }
6948       quantities[iface] = nbFaceNodes + nbInserted;
6949     }
6950
6951     // Replace or update the volume
6952     SMESHDS_Mesh *aMesh = GetMeshDS();
6953
6954     if (elem->IsPoly()) {
6955       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6956
6957     }
6958     else {
6959       int aShapeId = FindShape( elem );
6960
6961       SMDS_MeshElement* newElem =
6962         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6963       myLastCreatedElems.Append(newElem);
6964       if (aShapeId && newElem)
6965         aMesh->SetMeshElementOnShape(newElem, aShapeId);
6966
6967       aMesh->RemoveElement(elem);
6968     }
6969   }
6970 }
6971
6972 //=======================================================================
6973 /*!
6974  * \brief Convert elements contained in a submesh to quadratic
6975  * \retval int - nb of checked elements
6976  */
6977 //=======================================================================
6978
6979 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
6980                                              SMESH_MesherHelper& theHelper,
6981                                              const bool          theForce3d)
6982 {
6983   int nbElem = 0;
6984   if( !theSm ) return nbElem;
6985
6986   const bool notFromGroups = false;
6987   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
6988   while(ElemItr->more())
6989   {
6990     nbElem++;
6991     const SMDS_MeshElement* elem = ElemItr->next();
6992     if( !elem || elem->IsQuadratic() ) continue;
6993
6994     int id = elem->GetID();
6995     int nbNodes = elem->NbNodes();
6996     vector<const SMDS_MeshNode *> aNds (nbNodes);
6997
6998     for(int i = 0; i < nbNodes; i++)
6999     {
7000       aNds[i] = elem->GetNode(i);
7001     }
7002     SMDSAbs_ElementType aType = elem->GetType();
7003
7004     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7005
7006     const SMDS_MeshElement* NewElem = 0;
7007
7008     switch( aType )
7009     {
7010     case SMDSAbs_Edge :
7011     {
7012       NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7013       break;
7014     }
7015     case SMDSAbs_Face :
7016     {
7017       switch(nbNodes)
7018       {
7019       case 3:
7020         NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7021         break;
7022       case 4:
7023         NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7024         break;
7025       default:
7026         continue;
7027       }
7028       break;
7029     }
7030     case SMDSAbs_Volume :
7031     {
7032       switch(nbNodes)
7033       {
7034       case 4:
7035         NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7036         break;
7037       case 6:
7038         NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7039         break;
7040       case 8:
7041         NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7042                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7043         break;
7044       default:
7045         continue;
7046       }
7047       break;
7048     }
7049     default :
7050       continue;
7051     }
7052     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7053     if( NewElem )
7054       theSm->AddElement( NewElem );
7055   }
7056   return nbElem;
7057 }
7058
7059 //=======================================================================
7060 //function : ConvertToQuadratic
7061 //purpose  :
7062 //=======================================================================
7063 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7064 {
7065   SMESHDS_Mesh* meshDS = GetMeshDS();
7066
7067   SMESH_MesherHelper aHelper(*myMesh);
7068   aHelper.SetIsQuadratic( true );
7069   const bool notFromGroups = false;
7070
7071   int nbCheckedElems = 0;
7072   if ( myMesh->HasShapeToMesh() )
7073   {
7074     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7075     {
7076       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7077       while ( smIt->more() ) {
7078         SMESH_subMesh* sm = smIt->next();
7079         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7080           aHelper.SetSubShape( sm->GetSubShape() );
7081           if ( !theForce3d) aHelper.SetCheckNodePosition(true);
7082           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7083         }
7084       }
7085     }
7086   }
7087   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7088   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7089   {
7090     SMESHDS_SubMesh *smDS = 0;
7091     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7092     while(aEdgeItr->more())
7093     {
7094       const SMDS_MeshEdge* edge = aEdgeItr->next();
7095       if(edge && !edge->IsQuadratic())
7096       {
7097         int id = edge->GetID();
7098         const SMDS_MeshNode* n1 = edge->GetNode(0);
7099         const SMDS_MeshNode* n2 = edge->GetNode(1);
7100
7101         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7102
7103         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7104         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7105       }
7106     }
7107     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7108     while(aFaceItr->more())
7109     {
7110       const SMDS_MeshFace* face = aFaceItr->next();
7111       if(!face || face->IsQuadratic() ) continue;
7112
7113       int id = face->GetID();
7114       int nbNodes = face->NbNodes();
7115       vector<const SMDS_MeshNode *> aNds (nbNodes);
7116
7117       for(int i = 0; i < nbNodes; i++)
7118       {
7119         aNds[i] = face->GetNode(i);
7120       }
7121
7122       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7123
7124       SMDS_MeshFace * NewFace = 0;
7125       switch(nbNodes)
7126       {
7127       case 3:
7128         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7129         break;
7130       case 4:
7131         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7132         break;
7133       default:
7134         continue;
7135       }
7136       ReplaceElemInGroups( face, NewFace, GetMeshDS());
7137     }
7138     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7139     while(aVolumeItr->more())
7140     {
7141       const SMDS_MeshVolume* volume = aVolumeItr->next();
7142       if(!volume || volume->IsQuadratic() ) continue;
7143
7144       int id = volume->GetID();
7145       int nbNodes = volume->NbNodes();
7146       vector<const SMDS_MeshNode *> aNds (nbNodes);
7147
7148       for(int i = 0; i < nbNodes; i++)
7149       {
7150         aNds[i] = volume->GetNode(i);
7151       }
7152
7153       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7154
7155       SMDS_MeshVolume * NewVolume = 0;
7156       switch(nbNodes)
7157       {
7158       case 4:
7159         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7160                                       aNds[3], id, theForce3d );
7161         break;
7162       case 6:
7163         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7164                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
7165         break;
7166       case 8:
7167         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7168                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7169         break;
7170       default:
7171         continue;
7172       }
7173       ReplaceElemInGroups(volume, NewVolume, meshDS);
7174     }
7175   }
7176   if ( !theForce3d ) {
7177     aHelper.SetSubShape(0); // apply to the whole mesh
7178     aHelper.FixQuadraticElements();
7179   }
7180 }
7181
7182 //=======================================================================
7183 /*!
7184  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7185  * \retval int - nb of checked elements
7186  */
7187 //=======================================================================
7188
7189 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
7190                                      SMDS_ElemIteratorPtr theItr,
7191                                      const int            theShapeID)
7192 {
7193   int nbElem = 0;
7194   SMESHDS_Mesh* meshDS = GetMeshDS();
7195   const bool notFromGroups = false;
7196
7197   while( theItr->more() )
7198   {
7199     const SMDS_MeshElement* elem = theItr->next();
7200     nbElem++;
7201     if( elem && elem->IsQuadratic())
7202     {
7203       int id = elem->GetID();
7204       int nbNodes = elem->NbNodes();
7205       vector<const SMDS_MeshNode *> aNds, mediumNodes;
7206       aNds.reserve( nbNodes );
7207       mediumNodes.reserve( nbNodes );
7208
7209       for(int i = 0; i < nbNodes; i++)
7210       {
7211         const SMDS_MeshNode* n = elem->GetNode(i);
7212
7213         if( elem->IsMediumNode( n ) )
7214           mediumNodes.push_back( n );
7215         else
7216           aNds.push_back( n );
7217       }
7218       if( aNds.empty() ) continue;
7219       SMDSAbs_ElementType aType = elem->GetType();
7220
7221       //remove old quadratic element
7222       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7223
7224       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7225       ReplaceElemInGroups(elem, NewElem, meshDS);
7226       if( theSm && NewElem )
7227         theSm->AddElement( NewElem );
7228
7229       // remove medium nodes
7230       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7231       for ( ; nIt != mediumNodes.end(); ++nIt ) {
7232         const SMDS_MeshNode* n = *nIt;
7233         if ( n->NbInverseElements() == 0 ) {
7234           if ( n->GetPosition()->GetShapeId() != theShapeID )
7235             meshDS->RemoveFreeNode( n, meshDS->MeshElements
7236                                     ( n->GetPosition()->GetShapeId() ));
7237           else
7238             meshDS->RemoveFreeNode( n, theSm );
7239         }
7240       }
7241     }
7242   }
7243   return nbElem;
7244 }
7245
7246 //=======================================================================
7247 //function : ConvertFromQuadratic
7248 //purpose  :
7249 //=======================================================================
7250 bool  SMESH_MeshEditor::ConvertFromQuadratic()
7251 {
7252   int nbCheckedElems = 0;
7253   if ( myMesh->HasShapeToMesh() )
7254   {
7255     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7256     {
7257       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7258       while ( smIt->more() ) {
7259         SMESH_subMesh* sm = smIt->next();
7260         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7261           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7262       }
7263     }
7264   }
7265   
7266   int totalNbElems =
7267     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7268   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7269   {
7270     SMESHDS_SubMesh *aSM = 0;
7271     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7272   }
7273
7274   return true;
7275 }
7276
7277 //=======================================================================
7278 //function : SewSideElements
7279 //purpose  :
7280 //=======================================================================
7281
7282 SMESH_MeshEditor::Sew_Error
7283   SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
7284                                      TIDSortedElemSet&    theSide2,
7285                                      const SMDS_MeshNode* theFirstNode1,
7286                                      const SMDS_MeshNode* theFirstNode2,
7287                                      const SMDS_MeshNode* theSecondNode1,
7288                                      const SMDS_MeshNode* theSecondNode2)
7289 {
7290   myLastCreatedElems.Clear();
7291   myLastCreatedNodes.Clear();
7292
7293   MESSAGE ("::::SewSideElements()");
7294   if ( theSide1.size() != theSide2.size() )
7295     return SEW_DIFF_NB_OF_ELEMENTS;
7296
7297   Sew_Error aResult = SEW_OK;
7298   // Algo:
7299   // 1. Build set of faces representing each side
7300   // 2. Find which nodes of the side 1 to merge with ones on the side 2
7301   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7302
7303   // =======================================================================
7304   // 1. Build set of faces representing each side:
7305   // =======================================================================
7306   // a. build set of nodes belonging to faces
7307   // b. complete set of faces: find missing fices whose nodes are in set of nodes
7308   // c. create temporary faces representing side of volumes if correspondent
7309   //    face does not exist
7310
7311   SMESHDS_Mesh* aMesh = GetMeshDS();
7312   SMDS_Mesh aTmpFacesMesh;
7313   set<const SMDS_MeshElement*> faceSet1, faceSet2;
7314   set<const SMDS_MeshElement*> volSet1,  volSet2;
7315   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
7316   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7317   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
7318   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7319   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7320   int iSide, iFace, iNode;
7321
7322   for ( iSide = 0; iSide < 2; iSide++ ) {
7323     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
7324     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7325     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7326     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
7327     set<const SMDS_MeshElement*>::iterator vIt;
7328     TIDSortedElemSet::iterator eIt;
7329     set<const SMDS_MeshNode*>::iterator    nIt;
7330
7331     // check that given nodes belong to given elements
7332     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
7333     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
7334     int firstIndex = -1, secondIndex = -1;
7335     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7336       const SMDS_MeshElement* elem = *eIt;
7337       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
7338       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
7339       if ( firstIndex > -1 && secondIndex > -1 ) break;
7340     }
7341     if ( firstIndex < 0 || secondIndex < 0 ) {
7342       // we can simply return until temporary faces created
7343       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
7344     }
7345
7346     // -----------------------------------------------------------
7347     // 1a. Collect nodes of existing faces
7348     //     and build set of face nodes in order to detect missing
7349     //     faces corresponing to sides of volumes
7350     // -----------------------------------------------------------
7351
7352     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
7353
7354     // loop on the given element of a side
7355     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7356       //const SMDS_MeshElement* elem = *eIt;
7357       const SMDS_MeshElement* elem = *eIt;
7358       if ( elem->GetType() == SMDSAbs_Face ) {
7359         faceSet->insert( elem );
7360         set <const SMDS_MeshNode*> faceNodeSet;
7361         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
7362         while ( nodeIt->more() ) {
7363           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7364           nodeSet->insert( n );
7365           faceNodeSet.insert( n );
7366         }
7367         setOfFaceNodeSet.insert( faceNodeSet );
7368       }
7369       else if ( elem->GetType() == SMDSAbs_Volume )
7370         volSet->insert( elem );
7371     }
7372     // ------------------------------------------------------------------------------
7373     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
7374     // ------------------------------------------------------------------------------
7375
7376     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7377       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7378       while ( fIt->more() ) { // loop on faces sharing a node
7379         const SMDS_MeshElement* f = fIt->next();
7380         if ( faceSet->find( f ) == faceSet->end() ) {
7381           // check if all nodes are in nodeSet and
7382           // complete setOfFaceNodeSet if they are
7383           set <const SMDS_MeshNode*> faceNodeSet;
7384           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7385           bool allInSet = true;
7386           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7387             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7388             if ( nodeSet->find( n ) == nodeSet->end() )
7389               allInSet = false;
7390             else
7391               faceNodeSet.insert( n );
7392           }
7393           if ( allInSet ) {
7394             faceSet->insert( f );
7395             setOfFaceNodeSet.insert( faceNodeSet );
7396           }
7397         }
7398       }
7399     }
7400
7401     // -------------------------------------------------------------------------
7402     // 1c. Create temporary faces representing sides of volumes if correspondent
7403     //     face does not exist
7404     // -------------------------------------------------------------------------
7405
7406     if ( !volSet->empty() ) {
7407       //int nodeSetSize = nodeSet->size();
7408
7409       // loop on given volumes
7410       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
7411         SMDS_VolumeTool vol (*vIt);
7412         // loop on volume faces: find free faces
7413         // --------------------------------------
7414         list<const SMDS_MeshElement* > freeFaceList;
7415         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
7416           if ( !vol.IsFreeFace( iFace ))
7417             continue;
7418           // check if there is already a face with same nodes in a face set
7419           const SMDS_MeshElement* aFreeFace = 0;
7420           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
7421           int nbNodes = vol.NbFaceNodes( iFace );
7422           set <const SMDS_MeshNode*> faceNodeSet;
7423           vol.GetFaceNodes( iFace, faceNodeSet );
7424           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
7425           if ( isNewFace ) {
7426             // no such a face is given but it still can exist, check it
7427             if ( nbNodes == 3 ) {
7428               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
7429             }
7430             else if ( nbNodes == 4 ) {
7431               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7432             }
7433             else {
7434               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7435               aFreeFace = aMesh->FindFace(poly_nodes);
7436             }
7437           }
7438           if ( !aFreeFace ) {
7439             // create a temporary face
7440             if ( nbNodes == 3 ) {
7441               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
7442             }
7443             else if ( nbNodes == 4 ) {
7444               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7445             }
7446             else {
7447               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7448               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
7449             }
7450           }
7451           if ( aFreeFace )
7452             freeFaceList.push_back( aFreeFace );
7453
7454         } // loop on faces of a volume
7455
7456         // choose one of several free faces
7457         // --------------------------------------
7458         if ( freeFaceList.size() > 1 ) {
7459           // choose a face having max nb of nodes shared by other elems of a side
7460           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
7461           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
7462           while ( fIt != freeFaceList.end() ) { // loop on free faces
7463             int nbSharedNodes = 0;
7464             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7465             while ( nodeIt->more() ) { // loop on free face nodes
7466               const SMDS_MeshNode* n =
7467                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7468               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
7469               while ( invElemIt->more() ) {
7470                 const SMDS_MeshElement* e = invElemIt->next();
7471                 if ( faceSet->find( e ) != faceSet->end() )
7472                   nbSharedNodes++;
7473                 if ( elemSet->find( e ) != elemSet->end() )
7474                   nbSharedNodes++;
7475               }
7476             }
7477             if ( nbSharedNodes >= maxNbNodes ) {
7478               maxNbNodes = nbSharedNodes;
7479               fIt++;
7480             }
7481             else
7482               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
7483           }
7484           if ( freeFaceList.size() > 1 )
7485           {
7486             // could not choose one face, use another way
7487             // choose a face most close to the bary center of the opposite side
7488             gp_XYZ aBC( 0., 0., 0. );
7489             set <const SMDS_MeshNode*> addedNodes;
7490             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
7491             eIt = elemSet2->begin();
7492             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
7493               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
7494               while ( nodeIt->more() ) { // loop on free face nodes
7495                 const SMDS_MeshNode* n =
7496                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7497                 if ( addedNodes.insert( n ).second )
7498                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
7499               }
7500             }
7501             aBC /= addedNodes.size();
7502             double minDist = DBL_MAX;
7503             fIt = freeFaceList.begin();
7504             while ( fIt != freeFaceList.end() ) { // loop on free faces
7505               double dist = 0;
7506               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7507               while ( nodeIt->more() ) { // loop on free face nodes
7508                 const SMDS_MeshNode* n =
7509                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7510                 gp_XYZ p( n->X(),n->Y(),n->Z() );
7511                 dist += ( aBC - p ).SquareModulus();
7512               }
7513               if ( dist < minDist ) {
7514                 minDist = dist;
7515                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
7516               }
7517               else
7518                 fIt = freeFaceList.erase( fIt++ );
7519             }
7520           }
7521         } // choose one of several free faces of a volume
7522
7523         if ( freeFaceList.size() == 1 ) {
7524           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
7525           faceSet->insert( aFreeFace );
7526           // complete a node set with nodes of a found free face
7527 //           for ( iNode = 0; iNode < ; iNode++ )
7528 //             nodeSet->insert( fNodes[ iNode ] );
7529         }
7530
7531       } // loop on volumes of a side
7532
7533 //       // complete a set of faces if new nodes in a nodeSet appeared
7534 //       // ----------------------------------------------------------
7535 //       if ( nodeSetSize != nodeSet->size() ) {
7536 //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7537 //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7538 //           while ( fIt->more() ) { // loop on faces sharing a node
7539 //             const SMDS_MeshElement* f = fIt->next();
7540 //             if ( faceSet->find( f ) == faceSet->end() ) {
7541 //               // check if all nodes are in nodeSet and
7542 //               // complete setOfFaceNodeSet if they are
7543 //               set <const SMDS_MeshNode*> faceNodeSet;
7544 //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7545 //               bool allInSet = true;
7546 //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7547 //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7548 //                 if ( nodeSet->find( n ) == nodeSet->end() )
7549 //                   allInSet = false;
7550 //                 else
7551 //                   faceNodeSet.insert( n );
7552 //               }
7553 //               if ( allInSet ) {
7554 //                 faceSet->insert( f );
7555 //                 setOfFaceNodeSet.insert( faceNodeSet );
7556 //               }
7557 //             }
7558 //           }
7559 //         }
7560 //       }
7561     } // Create temporary faces, if there are volumes given
7562   } // loop on sides
7563
7564   if ( faceSet1.size() != faceSet2.size() ) {
7565     // delete temporary faces: they are in reverseElements of actual nodes
7566     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7567     while ( tmpFaceIt->more() )
7568       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7569     MESSAGE("Diff nb of faces");
7570     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7571   }
7572
7573   // ============================================================
7574   // 2. Find nodes to merge:
7575   //              bind a node to remove to a node to put instead
7576   // ============================================================
7577
7578   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
7579   if ( theFirstNode1 != theFirstNode2 )
7580     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
7581   if ( theSecondNode1 != theSecondNode2 )
7582     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
7583
7584   LinkID_Gen aLinkID_Gen( GetMeshDS() );
7585   set< long > linkIdSet; // links to process
7586   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
7587
7588   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
7589   list< NLink > linkList[2];
7590   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
7591   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
7592   // loop on links in linkList; find faces by links and append links
7593   // of the found faces to linkList
7594   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
7595   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
7596     NLink link[] = { *linkIt[0], *linkIt[1] };
7597     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
7598     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
7599       continue;
7600
7601     // by links, find faces in the face sets,
7602     // and find indices of link nodes in the found faces;
7603     // in a face set, there is only one or no face sharing a link
7604     // ---------------------------------------------------------------
7605
7606     const SMDS_MeshElement* face[] = { 0, 0 };
7607     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
7608     vector<const SMDS_MeshNode*> fnodes1(9);
7609     vector<const SMDS_MeshNode*> fnodes2(9);
7610     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
7611     vector<const SMDS_MeshNode*> notLinkNodes1(6);
7612     vector<const SMDS_MeshNode*> notLinkNodes2(6);
7613     int iLinkNode[2][2];
7614     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7615       const SMDS_MeshNode* n1 = link[iSide].first;
7616       const SMDS_MeshNode* n2 = link[iSide].second;
7617       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7618       set< const SMDS_MeshElement* > fMap;
7619       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
7620         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
7621         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
7622         while ( fIt->more() ) { // loop on faces sharing a node
7623           const SMDS_MeshElement* f = fIt->next();
7624           if (faceSet->find( f ) != faceSet->end() && // f is in face set
7625               ! fMap.insert( f ).second ) // f encounters twice
7626           {
7627             if ( face[ iSide ] ) {
7628               MESSAGE( "2 faces per link " );
7629               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
7630               break;
7631             }
7632             face[ iSide ] = f;
7633             faceSet->erase( f );
7634             // get face nodes and find ones of a link
7635             iNode = 0;
7636             int nbl = -1;
7637             if(f->IsPoly()) {
7638               if(iSide==0) {
7639                 fnodes1.resize(f->NbNodes()+1);
7640                 notLinkNodes1.resize(f->NbNodes()-2);
7641               }
7642               else {
7643                 fnodes2.resize(f->NbNodes()+1);
7644                 notLinkNodes2.resize(f->NbNodes()-2);
7645               }
7646             }
7647             if(!f->IsQuadratic()) {
7648               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
7649               while ( nIt->more() ) {
7650                 const SMDS_MeshNode* n =
7651                   static_cast<const SMDS_MeshNode*>( nIt->next() );
7652                 if ( n == n1 ) {
7653                   iLinkNode[ iSide ][ 0 ] = iNode;
7654                 }
7655                 else if ( n == n2 ) {
7656                   iLinkNode[ iSide ][ 1 ] = iNode;
7657                 }
7658                 //else if ( notLinkNodes[ iSide ][ 0 ] )
7659                 //  notLinkNodes[ iSide ][ 1 ] = n;
7660                 //else
7661                 //  notLinkNodes[ iSide ][ 0 ] = n;
7662                 else {
7663                   nbl++;
7664                   if(iSide==0)
7665                     notLinkNodes1[nbl] = n;
7666                     //notLinkNodes1.push_back(n);
7667                   else
7668                     notLinkNodes2[nbl] = n;
7669                     //notLinkNodes2.push_back(n);
7670                 }
7671                 //faceNodes[ iSide ][ iNode++ ] = n;
7672                 if(iSide==0) {
7673                   fnodes1[iNode++] = n;
7674                 }
7675                 else {
7676                   fnodes2[iNode++] = n;
7677                 }
7678               }
7679             }
7680             else { // f->IsQuadratic()
7681               const SMDS_QuadraticFaceOfNodes* F =
7682                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
7683               // use special nodes iterator
7684               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7685               while ( anIter->more() ) {
7686                 const SMDS_MeshNode* n =
7687                   static_cast<const SMDS_MeshNode*>( anIter->next() );
7688                 if ( n == n1 ) {
7689                   iLinkNode[ iSide ][ 0 ] = iNode;
7690                 }
7691                 else if ( n == n2 ) {
7692                   iLinkNode[ iSide ][ 1 ] = iNode;
7693                 }
7694                 else {
7695                   nbl++;
7696                   if(iSide==0) {
7697                     notLinkNodes1[nbl] = n;
7698                   }
7699                   else {
7700                     notLinkNodes2[nbl] = n;
7701                   }
7702                 }
7703                 if(iSide==0) {
7704                   fnodes1[iNode++] = n;
7705                 }
7706                 else {
7707                   fnodes2[iNode++] = n;
7708                 }
7709               }
7710             }
7711             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
7712             if(iSide==0) {
7713               fnodes1[iNode] = fnodes1[0];
7714             }
7715             else {
7716               fnodes2[iNode] = fnodes1[0];
7717             }
7718           }
7719         }
7720       }
7721     }
7722
7723     // check similarity of elements of the sides
7724     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7725       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7726       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7727         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7728       }
7729       else {
7730         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7731       }
7732       break; // do not return because it s necessary to remove tmp faces
7733     }
7734
7735     // set nodes to merge
7736     // -------------------
7737
7738     if ( face[0] && face[1] )  {
7739       int nbNodes = face[0]->NbNodes();
7740       if ( nbNodes != face[1]->NbNodes() ) {
7741         MESSAGE("Diff nb of face nodes");
7742         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7743         break; // do not return because it s necessary to remove tmp faces
7744       }
7745       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
7746       if ( nbNodes == 3 ) {
7747         //nReplaceMap.insert( TNodeNodeMap::value_type
7748         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7749         nReplaceMap.insert( TNodeNodeMap::value_type
7750                            ( notLinkNodes1[0], notLinkNodes2[0] ));
7751       }
7752       else {
7753         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7754           // analyse link orientation in faces
7755           int i1 = iLinkNode[ iSide ][ 0 ];
7756           int i2 = iLinkNode[ iSide ][ 1 ];
7757           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
7758           // if notLinkNodes are the first and the last ones, then
7759           // their order does not correspond to the link orientation
7760           if (( i1 == 1 && i2 == 2 ) ||
7761               ( i1 == 2 && i2 == 1 ))
7762             reverse[ iSide ] = !reverse[ iSide ];
7763         }
7764         if ( reverse[0] == reverse[1] ) {
7765           //nReplaceMap.insert( TNodeNodeMap::value_type
7766           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7767           //nReplaceMap.insert( TNodeNodeMap::value_type
7768           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
7769           for(int nn=0; nn<nbNodes-2; nn++) {
7770             nReplaceMap.insert( TNodeNodeMap::value_type
7771                              ( notLinkNodes1[nn], notLinkNodes2[nn] ));
7772           }
7773         }
7774         else {
7775           //nReplaceMap.insert( TNodeNodeMap::value_type
7776           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
7777           //nReplaceMap.insert( TNodeNodeMap::value_type
7778           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
7779           for(int nn=0; nn<nbNodes-2; nn++) {
7780             nReplaceMap.insert( TNodeNodeMap::value_type
7781                              ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
7782           }
7783         }
7784       }
7785
7786       // add other links of the faces to linkList
7787       // -----------------------------------------
7788
7789       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
7790       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
7791         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
7792         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
7793         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
7794         if ( !iter_isnew.second ) { // already in a set: no need to process
7795           linkIdSet.erase( iter_isnew.first );
7796         }
7797         else // new in set == encountered for the first time: add
7798         {
7799           //const SMDS_MeshNode* n1 = nodes[ iNode ];
7800           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
7801           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
7802           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
7803           linkList[0].push_back ( NLink( n1, n2 ));
7804           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
7805         }
7806       }
7807     } // 2 faces found
7808   } // loop on link lists
7809
7810   if ( aResult == SEW_OK &&
7811       ( linkIt[0] != linkList[0].end() ||
7812        !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
7813     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
7814             " " << (faceSetPtr[1]->empty()));
7815     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7816   }
7817
7818   // ====================================================================
7819   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7820   // ====================================================================
7821
7822   // delete temporary faces: they are in reverseElements of actual nodes
7823   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7824   while ( tmpFaceIt->more() )
7825     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7826
7827   if ( aResult != SEW_OK)
7828     return aResult;
7829
7830   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
7831   // loop on nodes replacement map
7832   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
7833   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
7834     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
7835       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
7836       nodeIDsToRemove.push_back( nToRemove->GetID() );
7837       // loop on elements sharing nToRemove
7838       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7839       while ( invElemIt->more() ) {
7840         const SMDS_MeshElement* e = invElemIt->next();
7841         // get a new suite of nodes: make replacement
7842         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
7843         vector< const SMDS_MeshNode*> nodes( nbNodes );
7844         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7845         while ( nIt->more() ) {
7846           const SMDS_MeshNode* n =
7847             static_cast<const SMDS_MeshNode*>( nIt->next() );
7848           nnIt = nReplaceMap.find( n );
7849           if ( nnIt != nReplaceMap.end() ) {
7850             nbReplaced++;
7851             n = (*nnIt).second;
7852           }
7853           nodes[ i++ ] = n;
7854         }
7855         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
7856         //         elemIDsToRemove.push_back( e->GetID() );
7857         //       else
7858         if ( nbReplaced )
7859           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
7860       }
7861     }
7862
7863   Remove( nodeIDsToRemove, true );
7864
7865   return aResult;
7866 }
7867
7868 //================================================================================
7869   /*!
7870    * \brief Find corresponding nodes in two sets of faces
7871     * \param theSide1 - first face set
7872     * \param theSide2 - second first face
7873     * \param theFirstNode1 - a boundary node of set 1
7874     * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
7875     * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
7876     * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
7877     * \param nReplaceMap - output map of corresponding nodes
7878     * \retval bool  - is a success or not
7879    */
7880 //================================================================================
7881
7882 #ifdef _DEBUG_
7883 //#define DEBUG_MATCHING_NODES
7884 #endif
7885
7886 SMESH_MeshEditor::Sew_Error
7887 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
7888                                     set<const SMDS_MeshElement*>& theSide2,
7889                                     const SMDS_MeshNode*          theFirstNode1,
7890                                     const SMDS_MeshNode*          theFirstNode2,
7891                                     const SMDS_MeshNode*          theSecondNode1,
7892                                     const SMDS_MeshNode*          theSecondNode2,
7893                                     TNodeNodeMap &                nReplaceMap)
7894 {
7895   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
7896
7897   nReplaceMap.clear();
7898   if ( theFirstNode1 != theFirstNode2 )
7899     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
7900   if ( theSecondNode1 != theSecondNode2 )
7901     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
7902
7903   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
7904   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
7905
7906   list< NLink > linkList[2];
7907   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
7908   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
7909
7910   // loop on links in linkList; find faces by links and append links
7911   // of the found faces to linkList
7912   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
7913   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
7914     NLink link[] = { *linkIt[0], *linkIt[1] };
7915     if ( linkSet.find( link[0] ) == linkSet.end() )
7916       continue;
7917
7918     // by links, find faces in the face sets,
7919     // and find indices of link nodes in the found faces;
7920     // in a face set, there is only one or no face sharing a link
7921     // ---------------------------------------------------------------
7922
7923     const SMDS_MeshElement* face[] = { 0, 0 };
7924     list<const SMDS_MeshNode*> notLinkNodes[2];
7925     //bool reverse[] = { false, false }; // order of notLinkNodes
7926     int nbNodes[2];
7927     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
7928     {
7929       const SMDS_MeshNode* n1 = link[iSide].first;
7930       const SMDS_MeshNode* n2 = link[iSide].second;
7931       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7932       set< const SMDS_MeshElement* > facesOfNode1;
7933       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
7934       {
7935         // during a loop of the first node, we find all faces around n1,
7936         // during a loop of the second node, we find one face sharing both n1 and n2
7937         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
7938         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
7939         while ( fIt->more() ) { // loop on faces sharing a node
7940           const SMDS_MeshElement* f = fIt->next();
7941           if (faceSet->find( f ) != faceSet->end() && // f is in face set
7942               ! facesOfNode1.insert( f ).second ) // f encounters twice
7943           {
7944             if ( face[ iSide ] ) {
7945               MESSAGE( "2 faces per link " );
7946               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7947             }
7948             face[ iSide ] = f;
7949             faceSet->erase( f );
7950
7951             // get not link nodes
7952             int nbN = f->NbNodes();
7953             if ( f->IsQuadratic() )
7954               nbN /= 2;
7955             nbNodes[ iSide ] = nbN;
7956             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
7957             int i1 = f->GetNodeIndex( n1 );
7958             int i2 = f->GetNodeIndex( n2 );
7959             int iEnd = nbN, iBeg = -1, iDelta = 1;
7960             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
7961             if ( reverse ) {
7962               std::swap( iEnd, iBeg ); iDelta = -1;
7963             }
7964             int i = i2;
7965             while ( true ) {
7966               i += iDelta;
7967               if ( i == iEnd ) i = iBeg + iDelta;
7968               if ( i == i1 ) break;
7969               nodes.push_back ( f->GetNode( i ) );
7970             }
7971           }
7972         }
7973       }
7974     }
7975     // check similarity of elements of the sides
7976     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7977       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7978       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7979         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7980       }
7981       else {
7982         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7983       }
7984     }
7985
7986     // set nodes to merge
7987     // -------------------
7988
7989     if ( face[0] && face[1] )  {
7990       if ( nbNodes[0] != nbNodes[1] ) {
7991         MESSAGE("Diff nb of face nodes");
7992         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7993       }
7994 #ifdef DEBUG_MATCHING_NODES
7995       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
7996              << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
7997              << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
7998 #endif
7999       int nbN = nbNodes[0];
8000       {
8001         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8002         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8003         for ( int i = 0 ; i < nbN - 2; ++i ) {
8004 #ifdef DEBUG_MATCHING_NODES
8005           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8006 #endif
8007           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8008         }
8009       }
8010
8011       // add other links of the face 1 to linkList
8012       // -----------------------------------------
8013
8014       const SMDS_MeshElement* f0 = face[0];
8015       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8016       for ( int i = 0; i < nbN; i++ )
8017       {
8018         const SMDS_MeshNode* n2 = f0->GetNode( i );
8019         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8020           linkSet.insert( SMESH_TLink( n1, n2 ));
8021         if ( !iter_isnew.second ) { // already in a set: no need to process
8022           linkSet.erase( iter_isnew.first );
8023         }
8024         else // new in set == encountered for the first time: add
8025         {
8026 #ifdef DEBUG_MATCHING_NODES
8027           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8028           << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8029 #endif
8030           linkList[0].push_back ( NLink( n1, n2 ));
8031           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8032         }
8033         n1 = n2;
8034       }
8035     } // 2 faces found
8036   } // loop on link lists
8037
8038   return SEW_OK;
8039 }
8040
8041 /*!
8042   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8043   \param theNodes - identifiers of nodes to be doubled
8044   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
8045          nodes. If list of element identifiers is empty then nodes are doubled but 
8046          they not assigned to elements
8047   \return TRUE if operation has been completed successfully, FALSE otherwise
8048 */
8049 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
8050                                     const std::list< int >& theListOfModifiedElems )
8051 {
8052   myLastCreatedElems.Clear();
8053   myLastCreatedNodes.Clear();
8054
8055   if ( theListOfNodes.size() == 0 )
8056     return false;
8057
8058   SMESHDS_Mesh* aMeshDS = GetMeshDS();
8059   if ( !aMeshDS )
8060     return false;
8061
8062   // iterate through nodes and duplicate them
8063
8064   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8065
8066   std::list< int >::const_iterator aNodeIter;
8067   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
8068   {
8069     int aCurr = *aNodeIter;
8070     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
8071     if ( !aNode )
8072       continue;
8073
8074     // duplicate node
8075
8076     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
8077     if ( aNewNode )
8078     {
8079       anOldNodeToNewNode[ aNode ] = aNewNode;
8080       myLastCreatedNodes.Append( aNewNode );
8081     }
8082   }
8083
8084   // Create map of new nodes for modified elements
8085
8086   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
8087
8088   std::list< int >::const_iterator anElemIter;
8089   for ( anElemIter = theListOfModifiedElems.begin(); 
8090         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
8091   {
8092     int aCurr = *anElemIter;
8093     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
8094     if ( !anElem )
8095       continue;
8096
8097     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
8098
8099     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8100     int ind = 0;
8101     while ( anIter->more() ) 
8102     { 
8103       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8104       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
8105       {
8106         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
8107         aNodeArr[ ind++ ] = aNewNode;
8108       }
8109       else
8110         aNodeArr[ ind++ ] = aCurrNode;
8111     }
8112     anElemToNodes[ anElem ] = aNodeArr;
8113   }
8114
8115   // Change nodes of elements  
8116
8117   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
8118     anElemToNodesIter = anElemToNodes.begin();
8119   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
8120   {
8121     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
8122     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
8123     if ( anElem )
8124       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
8125   }
8126
8127   return true;
8128 }