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