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