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