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