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