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