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