Salome HOME
88f48eabdb45815ddbef412c64b7593c07ddd09a
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  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
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
48
49 #include "utilities.h"
50
51 #include <BRepAdaptor_Surface.hxx>
52 #include <BRepClass3d_SolidClassifier.hxx>
53 #include <BRep_Tool.hxx>
54 #include <ElCLib.hxx>
55 #include <Extrema_GenExtPS.hxx>
56 #include <Extrema_POnCurv.hxx>
57 #include <Extrema_POnSurf.hxx>
58 #include <GC_MakeSegment.hxx>
59 #include <Geom2d_Curve.hxx>
60 #include <GeomAPI_ExtremaCurveCurve.hxx>
61 #include <GeomAdaptor_Surface.hxx>
62 #include <Geom_Curve.hxx>
63 #include <Geom_Line.hxx>
64 #include <Geom_Surface.hxx>
65 #include <IntAna_IntConicQuad.hxx>
66 #include <IntAna_Quadric.hxx>
67 #include <Precision.hxx>
68 #include <TColStd_ListOfInteger.hxx>
69 #include <TopAbs_State.hxx>
70 #include <TopExp.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopTools_ListIteratorOfListOfShape.hxx>
73 #include <TopTools_ListOfShape.hxx>
74 #include <TopTools_SequenceOfShape.hxx>
75 #include <TopoDS.hxx>
76 #include <TopoDS_Face.hxx>
77 #include <gp.hxx>
78 #include <gp_Ax1.hxx>
79 #include <gp_Dir.hxx>
80 #include <gp_Lin.hxx>
81 #include <gp_Pln.hxx>
82 #include <gp_Trsf.hxx>
83 #include <gp_Vec.hxx>
84 #include <gp_XY.hxx>
85 #include <gp_XYZ.hxx>
86
87 #include <math.h>
88
89 #include <map>
90 #include <set>
91 #include <numeric>
92 #include <limits>
93
94 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
95
96 using namespace std;
97 using namespace SMESH::Controls;
98
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
101
102 //=======================================================================
103 //function : SMESH_MeshEditor
104 //purpose  :
105 //=======================================================================
106
107 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
108   :myMesh( theMesh ) // theMesh may be NULL
109 {
110 }
111
112 //=======================================================================
113 /*!
114  * \brief Add element
115  */
116 //=======================================================================
117
118 SMDS_MeshElement*
119 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
120                              const SMDSAbs_ElementType            type,
121                              const bool                           isPoly,
122                              const int                            ID)
123 {
124   SMDS_MeshElement* e = 0;
125   int nbnode = node.size();
126   SMESHDS_Mesh* mesh = GetMeshDS();
127   switch ( type ) {
128   case SMDSAbs_0DElement:
129     if ( nbnode == 1 )
130       if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
131       else      e = mesh->Add0DElement      (node[0] );
132     break;
133   case SMDSAbs_Edge:
134     if ( nbnode == 2 )
135       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
136       else      e = mesh->AddEdge      (node[0], node[1] );
137     else if ( nbnode == 3 )
138       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
139       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
140     break;
141   case SMDSAbs_Face:
142     if ( !isPoly ) {
143       if      (nbnode == 3)
144         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
145         else      e = mesh->AddFace      (node[0], node[1], node[2] );
146       else if (nbnode == 4) 
147         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
148         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
149       else if (nbnode == 6)
150         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
151                                           node[4], node[5], ID);
152         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
153                                           node[4], node[5] );
154       else if (nbnode == 8)
155         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
156                                           node[4], node[5], node[6], node[7], ID);
157         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
158                                           node[4], node[5], node[6], node[7] );
159     } else {
160       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
161       else      e = mesh->AddPolygonalFace      (node    );
162     }
163     break;
164   case SMDSAbs_Volume:
165     if ( !isPoly ) {
166       if      (nbnode == 4)
167         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
168         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
169       else if (nbnode == 5)
170         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171                                             node[4], ID);
172         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
173                                             node[4] );
174       else if (nbnode == 6)
175         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
176                                             node[4], node[5], ID);
177         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
178                                             node[4], node[5] );
179       else if (nbnode == 8)
180         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
181                                             node[4], node[5], node[6], node[7], ID);
182         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
183                                             node[4], node[5], node[6], node[7] );
184       else if (nbnode == 10)
185         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
186                                             node[4], node[5], node[6], node[7],
187                                             node[8], node[9], ID);
188         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
189                                             node[4], node[5], node[6], node[7],
190                                             node[8], node[9] );
191       else if (nbnode == 13)
192         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193                                             node[4], node[5], node[6], node[7],
194                                             node[8], node[9], node[10],node[11],
195                                             node[12],ID);
196         else      e = mesh->AddVolume      (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] );
200       else if (nbnode == 15)
201         if ( ID ) e = mesh->AddVolumeWithID(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],ID);
205         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
206                                             node[4], node[5], node[6], node[7],
207                                             node[8], node[9], node[10],node[11],
208                                             node[12],node[13],node[14] );
209       else if (nbnode == 20)
210         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
211                                             node[4], node[5], node[6], node[7],
212                                             node[8], node[9], node[10],node[11],
213                                             node[12],node[13],node[14],node[15],
214                                             node[16],node[17],node[18],node[19],ID);
215         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
216                                             node[4], node[5], node[6], node[7],
217                                             node[8], node[9], node[10],node[11],
218                                             node[12],node[13],node[14],node[15],
219                                             node[16],node[17],node[18],node[19] );
220     }
221   }
222   return e;
223 }
224
225 //=======================================================================
226 /*!
227  * \brief Add element
228  */
229 //=======================================================================
230
231 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
232                                                const SMDSAbs_ElementType type,
233                                                const bool                isPoly,
234                                                const int                 ID)
235 {
236   vector<const SMDS_MeshNode*> nodes;
237   nodes.reserve( nodeIDs.size() );
238   vector<int>::const_iterator id = nodeIDs.begin();
239   while ( id != nodeIDs.end() ) {
240     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
241       nodes.push_back( node );
242     else
243       return 0;
244   }
245   return AddElement( nodes, type, isPoly, ID );
246 }
247
248 //=======================================================================
249 //function : Remove
250 //purpose  : Remove a node or an element.
251 //           Modify a compute state of sub-meshes which become empty
252 //=======================================================================
253
254 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
255                               const bool         isNodes )
256 {
257   myLastCreatedElems.Clear();
258   myLastCreatedNodes.Clear();
259
260   SMESHDS_Mesh* aMesh = GetMeshDS();
261   set< SMESH_subMesh *> smmap;
262
263   int removed = 0;
264   list<int>::const_iterator it = theIDs.begin();
265   for ( ; it != theIDs.end(); it++ ) {
266     const SMDS_MeshElement * elem;
267     if ( isNodes )
268       elem = aMesh->FindNode( *it );
269     else
270       elem = aMesh->FindElement( *it );
271     if ( !elem )
272       continue;
273
274     // Notify VERTEX sub-meshes about modification
275     if ( isNodes ) {
276       const SMDS_MeshNode* node = cast2Node( elem );
277       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
278         if ( int aShapeID = node->GetPosition()->GetShapeId() )
279           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
280             smmap.insert( sm );
281     }
282     // Find sub-meshes to notify about modification
283     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
284     //     while ( nodeIt->more() ) {
285     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
286     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
287     //       if ( aPosition.get() ) {
288     //         if ( int aShapeID = aPosition->GetShapeId() ) {
289     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
290     //             smmap.insert( sm );
291     //         }
292     //       }
293     //     }
294
295     // Do remove
296     if ( isNodes )
297       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
298     else
299       aMesh->RemoveElement( elem );
300     removed++;
301   }
302
303   // Notify sub-meshes about modification
304   if ( !smmap.empty() ) {
305     set< SMESH_subMesh *>::iterator smIt;
306     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
307       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
308   }
309
310   //   // Check if the whole mesh becomes empty
311   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
312   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
313
314   return removed;
315 }
316
317 //=======================================================================
318 //function : FindShape
319 //purpose  : Return an index of the shape theElem is on
320 //           or zero if a shape not found
321 //=======================================================================
322
323 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
324 {
325   myLastCreatedElems.Clear();
326   myLastCreatedNodes.Clear();
327
328   SMESHDS_Mesh * aMesh = GetMeshDS();
329   if ( aMesh->ShapeToMesh().IsNull() )
330     return 0;
331
332   if ( theElem->GetType() == SMDSAbs_Node ) {
333     const SMDS_PositionPtr& aPosition =
334       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
335     if ( aPosition.get() )
336       return aPosition->GetShapeId();
337     else
338       return 0;
339   }
340
341   TopoDS_Shape aShape; // the shape a node is on
342   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
343   while ( nodeIt->more() ) {
344     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
345     const SMDS_PositionPtr& aPosition = node->GetPosition();
346     if ( aPosition.get() ) {
347       int aShapeID = aPosition->GetShapeId();
348       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
349       if ( sm ) {
350         if ( sm->Contains( theElem ))
351           return aShapeID;
352         if ( aShape.IsNull() )
353           aShape = aMesh->IndexToShape( aShapeID );
354       }
355       else {
356         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
357       }
358     }
359   }
360
361   // None of nodes is on a proper shape,
362   // find the shape among ancestors of aShape on which a node is
363   if ( aShape.IsNull() ) {
364     //MESSAGE ("::FindShape() - NONE node is on shape")
365     return 0;
366   }
367   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
368   for ( ; ancIt.More(); ancIt.Next() ) {
369     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
370     if ( sm && sm->Contains( theElem ))
371       return aMesh->ShapeToIndex( ancIt.Value() );
372   }
373
374   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
375   return 0;
376 }
377
378 //=======================================================================
379 //function : IsMedium
380 //purpose  :
381 //=======================================================================
382
383 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
384                                 const SMDSAbs_ElementType typeToCheck)
385 {
386   bool isMedium = false;
387   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
388   while (it->more() && !isMedium ) {
389     const SMDS_MeshElement* elem = it->next();
390     isMedium = elem->IsMediumNode(node);
391   }
392   return isMedium;
393 }
394
395 //=======================================================================
396 //function : ShiftNodesQuadTria
397 //purpose  : auxilary
398 //           Shift nodes in the array corresponded to quadratic triangle
399 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
400 //=======================================================================
401 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
402 {
403   const SMDS_MeshNode* nd1 = aNodes[0];
404   aNodes[0] = aNodes[1];
405   aNodes[1] = aNodes[2];
406   aNodes[2] = nd1;
407   const SMDS_MeshNode* nd2 = aNodes[3];
408   aNodes[3] = aNodes[4];
409   aNodes[4] = aNodes[5];
410   aNodes[5] = nd2;
411 }
412
413 //=======================================================================
414 //function : GetNodesFromTwoTria
415 //purpose  : auxilary
416 //           Shift nodes in the array corresponded to quadratic triangle
417 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
418 //=======================================================================
419 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
420                                 const SMDS_MeshElement * theTria2,
421                                 const SMDS_MeshNode* N1[],
422                                 const SMDS_MeshNode* N2[])
423 {
424   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
425   int i=0;
426   while(i<6) {
427     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
428     i++;
429   }
430   if(it->more()) return false;
431   it = theTria2->nodesIterator();
432   i=0;
433   while(i<6) {
434     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
435     i++;
436   }
437   if(it->more()) return false;
438
439   int sames[3] = {-1,-1,-1};
440   int nbsames = 0;
441   int j;
442   for(i=0; i<3; i++) {
443     for(j=0; j<3; j++) {
444       if(N1[i]==N2[j]) {
445         sames[i] = j;
446         nbsames++;
447         break;
448       }
449     }
450   }
451   if(nbsames!=2) return false;
452   if(sames[0]>-1) {
453     ShiftNodesQuadTria(N1);
454     if(sames[1]>-1) {
455       ShiftNodesQuadTria(N1);
456     }
457   }
458   i = sames[0] + sames[1] + sames[2];
459   for(; i<2; i++) {
460     ShiftNodesQuadTria(N2);
461   }
462   // now we receive following N1 and N2 (using numeration as above image)
463   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
464   // i.e. first nodes from both arrays determ new diagonal
465   return true;
466 }
467
468 //=======================================================================
469 //function : InverseDiag
470 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
471 //           but having other common link.
472 //           Return False if args are improper
473 //=======================================================================
474
475 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
476                                     const SMDS_MeshElement * theTria2 )
477 {
478   myLastCreatedElems.Clear();
479   myLastCreatedNodes.Clear();
480
481   if (!theTria1 || !theTria2)
482     return false;
483
484   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
485   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
486   if (F1 && F2) {
487
488     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
489     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
490     //    |/ |                                         | \|
491     //  B +--+ 2                                     B +--+ 2
492
493     // put nodes in array and find out indices of the same ones
494     const SMDS_MeshNode* aNodes [6];
495     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
496     int i = 0;
497     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
498     while ( it->more() ) {
499       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
500
501       if ( i > 2 ) // theTria2
502         // find same node of theTria1
503         for ( int j = 0; j < 3; j++ )
504           if ( aNodes[ i ] == aNodes[ j ]) {
505             sameInd[ j ] = i;
506             sameInd[ i ] = j;
507             break;
508           }
509       // next
510       i++;
511       if ( i == 3 ) {
512         if ( it->more() )
513           return false; // theTria1 is not a triangle
514         it = theTria2->nodesIterator();
515       }
516       if ( i == 6 && it->more() )
517         return false; // theTria2 is not a triangle
518     }
519
520     // find indices of 1,2 and of A,B in theTria1
521     int iA = 0, iB = 0, i1 = 0, i2 = 0;
522     for ( i = 0; i < 6; i++ ) {
523       if ( sameInd [ i ] == 0 )
524         if ( i < 3 ) i1 = i;
525         else         i2 = i;
526       else if (i < 3)
527         if ( iA ) iB = i;
528         else      iA = i;
529     }
530     // nodes 1 and 2 should not be the same
531     if ( aNodes[ i1 ] == aNodes[ i2 ] )
532       return false;
533
534     // theTria1: A->2
535     aNodes[ iA ] = aNodes[ i2 ];
536     // theTria2: B->1
537     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
538
539     //MESSAGE( theTria1 << theTria2 );
540
541     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
542     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
543
544     //MESSAGE( theTria1 << theTria2 );
545
546     return true;
547
548   } // end if(F1 && F2)
549
550   // check case of quadratic faces
551   const SMDS_QuadraticFaceOfNodes* QF1 =
552     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
553   if(!QF1) return false;
554   const SMDS_QuadraticFaceOfNodes* QF2 =
555     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
556   if(!QF2) return false;
557
558   //       5
559   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
560   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
561   //    |   / |
562   //  7 +  +  + 6
563   //    | /9  |
564   //    |/    |
565   //  4 +--+--+ 3
566   //       8
567
568   const SMDS_MeshNode* N1 [6];
569   const SMDS_MeshNode* N2 [6];
570   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
571     return false;
572   // now we receive following N1 and N2 (using numeration as above image)
573   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
574   // i.e. first nodes from both arrays determ new diagonal
575
576   const SMDS_MeshNode* N1new [6];
577   const SMDS_MeshNode* N2new [6];
578   N1new[0] = N1[0];
579   N1new[1] = N2[0];
580   N1new[2] = N2[1];
581   N1new[3] = N1[4];
582   N1new[4] = N2[3];
583   N1new[5] = N1[5];
584   N2new[0] = N1[0];
585   N2new[1] = N1[1];
586   N2new[2] = N2[0];
587   N2new[3] = N1[3];
588   N2new[4] = N2[5];
589   N2new[5] = N1[4];
590   // replaces nodes in faces
591   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
592   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
593
594   return true;
595 }
596
597 //=======================================================================
598 //function : findTriangles
599 //purpose  : find triangles sharing theNode1-theNode2 link
600 //=======================================================================
601
602 static bool findTriangles(const SMDS_MeshNode *    theNode1,
603                           const SMDS_MeshNode *    theNode2,
604                           const SMDS_MeshElement*& theTria1,
605                           const SMDS_MeshElement*& theTria2)
606 {
607   if ( !theNode1 || !theNode2 ) return false;
608
609   theTria1 = theTria2 = 0;
610
611   set< const SMDS_MeshElement* > emap;
612   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
613   while (it->more()) {
614     const SMDS_MeshElement* elem = it->next();
615     if ( elem->NbNodes() == 3 )
616       emap.insert( elem );
617   }
618   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
619   while (it->more()) {
620     const SMDS_MeshElement* elem = it->next();
621     if ( emap.find( elem ) != emap.end() )
622       if ( theTria1 ) {
623         // theTria1 must be element with minimum ID
624         if( theTria1->GetID() < elem->GetID() ) {
625           theTria2 = elem;
626         }
627         else {
628           theTria2 = theTria1;
629           theTria1 = elem;
630         }
631         break;
632       }
633       else {
634         theTria1 = elem;
635       }
636   }
637   return ( theTria1 && theTria2 );
638 }
639
640 //=======================================================================
641 //function : InverseDiag
642 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
643 //           with ones built on the same 4 nodes but having other common link.
644 //           Return false if proper faces not found
645 //=======================================================================
646
647 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
648                                     const SMDS_MeshNode * theNode2)
649 {
650   myLastCreatedElems.Clear();
651   myLastCreatedNodes.Clear();
652
653   MESSAGE( "::InverseDiag()" );
654
655   const SMDS_MeshElement *tr1, *tr2;
656   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
657     return false;
658
659   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
660   //if (!F1) return false;
661   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
662   //if (!F2) return false;
663   if (F1 && F2) {
664
665     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
666     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
667     //    |/ |                                    | \|
668     //  B +--+ 2                                B +--+ 2
669
670     // put nodes in array
671     // and find indices of 1,2 and of A in tr1 and of B in tr2
672     int i, iA1 = 0, i1 = 0;
673     const SMDS_MeshNode* aNodes1 [3];
674     SMDS_ElemIteratorPtr it;
675     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
676       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
677       if ( aNodes1[ i ] == theNode1 )
678         iA1 = i; // node A in tr1
679       else if ( aNodes1[ i ] != theNode2 )
680         i1 = i;  // node 1
681     }
682     int iB2 = 0, i2 = 0;
683     const SMDS_MeshNode* aNodes2 [3];
684     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
685       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
686       if ( aNodes2[ i ] == theNode2 )
687         iB2 = i; // node B in tr2
688       else if ( aNodes2[ i ] != theNode1 )
689         i2 = i;  // node 2
690     }
691
692     // nodes 1 and 2 should not be the same
693     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
694       return false;
695
696     // tr1: A->2
697     aNodes1[ iA1 ] = aNodes2[ i2 ];
698     // tr2: B->1
699     aNodes2[ iB2 ] = aNodes1[ i1 ];
700
701     //MESSAGE( tr1 << tr2 );
702
703     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
704     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
705
706     //MESSAGE( tr1 << tr2 );
707
708     return true;
709   }
710
711   // check case of quadratic faces
712   const SMDS_QuadraticFaceOfNodes* QF1 =
713     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
714   if(!QF1) return false;
715   const SMDS_QuadraticFaceOfNodes* QF2 =
716     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
717   if(!QF2) return false;
718   return InverseDiag(tr1,tr2);
719 }
720
721 //=======================================================================
722 //function : getQuadrangleNodes
723 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
724 //           fusion of triangles tr1 and tr2 having shared link on
725 //           theNode1 and theNode2
726 //=======================================================================
727
728 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
729                         const SMDS_MeshNode *    theNode1,
730                         const SMDS_MeshNode *    theNode2,
731                         const SMDS_MeshElement * tr1,
732                         const SMDS_MeshElement * tr2 )
733 {
734   if( tr1->NbNodes() != tr2->NbNodes() )
735     return false;
736   // find the 4-th node to insert into tr1
737   const SMDS_MeshNode* n4 = 0;
738   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
739   int i=0;
740   while ( !n4 && i<3 ) {
741     const SMDS_MeshNode * n = cast2Node( it->next() );
742     i++;
743     bool isDiag = ( n == theNode1 || n == theNode2 );
744     if ( !isDiag )
745       n4 = n;
746   }
747   // Make an array of nodes to be in a quadrangle
748   int iNode = 0, iFirstDiag = -1;
749   it = tr1->nodesIterator();
750   i=0;
751   while ( i<3 ) {
752     const SMDS_MeshNode * n = cast2Node( it->next() );
753     i++;
754     bool isDiag = ( n == theNode1 || n == theNode2 );
755     if ( isDiag ) {
756       if ( iFirstDiag < 0 )
757         iFirstDiag = iNode;
758       else if ( iNode - iFirstDiag == 1 )
759         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
760     }
761     else if ( n == n4 ) {
762       return false; // tr1 and tr2 should not have all the same nodes
763     }
764     theQuadNodes[ iNode++ ] = n;
765   }
766   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
767     theQuadNodes[ iNode ] = n4;
768
769   return true;
770 }
771
772 //=======================================================================
773 //function : DeleteDiag
774 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
775 //           with a quadrangle built on the same 4 nodes.
776 //           Return false if proper faces not found
777 //=======================================================================
778
779 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
780                                    const SMDS_MeshNode * theNode2)
781 {
782   myLastCreatedElems.Clear();
783   myLastCreatedNodes.Clear();
784
785   MESSAGE( "::DeleteDiag()" );
786
787   const SMDS_MeshElement *tr1, *tr2;
788   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
789     return false;
790
791   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
792   //if (!F1) return false;
793   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
794   //if (!F2) return false;
795   if (F1 && F2) {
796
797     const SMDS_MeshNode* aNodes [ 4 ];
798     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
799       return false;
800
801     //MESSAGE( endl << tr1 << tr2 );
802
803     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
804     myLastCreatedElems.Append(tr1);
805     GetMeshDS()->RemoveElement( tr2 );
806
807     //MESSAGE( endl << tr1 );
808
809     return true;
810   }
811
812   // check case of quadratic faces
813   const SMDS_QuadraticFaceOfNodes* QF1 =
814     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
815   if(!QF1) return false;
816   const SMDS_QuadraticFaceOfNodes* QF2 =
817     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
818   if(!QF2) return false;
819
820   //       5
821   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
822   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
823   //    |   / |
824   //  7 +  +  + 6
825   //    | /9  |
826   //    |/    |
827   //  4 +--+--+ 3
828   //       8
829
830   const SMDS_MeshNode* N1 [6];
831   const SMDS_MeshNode* N2 [6];
832   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
833     return false;
834   // now we receive following N1 and N2 (using numeration as above image)
835   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
836   // i.e. first nodes from both arrays determ new diagonal
837
838   const SMDS_MeshNode* aNodes[8];
839   aNodes[0] = N1[0];
840   aNodes[1] = N1[1];
841   aNodes[2] = N2[0];
842   aNodes[3] = N2[1];
843   aNodes[4] = N1[3];
844   aNodes[5] = N2[5];
845   aNodes[6] = N2[3];
846   aNodes[7] = N1[5];
847
848   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
849   myLastCreatedElems.Append(tr1);
850   GetMeshDS()->RemoveElement( tr2 );
851
852   // remove middle node (9)
853   GetMeshDS()->RemoveNode( N1[4] );
854
855   return true;
856 }
857
858 //=======================================================================
859 //function : Reorient
860 //purpose  : Reverse theElement orientation
861 //=======================================================================
862
863 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
864 {
865   myLastCreatedElems.Clear();
866   myLastCreatedNodes.Clear();
867
868   if (!theElem)
869     return false;
870   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
871   if ( !it || !it->more() )
872     return false;
873
874   switch ( theElem->GetType() ) {
875
876   case SMDSAbs_Edge:
877   case SMDSAbs_Face: {
878     if(!theElem->IsQuadratic()) {
879       int i = theElem->NbNodes();
880       vector<const SMDS_MeshNode*> aNodes( i );
881       while ( it->more() )
882         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
883       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
884     }
885     else {
886       // quadratic elements
887       if(theElem->GetType()==SMDSAbs_Edge) {
888         vector<const SMDS_MeshNode*> aNodes(3);
889         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
890         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
891         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
892         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
893       }
894       else {
895         int nbn = theElem->NbNodes();
896         vector<const SMDS_MeshNode*> aNodes(nbn);
897         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
898         int i=1;
899         for(; i<nbn/2; i++) {
900           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
901         }
902         for(i=0; i<nbn/2; i++) {
903           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
904         }
905         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
906       }
907     }
908   }
909   case SMDSAbs_Volume: {
910     if (theElem->IsPoly()) {
911       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
912         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
913       if (!aPolyedre) {
914         MESSAGE("Warning: bad volumic element");
915         return false;
916       }
917
918       int nbFaces = aPolyedre->NbFaces();
919       vector<const SMDS_MeshNode *> poly_nodes;
920       vector<int> quantities (nbFaces);
921
922       // reverse each face of the polyedre
923       for (int iface = 1; iface <= nbFaces; iface++) {
924         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
925         quantities[iface - 1] = nbFaceNodes;
926
927         for (inode = nbFaceNodes; inode >= 1; inode--) {
928           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
929           poly_nodes.push_back(curNode);
930         }
931       }
932
933       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
934
935     }
936     else {
937       SMDS_VolumeTool vTool;
938       if ( !vTool.Set( theElem ))
939         return false;
940       vTool.Inverse();
941       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
942     }
943   }
944   default:;
945   }
946
947   return false;
948 }
949
950 //=======================================================================
951 //function : getBadRate
952 //purpose  :
953 //=======================================================================
954
955 static double getBadRate (const SMDS_MeshElement*               theElem,
956                           SMESH::Controls::NumericalFunctorPtr& theCrit)
957 {
958   SMESH::Controls::TSequenceOfXYZ P;
959   if ( !theElem || !theCrit->GetPoints( theElem, P ))
960     return 1e100;
961   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
962   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
963 }
964
965 //=======================================================================
966 //function : QuadToTri
967 //purpose  : Cut quadrangles into triangles.
968 //           theCrit is used to select a diagonal to cut
969 //=======================================================================
970
971 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
972                                   SMESH::Controls::NumericalFunctorPtr theCrit)
973 {
974   myLastCreatedElems.Clear();
975   myLastCreatedNodes.Clear();
976
977   MESSAGE( "::QuadToTri()" );
978
979   if ( !theCrit.get() )
980     return false;
981
982   SMESHDS_Mesh * aMesh = GetMeshDS();
983
984   Handle(Geom_Surface) surface;
985   SMESH_MesherHelper   helper( *GetMesh() );
986
987   TIDSortedElemSet::iterator itElem;
988   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
989     const SMDS_MeshElement* elem = *itElem;
990     if ( !elem || elem->GetType() != SMDSAbs_Face )
991       continue;
992     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
993       continue;
994
995     // retrieve element nodes
996     const SMDS_MeshNode* aNodes [8];
997     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
998     int i = 0;
999     while ( itN->more() )
1000       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1001
1002     // compare two sets of possible triangles
1003     double aBadRate1, aBadRate2; // to what extent a set is bad
1004     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1005     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1006     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1007
1008     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1009     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1010     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1011
1012     int aShapeId = FindShape( elem );
1013     const SMDS_MeshElement* newElem = 0;
1014
1015     if( !elem->IsQuadratic() ) {
1016
1017       // split liner quadrangle
1018
1019       if ( aBadRate1 <= aBadRate2 ) {
1020         // tr1 + tr2 is better
1021         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1022         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1023       }
1024       else {
1025         // tr3 + tr4 is better
1026         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1027         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1028       }
1029     }
1030     else {
1031
1032       // split quadratic quadrangle
1033
1034       // get surface elem is on
1035       if ( aShapeId != helper.GetSubShapeID() ) {
1036         surface.Nullify();
1037         TopoDS_Shape shape;
1038         if ( aShapeId > 0 )
1039           shape = aMesh->IndexToShape( aShapeId );
1040         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1041           TopoDS_Face face = TopoDS::Face( shape );
1042           surface = BRep_Tool::Surface( face );
1043           if ( !surface.IsNull() )
1044             helper.SetSubShape( shape );
1045         }
1046       }
1047       // get elem nodes
1048       const SMDS_MeshNode* aNodes [8];
1049       const SMDS_MeshNode* inFaceNode = 0;
1050       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1051       int i = 0;
1052       while ( itN->more() ) {
1053         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1054         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1055              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1056         {
1057           inFaceNode = aNodes[ i-1 ];
1058         }
1059       }
1060       // find middle point for (0,1,2,3)
1061       // and create a node in this point;
1062       gp_XYZ p( 0,0,0 );
1063       if ( surface.IsNull() ) {
1064         for(i=0; i<4; i++)
1065           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1066         p /= 4;
1067       }
1068       else {
1069         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1070         gp_XY uv( 0,0 );
1071         for(i=0; i<4; i++)
1072           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1073         uv /= 4.;
1074         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1075       }
1076       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1077       myLastCreatedNodes.Append(newN);
1078
1079       // create a new element
1080       const SMDS_MeshNode* N[6];
1081       if ( aBadRate1 <= aBadRate2 ) {
1082         N[0] = aNodes[0];
1083         N[1] = aNodes[1];
1084         N[2] = aNodes[2];
1085         N[3] = aNodes[4];
1086         N[4] = aNodes[5];
1087         N[5] = newN;
1088         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1089                                  aNodes[6], aNodes[7], newN );
1090       }
1091       else {
1092         N[0] = aNodes[1];
1093         N[1] = aNodes[2];
1094         N[2] = aNodes[3];
1095         N[3] = aNodes[5];
1096         N[4] = aNodes[6];
1097         N[5] = newN;
1098         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1099                                  aNodes[7], aNodes[4], newN );
1100       }
1101       aMesh->ChangeElementNodes( elem, N, 6 );
1102
1103     } // quadratic case
1104
1105     // care of a new element
1106
1107     myLastCreatedElems.Append(newElem);
1108     AddToSameGroups( newElem, elem, aMesh );
1109
1110     // put a new triangle on the same shape
1111     if ( aShapeId )
1112       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1113   }
1114   return true;
1115 }
1116
1117 //=======================================================================
1118 //function : BestSplit
1119 //purpose  : Find better diagonal for cutting.
1120 //=======================================================================
1121
1122 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1123                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1124 {
1125   myLastCreatedElems.Clear();
1126   myLastCreatedNodes.Clear();
1127
1128   if (!theCrit.get())
1129     return -1;
1130
1131   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1132     return -1;
1133
1134   if( theQuad->NbNodes()==4 ||
1135       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1136
1137     // retrieve element nodes
1138     const SMDS_MeshNode* aNodes [4];
1139     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1140     int i = 0;
1141     //while (itN->more())
1142     while (i<4) {
1143       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1144     }
1145     // compare two sets of possible triangles
1146     double aBadRate1, aBadRate2; // to what extent a set is bad
1147     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1148     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1149     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1150
1151     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1152     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1153     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1154
1155     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1156       return 1; // diagonal 1-3
1157
1158     return 2; // diagonal 2-4
1159   }
1160   return -1;
1161 }
1162
1163 namespace
1164 {
1165   // Methods of splitting volumes into tetra
1166
1167   const int theHexTo5_1[5*4+1] =
1168     {
1169       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1170     };
1171   const int theHexTo5_2[5*4+1] =
1172     {
1173       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1174     };
1175   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1176
1177   const int theHexTo6_1[6*4+1] =
1178     {
1179       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1180     };
1181   const int theHexTo6_2[6*4+1] =
1182     {
1183       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1184     };
1185   const int theHexTo6_3[6*4+1] =
1186     {
1187       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1188     };
1189   const int theHexTo6_4[6*4+1] =
1190     {
1191       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1192     };
1193   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1194
1195   const int thePyraTo2_1[2*4+1] =
1196     {
1197       0, 1, 2, 4,    0, 2, 3, 4,   -1
1198     };
1199   const int thePyraTo2_2[2*4+1] =
1200     {
1201       1, 2, 3, 4,    1, 3, 0, 4,   -1
1202     };
1203   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1204
1205   const int thePentaTo3_1[3*4+1] =
1206     {
1207       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1208     };
1209   const int thePentaTo3_2[3*4+1] =
1210     {
1211       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1212     };
1213   const int thePentaTo3_3[3*4+1] =
1214     {
1215       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1216     };
1217   const int thePentaTo3_4[3*4+1] =
1218     {
1219       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1220     };
1221   const int thePentaTo3_5[3*4+1] =
1222     {
1223       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1224     };
1225   const int thePentaTo3_6[3*4+1] =
1226     {
1227       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1228     };
1229   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1230                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1231
1232   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1233   {
1234     int _n1, _n2, _n3;
1235     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1236     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1237     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1238   };
1239   struct TSplitMethod
1240   {
1241     int        _nbTetra;
1242     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1243     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1244     bool       _ownConn;      //!< to delete _connectivity in destructor
1245
1246     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1247       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1248     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1249     bool hasFacet( const TTriangleFacet& facet ) const
1250     {
1251       const int* tetConn = _connectivity;
1252       for ( ; tetConn[0] >= 0; tetConn += 4 )
1253         if (( facet.contains( tetConn[0] ) +
1254               facet.contains( tetConn[1] ) +
1255               facet.contains( tetConn[2] ) +
1256               facet.contains( tetConn[3] )) == 3 )
1257           return true;
1258       return false;
1259     }
1260   };
1261
1262   //=======================================================================
1263   /*!
1264    * \brief return TSplitMethod for the given element
1265    */
1266   //=======================================================================
1267
1268   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1269   {
1270     int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1271
1272     // Find out how adjacent volumes are split
1273
1274     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1275     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1276     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1277     {
1278       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1279       maxTetConnSize += 4 * ( nbNodes - 2 );
1280       if ( nbNodes < 4 ) continue;
1281
1282       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1283       const int* nInd = vol.GetFaceNodesIndices( iF );
1284       if ( nbNodes == 4 )
1285       {
1286         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1287         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1288         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1289         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1290       }
1291       else
1292       {
1293         int iCom = 0; // common node of triangle faces to split into
1294         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1295         {
1296           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1297                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1298                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1299           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1300                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1301                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1302           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1303           {
1304             triaSplits.push_back( t012 );
1305             triaSplits.push_back( t023 );
1306             break;
1307           }
1308         }
1309       }
1310       if ( !triaSplits.empty() )
1311         hasAdjacentSplits = true;
1312     }
1313
1314     // Among variants of split method select one compliant with adjacent volumes
1315
1316     TSplitMethod method;
1317     if ( !vol.Element()->IsPoly() )
1318     {
1319       int nbVariants = 2, nbTet = 0;
1320       const int** connVariants = 0;
1321       switch ( vol.Element()->GetEntityType() )
1322       {
1323       case SMDSEntity_Hexa:
1324       case SMDSEntity_Quad_Hexa:
1325         if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1326           connVariants = theHexTo5, nbTet = 5;
1327         else
1328           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1329         break;
1330       case SMDSEntity_Pyramid:
1331       case SMDSEntity_Quad_Pyramid:
1332         connVariants = thePyraTo2;  nbTet = 2;
1333         break;
1334       case SMDSEntity_Penta:
1335       case SMDSEntity_Quad_Penta:
1336         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1337         break;
1338       default:
1339         nbVariants = 0;
1340       }
1341       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1342       {
1343         // check method compliancy with adjacent tetras,
1344         // all found splits must be among facets of tetras described by this method
1345         method = TSplitMethod( nbTet, connVariants[variant] );
1346         if ( hasAdjacentSplits && method._nbTetra > 0 )
1347         {
1348           bool facetCreated = true;
1349           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1350           {
1351             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1352             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1353               facetCreated = method.hasFacet( *facet );
1354           }
1355           if ( !facetCreated )
1356             method = TSplitMethod(0); // incompatible method
1357         }
1358       }
1359     }
1360     if ( method._nbTetra < 1 )
1361     {
1362       // No standard method is applicable, use a generic solution:
1363       // each facet of a volume is split into triangles and
1364       // each of triangles and a volume barycenter form a tetrahedron.
1365
1366       int* connectivity = new int[ maxTetConnSize + 1 ];
1367       method._connectivity = connectivity;
1368       method._ownConn = true;
1369       method._baryNode = true;
1370
1371       int connSize = 0;
1372       int baryCenInd = vol.NbNodes();
1373       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1374       {
1375         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1376         const int*   nInd = vol.GetFaceNodesIndices( iF );
1377         // find common node of triangle facets of tetra to create
1378         int iCommon = 0; // index in linear numeration
1379         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1380         if ( !triaSplits.empty() )
1381         {
1382           // by found facets
1383           const TTriangleFacet* facet = &triaSplits.front();
1384           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1385             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1386                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1387               break;
1388         }
1389         else if ( nbNodes > 3 )
1390         {
1391           // find the best method of splitting into triangles by aspect ratio
1392           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1393           map< double, int > badness2iCommon;
1394           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1395           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1396           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1397             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1398             {
1399               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1400                                       nodes[ iQ*((iLast-1)%nbNodes)],
1401                                       nodes[ iQ*((iLast  )%nbNodes)]);
1402               double badness = getBadRate( &tria, aspectRatio );
1403               badness2iCommon.insert( make_pair( badness, iCommon ));
1404             }
1405           // use iCommon with lowest badness
1406           iCommon = badness2iCommon.begin()->second;
1407         }
1408         if ( iCommon >= nbNodes )
1409           iCommon = 0; // something wrong
1410         // fill connectivity of tetra
1411         int nbTet = nbNodes - 2;
1412         for ( int i = 0; i < nbTet; ++i )
1413         {
1414           int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1415           if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1416           connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1417           connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1418           connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1419           connectivity[ connSize++ ] = baryCenInd;
1420           ++method._nbTetra;
1421         }
1422       }
1423       connectivity[ connSize++ ] = -1;
1424     }
1425     return method;
1426   }
1427   //================================================================================
1428   /*!
1429    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1430    */
1431   //================================================================================
1432
1433   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1434   {
1435     // find the tetrahedron including the three nodes of facet
1436     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1437     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1438     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1439     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1440     while ( volIt1->more() )
1441     {
1442       const SMDS_MeshElement* v = volIt1->next();
1443       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1444         continue;
1445       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1446       while ( volIt2->more() )
1447         if ( v != volIt2->next() )
1448           continue;
1449       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1450       while ( volIt3->more() )
1451         if ( v == volIt3->next() )
1452           return true;
1453     }
1454     return false;
1455   }
1456 } // namespace
1457
1458 //=======================================================================
1459 //function : SplitVolumesIntoTetra
1460 //purpose  : Split volumic elements into tetrahedra.
1461 //=======================================================================
1462
1463 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1464                                               const int                theMethodFlags)
1465 {
1466   // std-like iterator on coordinates of nodes of mesh element
1467   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1468   NXyzIterator xyzEnd;
1469
1470   SMDS_VolumeTool    volTool;
1471   SMESH_MesherHelper helper( *GetMesh());
1472
1473   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1474   SMESHDS_SubMesh* fSubMesh = subMesh;
1475   
1476   SMESH_SequenceOfElemPtr newNodes, newElems;
1477
1478   TIDSortedElemSet::const_iterator elem = theElems.begin();
1479   for ( ; elem != theElems.end(); ++elem )
1480   {
1481     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1482     if ( geomType <= SMDSEntity_Quad_Tetra )
1483       continue; // tetra or face or ...
1484
1485     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1486
1487     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1488     if ( splitMethod._nbTetra < 1 ) continue;
1489
1490     // find submesh to add new tetras in
1491     if ( !subMesh || !subMesh->Contains( *elem ))
1492     {
1493       int shapeID = FindShape( *elem );
1494       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1495       subMesh = GetMeshDS()->MeshElements( shapeID );
1496     }
1497     int iQ;
1498     if ( (*elem)->IsQuadratic() )
1499     {
1500       iQ = 2;
1501       // add quadratic links to the helper
1502       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1503       {
1504         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1505         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1506           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1507       }
1508       helper.SetIsQuadratic( true );
1509     }
1510     else
1511     {
1512       iQ = 1;
1513       helper.SetIsQuadratic( false );
1514     }
1515     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1516     if ( splitMethod._baryNode )
1517     {
1518       // make a node at barycenter
1519       gp_XYZ gc( 0,0,0 );
1520       gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1521       SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1522       nodes.push_back( gcNode );
1523       newNodes.Append( gcNode );
1524     }
1525
1526     // make tetras
1527     helper.SetElementsOnShape( true );
1528     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1529     const int* tetConn = splitMethod._connectivity;
1530     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1531       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1532                                                        nodes[ tetConn[1] ],
1533                                                        nodes[ tetConn[2] ],
1534                                                        nodes[ tetConn[3] ]));
1535
1536     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1537
1538     // Split faces on sides of the split volume
1539
1540     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1541     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1542     {
1543       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1544       if ( nbNodes < 4 ) continue;
1545
1546       // find an existing face
1547       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1548                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1549       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1550       {
1551         // among possible triangles create ones discribed by split method
1552         const int* nInd = volTool.GetFaceNodesIndices( iF );
1553         int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1554         int iCom = 0; // common node of triangle faces to split into
1555         list< TTriangleFacet > facets;
1556         for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1557         {
1558           TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1559                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1560                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1561           TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1562                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1563                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1564           if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1565           {
1566             facets.push_back( t012 );
1567             facets.push_back( t023 );
1568             for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1569               facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1570                                                 nInd[ iQ * ((iLast-1)%nbNodes )],
1571                                                 nInd[ iQ * ((iLast  )%nbNodes )]));
1572             break;
1573           }
1574         }
1575         // find submesh to add new faces in
1576         if ( !fSubMesh || !fSubMesh->Contains( face ))
1577         {
1578           int shapeID = FindShape( face );
1579           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1580         }
1581         // make triangles
1582         helper.SetElementsOnShape( false );
1583         vector< const SMDS_MeshElement* > triangles;
1584         list< TTriangleFacet >::iterator facet = facets.begin();
1585         for ( ; facet != facets.end(); ++facet )
1586         {
1587           if ( !volTool.IsFaceExternal( iF ))
1588             swap( facet->_n2, facet->_n3 );
1589           triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1590                                                volNodes[ facet->_n2 ],
1591                                                volNodes[ facet->_n3 ]));
1592           if ( triangles.back() && fSubMesh )
1593             fSubMesh->AddElement( triangles.back());
1594           newElems.Append( triangles.back() );
1595         }
1596         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1597         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1598       }
1599
1600     } // loop on volume faces to split them into triangles
1601
1602     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1603
1604   } // loop on volumes to split
1605
1606   myLastCreatedNodes = newNodes;
1607   myLastCreatedElems = newElems;
1608 }
1609
1610 //=======================================================================
1611 //function : AddToSameGroups
1612 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1613 //=======================================================================
1614
1615 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1616                                         const SMDS_MeshElement* elemInGroups,
1617                                         SMESHDS_Mesh *          aMesh)
1618 {
1619   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1620   if (!groups.empty()) {
1621     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1622     for ( ; grIt != groups.end(); grIt++ ) {
1623       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1624       if ( group && group->Contains( elemInGroups ))
1625         group->SMDSGroup().Add( elemToAdd );
1626     }
1627   }
1628 }
1629
1630
1631 //=======================================================================
1632 //function : RemoveElemFromGroups
1633 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1634 //=======================================================================
1635 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1636                                              SMESHDS_Mesh *          aMesh)
1637 {
1638   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1639   if (!groups.empty())
1640   {
1641     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1642     for (; GrIt != groups.end(); GrIt++)
1643     {
1644       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1645       if (!grp || grp->IsEmpty()) continue;
1646       grp->SMDSGroup().Remove(removeelem);
1647     }
1648   }
1649 }
1650
1651 //================================================================================
1652 /*!
1653  * \brief Replace elemToRm by elemToAdd in the all groups
1654  */
1655 //================================================================================
1656
1657 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1658                                             const SMDS_MeshElement* elemToAdd,
1659                                             SMESHDS_Mesh *          aMesh)
1660 {
1661   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1662   if (!groups.empty()) {
1663     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1664     for ( ; grIt != groups.end(); grIt++ ) {
1665       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1666       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1667         group->SMDSGroup().Add( elemToAdd );
1668     }
1669   }
1670 }
1671
1672 //================================================================================
1673 /*!
1674  * \brief Replace elemToRm by elemToAdd in the all groups
1675  */
1676 //================================================================================
1677
1678 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1679                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1680                                             SMESHDS_Mesh *                         aMesh)
1681 {
1682   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1683   if (!groups.empty())
1684   {
1685     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1686     for ( ; grIt != groups.end(); grIt++ ) {
1687       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1688       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1689         for ( int i = 0; i < elemToAdd.size(); ++i )
1690           group->SMDSGroup().Add( elemToAdd[ i ] );
1691     }
1692   }
1693 }
1694
1695 //=======================================================================
1696 //function : QuadToTri
1697 //purpose  : Cut quadrangles into triangles.
1698 //           theCrit is used to select a diagonal to cut
1699 //=======================================================================
1700
1701 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1702                                   const bool         the13Diag)
1703 {
1704   myLastCreatedElems.Clear();
1705   myLastCreatedNodes.Clear();
1706
1707   MESSAGE( "::QuadToTri()" );
1708
1709   SMESHDS_Mesh * aMesh = GetMeshDS();
1710
1711   Handle(Geom_Surface) surface;
1712   SMESH_MesherHelper   helper( *GetMesh() );
1713
1714   TIDSortedElemSet::iterator itElem;
1715   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1716     const SMDS_MeshElement* elem = *itElem;
1717     if ( !elem || elem->GetType() != SMDSAbs_Face )
1718       continue;
1719     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1720     if(!isquad) continue;
1721
1722     if(elem->NbNodes()==4) {
1723       // retrieve element nodes
1724       const SMDS_MeshNode* aNodes [4];
1725       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1726       int i = 0;
1727       while ( itN->more() )
1728         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1729
1730       int aShapeId = FindShape( elem );
1731       const SMDS_MeshElement* newElem = 0;
1732       if ( the13Diag ) {
1733         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1734         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1735       }
1736       else {
1737         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1738         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1739       }
1740       myLastCreatedElems.Append(newElem);
1741       // put a new triangle on the same shape and add to the same groups
1742       if ( aShapeId )
1743         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1744       AddToSameGroups( newElem, elem, aMesh );
1745     }
1746
1747     // Quadratic quadrangle
1748
1749     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1750
1751       // get surface elem is on
1752       int aShapeId = FindShape( elem );
1753       if ( aShapeId != helper.GetSubShapeID() ) {
1754         surface.Nullify();
1755         TopoDS_Shape shape;
1756         if ( aShapeId > 0 )
1757           shape = aMesh->IndexToShape( aShapeId );
1758         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1759           TopoDS_Face face = TopoDS::Face( shape );
1760           surface = BRep_Tool::Surface( face );
1761           if ( !surface.IsNull() )
1762             helper.SetSubShape( shape );
1763         }
1764       }
1765
1766       const SMDS_MeshNode* aNodes [8];
1767       const SMDS_MeshNode* inFaceNode = 0;
1768       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1769       int i = 0;
1770       while ( itN->more() ) {
1771         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1772         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1773              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1774         {
1775           inFaceNode = aNodes[ i-1 ];
1776         }
1777       }
1778
1779       // find middle point for (0,1,2,3)
1780       // and create a node in this point;
1781       gp_XYZ p( 0,0,0 );
1782       if ( surface.IsNull() ) {
1783         for(i=0; i<4; i++)
1784           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1785         p /= 4;
1786       }
1787       else {
1788         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1789         gp_XY uv( 0,0 );
1790         for(i=0; i<4; i++)
1791           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1792         uv /= 4.;
1793         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1794       }
1795       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1796       myLastCreatedNodes.Append(newN);
1797
1798       // create a new element
1799       const SMDS_MeshElement* newElem = 0;
1800       const SMDS_MeshNode* N[6];
1801       if ( the13Diag ) {
1802         N[0] = aNodes[0];
1803         N[1] = aNodes[1];
1804         N[2] = aNodes[2];
1805         N[3] = aNodes[4];
1806         N[4] = aNodes[5];
1807         N[5] = newN;
1808         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1809                                  aNodes[6], aNodes[7], newN );
1810       }
1811       else {
1812         N[0] = aNodes[1];
1813         N[1] = aNodes[2];
1814         N[2] = aNodes[3];
1815         N[3] = aNodes[5];
1816         N[4] = aNodes[6];
1817         N[5] = newN;
1818         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1819                                  aNodes[7], aNodes[4], newN );
1820       }
1821       myLastCreatedElems.Append(newElem);
1822       aMesh->ChangeElementNodes( elem, N, 6 );
1823       // put a new triangle on the same shape and add to the same groups
1824       if ( aShapeId )
1825         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1826       AddToSameGroups( newElem, elem, aMesh );
1827     }
1828   }
1829
1830   return true;
1831 }
1832
1833 //=======================================================================
1834 //function : getAngle
1835 //purpose  :
1836 //=======================================================================
1837
1838 double getAngle(const SMDS_MeshElement * tr1,
1839                 const SMDS_MeshElement * tr2,
1840                 const SMDS_MeshNode *    n1,
1841                 const SMDS_MeshNode *    n2)
1842 {
1843   double angle = 2*PI; // bad angle
1844
1845   // get normals
1846   SMESH::Controls::TSequenceOfXYZ P1, P2;
1847   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1848        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1849     return angle;
1850   gp_Vec N1,N2;
1851   if(!tr1->IsQuadratic())
1852     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1853   else
1854     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1855   if ( N1.SquareMagnitude() <= gp::Resolution() )
1856     return angle;
1857   if(!tr2->IsQuadratic())
1858     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1859   else
1860     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1861   if ( N2.SquareMagnitude() <= gp::Resolution() )
1862     return angle;
1863
1864   // find the first diagonal node n1 in the triangles:
1865   // take in account a diagonal link orientation
1866   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1867   for ( int t = 0; t < 2; t++ ) {
1868     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1869     int i = 0, iDiag = -1;
1870     while ( it->more()) {
1871       const SMDS_MeshElement *n = it->next();
1872       if ( n == n1 || n == n2 )
1873         if ( iDiag < 0)
1874           iDiag = i;
1875         else {
1876           if ( i - iDiag == 1 )
1877             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1878           else
1879             nFirst[ t ] = n;
1880           break;
1881         }
1882       i++;
1883     }
1884   }
1885   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1886     N2.Reverse();
1887
1888   angle = N1.Angle( N2 );
1889   //SCRUTE( angle );
1890   return angle;
1891 }
1892
1893 // =================================================
1894 // class generating a unique ID for a pair of nodes
1895 // and able to return nodes by that ID
1896 // =================================================
1897 class LinkID_Gen {
1898 public:
1899
1900   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1901     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1902   {}
1903
1904   long GetLinkID (const SMDS_MeshNode * n1,
1905                   const SMDS_MeshNode * n2) const
1906   {
1907     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1908   }
1909
1910   bool GetNodes (const long             theLinkID,
1911                  const SMDS_MeshNode* & theNode1,
1912                  const SMDS_MeshNode* & theNode2) const
1913   {
1914     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1915     if ( !theNode1 ) return false;
1916     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1917     if ( !theNode2 ) return false;
1918     return true;
1919   }
1920
1921 private:
1922   LinkID_Gen();
1923   const SMESHDS_Mesh* myMesh;
1924   long                myMaxID;
1925 };
1926
1927
1928 //=======================================================================
1929 //function : TriToQuad
1930 //purpose  : Fuse neighbour triangles into quadrangles.
1931 //           theCrit is used to select a neighbour to fuse with.
1932 //           theMaxAngle is a max angle between element normals at which
1933 //           fusion is still performed.
1934 //=======================================================================
1935
1936 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1937                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1938                                   const double                         theMaxAngle)
1939 {
1940   myLastCreatedElems.Clear();
1941   myLastCreatedNodes.Clear();
1942
1943   MESSAGE( "::TriToQuad()" );
1944
1945   if ( !theCrit.get() )
1946     return false;
1947
1948   SMESHDS_Mesh * aMesh = GetMeshDS();
1949
1950   // Prepare data for algo: build
1951   // 1. map of elements with their linkIDs
1952   // 2. map of linkIDs with their elements
1953
1954   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1955   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1956   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
1957   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1958
1959   TIDSortedElemSet::iterator itElem;
1960   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1961     const SMDS_MeshElement* elem = *itElem;
1962     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1963     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1964     if(!IsTria) continue;
1965
1966     // retrieve element nodes
1967     const SMDS_MeshNode* aNodes [4];
1968     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1969     int i = 0;
1970     while ( i<3 )
1971       aNodes[ i++ ] = cast2Node( itN->next() );
1972     aNodes[ 3 ] = aNodes[ 0 ];
1973
1974     // fill maps
1975     for ( i = 0; i < 3; i++ ) {
1976       SMESH_TLink link( aNodes[i], aNodes[i+1] );
1977       // check if elements sharing a link can be fused
1978       itLE = mapLi_listEl.find( link );
1979       if ( itLE != mapLi_listEl.end() ) {
1980         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1981           continue;
1982         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1983         //if ( FindShape( elem ) != FindShape( elem2 ))
1984         //  continue; // do not fuse triangles laying on different shapes
1985         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1986           continue; // avoid making badly shaped quads
1987         (*itLE).second.push_back( elem );
1988       }
1989       else {
1990         mapLi_listEl[ link ].push_back( elem );
1991       }
1992       mapEl_setLi [ elem ].insert( link );
1993     }
1994   }
1995   // Clean the maps from the links shared by a sole element, ie
1996   // links to which only one element is bound in mapLi_listEl
1997
1998   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1999     int nbElems = (*itLE).second.size();
2000     if ( nbElems < 2  ) {
2001       const SMDS_MeshElement* elem = (*itLE).second.front();
2002       SMESH_TLink link = (*itLE).first;
2003       mapEl_setLi[ elem ].erase( link );
2004       if ( mapEl_setLi[ elem ].empty() )
2005         mapEl_setLi.erase( elem );
2006     }
2007   }
2008
2009   // Algo: fuse triangles into quadrangles
2010
2011   while ( ! mapEl_setLi.empty() ) {
2012     // Look for the start element:
2013     // the element having the least nb of shared links
2014     const SMDS_MeshElement* startElem = 0;
2015     int minNbLinks = 4;
2016     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2017       int nbLinks = (*itEL).second.size();
2018       if ( nbLinks < minNbLinks ) {
2019         startElem = (*itEL).first;
2020         minNbLinks = nbLinks;
2021         if ( minNbLinks == 1 )
2022           break;
2023       }
2024     }
2025
2026     // search elements to fuse starting from startElem or links of elements
2027     // fused earlyer - startLinks
2028     list< SMESH_TLink > startLinks;
2029     while ( startElem || !startLinks.empty() ) {
2030       while ( !startElem && !startLinks.empty() ) {
2031         // Get an element to start, by a link
2032         SMESH_TLink linkId = startLinks.front();
2033         startLinks.pop_front();
2034         itLE = mapLi_listEl.find( linkId );
2035         if ( itLE != mapLi_listEl.end() ) {
2036           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2037           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2038           for ( ; itE != listElem.end() ; itE++ )
2039             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2040               startElem = (*itE);
2041           mapLi_listEl.erase( itLE );
2042         }
2043       }
2044
2045       if ( startElem ) {
2046         // Get candidates to be fused
2047         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2048         const SMESH_TLink *link12, *link13;
2049         startElem = 0;
2050         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2051         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2052         ASSERT( !setLi.empty() );
2053         set< SMESH_TLink >::iterator itLi;
2054         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2055         {
2056           const SMESH_TLink & link = (*itLi);
2057           itLE = mapLi_listEl.find( link );
2058           if ( itLE == mapLi_listEl.end() )
2059             continue;
2060
2061           const SMDS_MeshElement* elem = (*itLE).second.front();
2062           if ( elem == tr1 )
2063             elem = (*itLE).second.back();
2064           mapLi_listEl.erase( itLE );
2065           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2066             continue;
2067           if ( tr2 ) {
2068             tr3 = elem;
2069             link13 = &link;
2070           }
2071           else {
2072             tr2 = elem;
2073             link12 = &link;
2074           }
2075
2076           // add other links of elem to list of links to re-start from
2077           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2078           set< SMESH_TLink >::iterator it;
2079           for ( it = links.begin(); it != links.end(); it++ ) {
2080             const SMESH_TLink& link2 = (*it);
2081             if ( link2 != link )
2082               startLinks.push_back( link2 );
2083           }
2084         }
2085
2086         // Get nodes of possible quadrangles
2087         const SMDS_MeshNode *n12 [4], *n13 [4];
2088         bool Ok12 = false, Ok13 = false;
2089         const SMDS_MeshNode *linkNode1, *linkNode2;
2090         if(tr2) {
2091           linkNode1 = link12->first;
2092           linkNode2 = link12->second;
2093           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2094             Ok12 = true;
2095         }
2096         if(tr3) {
2097           linkNode1 = link13->first;
2098           linkNode2 = link13->second;
2099           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2100             Ok13 = true;
2101         }
2102
2103         // Choose a pair to fuse
2104         if ( Ok12 && Ok13 ) {
2105           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2106           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2107           double aBadRate12 = getBadRate( &quad12, theCrit );
2108           double aBadRate13 = getBadRate( &quad13, theCrit );
2109           if (  aBadRate13 < aBadRate12 )
2110             Ok12 = false;
2111           else
2112             Ok13 = false;
2113         }
2114
2115         // Make quadrangles
2116         // and remove fused elems and removed links from the maps
2117         mapEl_setLi.erase( tr1 );
2118         if ( Ok12 ) {
2119           mapEl_setLi.erase( tr2 );
2120           mapLi_listEl.erase( *link12 );
2121           if(tr1->NbNodes()==3) {
2122             if( tr1->GetID() < tr2->GetID() ) {
2123               aMesh->ChangeElementNodes( tr1, n12, 4 );
2124               myLastCreatedElems.Append(tr1);
2125               aMesh->RemoveElement( tr2 );
2126             }
2127             else {
2128               aMesh->ChangeElementNodes( tr2, n12, 4 );
2129               myLastCreatedElems.Append(tr2);
2130               aMesh->RemoveElement( tr1);
2131             }
2132           }
2133           else {
2134             const SMDS_MeshNode* N1 [6];
2135             const SMDS_MeshNode* N2 [6];
2136             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2137             // now we receive following N1 and N2 (using numeration as above image)
2138             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2139             // i.e. first nodes from both arrays determ new diagonal
2140             const SMDS_MeshNode* aNodes[8];
2141             aNodes[0] = N1[0];
2142             aNodes[1] = N1[1];
2143             aNodes[2] = N2[0];
2144             aNodes[3] = N2[1];
2145             aNodes[4] = N1[3];
2146             aNodes[5] = N2[5];
2147             aNodes[6] = N2[3];
2148             aNodes[7] = N1[5];
2149             if( tr1->GetID() < tr2->GetID() ) {
2150               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2151               myLastCreatedElems.Append(tr1);
2152               GetMeshDS()->RemoveElement( tr2 );
2153             }
2154             else {
2155               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2156               myLastCreatedElems.Append(tr2);
2157               GetMeshDS()->RemoveElement( tr1 );
2158             }
2159             // remove middle node (9)
2160             GetMeshDS()->RemoveNode( N1[4] );
2161           }
2162         }
2163         else if ( Ok13 ) {
2164           mapEl_setLi.erase( tr3 );
2165           mapLi_listEl.erase( *link13 );
2166           if(tr1->NbNodes()==3) {
2167             if( tr1->GetID() < tr2->GetID() ) {
2168               aMesh->ChangeElementNodes( tr1, n13, 4 );
2169               myLastCreatedElems.Append(tr1);
2170               aMesh->RemoveElement( tr3 );
2171             }
2172             else {
2173               aMesh->ChangeElementNodes( tr3, n13, 4 );
2174               myLastCreatedElems.Append(tr3);
2175               aMesh->RemoveElement( tr1 );
2176             }
2177           }
2178           else {
2179             const SMDS_MeshNode* N1 [6];
2180             const SMDS_MeshNode* N2 [6];
2181             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2182             // now we receive following N1 and N2 (using numeration as above image)
2183             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2184             // i.e. first nodes from both arrays determ new diagonal
2185             const SMDS_MeshNode* aNodes[8];
2186             aNodes[0] = N1[0];
2187             aNodes[1] = N1[1];
2188             aNodes[2] = N2[0];
2189             aNodes[3] = N2[1];
2190             aNodes[4] = N1[3];
2191             aNodes[5] = N2[5];
2192             aNodes[6] = N2[3];
2193             aNodes[7] = N1[5];
2194             if( tr1->GetID() < tr2->GetID() ) {
2195               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2196               myLastCreatedElems.Append(tr1);
2197               GetMeshDS()->RemoveElement( tr3 );
2198             }
2199             else {
2200               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2201               myLastCreatedElems.Append(tr3);
2202               GetMeshDS()->RemoveElement( tr1 );
2203             }
2204             // remove middle node (9)
2205             GetMeshDS()->RemoveNode( N1[4] );
2206           }
2207         }
2208
2209         // Next element to fuse: the rejected one
2210         if ( tr3 )
2211           startElem = Ok12 ? tr3 : tr2;
2212
2213       } // if ( startElem )
2214     } // while ( startElem || !startLinks.empty() )
2215   } // while ( ! mapEl_setLi.empty() )
2216
2217   return true;
2218 }
2219
2220
2221 /*#define DUMPSO(txt) \
2222 //  cout << txt << endl;
2223 //=============================================================================
2224 //
2225 //
2226 //
2227 //=============================================================================
2228 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2229 {
2230 if ( i1 == i2 )
2231 return;
2232 int tmp = idNodes[ i1 ];
2233 idNodes[ i1 ] = idNodes[ i2 ];
2234 idNodes[ i2 ] = tmp;
2235 gp_Pnt Ptmp = P[ i1 ];
2236 P[ i1 ] = P[ i2 ];
2237 P[ i2 ] = Ptmp;
2238 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2239 }
2240
2241 //=======================================================================
2242 //function : SortQuadNodes
2243 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2244 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2245 //           1 or 2 else 0.
2246 //=======================================================================
2247
2248 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2249 int               idNodes[] )
2250 {
2251   gp_Pnt P[4];
2252   int i;
2253   for ( i = 0; i < 4; i++ ) {
2254     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2255     if ( !n ) return 0;
2256     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2257   }
2258
2259   gp_Vec V1(P[0], P[1]);
2260   gp_Vec V2(P[0], P[2]);
2261   gp_Vec V3(P[0], P[3]);
2262
2263   gp_Vec Cross1 = V1 ^ V2;
2264   gp_Vec Cross2 = V2 ^ V3;
2265
2266   i = 0;
2267   if (Cross1.Dot(Cross2) < 0)
2268   {
2269     Cross1 = V2 ^ V1;
2270     Cross2 = V1 ^ V3;
2271
2272     if (Cross1.Dot(Cross2) < 0)
2273       i = 2;
2274     else
2275       i = 1;
2276     swap ( i, i + 1, idNodes, P );
2277
2278     //     for ( int ii = 0; ii < 4; ii++ ) {
2279     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2280     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2281     //     }
2282   }
2283   return i;
2284 }
2285
2286 //=======================================================================
2287 //function : SortHexaNodes
2288 //purpose  : Set 8 nodes of a hexahedron in a good order.
2289 //           Return success status
2290 //=======================================================================
2291
2292 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2293                                       int               idNodes[] )
2294 {
2295   gp_Pnt P[8];
2296   int i;
2297   DUMPSO( "INPUT: ========================================");
2298   for ( i = 0; i < 8; i++ ) {
2299     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2300     if ( !n ) return false;
2301     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2302     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2303   }
2304   DUMPSO( "========================================");
2305
2306
2307   set<int> faceNodes;  // ids of bottom face nodes, to be found
2308   set<int> checkedId1; // ids of tried 2-nd nodes
2309   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2310   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2311   int iMin, iLoop1 = 0;
2312
2313   // Loop to try the 2-nd nodes
2314
2315   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2316   {
2317     // Find not checked 2-nd node
2318     for ( i = 1; i < 8; i++ )
2319       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2320         int id1 = idNodes[i];
2321         swap ( 1, i, idNodes, P );
2322         checkedId1.insert ( id1 );
2323         break;
2324       }
2325
2326     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2327     // ie that all but meybe one (id3 which is on the same face) nodes
2328     // lay on the same side from the triangle plane.
2329
2330     bool manyInPlane = false; // more than 4 nodes lay in plane
2331     int iLoop2 = 0;
2332     while ( ++iLoop2 < 6 ) {
2333
2334       // get 1-2-3 plane coeffs
2335       Standard_Real A, B, C, D;
2336       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2337       if ( N.SquareMagnitude() > gp::Resolution() )
2338       {
2339         gp_Pln pln ( P[0], N );
2340         pln.Coefficients( A, B, C, D );
2341
2342         // find the node (iMin) closest to pln
2343         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2344         set<int> idInPln;
2345         for ( i = 3; i < 8; i++ ) {
2346           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2347           if ( fabs( dist[i] ) < minDist ) {
2348             minDist = fabs( dist[i] );
2349             iMin = i;
2350           }
2351           if ( fabs( dist[i] ) <= tol )
2352             idInPln.insert( idNodes[i] );
2353         }
2354
2355         // there should not be more than 4 nodes in bottom plane
2356         if ( idInPln.size() > 1 )
2357         {
2358           DUMPSO( "### idInPln.size() = " << idInPln.size());
2359           // idInPlane does not contain the first 3 nodes
2360           if ( manyInPlane || idInPln.size() == 5)
2361             return false; // all nodes in one plane
2362           manyInPlane = true;
2363
2364           // set the 1-st node to be not in plane
2365           for ( i = 3; i < 8; i++ ) {
2366             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2367               DUMPSO( "### Reset 0-th node");
2368               swap( 0, i, idNodes, P );
2369               break;
2370             }
2371           }
2372
2373           // reset to re-check second nodes
2374           leastDist = DBL_MAX;
2375           faceNodes.clear();
2376           checkedId1.clear();
2377           iLoop1 = 0;
2378           break; // from iLoop2;
2379         }
2380
2381         // check that the other 4 nodes are on the same side
2382         bool sameSide = true;
2383         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2384         for ( i = 3; sameSide && i < 8; i++ ) {
2385           if ( i != iMin )
2386             sameSide = ( isNeg == dist[i] <= 0.);
2387         }
2388
2389         // keep best solution
2390         if ( sameSide && minDist < leastDist ) {
2391           leastDist = minDist;
2392           faceNodes.clear();
2393           faceNodes.insert( idNodes[ 1 ] );
2394           faceNodes.insert( idNodes[ 2 ] );
2395           faceNodes.insert( idNodes[ iMin ] );
2396           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2397                   << " leastDist = " << leastDist);
2398           if ( leastDist <= DBL_MIN )
2399             break;
2400         }
2401       }
2402
2403       // set next 3-d node to check
2404       int iNext = 2 + iLoop2;
2405       if ( iNext < 8 ) {
2406         DUMPSO( "Try 2-nd");
2407         swap ( 2, iNext, idNodes, P );
2408       }
2409     } // while ( iLoop2 < 6 )
2410   } // iLoop1
2411
2412   if ( faceNodes.empty() ) return false;
2413
2414   // Put the faceNodes in proper places
2415   for ( i = 4; i < 8; i++ ) {
2416     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2417       // find a place to put
2418       int iTo = 1;
2419       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2420         iTo++;
2421       DUMPSO( "Set faceNodes");
2422       swap ( iTo, i, idNodes, P );
2423     }
2424   }
2425
2426
2427   // Set nodes of the found bottom face in good order
2428   DUMPSO( " Found bottom face: ");
2429   i = SortQuadNodes( theMesh, idNodes );
2430   if ( i ) {
2431     gp_Pnt Ptmp = P[ i ];
2432     P[ i ] = P[ i+1 ];
2433     P[ i+1 ] = Ptmp;
2434   }
2435   //   else
2436   //     for ( int ii = 0; ii < 4; ii++ ) {
2437   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2438   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2439   //    }
2440
2441   // Gravity center of the top and bottom faces
2442   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2443   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2444
2445   // Get direction from the bottom to the top face
2446   gp_Vec upDir ( aGCb, aGCt );
2447   Standard_Real upDirSize = upDir.Magnitude();
2448   if ( upDirSize <= gp::Resolution() ) return false;
2449   upDir / upDirSize;
2450
2451   // Assure that the bottom face normal points up
2452   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2453   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2454   if ( Nb.Dot( upDir ) < 0 ) {
2455     DUMPSO( "Reverse bottom face");
2456     swap( 1, 3, idNodes, P );
2457   }
2458
2459   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2460   Standard_Real minDist = DBL_MAX;
2461   for ( i = 4; i < 8; i++ ) {
2462     // projection of P[i] to the plane defined by P[0] and upDir
2463     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2464     Standard_Real sqDist = P[0].SquareDistance( Pp );
2465     if ( sqDist < minDist ) {
2466       minDist = sqDist;
2467       iMin = i;
2468     }
2469   }
2470   DUMPSO( "Set 4-th");
2471   swap ( 4, iMin, idNodes, P );
2472
2473   // Set nodes of the top face in good order
2474   DUMPSO( "Sort top face");
2475   i = SortQuadNodes( theMesh, &idNodes[4] );
2476   if ( i ) {
2477     i += 4;
2478     gp_Pnt Ptmp = P[ i ];
2479     P[ i ] = P[ i+1 ];
2480     P[ i+1 ] = Ptmp;
2481   }
2482
2483   // Assure that direction of the top face normal is from the bottom face
2484   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2485   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2486   if ( Nt.Dot( upDir ) < 0 ) {
2487     DUMPSO( "Reverse top face");
2488     swap( 5, 7, idNodes, P );
2489   }
2490
2491   //   DUMPSO( "OUTPUT: ========================================");
2492   //   for ( i = 0; i < 8; i++ ) {
2493   //     float *p = ugrid->GetPoint(idNodes[i]);
2494   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2495   //   }
2496
2497   return true;
2498 }*/
2499
2500 //================================================================================
2501 /*!
2502  * \brief Return nodes linked to the given one
2503  * \param theNode - the node
2504  * \param linkedNodes - the found nodes
2505  * \param type - the type of elements to check
2506  *
2507  * Medium nodes are ignored
2508  */
2509 //================================================================================
2510
2511 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2512                                        TIDSortedElemSet &   linkedNodes,
2513                                        SMDSAbs_ElementType  type )
2514 {
2515   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2516   while ( elemIt->more() )
2517   {
2518     const SMDS_MeshElement* elem = elemIt->next();
2519     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2520     if ( elem->GetType() == SMDSAbs_Volume )
2521     {
2522       SMDS_VolumeTool vol( elem );
2523       while ( nodeIt->more() ) {
2524         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2525         if ( theNode != n && vol.IsLinked( theNode, n ))
2526           linkedNodes.insert( n );
2527       }
2528     }
2529     else
2530     {
2531       for ( int i = 0; nodeIt->more(); ++i ) {
2532         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2533         if ( n == theNode ) {
2534           int iBefore = i - 1;
2535           int iAfter  = i + 1;
2536           if ( elem->IsQuadratic() ) {
2537             int nb = elem->NbNodes() / 2;
2538             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2539             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2540           }
2541           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2542           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2543         }
2544       }
2545     }
2546   }
2547 }
2548
2549 //=======================================================================
2550 //function : laplacianSmooth
2551 //purpose  : pulls theNode toward the center of surrounding nodes directly
2552 //           connected to that node along an element edge
2553 //=======================================================================
2554
2555 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2556                      const Handle(Geom_Surface)&          theSurface,
2557                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2558 {
2559   // find surrounding nodes
2560
2561   TIDSortedElemSet nodeSet;
2562   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2563
2564   // compute new coodrs
2565
2566   double coord[] = { 0., 0., 0. };
2567   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2568   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2569     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2570     if ( theSurface.IsNull() ) { // smooth in 3D
2571       coord[0] += node->X();
2572       coord[1] += node->Y();
2573       coord[2] += node->Z();
2574     }
2575     else { // smooth in 2D
2576       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2577       gp_XY* uv = theUVMap[ node ];
2578       coord[0] += uv->X();
2579       coord[1] += uv->Y();
2580     }
2581   }
2582   int nbNodes = nodeSet.size();
2583   if ( !nbNodes )
2584     return;
2585   coord[0] /= nbNodes;
2586   coord[1] /= nbNodes;
2587
2588   if ( !theSurface.IsNull() ) {
2589     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2590     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2591     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2592     coord[0] = p3d.X();
2593     coord[1] = p3d.Y();
2594     coord[2] = p3d.Z();
2595   }
2596   else
2597     coord[2] /= nbNodes;
2598
2599   // move node
2600
2601   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2602 }
2603
2604 //=======================================================================
2605 //function : centroidalSmooth
2606 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2607 //           surrounding elements
2608 //=======================================================================
2609
2610 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2611                       const Handle(Geom_Surface)&          theSurface,
2612                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2613 {
2614   gp_XYZ aNewXYZ(0.,0.,0.);
2615   SMESH::Controls::Area anAreaFunc;
2616   double totalArea = 0.;
2617   int nbElems = 0;
2618
2619   // compute new XYZ
2620
2621   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2622   while ( elemIt->more() )
2623   {
2624     const SMDS_MeshElement* elem = elemIt->next();
2625     nbElems++;
2626
2627     gp_XYZ elemCenter(0.,0.,0.);
2628     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2629     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2630     int nn = elem->NbNodes();
2631     if(elem->IsQuadratic()) nn = nn/2;
2632     int i=0;
2633     //while ( itN->more() ) {
2634     while ( i<nn ) {
2635       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2636       i++;
2637       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2638       aNodePoints.push_back( aP );
2639       if ( !theSurface.IsNull() ) { // smooth in 2D
2640         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2641         gp_XY* uv = theUVMap[ aNode ];
2642         aP.SetCoord( uv->X(), uv->Y(), 0. );
2643       }
2644       elemCenter += aP;
2645     }
2646     double elemArea = anAreaFunc.GetValue( aNodePoints );
2647     totalArea += elemArea;
2648     elemCenter /= nn;
2649     aNewXYZ += elemCenter * elemArea;
2650   }
2651   aNewXYZ /= totalArea;
2652   if ( !theSurface.IsNull() ) {
2653     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2654     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2655   }
2656
2657   // move node
2658
2659   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2660 }
2661
2662 //=======================================================================
2663 //function : getClosestUV
2664 //purpose  : return UV of closest projection
2665 //=======================================================================
2666
2667 static bool getClosestUV (Extrema_GenExtPS& projector,
2668                           const gp_Pnt&     point,
2669                           gp_XY &           result)
2670 {
2671   projector.Perform( point );
2672   if ( projector.IsDone() ) {
2673     double u, v, minVal = DBL_MAX;
2674     for ( int i = projector.NbExt(); i > 0; i-- )
2675       if ( projector.Value( i ) < minVal ) {
2676         minVal = projector.Value( i );
2677         projector.Point( i ).Parameter( u, v );
2678       }
2679     result.SetCoord( u, v );
2680     return true;
2681   }
2682   return false;
2683 }
2684
2685 //=======================================================================
2686 //function : Smooth
2687 //purpose  : Smooth theElements during theNbIterations or until a worst
2688 //           element has aspect ratio <= theTgtAspectRatio.
2689 //           Aspect Ratio varies in range [1.0, inf].
2690 //           If theElements is empty, the whole mesh is smoothed.
2691 //           theFixedNodes contains additionally fixed nodes. Nodes built
2692 //           on edges and boundary nodes are always fixed.
2693 //=======================================================================
2694
2695 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2696                                set<const SMDS_MeshNode*> & theFixedNodes,
2697                                const SmoothMethod          theSmoothMethod,
2698                                const int                   theNbIterations,
2699                                double                      theTgtAspectRatio,
2700                                const bool                  the2D)
2701 {
2702   myLastCreatedElems.Clear();
2703   myLastCreatedNodes.Clear();
2704
2705   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2706
2707   if ( theTgtAspectRatio < 1.0 )
2708     theTgtAspectRatio = 1.0;
2709
2710   const double disttol = 1.e-16;
2711
2712   SMESH::Controls::AspectRatio aQualityFunc;
2713
2714   SMESHDS_Mesh* aMesh = GetMeshDS();
2715
2716   if ( theElems.empty() ) {
2717     // add all faces to theElems
2718     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2719     while ( fIt->more() ) {
2720       const SMDS_MeshElement* face = fIt->next();
2721       theElems.insert( face );
2722     }
2723   }
2724   // get all face ids theElems are on
2725   set< int > faceIdSet;
2726   TIDSortedElemSet::iterator itElem;
2727   if ( the2D )
2728     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2729       int fId = FindShape( *itElem );
2730       // check that corresponding submesh exists and a shape is face
2731       if (fId &&
2732           faceIdSet.find( fId ) == faceIdSet.end() &&
2733           aMesh->MeshElements( fId )) {
2734         TopoDS_Shape F = aMesh->IndexToShape( fId );
2735         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2736           faceIdSet.insert( fId );
2737       }
2738     }
2739   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2740
2741   // ===============================================
2742   // smooth elements on each TopoDS_Face separately
2743   // ===============================================
2744
2745   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2746   for ( ; fId != faceIdSet.rend(); ++fId ) {
2747     // get face surface and submesh
2748     Handle(Geom_Surface) surface;
2749     SMESHDS_SubMesh* faceSubMesh = 0;
2750     TopoDS_Face face;
2751     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2752     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2753     bool isUPeriodic = false, isVPeriodic = false;
2754     if ( *fId ) {
2755       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2756       surface = BRep_Tool::Surface( face );
2757       faceSubMesh = aMesh->MeshElements( *fId );
2758       fToler2 = BRep_Tool::Tolerance( face );
2759       fToler2 *= fToler2 * 10.;
2760       isUPeriodic = surface->IsUPeriodic();
2761       if ( isUPeriodic )
2762         vPeriod = surface->UPeriod();
2763       isVPeriodic = surface->IsVPeriodic();
2764       if ( isVPeriodic )
2765         uPeriod = surface->VPeriod();
2766       surface->Bounds( u1, u2, v1, v2 );
2767     }
2768     // ---------------------------------------------------------
2769     // for elements on a face, find movable and fixed nodes and
2770     // compute UV for them
2771     // ---------------------------------------------------------
2772     bool checkBoundaryNodes = false;
2773     bool isQuadratic = false;
2774     set<const SMDS_MeshNode*> setMovableNodes;
2775     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2776     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2777     list< const SMDS_MeshElement* > elemsOnFace;
2778
2779     Extrema_GenExtPS projector;
2780     GeomAdaptor_Surface surfAdaptor;
2781     if ( !surface.IsNull() ) {
2782       surfAdaptor.Load( surface );
2783       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2784     }
2785     int nbElemOnFace = 0;
2786     itElem = theElems.begin();
2787     // loop on not yet smoothed elements: look for elems on a face
2788     while ( itElem != theElems.end() ) {
2789       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2790         break; // all elements found
2791
2792       const SMDS_MeshElement* elem = *itElem;
2793       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2794            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2795         ++itElem;
2796         continue;
2797       }
2798       elemsOnFace.push_back( elem );
2799       theElems.erase( itElem++ );
2800       nbElemOnFace++;
2801
2802       if ( !isQuadratic )
2803         isQuadratic = elem->IsQuadratic();
2804
2805       // get movable nodes of elem
2806       const SMDS_MeshNode* node;
2807       SMDS_TypeOfPosition posType;
2808       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2809       int nn = 0, nbn =  elem->NbNodes();
2810       if(elem->IsQuadratic())
2811         nbn = nbn/2;
2812       while ( nn++ < nbn ) {
2813         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2814         const SMDS_PositionPtr& pos = node->GetPosition();
2815         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2816         if (posType != SMDS_TOP_EDGE &&
2817             posType != SMDS_TOP_VERTEX &&
2818             theFixedNodes.find( node ) == theFixedNodes.end())
2819         {
2820           // check if all faces around the node are on faceSubMesh
2821           // because a node on edge may be bound to face
2822           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2823           bool all = true;
2824           if ( faceSubMesh ) {
2825             while ( eIt->more() && all ) {
2826               const SMDS_MeshElement* e = eIt->next();
2827               all = faceSubMesh->Contains( e );
2828             }
2829           }
2830           if ( all )
2831             setMovableNodes.insert( node );
2832           else
2833             checkBoundaryNodes = true;
2834         }
2835         if ( posType == SMDS_TOP_3DSPACE )
2836           checkBoundaryNodes = true;
2837       }
2838
2839       if ( surface.IsNull() )
2840         continue;
2841
2842       // get nodes to check UV
2843       list< const SMDS_MeshNode* > uvCheckNodes;
2844       itN = elem->nodesIterator();
2845       nn = 0; nbn =  elem->NbNodes();
2846       if(elem->IsQuadratic())
2847         nbn = nbn/2;
2848       while ( nn++ < nbn ) {
2849         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2850         if ( uvMap.find( node ) == uvMap.end() )
2851           uvCheckNodes.push_back( node );
2852         // add nodes of elems sharing node
2853         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2854         //         while ( eIt->more() ) {
2855         //           const SMDS_MeshElement* e = eIt->next();
2856         //           if ( e != elem ) {
2857         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2858         //             while ( nIt->more() ) {
2859         //               const SMDS_MeshNode* n =
2860         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2861         //               if ( uvMap.find( n ) == uvMap.end() )
2862         //                 uvCheckNodes.push_back( n );
2863         //             }
2864         //           }
2865         //         }
2866       }
2867       // check UV on face
2868       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2869       for ( ; n != uvCheckNodes.end(); ++n ) {
2870         node = *n;
2871         gp_XY uv( 0, 0 );
2872         const SMDS_PositionPtr& pos = node->GetPosition();
2873         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2874         // get existing UV
2875         switch ( posType ) {
2876         case SMDS_TOP_FACE: {
2877           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2878           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2879           break;
2880         }
2881         case SMDS_TOP_EDGE: {
2882           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2883           Handle(Geom2d_Curve) pcurve;
2884           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2885             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2886           if ( !pcurve.IsNull() ) {
2887             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2888             uv = pcurve->Value( u ).XY();
2889           }
2890           break;
2891         }
2892         case SMDS_TOP_VERTEX: {
2893           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2894           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2895             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2896           break;
2897         }
2898         default:;
2899         }
2900         // check existing UV
2901         bool project = true;
2902         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2903         double dist1 = DBL_MAX, dist2 = 0;
2904         if ( posType != SMDS_TOP_3DSPACE ) {
2905           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2906           project = dist1 > fToler2;
2907         }
2908         if ( project ) { // compute new UV
2909           gp_XY newUV;
2910           if ( !getClosestUV( projector, pNode, newUV )) {
2911             MESSAGE("Node Projection Failed " << node);
2912           }
2913           else {
2914             if ( isUPeriodic )
2915               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2916             if ( isVPeriodic )
2917               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2918             // check new UV
2919             if ( posType != SMDS_TOP_3DSPACE )
2920               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2921             if ( dist2 < dist1 )
2922               uv = newUV;
2923           }
2924         }
2925         // store UV in the map
2926         listUV.push_back( uv );
2927         uvMap.insert( make_pair( node, &listUV.back() ));
2928       }
2929     } // loop on not yet smoothed elements
2930
2931     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2932       checkBoundaryNodes = true;
2933
2934     // fix nodes on mesh boundary
2935
2936     if ( checkBoundaryNodes ) {
2937       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2938       map< NLink, int >::iterator link_nb;
2939       // put all elements links to linkNbMap
2940       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2941       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2942         const SMDS_MeshElement* elem = (*elemIt);
2943         int nbn =  elem->NbNodes();
2944         if(elem->IsQuadratic())
2945           nbn = nbn/2;
2946         // loop on elem links: insert them in linkNbMap
2947         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2948         for ( int iN = 0; iN < nbn; ++iN ) {
2949           curNode = elem->GetNode( iN );
2950           NLink link;
2951           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2952           else                      link = make_pair( prevNode , curNode );
2953           prevNode = curNode;
2954           link_nb = linkNbMap.find( link );
2955           if ( link_nb == linkNbMap.end() )
2956             linkNbMap.insert( make_pair ( link, 1 ));
2957           else
2958             link_nb->second++;
2959         }
2960       }
2961       // remove nodes that are in links encountered only once from setMovableNodes
2962       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2963         if ( link_nb->second == 1 ) {
2964           setMovableNodes.erase( link_nb->first.first );
2965           setMovableNodes.erase( link_nb->first.second );
2966         }
2967       }
2968     }
2969
2970     // -----------------------------------------------------
2971     // for nodes on seam edge, compute one more UV ( uvMap2 );
2972     // find movable nodes linked to nodes on seam and which
2973     // are to be smoothed using the second UV ( uvMap2 )
2974     // -----------------------------------------------------
2975
2976     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2977     if ( !surface.IsNull() ) {
2978       TopExp_Explorer eExp( face, TopAbs_EDGE );
2979       for ( ; eExp.More(); eExp.Next() ) {
2980         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2981         if ( !BRep_Tool::IsClosed( edge, face ))
2982           continue;
2983         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2984         if ( !sm ) continue;
2985         // find out which parameter varies for a node on seam
2986         double f,l;
2987         gp_Pnt2d uv1, uv2;
2988         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2989         if ( pcurve.IsNull() ) continue;
2990         uv1 = pcurve->Value( f );
2991         edge.Reverse();
2992         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2993         if ( pcurve.IsNull() ) continue;
2994         uv2 = pcurve->Value( f );
2995         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2996         // assure uv1 < uv2
2997         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2998           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2999         }
3000         // get nodes on seam and its vertices
3001         list< const SMDS_MeshNode* > seamNodes;
3002         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3003         while ( nSeamIt->more() ) {
3004           const SMDS_MeshNode* node = nSeamIt->next();
3005           if ( !isQuadratic || !IsMedium( node ))
3006             seamNodes.push_back( node );
3007         }
3008         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3009         for ( ; vExp.More(); vExp.Next() ) {
3010           sm = aMesh->MeshElements( vExp.Current() );
3011           if ( sm ) {
3012             nSeamIt = sm->GetNodes();
3013             while ( nSeamIt->more() )
3014               seamNodes.push_back( nSeamIt->next() );
3015           }
3016         }
3017         // loop on nodes on seam
3018         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3019         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3020           const SMDS_MeshNode* nSeam = *noSeIt;
3021           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3022           if ( n_uv == uvMap.end() )
3023             continue;
3024           // set the first UV
3025           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3026           // set the second UV
3027           listUV.push_back( *n_uv->second );
3028           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3029           if ( uvMap2.empty() )
3030             uvMap2 = uvMap; // copy the uvMap contents
3031           uvMap2[ nSeam ] = &listUV.back();
3032
3033           // collect movable nodes linked to ones on seam in nodesNearSeam
3034           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3035           while ( eIt->more() ) {
3036             const SMDS_MeshElement* e = eIt->next();
3037             int nbUseMap1 = 0, nbUseMap2 = 0;
3038             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3039             int nn = 0, nbn =  e->NbNodes();
3040             if(e->IsQuadratic()) nbn = nbn/2;
3041             while ( nn++ < nbn )
3042             {
3043               const SMDS_MeshNode* n =
3044                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3045               if (n == nSeam ||
3046                   setMovableNodes.find( n ) == setMovableNodes.end() )
3047                 continue;
3048               // add only nodes being closer to uv2 than to uv1
3049               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3050                            0.5 * ( n->Y() + nSeam->Y() ),
3051                            0.5 * ( n->Z() + nSeam->Z() ));
3052               gp_XY uv;
3053               getClosestUV( projector, pMid, uv );
3054               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3055                 nodesNearSeam.insert( n );
3056                 nbUseMap2++;
3057               }
3058               else
3059                 nbUseMap1++;
3060             }
3061             // for centroidalSmooth all element nodes must
3062             // be on one side of a seam
3063             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3064               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3065               nn = 0;
3066               while ( nn++ < nbn ) {
3067                 const SMDS_MeshNode* n =
3068                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3069                 setMovableNodes.erase( n );
3070               }
3071             }
3072           }
3073         } // loop on nodes on seam
3074       } // loop on edge of a face
3075     } // if ( !face.IsNull() )
3076
3077     if ( setMovableNodes.empty() ) {
3078       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3079       continue; // goto next face
3080     }
3081
3082     // -------------
3083     // SMOOTHING //
3084     // -------------
3085
3086     int it = -1;
3087     double maxRatio = -1., maxDisplacement = -1.;
3088     set<const SMDS_MeshNode*>::iterator nodeToMove;
3089     for ( it = 0; it < theNbIterations; it++ ) {
3090       maxDisplacement = 0.;
3091       nodeToMove = setMovableNodes.begin();
3092       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3093         const SMDS_MeshNode* node = (*nodeToMove);
3094         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3095
3096         // smooth
3097         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3098         if ( theSmoothMethod == LAPLACIAN )
3099           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3100         else
3101           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3102
3103         // node displacement
3104         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3105         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3106         if ( aDispl > maxDisplacement )
3107           maxDisplacement = aDispl;
3108       }
3109       // no node movement => exit
3110       //if ( maxDisplacement < 1.e-16 ) {
3111       if ( maxDisplacement < disttol ) {
3112         MESSAGE("-- no node movement --");
3113         break;
3114       }
3115
3116       // check elements quality
3117       maxRatio  = 0;
3118       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3119       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3120         const SMDS_MeshElement* elem = (*elemIt);
3121         if ( !elem || elem->GetType() != SMDSAbs_Face )
3122           continue;
3123         SMESH::Controls::TSequenceOfXYZ aPoints;
3124         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3125           double aValue = aQualityFunc.GetValue( aPoints );
3126           if ( aValue > maxRatio )
3127             maxRatio = aValue;
3128         }
3129       }
3130       if ( maxRatio <= theTgtAspectRatio ) {
3131         MESSAGE("-- quality achived --");
3132         break;
3133       }
3134       if (it+1 == theNbIterations) {
3135         MESSAGE("-- Iteration limit exceeded --");
3136       }
3137     } // smoothing iterations
3138
3139     MESSAGE(" Face id: " << *fId <<
3140             " Nb iterstions: " << it <<
3141             " Displacement: " << maxDisplacement <<
3142             " Aspect Ratio " << maxRatio);
3143
3144     // ---------------------------------------
3145     // new nodes positions are computed,
3146     // record movement in DS and set new UV
3147     // ---------------------------------------
3148     nodeToMove = setMovableNodes.begin();
3149     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3150       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3151       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3152       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3153       if ( node_uv != uvMap.end() ) {
3154         gp_XY* uv = node_uv->second;
3155         node->SetPosition
3156           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3157       }
3158     }
3159
3160     // move medium nodes of quadratic elements
3161     if ( isQuadratic )
3162     {
3163       SMESH_MesherHelper helper( *GetMesh() );
3164       if ( !face.IsNull() )
3165         helper.SetSubShape( face );
3166       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3167       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3168         const SMDS_QuadraticFaceOfNodes* QF =
3169           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3170         if(QF) {
3171           vector<const SMDS_MeshNode*> Ns;
3172           Ns.reserve(QF->NbNodes()+1);
3173           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3174           while ( anIter->more() )
3175             Ns.push_back( anIter->next() );
3176           Ns.push_back( Ns[0] );
3177           double x, y, z;
3178           for(int i=0; i<QF->NbNodes(); i=i+2) {
3179             if ( !surface.IsNull() ) {
3180               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3181               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3182               gp_XY uv = ( uv1 + uv2 ) / 2.;
3183               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3184               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3185             }
3186             else {
3187               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3188               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3189               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3190             }
3191             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3192                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3193                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3194               // we have to move i+1 node
3195               aMesh->MoveNode( Ns[i+1], x, y, z );
3196             }
3197           }
3198         }
3199       }
3200     }
3201
3202   } // loop on face ids
3203
3204 }
3205
3206 //=======================================================================
3207 //function : isReverse
3208 //purpose  : Return true if normal of prevNodes is not co-directied with
3209 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3210 //           iNotSame is where prevNodes and nextNodes are different
3211 //=======================================================================
3212
3213 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3214                       vector<const SMDS_MeshNode*> nextNodes,
3215                       const int            nbNodes,
3216                       const int            iNotSame)
3217 {
3218   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3219   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3220
3221   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3222   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3223   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3224   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3225
3226   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3227   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3228   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3229   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3230
3231   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3232
3233   return (vA ^ vB) * vN < 0.0;
3234 }
3235
3236 //=======================================================================
3237 /*!
3238  * \brief Create elements by sweeping an element
3239  * \param elem - element to sweep
3240  * \param newNodesItVec - nodes generated from each node of the element
3241  * \param newElems - generated elements
3242  * \param nbSteps - number of sweeping steps
3243  * \param srcElements - to append elem for each generated element
3244  */
3245 //=======================================================================
3246
3247 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3248                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3249                                     list<const SMDS_MeshElement*>&        newElems,
3250                                     const int                             nbSteps,
3251                                     SMESH_SequenceOfElemPtr&              srcElements)
3252 {
3253   SMESHDS_Mesh* aMesh = GetMeshDS();
3254
3255   // Loop on elem nodes:
3256   // find new nodes and detect same nodes indices
3257   int nbNodes = elem->NbNodes();
3258   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3259   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3260   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3261   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3262
3263   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3264   vector<int> sames(nbNodes);
3265   vector<bool> issimple(nbNodes);
3266
3267   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3268     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3269     const SMDS_MeshNode*                 node         = nnIt->first;
3270     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3271     if ( listNewNodes.empty() ) {
3272       return;
3273     }
3274
3275     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3276
3277     itNN[ iNode ] = listNewNodes.begin();
3278     prevNod[ iNode ] = node;
3279     nextNod[ iNode ] = listNewNodes.front();
3280     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3281       if ( prevNod[ iNode ] != nextNod [ iNode ])
3282         iNotSameNode = iNode;
3283       else {
3284         iSameNode = iNode;
3285         //nbSame++;
3286         sames[nbSame++] = iNode;
3287       }
3288     }
3289   }
3290
3291   //cout<<"  nbSame = "<<nbSame<<endl;
3292   if ( nbSame == nbNodes || nbSame > 2) {
3293     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3294     //INFOS( " Too many same nodes of element " << elem->GetID() );
3295     return;
3296   }
3297
3298   //  if( elem->IsQuadratic() && nbSame>0 ) {
3299   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3300   //    return;
3301   //  }
3302
3303   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3304   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3305   if ( nbSame > 0 ) {
3306     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3307     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3308     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3309   }
3310
3311   //if(nbNodes==8)
3312   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3313   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3314   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3315   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3316
3317   // check element orientation
3318   int i0 = 0, i2 = 2;
3319   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3320     //MESSAGE("Reversed elem " << elem );
3321     i0 = 2;
3322     i2 = 0;
3323     if ( nbSame > 0 )
3324       std::swap( iBeforeSame, iAfterSame );
3325   }
3326
3327   // make new elements
3328   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3329     // get next nodes
3330     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3331       if(issimple[iNode]) {
3332         nextNod[ iNode ] = *itNN[ iNode ];
3333         itNN[ iNode ]++;
3334       }
3335       else {
3336         if( elem->GetType()==SMDSAbs_Node ) {
3337           // we have to use two nodes
3338           midlNod[ iNode ] = *itNN[ iNode ];
3339           itNN[ iNode ]++;
3340           nextNod[ iNode ] = *itNN[ iNode ];
3341           itNN[ iNode ]++;
3342         }
3343         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3344           // we have to use each second node
3345           //itNN[ iNode ]++;
3346           nextNod[ iNode ] = *itNN[ iNode ];
3347           itNN[ iNode ]++;
3348         }
3349         else {
3350           // we have to use two nodes
3351           midlNod[ iNode ] = *itNN[ iNode ];
3352           itNN[ iNode ]++;
3353           nextNod[ iNode ] = *itNN[ iNode ];
3354           itNN[ iNode ]++;
3355         }
3356       }
3357     }
3358     SMDS_MeshElement* aNewElem = 0;
3359     if(!elem->IsPoly()) {
3360       switch ( nbNodes ) {
3361       case 0:
3362         return;
3363       case 1: { // NODE
3364         if ( nbSame == 0 ) {
3365           if(issimple[0])
3366             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3367           else
3368             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3369         }
3370         break;
3371       }
3372       case 2: { // EDGE
3373         if ( nbSame == 0 )
3374           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3375                                     nextNod[ 1 ], nextNod[ 0 ] );
3376         else
3377           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3378                                     nextNod[ iNotSameNode ] );
3379         break;
3380       }
3381
3382       case 3: { // TRIANGLE or quadratic edge
3383         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3384
3385           if ( nbSame == 0 )       // --- pentahedron
3386             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3387                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3388
3389           else if ( nbSame == 1 )  // --- pyramid
3390             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3391                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3392                                          nextNod[ iSameNode ]);
3393
3394           else // 2 same nodes:      --- tetrahedron
3395             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3396                                          nextNod[ iNotSameNode ]);
3397         }
3398         else { // quadratic edge
3399           if(nbSame==0) {     // quadratic quadrangle
3400             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3401                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3402           }
3403           else if(nbSame==1) { // quadratic triangle
3404             if(sames[0]==2) {
3405               return; // medium node on axis
3406             }
3407             else if(sames[0]==0) {
3408               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3409                                         nextNod[2], midlNod[1], prevNod[2]);
3410             }
3411             else { // sames[0]==1
3412               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3413                                         midlNod[0], nextNod[2], prevNod[2]);
3414             }
3415           }
3416           else {
3417             return;
3418           }
3419         }
3420         break;
3421       }
3422       case 4: { // QUADRANGLE
3423
3424         if ( nbSame == 0 )       // --- hexahedron
3425           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3426                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3427
3428         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3429           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3430                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3431                                        nextNod[ iSameNode ]);
3432           newElems.push_back( aNewElem );
3433           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3434                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3435                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3436         }
3437         else if ( nbSame == 2 ) { // pentahedron
3438           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3439             // iBeforeSame is same too
3440             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3441                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3442                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3443           else
3444             // iAfterSame is same too
3445             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3446                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3447                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3448         }
3449         break;
3450       }
3451       case 6: { // quadratic triangle
3452         // create pentahedron with 15 nodes
3453         if(nbSame==0) {
3454           if(i0>0) { // reversed case
3455             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3456                                          nextNod[0], nextNod[2], nextNod[1],
3457                                          prevNod[5], prevNod[4], prevNod[3],
3458                                          nextNod[5], nextNod[4], nextNod[3],
3459                                          midlNod[0], midlNod[2], midlNod[1]);
3460           }
3461           else { // not reversed case
3462             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3463                                          nextNod[0], nextNod[1], nextNod[2],
3464                                          prevNod[3], prevNod[4], prevNod[5],
3465                                          nextNod[3], nextNod[4], nextNod[5],
3466                                          midlNod[0], midlNod[1], midlNod[2]);
3467           }
3468         }
3469         else if(nbSame==1) {
3470           // 2d order pyramid of 13 nodes
3471           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3472           //                                 int n12,int n23,int n34,int n41,
3473           //                                 int n15,int n25,int n35,int n45, int ID);
3474           int n5 = iSameNode;
3475           int n1,n4,n41,n15,n45;
3476           if(i0>0) { // reversed case
3477             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3478             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3479             n41 = n1 + 3;
3480             n15 = n5 + 3;
3481             n45 = n4 + 3;
3482           }
3483           else {
3484             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3485             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3486             n41 = n4 + 3;
3487             n15 = n1 + 3;
3488             n45 = n5 + 3;
3489           }
3490           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3491                                       nextNod[n4], prevNod[n4], prevNod[n5],
3492                                       midlNod[n1], nextNod[n41],
3493                                       midlNod[n4], prevNod[n41],
3494                                       prevNod[n15], nextNod[n15],
3495                                       nextNod[n45], prevNod[n45]);
3496         }
3497         else if(nbSame==2) {
3498           // 2d order tetrahedron of 10 nodes
3499           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3500           //                                 int n12,int n23,int n31,
3501           //                                 int n14,int n24,int n34, int ID);
3502           int n1 = iNotSameNode;
3503           int n2,n3,n12,n23,n31;
3504           if(i0>0) { // reversed case
3505             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3506             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3507             n12 = n2 + 3;
3508             n23 = n3 + 3;
3509             n31 = n1 + 3;
3510           }
3511           else {
3512             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3513             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3514             n12 = n1 + 3;
3515             n23 = n2 + 3;
3516             n31 = n3 + 3;
3517           }
3518           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3519                                        prevNod[n12], prevNod[n23], prevNod[n31],
3520                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3521         }
3522         break;
3523       }
3524       case 8: { // quadratic quadrangle
3525         if(nbSame==0) {
3526           // create hexahedron with 20 nodes
3527           if(i0>0) { // reversed case
3528             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3529                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3530                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3531                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3532                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3533           }
3534           else { // not reversed case
3535             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3536                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3537                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3538                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3539                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3540           }
3541         }
3542         else if(nbSame==1) { 
3543           // --- pyramid + pentahedron - can not be created since it is needed 
3544           // additional middle node ot the center of face
3545           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3546           return;
3547         }
3548         else if(nbSame==2) {
3549           // 2d order Pentahedron with 15 nodes
3550           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3551           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3552           //                                 int n14,int n25,int n36, int ID);
3553           int n1,n2,n4,n5;
3554           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3555             // iBeforeSame is same too
3556             n1 = iBeforeSame;
3557             n2 = iOpposSame;
3558             n4 = iSameNode;
3559             n5 = iAfterSame;
3560           }
3561           else {
3562             // iAfterSame is same too
3563             n1 = iSameNode;
3564             n2 = iBeforeSame;
3565             n4 = iAfterSame;
3566             n5 = iOpposSame;
3567           }
3568           int n12,n45,n14,n25;
3569           if(i0>0) { //reversed case
3570             n12 = n1 + 4;
3571             n45 = n5 + 4;
3572             n14 = n4 + 4;
3573             n25 = n2 + 4;
3574           }
3575           else {
3576             n12 = n2 + 4;
3577             n45 = n4 + 4;
3578             n14 = n1 + 4;
3579             n25 = n5 + 4;
3580           }
3581           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3582                                        prevNod[n4], prevNod[n5], nextNod[n5],
3583                                        prevNod[n12], midlNod[n2], nextNod[n12],
3584                                        prevNod[n45], midlNod[n5], nextNod[n45],
3585                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3586         }
3587         break;
3588       }
3589       default: {
3590         // realized for extrusion only
3591         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3592         //vector<int> quantities (nbNodes + 2);
3593
3594         //quantities[0] = nbNodes; // bottom of prism
3595         //for (int inode = 0; inode < nbNodes; inode++) {
3596         //  polyedre_nodes[inode] = prevNod[inode];
3597         //}
3598
3599         //quantities[1] = nbNodes; // top of prism
3600         //for (int inode = 0; inode < nbNodes; inode++) {
3601         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3602         //}
3603
3604         //for (int iface = 0; iface < nbNodes; iface++) {
3605         //  quantities[iface + 2] = 4;
3606         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3607         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3608         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3609         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3610         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3611         //}
3612         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3613         break;
3614       }
3615       }
3616     }
3617
3618     if(!aNewElem) {
3619       // realized for extrusion only
3620       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3621       vector<int> quantities (nbNodes + 2);
3622
3623       quantities[0] = nbNodes; // bottom of prism
3624       for (int inode = 0; inode < nbNodes; inode++) {
3625         polyedre_nodes[inode] = prevNod[inode];
3626       }
3627
3628       quantities[1] = nbNodes; // top of prism
3629       for (int inode = 0; inode < nbNodes; inode++) {
3630         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3631       }
3632
3633       for (int iface = 0; iface < nbNodes; iface++) {
3634         quantities[iface + 2] = 4;
3635         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3636         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3637         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3638         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3639         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3640       }
3641       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3642     }
3643
3644     if ( aNewElem ) {
3645       newElems.push_back( aNewElem );
3646       myLastCreatedElems.Append(aNewElem);
3647       srcElements.Append( elem );
3648     }
3649
3650     // set new prev nodes
3651     for ( iNode = 0; iNode < nbNodes; iNode++ )
3652       prevNod[ iNode ] = nextNod[ iNode ];
3653
3654   } // for steps
3655 }
3656
3657 //=======================================================================
3658 /*!
3659  * \brief Create 1D and 2D elements around swept elements
3660  * \param mapNewNodes - source nodes and ones generated from them
3661  * \param newElemsMap - source elements and ones generated from them
3662  * \param elemNewNodesMap - nodes generated from each node of each element
3663  * \param elemSet - all swept elements
3664  * \param nbSteps - number of sweeping steps
3665  * \param srcElements - to append elem for each generated element
3666  */
3667 //=======================================================================
3668
3669 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3670                                   TElemOfElemListMap &     newElemsMap,
3671                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3672                                   TIDSortedElemSet&        elemSet,
3673                                   const int                nbSteps,
3674                                   SMESH_SequenceOfElemPtr& srcElements)
3675 {
3676   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3677   SMESHDS_Mesh* aMesh = GetMeshDS();
3678
3679   // Find nodes belonging to only one initial element - sweep them to get edges.
3680
3681   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3682   for ( ; nList != mapNewNodes.end(); nList++ ) {
3683     const SMDS_MeshNode* node =
3684       static_cast<const SMDS_MeshNode*>( nList->first );
3685     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3686     int nbInitElems = 0;
3687     const SMDS_MeshElement* el = 0;
3688     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3689     while ( eIt->more() && nbInitElems < 2 ) {
3690       el = eIt->next();
3691       SMDSAbs_ElementType type = el->GetType();
3692       if ( type == SMDSAbs_Volume || type < highType ) continue;
3693       if ( type > highType ) {
3694         nbInitElems = 0;
3695         highType = type;
3696       }
3697       if ( elemSet.find(el) != elemSet.end() )
3698         nbInitElems++;
3699     }
3700     if ( nbInitElems < 2 ) {
3701       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3702       if(!NotCreateEdge) {
3703         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3704         list<const SMDS_MeshElement*> newEdges;
3705         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3706       }
3707     }
3708   }
3709
3710   // Make a ceiling for each element ie an equal element of last new nodes.
3711   // Find free links of faces - make edges and sweep them into faces.
3712
3713   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3714   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3715   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3716     const SMDS_MeshElement* elem = itElem->first;
3717     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3718
3719     if ( elem->GetType() == SMDSAbs_Edge ) {
3720       // create a ceiling edge
3721       if (!elem->IsQuadratic()) {
3722         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3723                                vecNewNodes[ 1 ]->second.back())) {
3724           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3725                                                    vecNewNodes[ 1 ]->second.back()));
3726           srcElements.Append( myLastCreatedElems.Last() );
3727         }
3728       }
3729       else {
3730         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3731                                vecNewNodes[ 1 ]->second.back(),
3732                                vecNewNodes[ 2 ]->second.back())) {
3733           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3734                                                    vecNewNodes[ 1 ]->second.back(),
3735                                                    vecNewNodes[ 2 ]->second.back()));
3736           srcElements.Append( myLastCreatedElems.Last() );
3737         }
3738       }
3739     }
3740     if ( elem->GetType() != SMDSAbs_Face )
3741       continue;
3742
3743     if(itElem->second.size()==0) continue;
3744
3745     bool hasFreeLinks = false;
3746
3747     TIDSortedElemSet avoidSet;
3748     avoidSet.insert( elem );
3749
3750     set<const SMDS_MeshNode*> aFaceLastNodes;
3751     int iNode, nbNodes = vecNewNodes.size();
3752     if(!elem->IsQuadratic()) {
3753       // loop on the face nodes
3754       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3755         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3756         // look for free links of the face
3757         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3758         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3759         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3760         // check if a link is free
3761         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3762           hasFreeLinks = true;
3763           // make an edge and a ceiling for a new edge
3764           if ( !aMesh->FindEdge( n1, n2 )) {
3765             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3766             srcElements.Append( myLastCreatedElems.Last() );
3767           }
3768           n1 = vecNewNodes[ iNode ]->second.back();
3769           n2 = vecNewNodes[ iNext ]->second.back();
3770           if ( !aMesh->FindEdge( n1, n2 )) {
3771             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3772             srcElements.Append( myLastCreatedElems.Last() );
3773           }
3774         }
3775       }
3776     }
3777     else { // elem is quadratic face
3778       int nbn = nbNodes/2;
3779       for ( iNode = 0; iNode < nbn; iNode++ ) {
3780         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3781         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3782         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3783         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3784         // check if a link is free
3785         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3786           hasFreeLinks = true;
3787           // make an edge and a ceiling for a new edge
3788           // find medium node
3789           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3790           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3791             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3792             srcElements.Append( myLastCreatedElems.Last() );
3793           }
3794           n1 = vecNewNodes[ iNode ]->second.back();
3795           n2 = vecNewNodes[ iNext ]->second.back();
3796           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3797           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3798             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3799             srcElements.Append( myLastCreatedElems.Last() );
3800           }
3801         }
3802       }
3803       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3804         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3805       }
3806     }
3807
3808     // sweep free links into faces
3809
3810     if ( hasFreeLinks )  {
3811       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3812       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3813
3814       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3815       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3816         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3817         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3818       }
3819       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3820         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3821         iVol = 0;
3822         while ( iVol++ < volNb ) v++;
3823         // find indices of free faces of a volume and their source edges
3824         list< int > freeInd;
3825         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3826         SMDS_VolumeTool vTool( *v );
3827         int iF, nbF = vTool.NbFaces();
3828         for ( iF = 0; iF < nbF; iF ++ ) {
3829           if (vTool.IsFreeFace( iF ) &&
3830               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3831               initNodeSet != faceNodeSet) // except an initial face
3832           {
3833             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3834               continue;
3835             freeInd.push_back( iF );
3836             // find source edge of a free face iF
3837             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3838             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3839             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3840                                    initNodeSet.begin(), initNodeSet.end(),
3841                                    commonNodes.begin());
3842             if ( (*v)->IsQuadratic() )
3843               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3844             else
3845               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3846 #ifdef _DEBUG_
3847             if ( !srcEdges.back() )
3848             {
3849               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3850                    << iF << " of volume #" << vTool.ID() << endl;
3851             }
3852 #endif
3853           }
3854         }
3855         if ( freeInd.empty() )
3856           continue;
3857
3858         // create faces for all steps;
3859         // if such a face has been already created by sweep of edge,
3860         // assure that its orientation is OK
3861         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3862           vTool.Set( *v );
3863           vTool.SetExternalNormal();
3864           list< int >::iterator ind = freeInd.begin();
3865           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3866           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3867           {
3868             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3869             int nbn = vTool.NbFaceNodes( *ind );
3870             switch ( nbn ) {
3871             case 3: { ///// triangle
3872               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3873               if ( !f )
3874                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3875               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3876                 aMesh->ChangeElementNodes( f, nodes, nbn );
3877               break;
3878             }
3879             case 4: { ///// quadrangle
3880               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3881               if ( !f )
3882                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3883               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3884                 aMesh->ChangeElementNodes( f, nodes, nbn );
3885               break;
3886             }
3887             default:
3888               if( (*v)->IsQuadratic() ) {
3889                 if(nbn==6) { /////// quadratic triangle
3890                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3891                                                              nodes[1], nodes[3], nodes[5] );
3892                   if ( !f ) {
3893                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3894                                                              nodes[1], nodes[3], nodes[5]));
3895                   }
3896                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3897                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3898                     tmpnodes[0] = nodes[0];
3899                     tmpnodes[1] = nodes[2];
3900                     tmpnodes[2] = nodes[4];
3901                     tmpnodes[3] = nodes[1];
3902                     tmpnodes[4] = nodes[3];
3903                     tmpnodes[5] = nodes[5];
3904                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3905                   }
3906                 }
3907                 else {       /////// quadratic quadrangle
3908                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3909                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3910                   if ( !f ) {
3911                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3912                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3913                   }
3914                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3915                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3916                     tmpnodes[0] = nodes[0];
3917                     tmpnodes[1] = nodes[2];
3918                     tmpnodes[2] = nodes[4];
3919                     tmpnodes[3] = nodes[6];
3920                     tmpnodes[4] = nodes[1];
3921                     tmpnodes[5] = nodes[3];
3922                     tmpnodes[6] = nodes[5];
3923                     tmpnodes[7] = nodes[7];
3924                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3925                   }
3926                 }
3927               }
3928               else { //////// polygon
3929                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3930                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3931                 if ( !f )
3932                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3933                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3934                   aMesh->ChangeElementNodes( f, nodes, nbn );
3935               }
3936             }
3937             while ( srcElements.Length() < myLastCreatedElems.Length() )
3938               srcElements.Append( *srcEdge );
3939
3940           }  // loop on free faces
3941
3942           // go to the next volume
3943           iVol = 0;
3944           while ( iVol++ < nbVolumesByStep ) v++;
3945         }
3946       }
3947     } // sweep free links into faces
3948
3949     // Make a ceiling face with a normal external to a volume
3950
3951     SMDS_VolumeTool lastVol( itElem->second.back() );
3952
3953     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3954     if ( iF >= 0 ) {
3955       lastVol.SetExternalNormal();
3956       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3957       int nbn = lastVol.NbFaceNodes( iF );
3958       switch ( nbn ) {
3959       case 3:
3960         if (!hasFreeLinks ||
3961             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3962           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3963         break;
3964       case 4:
3965         if (!hasFreeLinks ||
3966             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3967           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3968         break;
3969       default:
3970         if(itElem->second.back()->IsQuadratic()) {
3971           if(nbn==6) {
3972             if (!hasFreeLinks ||
3973                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3974                                  nodes[1], nodes[3], nodes[5]) ) {
3975               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3976                                                        nodes[1], nodes[3], nodes[5]));
3977             }
3978           }
3979           else { // nbn==8
3980             if (!hasFreeLinks ||
3981                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3982                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3983               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3984                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3985           }
3986         }
3987         else {
3988           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3989           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3990             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3991         }
3992       } // switch
3993
3994       while ( srcElements.Length() < myLastCreatedElems.Length() )
3995         srcElements.Append( myLastCreatedElems.Last() );
3996     }
3997   } // loop on swept elements
3998 }
3999
4000 //=======================================================================
4001 //function : RotationSweep
4002 //purpose  :
4003 //=======================================================================
4004
4005 SMESH_MeshEditor::PGroupIDs
4006 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4007                                 const gp_Ax1&      theAxis,
4008                                 const double       theAngle,
4009                                 const int          theNbSteps,
4010                                 const double       theTol,
4011                                 const bool         theMakeGroups,
4012                                 const bool         theMakeWalls)
4013 {
4014   myLastCreatedElems.Clear();
4015   myLastCreatedNodes.Clear();
4016
4017   // source elements for each generated one
4018   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4019
4020   MESSAGE( "RotationSweep()");
4021   gp_Trsf aTrsf;
4022   aTrsf.SetRotation( theAxis, theAngle );
4023   gp_Trsf aTrsf2;
4024   aTrsf2.SetRotation( theAxis, theAngle/2. );
4025
4026   gp_Lin aLine( theAxis );
4027   double aSqTol = theTol * theTol;
4028
4029   SMESHDS_Mesh* aMesh = GetMeshDS();
4030
4031   TNodeOfNodeListMap mapNewNodes;
4032   TElemOfVecOfNnlmiMap mapElemNewNodes;
4033   TElemOfElemListMap newElemsMap;
4034
4035   // loop on theElems
4036   TIDSortedElemSet::iterator itElem;
4037   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4038     const SMDS_MeshElement* elem = *itElem;
4039     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4040       continue;
4041     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4042     newNodesItVec.reserve( elem->NbNodes() );
4043
4044     // loop on elem nodes
4045     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4046     while ( itN->more() ) {
4047       // check if a node has been already sweeped
4048       const SMDS_MeshNode* node = cast2Node( itN->next() );
4049
4050       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4051       double coord[3];
4052       aXYZ.Coord( coord[0], coord[1], coord[2] );
4053       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4054
4055       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4056       if ( nIt == mapNewNodes.end() ) {
4057         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4058         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4059
4060         // make new nodes
4061         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4062         //double coord[3];
4063         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4064         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4065         const SMDS_MeshNode * newNode = node;
4066         for ( int i = 0; i < theNbSteps; i++ ) {
4067           if ( !isOnAxis ) {
4068             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4069               // create two nodes
4070               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4071               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4072               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4073               myLastCreatedNodes.Append(newNode);
4074               srcNodes.Append( node );
4075               listNewNodes.push_back( newNode );
4076               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4077               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4078             }
4079             else {
4080               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4081             }
4082             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4083             myLastCreatedNodes.Append(newNode);
4084             srcNodes.Append( node );
4085             listNewNodes.push_back( newNode );
4086           }
4087           else {
4088             listNewNodes.push_back( newNode );
4089             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4090               listNewNodes.push_back( newNode );
4091             }
4092           }
4093         }
4094       }
4095       /*
4096         else {
4097         // if current elem is quadratic and current node is not medium
4098         // we have to check - may be it is needed to insert additional nodes
4099         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4100         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4101         if(listNewNodes.size()==theNbSteps) {
4102         listNewNodes.clear();
4103         // make new nodes
4104         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4105         //double coord[3];
4106         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4107         const SMDS_MeshNode * newNode = node;
4108         if ( !isOnAxis ) {
4109         for(int i = 0; i<theNbSteps; i++) {
4110         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4111         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4112         cout<<"    3 AddNode:  "<<newNode;
4113         myLastCreatedNodes.Append(newNode);
4114         listNewNodes.push_back( newNode );
4115         srcNodes.Append( node );
4116         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4117         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4118         cout<<"    4 AddNode:  "<<newNode;
4119         myLastCreatedNodes.Append(newNode);
4120         srcNodes.Append( node );
4121         listNewNodes.push_back( newNode );
4122         }
4123         }
4124         else {
4125         listNewNodes.push_back( newNode );
4126         }
4127         }
4128         }
4129         }
4130       */
4131       newNodesItVec.push_back( nIt );
4132     }
4133     // make new elements
4134     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4135   }
4136
4137   if ( theMakeWalls )
4138     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4139
4140   PGroupIDs newGroupIDs;
4141   if ( theMakeGroups )
4142     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4143
4144   return newGroupIDs;
4145 }
4146
4147
4148 //=======================================================================
4149 //function : CreateNode
4150 //purpose  :
4151 //=======================================================================
4152 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4153                                                   const double y,
4154                                                   const double z,
4155                                                   const double tolnode,
4156                                                   SMESH_SequenceOfNode& aNodes)
4157 {
4158   myLastCreatedElems.Clear();
4159   myLastCreatedNodes.Clear();
4160
4161   gp_Pnt P1(x,y,z);
4162   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4163
4164   // try to search in sequence of existing nodes
4165   // if aNodes.Length()>0 we 'nave to use given sequence
4166   // else - use all nodes of mesh
4167   if(aNodes.Length()>0) {
4168     int i;
4169     for(i=1; i<=aNodes.Length(); i++) {
4170       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4171       if(P1.Distance(P2)<tolnode)
4172         return aNodes.Value(i);
4173     }
4174   }
4175   else {
4176     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4177     while(itn->more()) {
4178       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4179       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4180       if(P1.Distance(P2)<tolnode)
4181         return aN;
4182     }
4183   }
4184
4185   // create new node and return it
4186   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4187   myLastCreatedNodes.Append(NewNode);
4188   return NewNode;
4189 }
4190
4191
4192 //=======================================================================
4193 //function : ExtrusionSweep
4194 //purpose  :
4195 //=======================================================================
4196
4197 SMESH_MeshEditor::PGroupIDs
4198 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4199                                   const gp_Vec&       theStep,
4200                                   const int           theNbSteps,
4201                                   TElemOfElemListMap& newElemsMap,
4202                                   const bool          theMakeGroups,
4203                                   const int           theFlags,
4204                                   const double        theTolerance)
4205 {
4206   ExtrusParam aParams;
4207   aParams.myDir = gp_Dir(theStep);
4208   aParams.myNodes.Clear();
4209   aParams.mySteps = new TColStd_HSequenceOfReal;
4210   int i;
4211   for(i=1; i<=theNbSteps; i++)
4212     aParams.mySteps->Append(theStep.Magnitude());
4213
4214   return
4215     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4216 }
4217
4218
4219 //=======================================================================
4220 //function : ExtrusionSweep
4221 //purpose  :
4222 //=======================================================================
4223
4224 SMESH_MeshEditor::PGroupIDs
4225 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4226                                   ExtrusParam&        theParams,
4227                                   TElemOfElemListMap& newElemsMap,
4228                                   const bool          theMakeGroups,
4229                                   const int           theFlags,
4230                                   const double        theTolerance)
4231 {
4232   myLastCreatedElems.Clear();
4233   myLastCreatedNodes.Clear();
4234
4235   // source elements for each generated one
4236   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4237
4238   SMESHDS_Mesh* aMesh = GetMeshDS();
4239
4240   int nbsteps = theParams.mySteps->Length();
4241
4242   TNodeOfNodeListMap mapNewNodes;
4243   //TNodeOfNodeVecMap mapNewNodes;
4244   TElemOfVecOfNnlmiMap mapElemNewNodes;
4245   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4246
4247   // loop on theElems
4248   TIDSortedElemSet::iterator itElem;
4249   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4250     // check element type
4251     const SMDS_MeshElement* elem = *itElem;
4252     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4253       continue;
4254
4255     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4256     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4257     newNodesItVec.reserve( elem->NbNodes() );
4258
4259     // loop on elem nodes
4260     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4261     while ( itN->more() )
4262     {
4263       // check if a node has been already sweeped
4264       const SMDS_MeshNode* node = cast2Node( itN->next() );
4265       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4266       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4267       if ( nIt == mapNewNodes.end() ) {
4268         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4269         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4270         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4271         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4272         //vecNewNodes.reserve(nbsteps);
4273
4274         // make new nodes
4275         double coord[] = { node->X(), node->Y(), node->Z() };
4276         //int nbsteps = theParams.mySteps->Length();
4277         for ( int i = 0; i < nbsteps; i++ ) {
4278           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4279             // create additional node
4280             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4281             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4282             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4283             if( theFlags & EXTRUSION_FLAG_SEW ) {
4284               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4285                                                          theTolerance, theParams.myNodes);
4286               listNewNodes.push_back( newNode );
4287             }
4288             else {
4289               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4290               myLastCreatedNodes.Append(newNode);
4291               srcNodes.Append( node );
4292               listNewNodes.push_back( newNode );
4293             }
4294           }
4295           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4296           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4297           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4298           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4299           if( theFlags & EXTRUSION_FLAG_SEW ) {
4300             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4301                                                        theTolerance, theParams.myNodes);
4302             listNewNodes.push_back( newNode );
4303             //vecNewNodes[i]=newNode;
4304           }
4305           else {
4306             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4307             myLastCreatedNodes.Append(newNode);
4308             srcNodes.Append( node );
4309             listNewNodes.push_back( newNode );
4310             //vecNewNodes[i]=newNode;
4311           }
4312         }
4313       }
4314       else {
4315         // if current elem is quadratic and current node is not medium
4316         // we have to check - may be it is needed to insert additional nodes
4317         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4318           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4319           if(listNewNodes.size()==nbsteps) {
4320             listNewNodes.clear();
4321             double coord[] = { node->X(), node->Y(), node->Z() };
4322             for ( int i = 0; i < nbsteps; i++ ) {
4323               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4324               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4325               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4326               if( theFlags & EXTRUSION_FLAG_SEW ) {
4327                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4328                                                            theTolerance, theParams.myNodes);
4329                 listNewNodes.push_back( newNode );
4330               }
4331               else {
4332                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4333                 myLastCreatedNodes.Append(newNode);
4334                 srcNodes.Append( node );
4335                 listNewNodes.push_back( newNode );
4336               }
4337               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4338               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4339               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4340               if( theFlags & EXTRUSION_FLAG_SEW ) {
4341                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4342                                                            theTolerance, theParams.myNodes);
4343                 listNewNodes.push_back( newNode );
4344               }
4345               else {
4346                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4347                 myLastCreatedNodes.Append(newNode);
4348                 srcNodes.Append( node );
4349                 listNewNodes.push_back( newNode );
4350               }
4351             }
4352           }
4353         }
4354       }
4355       newNodesItVec.push_back( nIt );
4356     }
4357     // make new elements
4358     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4359   }
4360
4361   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4362     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4363   }
4364   PGroupIDs newGroupIDs;
4365   if ( theMakeGroups )
4366     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4367
4368   return newGroupIDs;
4369 }
4370
4371 /*
4372 //=======================================================================
4373 //class    : SMESH_MeshEditor_PathPoint
4374 //purpose  : auxiliary class
4375 //=======================================================================
4376 class SMESH_MeshEditor_PathPoint {
4377 public:
4378 SMESH_MeshEditor_PathPoint() {
4379 myPnt.SetCoord(99., 99., 99.);
4380 myTgt.SetCoord(1.,0.,0.);
4381 myAngle=0.;
4382 myPrm=0.;
4383 }
4384 void SetPnt(const gp_Pnt& aP3D){
4385 myPnt=aP3D;
4386 }
4387 void SetTangent(const gp_Dir& aTgt){
4388 myTgt=aTgt;
4389 }
4390 void SetAngle(const double& aBeta){
4391 myAngle=aBeta;
4392 }
4393 void SetParameter(const double& aPrm){
4394 myPrm=aPrm;
4395 }
4396 const gp_Pnt& Pnt()const{
4397 return myPnt;
4398 }
4399 const gp_Dir& Tangent()const{
4400 return myTgt;
4401 }
4402 double Angle()const{
4403 return myAngle;
4404 }
4405 double Parameter()const{
4406 return myPrm;
4407 }
4408
4409 protected:
4410 gp_Pnt myPnt;
4411 gp_Dir myTgt;
4412 double myAngle;
4413 double myPrm;
4414 };
4415 */
4416
4417 //=======================================================================
4418 //function : ExtrusionAlongTrack
4419 //purpose  :
4420 //=======================================================================
4421 SMESH_MeshEditor::Extrusion_Error
4422 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4423                                        SMESH_subMesh*       theTrack,
4424                                        const SMDS_MeshNode* theN1,
4425                                        const bool           theHasAngles,
4426                                        list<double>&        theAngles,
4427                                        const bool           theLinearVariation,
4428                                        const bool           theHasRefPoint,
4429                                        const gp_Pnt&        theRefPoint,
4430                                        const bool           theMakeGroups)
4431 {
4432   myLastCreatedElems.Clear();
4433   myLastCreatedNodes.Clear();
4434
4435   int aNbE;
4436   std::list<double> aPrms;
4437   TIDSortedElemSet::iterator itElem;
4438
4439   gp_XYZ aGC;
4440   TopoDS_Edge aTrackEdge;
4441   TopoDS_Vertex aV1, aV2;
4442
4443   SMDS_ElemIteratorPtr aItE;
4444   SMDS_NodeIteratorPtr aItN;
4445   SMDSAbs_ElementType aTypeE;
4446
4447   TNodeOfNodeListMap mapNewNodes;
4448
4449   // 1. Check data
4450   aNbE = theElements.size();
4451   // nothing to do
4452   if ( !aNbE )
4453     return EXTR_NO_ELEMENTS;
4454
4455   // 1.1 Track Pattern
4456   ASSERT( theTrack );
4457
4458   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4459
4460   aItE = pSubMeshDS->GetElements();
4461   while ( aItE->more() ) {
4462     const SMDS_MeshElement* pE = aItE->next();
4463     aTypeE = pE->GetType();
4464     // Pattern must contain links only
4465     if ( aTypeE != SMDSAbs_Edge )
4466       return EXTR_PATH_NOT_EDGE;
4467   }
4468
4469   list<SMESH_MeshEditor_PathPoint> fullList;
4470
4471   const TopoDS_Shape& aS = theTrack->GetSubShape();
4472   // Sub shape for the Pattern must be an Edge or Wire
4473   if( aS.ShapeType() == TopAbs_EDGE ) {
4474     aTrackEdge = TopoDS::Edge( aS );
4475     // the Edge must not be degenerated
4476     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4477       return EXTR_BAD_PATH_SHAPE;
4478     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4479     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4480     const SMDS_MeshNode* aN1 = aItN->next();
4481     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4482     const SMDS_MeshNode* aN2 = aItN->next();
4483     // starting node must be aN1 or aN2
4484     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4485       return EXTR_BAD_STARTING_NODE;
4486     aItN = pSubMeshDS->GetNodes();
4487     while ( aItN->more() ) {
4488       const SMDS_MeshNode* pNode = aItN->next();
4489       const SMDS_EdgePosition* pEPos =
4490         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4491       double aT = pEPos->GetUParameter();
4492       aPrms.push_back( aT );
4493     }
4494     //Extrusion_Error err =
4495     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4496   }
4497   else if( aS.ShapeType() == TopAbs_WIRE ) {
4498     list< SMESH_subMesh* > LSM;
4499     TopTools_SequenceOfShape Edges;
4500     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4501     while(itSM->more()) {
4502       SMESH_subMesh* SM = itSM->next();
4503       LSM.push_back(SM);
4504       const TopoDS_Shape& aS = SM->GetSubShape();
4505       Edges.Append(aS);
4506     }
4507     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4508     int startNid = theN1->GetID();
4509     TColStd_MapOfInteger UsedNums;
4510     int NbEdges = Edges.Length();
4511     int i = 1;
4512     for(; i<=NbEdges; i++) {
4513       int k = 0;
4514       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4515       for(; itLSM!=LSM.end(); itLSM++) {
4516         k++;
4517         if(UsedNums.Contains(k)) continue;
4518         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4519         SMESH_subMesh* locTrack = *itLSM;
4520         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4521         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4522         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4523         const SMDS_MeshNode* aN1 = aItN->next();
4524         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4525         const SMDS_MeshNode* aN2 = aItN->next();
4526         // starting node must be aN1 or aN2
4527         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4528         // 2. Collect parameters on the track edge
4529         aPrms.clear();
4530         aItN = locMeshDS->GetNodes();
4531         while ( aItN->more() ) {
4532           const SMDS_MeshNode* pNode = aItN->next();
4533           const SMDS_EdgePosition* pEPos =
4534             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4535           double aT = pEPos->GetUParameter();
4536           aPrms.push_back( aT );
4537         }
4538         list<SMESH_MeshEditor_PathPoint> LPP;
4539         //Extrusion_Error err =
4540         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4541         LLPPs.push_back(LPP);
4542         UsedNums.Add(k);
4543         // update startN for search following egde
4544         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4545         else startNid = aN1->GetID();
4546         break;
4547       }
4548     }
4549     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4550     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4551     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4552     for(; itPP!=firstList.end(); itPP++) {
4553       fullList.push_back( *itPP );
4554     }
4555     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4556     fullList.pop_back();
4557     itLLPP++;
4558     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4559       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4560       itPP = currList.begin();
4561       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4562       gp_Dir D1 = PP1.Tangent();
4563       gp_Dir D2 = PP2.Tangent();
4564       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4565                            (D1.Z()+D2.Z())/2 ) );
4566       PP1.SetTangent(Dnew);
4567       fullList.push_back(PP1);
4568       itPP++;
4569       for(; itPP!=firstList.end(); itPP++) {
4570         fullList.push_back( *itPP );
4571       }
4572       PP1 = fullList.back();
4573       fullList.pop_back();
4574     }
4575     // if wire not closed
4576     fullList.push_back(PP1);
4577     // else ???
4578   }
4579   else {
4580     return EXTR_BAD_PATH_SHAPE;
4581   }
4582
4583   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4584                           theHasRefPoint, theRefPoint, theMakeGroups);
4585 }
4586
4587
4588 //=======================================================================
4589 //function : ExtrusionAlongTrack
4590 //purpose  :
4591 //=======================================================================
4592 SMESH_MeshEditor::Extrusion_Error
4593 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4594                                        SMESH_Mesh*          theTrack,
4595                                        const SMDS_MeshNode* theN1,
4596                                        const bool           theHasAngles,
4597                                        list<double>&        theAngles,
4598                                        const bool           theLinearVariation,
4599                                        const bool           theHasRefPoint,
4600                                        const gp_Pnt&        theRefPoint,
4601                                        const bool           theMakeGroups)
4602 {
4603   myLastCreatedElems.Clear();
4604   myLastCreatedNodes.Clear();
4605
4606   int aNbE;
4607   std::list<double> aPrms;
4608   TIDSortedElemSet::iterator itElem;
4609
4610   gp_XYZ aGC;
4611   TopoDS_Edge aTrackEdge;
4612   TopoDS_Vertex aV1, aV2;
4613
4614   SMDS_ElemIteratorPtr aItE;
4615   SMDS_NodeIteratorPtr aItN;
4616   SMDSAbs_ElementType aTypeE;
4617
4618   TNodeOfNodeListMap mapNewNodes;
4619
4620   // 1. Check data
4621   aNbE = theElements.size();
4622   // nothing to do
4623   if ( !aNbE )
4624     return EXTR_NO_ELEMENTS;
4625
4626   // 1.1 Track Pattern
4627   ASSERT( theTrack );
4628
4629   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4630
4631   aItE = pMeshDS->elementsIterator();
4632   while ( aItE->more() ) {
4633     const SMDS_MeshElement* pE = aItE->next();
4634     aTypeE = pE->GetType();
4635     // Pattern must contain links only
4636     if ( aTypeE != SMDSAbs_Edge )
4637       return EXTR_PATH_NOT_EDGE;
4638   }
4639
4640   list<SMESH_MeshEditor_PathPoint> fullList;
4641
4642   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4643   // Sub shape for the Pattern must be an Edge or Wire
4644   if( aS.ShapeType() == TopAbs_EDGE ) {
4645     aTrackEdge = TopoDS::Edge( aS );
4646     // the Edge must not be degenerated
4647     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4648       return EXTR_BAD_PATH_SHAPE;
4649     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4650     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4651     const SMDS_MeshNode* aN1 = aItN->next();
4652     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4653     const SMDS_MeshNode* aN2 = aItN->next();
4654     // starting node must be aN1 or aN2
4655     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4656       return EXTR_BAD_STARTING_NODE;
4657     aItN = pMeshDS->nodesIterator();
4658     while ( aItN->more() ) {
4659       const SMDS_MeshNode* pNode = aItN->next();
4660       if( pNode==aN1 || pNode==aN2 ) continue;
4661       const SMDS_EdgePosition* pEPos =
4662         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4663       double aT = pEPos->GetUParameter();
4664       aPrms.push_back( aT );
4665     }
4666     //Extrusion_Error err =
4667     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4668   }
4669   else if( aS.ShapeType() == TopAbs_WIRE ) {
4670     list< SMESH_subMesh* > LSM;
4671     TopTools_SequenceOfShape Edges;
4672     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4673     for(; eExp.More(); eExp.Next()) {
4674       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4675       if( BRep_Tool::Degenerated(E) ) continue;
4676       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4677       if(SM) {
4678         LSM.push_back(SM);
4679         Edges.Append(E);
4680       }
4681     }
4682     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4683     int startNid = theN1->GetID();
4684     TColStd_MapOfInteger UsedNums;
4685     int NbEdges = Edges.Length();
4686     int i = 1;
4687     for(; i<=NbEdges; i++) {
4688       int k = 0;
4689       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4690       for(; itLSM!=LSM.end(); itLSM++) {
4691         k++;
4692         if(UsedNums.Contains(k)) continue;
4693         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4694         SMESH_subMesh* locTrack = *itLSM;
4695         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4696         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4697         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4698         const SMDS_MeshNode* aN1 = aItN->next();
4699         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4700         const SMDS_MeshNode* aN2 = aItN->next();
4701         // starting node must be aN1 or aN2
4702         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4703         // 2. Collect parameters on the track edge
4704         aPrms.clear();
4705         aItN = locMeshDS->GetNodes();
4706         while ( aItN->more() ) {
4707           const SMDS_MeshNode* pNode = aItN->next();
4708           const SMDS_EdgePosition* pEPos =
4709             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4710           double aT = pEPos->GetUParameter();
4711           aPrms.push_back( aT );
4712         }
4713         list<SMESH_MeshEditor_PathPoint> LPP;
4714         //Extrusion_Error err =
4715         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4716         LLPPs.push_back(LPP);
4717         UsedNums.Add(k);
4718         // update startN for search following egde
4719         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4720         else startNid = aN1->GetID();
4721         break;
4722       }
4723     }
4724     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4725     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4726     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4727     for(; itPP!=firstList.end(); itPP++) {
4728       fullList.push_back( *itPP );
4729     }
4730     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4731     fullList.pop_back();
4732     itLLPP++;
4733     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4734       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4735       itPP = currList.begin();
4736       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4737       gp_Pnt P1 = PP1.Pnt();
4738       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4739       gp_Pnt P2 = PP2.Pnt();
4740       gp_Dir D1 = PP1.Tangent();
4741       gp_Dir D2 = PP2.Tangent();
4742       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4743                            (D1.Z()+D2.Z())/2 ) );
4744       PP1.SetTangent(Dnew);
4745       fullList.push_back(PP1);
4746       itPP++;
4747       for(; itPP!=currList.end(); itPP++) {
4748         fullList.push_back( *itPP );
4749       }
4750       PP1 = fullList.back();
4751       fullList.pop_back();
4752     }
4753     // if wire not closed
4754     fullList.push_back(PP1);
4755     // else ???
4756   }
4757   else {
4758     return EXTR_BAD_PATH_SHAPE;
4759   }
4760
4761   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4762                           theHasRefPoint, theRefPoint, theMakeGroups);
4763 }
4764
4765
4766 //=======================================================================
4767 //function : MakeEdgePathPoints
4768 //purpose  : auxilary for ExtrusionAlongTrack
4769 //=======================================================================
4770 SMESH_MeshEditor::Extrusion_Error
4771 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4772                                      const TopoDS_Edge& aTrackEdge,
4773                                      bool FirstIsStart,
4774                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4775 {
4776   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4777   aTolVec=1.e-7;
4778   aTolVec2=aTolVec*aTolVec;
4779   double aT1, aT2;
4780   TopoDS_Vertex aV1, aV2;
4781   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4782   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4783   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4784   // 2. Collect parameters on the track edge
4785   aPrms.push_front( aT1 );
4786   aPrms.push_back( aT2 );
4787   // sort parameters
4788   aPrms.sort();
4789   if( FirstIsStart ) {
4790     if ( aT1 > aT2 ) {
4791       aPrms.reverse();
4792     }
4793   }
4794   else {
4795     if ( aT2 > aT1 ) {
4796       aPrms.reverse();
4797     }
4798   }
4799   // 3. Path Points
4800   SMESH_MeshEditor_PathPoint aPP;
4801   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4802   std::list<double>::iterator aItD = aPrms.begin();
4803   for(; aItD != aPrms.end(); ++aItD) {
4804     double aT = *aItD;
4805     gp_Pnt aP3D;
4806     gp_Vec aVec;
4807     aC3D->D1( aT, aP3D, aVec );
4808     aL2 = aVec.SquareMagnitude();
4809     if ( aL2 < aTolVec2 )
4810       return EXTR_CANT_GET_TANGENT;
4811     gp_Dir aTgt( aVec );
4812     aPP.SetPnt( aP3D );
4813     aPP.SetTangent( aTgt );
4814     aPP.SetParameter( aT );
4815     LPP.push_back(aPP);
4816   }
4817   return EXTR_OK;
4818 }
4819
4820
4821 //=======================================================================
4822 //function : MakeExtrElements
4823 //purpose  : auxilary for ExtrusionAlongTrack
4824 //=======================================================================
4825 SMESH_MeshEditor::Extrusion_Error
4826 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4827                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4828                                    const bool theHasAngles,
4829                                    list<double>& theAngles,
4830                                    const bool theLinearVariation,
4831                                    const bool theHasRefPoint,
4832                                    const gp_Pnt& theRefPoint,
4833                                    const bool theMakeGroups)
4834 {
4835   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4836   int aNbTP = fullList.size();
4837   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4838   // Angles
4839   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4840     LinearAngleVariation(aNbTP-1, theAngles);
4841   }
4842   vector<double> aAngles( aNbTP );
4843   int j = 0;
4844   for(; j<aNbTP; ++j) {
4845     aAngles[j] = 0.;
4846   }
4847   if ( theHasAngles ) {
4848     double anAngle;;
4849     std::list<double>::iterator aItD = theAngles.begin();
4850     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4851       anAngle = *aItD;
4852       aAngles[j] = anAngle;
4853     }
4854   }
4855   // fill vector of path points with angles
4856   //aPPs.resize(fullList.size());
4857   j = -1;
4858   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4859   for(; itPP!=fullList.end(); itPP++) {
4860     j++;
4861     SMESH_MeshEditor_PathPoint PP = *itPP;
4862     PP.SetAngle(aAngles[j]);
4863     aPPs[j] = PP;
4864   }
4865
4866   TNodeOfNodeListMap mapNewNodes;
4867   TElemOfVecOfNnlmiMap mapElemNewNodes;
4868   TElemOfElemListMap newElemsMap;
4869   TIDSortedElemSet::iterator itElem;
4870   double aX, aY, aZ;
4871   int aNb;
4872   SMDSAbs_ElementType aTypeE;
4873   // source elements for each generated one
4874   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4875
4876   // 3. Center of rotation aV0
4877   gp_Pnt aV0 = theRefPoint;
4878   gp_XYZ aGC;
4879   if ( !theHasRefPoint ) {
4880     aNb = 0;
4881     aGC.SetCoord( 0.,0.,0. );
4882
4883     itElem = theElements.begin();
4884     for ( ; itElem != theElements.end(); itElem++ ) {
4885       const SMDS_MeshElement* elem = *itElem;
4886
4887       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4888       while ( itN->more() ) {
4889         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4890         aX = node->X();
4891         aY = node->Y();
4892         aZ = node->Z();
4893
4894         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4895           list<const SMDS_MeshNode*> aLNx;
4896           mapNewNodes[node] = aLNx;
4897           //
4898           gp_XYZ aXYZ( aX, aY, aZ );
4899           aGC += aXYZ;
4900           ++aNb;
4901         }
4902       }
4903     }
4904     aGC /= aNb;
4905     aV0.SetXYZ( aGC );
4906   } // if (!theHasRefPoint) {
4907   mapNewNodes.clear();
4908
4909   // 4. Processing the elements
4910   SMESHDS_Mesh* aMesh = GetMeshDS();
4911
4912   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4913     // check element type
4914     const SMDS_MeshElement* elem = *itElem;
4915     aTypeE = elem->GetType();
4916     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4917       continue;
4918
4919     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4920     newNodesItVec.reserve( elem->NbNodes() );
4921
4922     // loop on elem nodes
4923     int nodeIndex = -1;
4924     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4925     while ( itN->more() )
4926     {
4927       ++nodeIndex;
4928       // check if a node has been already processed
4929       const SMDS_MeshNode* node =
4930         static_cast<const SMDS_MeshNode*>( itN->next() );
4931       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4932       if ( nIt == mapNewNodes.end() ) {
4933         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4934         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4935
4936         // make new nodes
4937         aX = node->X();  aY = node->Y(); aZ = node->Z();
4938
4939         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4940         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4941         gp_Ax1 anAx1, anAxT1T0;
4942         gp_Dir aDT1x, aDT0x, aDT1T0;
4943
4944         aTolAng=1.e-4;
4945
4946         aV0x = aV0;
4947         aPN0.SetCoord(aX, aY, aZ);
4948
4949         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4950         aP0x = aPP0.Pnt();
4951         aDT0x= aPP0.Tangent();
4952         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4953
4954         for ( j = 1; j < aNbTP; ++j ) {
4955           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4956           aP1x = aPP1.Pnt();
4957           aDT1x = aPP1.Tangent();
4958           aAngle1x = aPP1.Angle();
4959
4960           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4961           // Translation
4962           gp_Vec aV01x( aP0x, aP1x );
4963           aTrsf.SetTranslation( aV01x );
4964
4965           // traslated point
4966           aV1x = aV0x.Transformed( aTrsf );
4967           aPN1 = aPN0.Transformed( aTrsf );
4968
4969           // rotation 1 [ T1,T0 ]
4970           aAngleT1T0=-aDT1x.Angle( aDT0x );
4971           if (fabs(aAngleT1T0) > aTolAng) {
4972             aDT1T0=aDT1x^aDT0x;
4973             anAxT1T0.SetLocation( aV1x );
4974             anAxT1T0.SetDirection( aDT1T0 );
4975             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4976
4977             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4978           }
4979
4980           // rotation 2
4981           if ( theHasAngles ) {
4982             anAx1.SetLocation( aV1x );
4983             anAx1.SetDirection( aDT1x );
4984             aTrsfRot.SetRotation( anAx1, aAngle1x );
4985
4986             aPN1 = aPN1.Transformed( aTrsfRot );
4987           }
4988
4989           // make new node
4990           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4991             // create additional node
4992             double x = ( aPN1.X() + aPN0.X() )/2.;
4993             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4994             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4995             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4996             myLastCreatedNodes.Append(newNode);
4997             srcNodes.Append( node );
4998             listNewNodes.push_back( newNode );
4999           }
5000           aX = aPN1.X();
5001           aY = aPN1.Y();
5002           aZ = aPN1.Z();
5003           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5004           myLastCreatedNodes.Append(newNode);
5005           srcNodes.Append( node );
5006           listNewNodes.push_back( newNode );
5007
5008           aPN0 = aPN1;
5009           aP0x = aP1x;
5010           aV0x = aV1x;
5011           aDT0x = aDT1x;
5012         }
5013       }
5014
5015       else {
5016         // if current elem is quadratic and current node is not medium
5017         // we have to check - may be it is needed to insert additional nodes
5018         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5019           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5020           if(listNewNodes.size()==aNbTP-1) {
5021             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5022             gp_XYZ P(node->X(), node->Y(), node->Z());
5023             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5024             int i;
5025             for(i=0; i<aNbTP-1; i++) {
5026               const SMDS_MeshNode* N = *it;
5027               double x = ( N->X() + P.X() )/2.;
5028               double y = ( N->Y() + P.Y() )/2.;
5029               double z = ( N->Z() + P.Z() )/2.;
5030               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5031               srcNodes.Append( node );
5032               myLastCreatedNodes.Append(newN);
5033               aNodes[2*i] = newN;
5034               aNodes[2*i+1] = N;
5035               P = gp_XYZ(N->X(),N->Y(),N->Z());
5036             }
5037             listNewNodes.clear();
5038             for(i=0; i<2*(aNbTP-1); i++) {
5039               listNewNodes.push_back(aNodes[i]);
5040             }
5041           }
5042         }
5043       }
5044
5045       newNodesItVec.push_back( nIt );
5046     }
5047     // make new elements
5048     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5049     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5050     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5051   }
5052
5053   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5054
5055   if ( theMakeGroups )
5056     generateGroups( srcNodes, srcElems, "extruded");
5057
5058   return EXTR_OK;
5059 }
5060
5061
5062 //=======================================================================
5063 //function : LinearAngleVariation
5064 //purpose  : auxilary for ExtrusionAlongTrack
5065 //=======================================================================
5066 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5067                                             list<double>& Angles)
5068 {
5069   int nbAngles = Angles.size();
5070   if( nbSteps > nbAngles ) {
5071     vector<double> theAngles(nbAngles);
5072     list<double>::iterator it = Angles.begin();
5073     int i = -1;
5074     for(; it!=Angles.end(); it++) {
5075       i++;
5076       theAngles[i] = (*it);
5077     }
5078     list<double> res;
5079     double rAn2St = double( nbAngles ) / double( nbSteps );
5080     double angPrev = 0, angle;
5081     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5082       double angCur = rAn2St * ( iSt+1 );
5083       double angCurFloor  = floor( angCur );
5084       double angPrevFloor = floor( angPrev );
5085       if ( angPrevFloor == angCurFloor )
5086         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5087       else {
5088         int iP = int( angPrevFloor );
5089         double angPrevCeil = ceil(angPrev);
5090         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5091
5092         int iC = int( angCurFloor );
5093         if ( iC < nbAngles )
5094           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5095
5096         iP = int( angPrevCeil );
5097         while ( iC-- > iP )
5098           angle += theAngles[ iC ];
5099       }
5100       res.push_back(angle);
5101       angPrev = angCur;
5102     }
5103     Angles.clear();
5104     it = res.begin();
5105     for(; it!=res.end(); it++)
5106       Angles.push_back( *it );
5107   }
5108 }
5109
5110
5111 //=======================================================================
5112 //function : Transform
5113 //purpose  :
5114 //=======================================================================
5115
5116 SMESH_MeshEditor::PGroupIDs
5117 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5118                              const gp_Trsf&     theTrsf,
5119                              const bool         theCopy,
5120                              const bool         theMakeGroups,
5121                              SMESH_Mesh*        theTargetMesh)
5122 {
5123   myLastCreatedElems.Clear();
5124   myLastCreatedNodes.Clear();
5125
5126   bool needReverse = false;
5127   string groupPostfix;
5128   switch ( theTrsf.Form() ) {
5129   case gp_PntMirror:
5130   case gp_Ax1Mirror:
5131   case gp_Ax2Mirror:
5132     needReverse = true;
5133     groupPostfix = "mirrored";
5134     break;
5135   case gp_Rotation:
5136     groupPostfix = "rotated";
5137     break;
5138   case gp_Translation:
5139     groupPostfix = "translated";
5140     break;
5141   case gp_Scale:
5142     groupPostfix = "scaled";
5143     break;
5144   default:
5145     needReverse = false;
5146     groupPostfix = "transformed";
5147   }
5148
5149   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5150   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5151   SMESHDS_Mesh* aMesh    = GetMeshDS();
5152
5153
5154   // map old node to new one
5155   TNodeNodeMap nodeMap;
5156
5157   // elements sharing moved nodes; those of them which have all
5158   // nodes mirrored but are not in theElems are to be reversed
5159   TIDSortedElemSet inverseElemSet;
5160
5161   // source elements for each generated one
5162   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5163
5164   // loop on theElems
5165   TIDSortedElemSet::iterator itElem;
5166   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5167     const SMDS_MeshElement* elem = *itElem;
5168     if ( !elem )
5169       continue;
5170
5171     // loop on elem nodes
5172     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5173     while ( itN->more() ) {
5174
5175       // check if a node has been already transformed
5176       const SMDS_MeshNode* node = cast2Node( itN->next() );
5177       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5178         nodeMap.insert( make_pair ( node, node ));
5179       if ( !n2n_isnew.second )
5180         continue;
5181
5182       double coord[3];
5183       coord[0] = node->X();
5184       coord[1] = node->Y();
5185       coord[2] = node->Z();
5186       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5187       if ( theTargetMesh ) {
5188         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5189         n2n_isnew.first->second = newNode;
5190         myLastCreatedNodes.Append(newNode);
5191         srcNodes.Append( node );
5192       }
5193       else if ( theCopy ) {
5194         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5195         n2n_isnew.first->second = newNode;
5196         myLastCreatedNodes.Append(newNode);
5197         srcNodes.Append( node );
5198       }
5199       else {
5200         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5201         // node position on shape becomes invalid
5202         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5203           ( SMDS_SpacePosition::originSpacePosition() );
5204       }
5205
5206       // keep inverse elements
5207       if ( !theCopy && !theTargetMesh && needReverse ) {
5208         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5209         while ( invElemIt->more() ) {
5210           const SMDS_MeshElement* iel = invElemIt->next();
5211           inverseElemSet.insert( iel );
5212         }
5213       }
5214     }
5215   }
5216
5217   // either create new elements or reverse mirrored ones
5218   if ( !theCopy && !needReverse && !theTargetMesh )
5219     return PGroupIDs();
5220
5221   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5222   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5223     theElems.insert( *invElemIt );
5224
5225   // replicate or reverse elements
5226
5227   enum {
5228     REV_TETRA   = 0,  //  = nbNodes - 4
5229     REV_PYRAMID = 1,  //  = nbNodes - 4
5230     REV_PENTA   = 2,  //  = nbNodes - 4
5231     REV_FACE    = 3,
5232     REV_HEXA    = 4,  //  = nbNodes - 4
5233     FORWARD     = 5
5234   };
5235   int index[][8] = {
5236     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5237     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5238     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5239     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5240     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5241     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5242   };
5243
5244   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5245   {
5246     const SMDS_MeshElement* elem = *itElem;
5247     if ( !elem || elem->GetType() == SMDSAbs_Node )
5248       continue;
5249
5250     int nbNodes = elem->NbNodes();
5251     int elemType = elem->GetType();
5252
5253     if (elem->IsPoly()) {
5254       // Polygon or Polyhedral Volume
5255       switch ( elemType ) {
5256       case SMDSAbs_Face:
5257         {
5258           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5259           int iNode = 0;
5260           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5261           while (itN->more()) {
5262             const SMDS_MeshNode* node =
5263               static_cast<const SMDS_MeshNode*>(itN->next());
5264             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5265             if (nodeMapIt == nodeMap.end())
5266               break; // not all nodes transformed
5267             if (needReverse) {
5268               // reverse mirrored faces and volumes
5269               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5270             } else {
5271               poly_nodes[iNode] = (*nodeMapIt).second;
5272             }
5273             iNode++;
5274           }
5275           if ( iNode != nbNodes )
5276             continue; // not all nodes transformed
5277
5278           if ( theTargetMesh ) {
5279             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5280             srcElems.Append( elem );
5281           }
5282           else if ( theCopy ) {
5283             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5284             srcElems.Append( elem );
5285           }
5286           else {
5287             aMesh->ChangePolygonNodes(elem, poly_nodes);
5288           }
5289         }
5290         break;
5291       case SMDSAbs_Volume:
5292         {
5293           // ATTENTION: Reversing is not yet done!!!
5294           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5295             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5296           if (!aPolyedre) {
5297             MESSAGE("Warning: bad volumic element");
5298             continue;
5299           }
5300
5301           vector<const SMDS_MeshNode*> poly_nodes;
5302           vector<int> quantities;
5303
5304           bool allTransformed = true;
5305           int nbFaces = aPolyedre->NbFaces();
5306           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5307             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5308             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5309               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5310               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5311               if (nodeMapIt == nodeMap.end()) {
5312                 allTransformed = false; // not all nodes transformed
5313               } else {
5314                 poly_nodes.push_back((*nodeMapIt).second);
5315               }
5316             }
5317             quantities.push_back(nbFaceNodes);
5318           }
5319           if ( !allTransformed )
5320             continue; // not all nodes transformed
5321
5322           if ( theTargetMesh ) {
5323             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5324             srcElems.Append( elem );
5325           }
5326           else if ( theCopy ) {
5327             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5328             srcElems.Append( elem );
5329           }
5330           else {
5331             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5332           }
5333         }
5334         break;
5335       default:;
5336       }
5337       continue;
5338     }
5339
5340     // Regular elements
5341     int* i = index[ FORWARD ];
5342     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5343       if ( elemType == SMDSAbs_Face )
5344         i = index[ REV_FACE ];
5345       else
5346         i = index[ nbNodes - 4 ];
5347
5348     if(elem->IsQuadratic()) {
5349       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5350       i = anIds;
5351       if(needReverse) {
5352         if(nbNodes==3) { // quadratic edge
5353           static int anIds[] = {1,0,2};
5354           i = anIds;
5355         }
5356         else if(nbNodes==6) { // quadratic triangle
5357           static int anIds[] = {0,2,1,5,4,3};
5358           i = anIds;
5359         }
5360         else if(nbNodes==8) { // quadratic quadrangle
5361           static int anIds[] = {0,3,2,1,7,6,5,4};
5362           i = anIds;
5363         }
5364         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5365           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5366           i = anIds;
5367         }
5368         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5369           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5370           i = anIds;
5371         }
5372         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5373           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5374           i = anIds;
5375         }
5376         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5377           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5378           i = anIds;
5379         }
5380       }
5381     }
5382
5383     // find transformed nodes
5384     vector<const SMDS_MeshNode*> nodes(nbNodes);
5385     int iNode = 0;
5386     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5387     while ( itN->more() ) {
5388       const SMDS_MeshNode* node =
5389         static_cast<const SMDS_MeshNode*>( itN->next() );
5390       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5391       if ( nodeMapIt == nodeMap.end() )
5392         break; // not all nodes transformed
5393       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5394     }
5395     if ( iNode != nbNodes )
5396       continue; // not all nodes transformed
5397
5398     if ( theTargetMesh ) {
5399       if ( SMDS_MeshElement* copy =
5400            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5401         myLastCreatedElems.Append( copy );
5402         srcElems.Append( elem );
5403       }
5404     }
5405     else if ( theCopy ) {
5406       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5407         myLastCreatedElems.Append( copy );
5408         srcElems.Append( elem );
5409       }
5410     }
5411     else {
5412       // reverse element as it was reversed by transformation
5413       if ( nbNodes > 2 )
5414         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5415     }
5416   }
5417
5418   PGroupIDs newGroupIDs;
5419
5420   if ( theMakeGroups && theCopy ||
5421        theMakeGroups && theTargetMesh )
5422     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5423
5424   return newGroupIDs;
5425 }
5426
5427
5428 //=======================================================================
5429 //function : Scale
5430 //purpose  :
5431 //=======================================================================
5432
5433 SMESH_MeshEditor::PGroupIDs
5434 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5435                          const gp_Pnt&            thePoint,
5436                          const std::list<double>& theScaleFact,
5437                          const bool         theCopy,
5438                          const bool         theMakeGroups,
5439                          SMESH_Mesh*        theTargetMesh)
5440 {
5441   myLastCreatedElems.Clear();
5442   myLastCreatedNodes.Clear();
5443
5444   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5445   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5446   SMESHDS_Mesh* aMesh    = GetMeshDS();
5447
5448   double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5449   std::list<double>::const_iterator itS = theScaleFact.begin();
5450   scaleX = (*itS);
5451   if(theScaleFact.size()==1) {
5452     scaleY = (*itS);
5453     scaleZ= (*itS);
5454   }
5455   if(theScaleFact.size()==2) {
5456     itS++;
5457     scaleY = (*itS);
5458     scaleZ= (*itS);
5459   }
5460   if(theScaleFact.size()>2) {
5461     itS++;
5462     scaleY = (*itS);
5463     itS++;
5464     scaleZ= (*itS);
5465   }
5466   
5467   // map old node to new one
5468   TNodeNodeMap nodeMap;
5469
5470   // elements sharing moved nodes; those of them which have all
5471   // nodes mirrored but are not in theElems are to be reversed
5472   TIDSortedElemSet inverseElemSet;
5473
5474   // source elements for each generated one
5475   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5476
5477   // loop on theElems
5478   TIDSortedElemSet::iterator itElem;
5479   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5480     const SMDS_MeshElement* elem = *itElem;
5481     if ( !elem )
5482       continue;
5483
5484     // loop on elem nodes
5485     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5486     while ( itN->more() ) {
5487
5488       // check if a node has been already transformed
5489       const SMDS_MeshNode* node = cast2Node( itN->next() );
5490       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5491         nodeMap.insert( make_pair ( node, node ));
5492       if ( !n2n_isnew.second )
5493         continue;
5494
5495       //double coord[3];
5496       //coord[0] = node->X();
5497       //coord[1] = node->Y();
5498       //coord[2] = node->Z();
5499       //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5500       double dx = (node->X() - thePoint.X()) * scaleX;
5501       double dy = (node->Y() - thePoint.Y()) * scaleY;
5502       double dz = (node->Z() - thePoint.Z()) * scaleZ;
5503       if ( theTargetMesh ) {
5504         //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5505         const SMDS_MeshNode * newNode =
5506           aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5507         n2n_isnew.first->second = newNode;
5508         myLastCreatedNodes.Append(newNode);
5509         srcNodes.Append( node );
5510       }
5511       else if ( theCopy ) {
5512         //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5513         const SMDS_MeshNode * newNode =
5514           aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5515         n2n_isnew.first->second = newNode;
5516         myLastCreatedNodes.Append(newNode);
5517         srcNodes.Append( node );
5518       }
5519       else {
5520         //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5521         aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5522         // node position on shape becomes invalid
5523         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5524           ( SMDS_SpacePosition::originSpacePosition() );
5525       }
5526
5527       // keep inverse elements
5528       //if ( !theCopy && !theTargetMesh && needReverse ) {
5529       //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5530       //  while ( invElemIt->more() ) {
5531       //    const SMDS_MeshElement* iel = invElemIt->next();
5532       //    inverseElemSet.insert( iel );
5533       //  }
5534       //}
5535     }
5536   }
5537
5538   // either create new elements or reverse mirrored ones
5539   //if ( !theCopy && !needReverse && !theTargetMesh )
5540   if ( !theCopy && !theTargetMesh )
5541     return PGroupIDs();
5542
5543   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5544   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5545     theElems.insert( *invElemIt );
5546
5547   // replicate or reverse elements
5548
5549   enum {
5550     REV_TETRA   = 0,  //  = nbNodes - 4
5551     REV_PYRAMID = 1,  //  = nbNodes - 4
5552     REV_PENTA   = 2,  //  = nbNodes - 4
5553     REV_FACE    = 3,
5554     REV_HEXA    = 4,  //  = nbNodes - 4
5555     FORWARD     = 5
5556   };
5557   int index[][8] = {
5558     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5559     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5560     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5561     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5562     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5563     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5564   };
5565
5566   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5567   {
5568     const SMDS_MeshElement* elem = *itElem;
5569     if ( !elem || elem->GetType() == SMDSAbs_Node )
5570       continue;
5571
5572     int nbNodes = elem->NbNodes();
5573     int elemType = elem->GetType();
5574
5575     if (elem->IsPoly()) {
5576       // Polygon or Polyhedral Volume
5577       switch ( elemType ) {
5578       case SMDSAbs_Face:
5579         {
5580           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5581           int iNode = 0;
5582           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5583           while (itN->more()) {
5584             const SMDS_MeshNode* node =
5585               static_cast<const SMDS_MeshNode*>(itN->next());
5586             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5587             if (nodeMapIt == nodeMap.end())
5588               break; // not all nodes transformed
5589             //if (needReverse) {
5590             //  // reverse mirrored faces and volumes
5591             //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5592             //} else {
5593             poly_nodes[iNode] = (*nodeMapIt).second;
5594             //}
5595             iNode++;
5596           }
5597           if ( iNode != nbNodes )
5598             continue; // not all nodes transformed
5599
5600           if ( theTargetMesh ) {
5601             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5602             srcElems.Append( elem );
5603           }
5604           else if ( theCopy ) {
5605             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5606             srcElems.Append( elem );
5607           }
5608           else {
5609             aMesh->ChangePolygonNodes(elem, poly_nodes);
5610           }
5611         }
5612         break;
5613       case SMDSAbs_Volume:
5614         {
5615           // ATTENTION: Reversing is not yet done!!!
5616           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5617             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5618           if (!aPolyedre) {
5619             MESSAGE("Warning: bad volumic element");
5620             continue;
5621           }
5622
5623           vector<const SMDS_MeshNode*> poly_nodes;
5624           vector<int> quantities;
5625
5626           bool allTransformed = true;
5627           int nbFaces = aPolyedre->NbFaces();
5628           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5629             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5630             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5631               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5632               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5633               if (nodeMapIt == nodeMap.end()) {
5634                 allTransformed = false; // not all nodes transformed
5635               } else {
5636                 poly_nodes.push_back((*nodeMapIt).second);
5637               }
5638             }
5639             quantities.push_back(nbFaceNodes);
5640           }
5641           if ( !allTransformed )
5642             continue; // not all nodes transformed
5643
5644           if ( theTargetMesh ) {
5645             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5646             srcElems.Append( elem );
5647           }
5648           else if ( theCopy ) {
5649             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5650             srcElems.Append( elem );
5651           }
5652           else {
5653             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5654           }
5655         }
5656         break;
5657       default:;
5658       }
5659       continue;
5660     }
5661
5662     // Regular elements
5663     int* i = index[ FORWARD ];
5664     //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5665     //  if ( elemType == SMDSAbs_Face )
5666     //    i = index[ REV_FACE ];
5667     //  else
5668     //    i = index[ nbNodes - 4 ];
5669
5670     if(elem->IsQuadratic()) {
5671       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5672       i = anIds;
5673       //if(needReverse) {
5674       //  if(nbNodes==3) { // quadratic edge
5675       //    static int anIds[] = {1,0,2};
5676       //    i = anIds;
5677       //  }
5678       //  else if(nbNodes==6) { // quadratic triangle
5679       //    static int anIds[] = {0,2,1,5,4,3};
5680       //    i = anIds;
5681       //  }
5682       //  else if(nbNodes==8) { // quadratic quadrangle
5683       //    static int anIds[] = {0,3,2,1,7,6,5,4};
5684       //    i = anIds;
5685       //  }
5686       //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5687       //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5688       //    i = anIds;
5689       //  }
5690       //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5691       //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5692       //    i = anIds;
5693       //  }
5694       //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5695       //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5696       //    i = anIds;
5697       //  }
5698       //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5699       //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5700       //    i = anIds;
5701       //  }
5702       //}
5703     }
5704
5705     // find transformed nodes
5706     vector<const SMDS_MeshNode*> nodes(nbNodes);
5707     int iNode = 0;
5708     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5709     while ( itN->more() ) {
5710       const SMDS_MeshNode* node =
5711         static_cast<const SMDS_MeshNode*>( itN->next() );
5712       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5713       if ( nodeMapIt == nodeMap.end() )
5714         break; // not all nodes transformed
5715       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5716     }
5717     if ( iNode != nbNodes )
5718       continue; // not all nodes transformed
5719
5720     if ( theTargetMesh ) {
5721       if ( SMDS_MeshElement* copy =
5722            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5723         myLastCreatedElems.Append( copy );
5724         srcElems.Append( elem );
5725       }
5726     }
5727     else if ( theCopy ) {
5728       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5729         myLastCreatedElems.Append( copy );
5730         srcElems.Append( elem );
5731       }
5732     }
5733     else {
5734       // reverse element as it was reversed by transformation
5735       if ( nbNodes > 2 )
5736         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5737     }
5738   }
5739
5740   PGroupIDs newGroupIDs;
5741
5742   if ( theMakeGroups && theCopy ||
5743        theMakeGroups && theTargetMesh ) {
5744     string groupPostfix = "scaled";
5745     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5746   }
5747
5748   return newGroupIDs;
5749 }
5750
5751
5752 //=======================================================================
5753 /*!
5754  * \brief Create groups of elements made during transformation
5755  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5756  * \param elemGens - elements making corresponding myLastCreatedElems
5757  * \param postfix - to append to names of new groups
5758  */
5759 //=======================================================================
5760
5761 SMESH_MeshEditor::PGroupIDs
5762 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5763                                  const SMESH_SequenceOfElemPtr& elemGens,
5764                                  const std::string&             postfix,
5765                                  SMESH_Mesh*                    targetMesh)
5766 {
5767   PGroupIDs newGroupIDs( new list<int> );
5768   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5769
5770   // Sort existing groups by types and collect their names
5771
5772   // to store an old group and a generated new one
5773   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5774   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5775   // group names
5776   set< string > groupNames;
5777   //
5778   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5779   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5780   while ( groupIt->more() ) {
5781     SMESH_Group * group = groupIt->next();
5782     if ( !group ) continue;
5783     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5784     if ( !groupDS || groupDS->IsEmpty() ) continue;
5785     groupNames.insert( group->GetName() );
5786     groupDS->SetStoreName( group->GetName() );
5787     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5788   }
5789
5790   // Groups creation
5791
5792   // loop on nodes and elements
5793   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5794   {
5795     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5796     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5797     if ( gens.Length() != elems.Length() )
5798       throw SALOME_Exception(LOCALIZED("invalid args"));
5799
5800     // loop on created elements
5801     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5802     {
5803       const SMDS_MeshElement* sourceElem = gens( iElem );
5804       if ( !sourceElem ) {
5805         MESSAGE("generateGroups(): NULL source element");
5806         continue;
5807       }
5808       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5809       if ( groupsOldNew.empty() ) {
5810         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5811           ++iElem; // skip all elements made by sourceElem
5812         continue;
5813       }
5814       // collect all elements made by sourceElem
5815       list< const SMDS_MeshElement* > resultElems;
5816       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5817         if ( resElem != sourceElem )
5818           resultElems.push_back( resElem );
5819       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5820         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5821           if ( resElem != sourceElem )
5822             resultElems.push_back( resElem );
5823       // do not generate element groups from node ones
5824       if ( sourceElem->GetType() == SMDSAbs_Node &&
5825            elems( iElem )->GetType() != SMDSAbs_Node )
5826         continue;
5827
5828       // add resultElems to groups made by ones the sourceElem belongs to
5829       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5830       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5831       {
5832         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5833         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5834         {
5835           SMDS_MeshGroup* & newGroup = gOldNew->second;
5836           if ( !newGroup )// create a new group
5837           {
5838             // make a name
5839             string name = oldGroup->GetStoreName();
5840             if ( !targetMesh ) {
5841               name += "_";
5842               name += postfix;
5843               int nb = 0;
5844               while ( !groupNames.insert( name ).second ) // name exists
5845               {
5846                 if ( nb == 0 ) {
5847                   name += "_1";
5848                 }
5849                 else {
5850                   TCollection_AsciiString nbStr(nb+1);
5851                   name.resize( name.rfind('_')+1 );
5852                   name += nbStr.ToCString();
5853                 }
5854                 ++nb;
5855               }
5856             }
5857             // make a group
5858             int id;
5859             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5860                                                  name.c_str(), id );
5861             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5862             newGroup = & groupDS->SMDSGroup();
5863             newGroupIDs->push_back( id );
5864           }
5865
5866           // fill in a new group
5867           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5868           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5869             newGroup->Add( *resElemIt );
5870         }
5871       }
5872     } // loop on created elements
5873   }// loop on nodes and elements
5874
5875   return newGroupIDs;
5876 }
5877
5878 //================================================================================
5879 /*!
5880  * \brief Return list of group of nodes close to each other within theTolerance
5881  *        Search among theNodes or in the whole mesh if theNodes is empty using
5882  *        an Octree algorithm
5883  */
5884 //================================================================================
5885
5886 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5887                                             const double                theTolerance,
5888                                             TListOfListOfNodes &        theGroupsOfNodes)
5889 {
5890   myLastCreatedElems.Clear();
5891   myLastCreatedNodes.Clear();
5892
5893   set<const SMDS_MeshNode*> nodes;
5894   if ( theNodes.empty() )
5895   { // get all nodes in the mesh
5896     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5897     while ( nIt->more() )
5898       nodes.insert( nodes.end(),nIt->next());
5899   }
5900   else
5901     nodes=theNodes;
5902
5903   SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5904 }
5905
5906
5907 //=======================================================================
5908 /*!
5909  * \brief Implementation of search for the node closest to point
5910  */
5911 //=======================================================================
5912
5913 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5914 {
5915   //---------------------------------------------------------------------
5916   /*!
5917    * \brief Constructor
5918    */
5919   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5920   {
5921     myMesh = ( SMESHDS_Mesh* ) theMesh;
5922
5923     set<const SMDS_MeshNode*> nodes;
5924     if ( theMesh ) {
5925       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5926       while ( nIt->more() )
5927         nodes.insert( nodes.end(), nIt->next() );
5928     }
5929     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5930
5931     // get max size of a leaf box
5932     SMESH_OctreeNode* tree = myOctreeNode;
5933     while ( !tree->isLeaf() )
5934     {
5935       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5936       if ( cIt->more() )
5937         tree = cIt->next();
5938     }
5939     myHalfLeafSize = tree->maxSize() / 2.;
5940   }
5941
5942   //---------------------------------------------------------------------
5943   /*!
5944    * \brief Move node and update myOctreeNode accordingly
5945    */
5946   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5947   {
5948     myOctreeNode->UpdateByMoveNode( node, toPnt );
5949     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5950   }
5951
5952   //---------------------------------------------------------------------
5953   /*!
5954    * \brief Do it's job
5955    */
5956   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5957   {
5958     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5959     map<double, const SMDS_MeshNode*> dist2Nodes;
5960     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5961     if ( !dist2Nodes.empty() )
5962       return dist2Nodes.begin()->second;
5963     list<const SMDS_MeshNode*> nodes;
5964     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5965
5966     double minSqDist = DBL_MAX;
5967     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5968     {
5969       // sort leafs by their distance from thePnt
5970       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5971       TDistTreeMap treeMap;
5972       list< SMESH_OctreeNode* > treeList;
5973       list< SMESH_OctreeNode* >::iterator trIt;
5974       treeList.push_back( myOctreeNode );
5975
5976       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5977       bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5978       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5979       {
5980         SMESH_OctreeNode* tree = *trIt;
5981         if ( !tree->isLeaf() ) // put children to the queue
5982         {
5983           if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5984           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5985           while ( cIt->more() )
5986             treeList.push_back( cIt->next() );
5987         }
5988         else if ( tree->NbNodes() ) // put a tree to the treeMap
5989         {
5990           const Bnd_B3d& box = tree->getBox();
5991           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5992           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5993           if ( !it_in.second ) // not unique distance to box center
5994             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5995         }
5996       }
5997       // find distance after which there is no sense to check tree's
5998       double sqLimit = DBL_MAX;
5999       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6000       if ( treeMap.size() > 5 ) {
6001         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6002         const Bnd_B3d& box = closestTree->getBox();
6003         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6004         sqLimit = limit * limit;
6005       }
6006       // get all nodes from trees
6007       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6008         if ( sqDist_tree->first > sqLimit )
6009           break;
6010         SMESH_OctreeNode* tree = sqDist_tree->second;
6011         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6012       }
6013     }
6014     // find closest among nodes
6015     minSqDist = DBL_MAX;
6016     const SMDS_MeshNode* closestNode = 0;
6017     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6018     for ( ; nIt != nodes.end(); ++nIt ) {
6019       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6020       if ( minSqDist > sqDist ) {
6021         closestNode = *nIt;
6022         minSqDist = sqDist;
6023       }
6024     }
6025     return closestNode;
6026   }
6027
6028   //---------------------------------------------------------------------
6029   /*!
6030    * \brief Destructor
6031    */
6032   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6033
6034   //---------------------------------------------------------------------
6035   /*!
6036    * \brief Return the node tree
6037    */
6038   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6039
6040 private:
6041   SMESH_OctreeNode* myOctreeNode;
6042   SMESHDS_Mesh*     myMesh;
6043   double            myHalfLeafSize; // max size of a leaf box
6044 };
6045
6046 //=======================================================================
6047 /*!
6048  * \brief Return SMESH_NodeSearcher
6049  */
6050 //=======================================================================
6051
6052 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6053 {
6054   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6055 }
6056
6057 // ========================================================================
6058 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6059 {
6060   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6061   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6062   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6063
6064   //=======================================================================
6065   /*!
6066    * \brief Octal tree of bounding boxes of elements
6067    */
6068   //=======================================================================
6069
6070   class ElementBndBoxTree : public SMESH_Octree
6071   {
6072   public:
6073
6074     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
6075     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6076     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6077     ~ElementBndBoxTree();
6078
6079   protected:
6080     ElementBndBoxTree() {}
6081     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6082     void buildChildrenData();
6083     Bnd_B3d* buildRootBox();
6084   private:
6085     //!< Bounding box of element
6086     struct ElementBox : public Bnd_B3d
6087     {
6088       const SMDS_MeshElement* _element;
6089       int                     _refCount; // an ElementBox can be included in several tree branches
6090       ElementBox(const SMDS_MeshElement* elem);
6091     };
6092     vector< ElementBox* > _elements;
6093   };
6094
6095   //================================================================================
6096   /*!
6097    * \brief ElementBndBoxTree creation
6098    */
6099   //================================================================================
6100
6101   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
6102     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6103   {
6104     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6105     _elements.reserve( nbElems );
6106
6107     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6108     while ( elemIt->more() )
6109       _elements.push_back( new ElementBox( elemIt->next() ));
6110
6111     if ( _elements.size() > MaxNbElemsInLeaf )
6112       compute();
6113     else
6114       myIsLeaf = true;
6115   }
6116
6117   //================================================================================
6118   /*!
6119    * \brief Destructor
6120    */
6121   //================================================================================
6122
6123   ElementBndBoxTree::~ElementBndBoxTree()
6124   {
6125     for ( int i = 0; i < _elements.size(); ++i )
6126       if ( --_elements[i]->_refCount <= 0 )
6127         delete _elements[i];
6128   }
6129
6130   //================================================================================
6131   /*!
6132    * \brief Return the maximal box
6133    */
6134   //================================================================================
6135
6136   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6137   {
6138     Bnd_B3d* box = new Bnd_B3d;
6139     for ( int i = 0; i < _elements.size(); ++i )
6140       box->Add( *_elements[i] );
6141     return box;
6142   }
6143
6144   //================================================================================
6145   /*!
6146    * \brief Redistrubute element boxes among children
6147    */
6148   //================================================================================
6149
6150   void ElementBndBoxTree::buildChildrenData()
6151   {
6152     for ( int i = 0; i < _elements.size(); ++i )
6153     {
6154       for (int j = 0; j < 8; j++)
6155       {
6156         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6157         {
6158           _elements[i]->_refCount++;
6159           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6160         }
6161       }
6162       _elements[i]->_refCount--;
6163     }
6164     _elements.clear();
6165
6166     for (int j = 0; j < 8; j++)
6167     {
6168       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6169       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6170         child->myIsLeaf = true;
6171
6172       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6173         child->_elements.resize( child->_elements.size() ); // compact
6174     }
6175   }
6176
6177   //================================================================================
6178   /*!
6179    * \brief Return elements which can include the point
6180    */
6181   //================================================================================
6182
6183   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6184                                                 TIDSortedElemSet& foundElems)
6185   {
6186     if ( level() && getBox().IsOut( point.XYZ() ))
6187       return;
6188
6189     if ( isLeaf() )
6190     {
6191       for ( int i = 0; i < _elements.size(); ++i )
6192         if ( !_elements[i]->IsOut( point.XYZ() ))
6193           foundElems.insert( _elements[i]->_element );
6194     }
6195     else
6196     {
6197       for (int i = 0; i < 8; i++)
6198         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6199     }
6200   }
6201
6202   //================================================================================
6203   /*!
6204    * \brief Return elements which can be intersected by the line
6205    */
6206   //================================================================================
6207
6208   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6209                                                TIDSortedElemSet& foundElems)
6210   {
6211     if ( level() && getBox().IsOut( line ))
6212       return;
6213
6214     if ( isLeaf() )
6215     {
6216       for ( int i = 0; i < _elements.size(); ++i )
6217         if ( !_elements[i]->IsOut( line ))
6218           foundElems.insert( _elements[i]->_element );
6219     }
6220     else
6221     {
6222       for (int i = 0; i < 8; i++)
6223         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6224     }
6225   }
6226
6227   //================================================================================
6228   /*!
6229    * \brief Construct the element box
6230    */
6231   //================================================================================
6232
6233   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
6234   {
6235     _element  = elem;
6236     _refCount = 1;
6237     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6238     while ( nIt->more() )
6239       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6240     Enlarge( NodeRadius );
6241   }
6242
6243 } // namespace
6244
6245 //=======================================================================
6246 /*!
6247  * \brief Implementation of search for the elements by point and
6248  *        of classification of point in 2D mesh
6249  */
6250 //=======================================================================
6251
6252 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6253 {
6254   SMESHDS_Mesh*                _mesh;
6255   ElementBndBoxTree*           _ebbTree;
6256   SMESH_NodeSearcherImpl*      _nodeSearcher;
6257   SMDSAbs_ElementType          _elementType;
6258   double                       _tolerance;
6259   bool                         _outerFacesFound;
6260   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6261
6262   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6263     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6264   ~SMESH_ElementSearcherImpl()
6265   {
6266     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6267     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6268   }
6269   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6270                                   SMDSAbs_ElementType                type,
6271                                   vector< const SMDS_MeshElement* >& foundElements);
6272   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6273
6274   double getTolerance();
6275   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6276                             const double tolerance, double & param);
6277   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6278   bool isOuterBoundary(const SMDS_MeshElement* face) const
6279   {
6280     return _outerFaces.empty() || _outerFaces.count(face);
6281   }
6282   struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
6283   {
6284     const SMDS_MeshElement* _face;
6285     gp_Vec                  _faceNorm;
6286     bool                    _coincides; //!< the line lays in face plane
6287     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6288       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6289   };
6290   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6291   {
6292     SMESH_TLink      _link;
6293     TIDSortedElemSet _faces;
6294     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6295       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6296   };
6297 };
6298
6299 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6300 {
6301   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6302              << ", _coincides="<<i._coincides << ")";
6303 }
6304
6305 //=======================================================================
6306 /*!
6307  * \brief define tolerance for search
6308  */
6309 //=======================================================================
6310
6311 double SMESH_ElementSearcherImpl::getTolerance()
6312 {
6313   if ( _tolerance < 0 )
6314   {
6315     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6316
6317     _tolerance = 0;
6318     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6319     {
6320       double boxSize = _nodeSearcher->getTree()->maxSize();
6321       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6322     }
6323     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6324     {
6325       double boxSize = _ebbTree->maxSize();
6326       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6327     }
6328     if ( _tolerance == 0 )
6329     {
6330       // define tolerance by size of a most complex element
6331       int complexType = SMDSAbs_Volume;
6332       while ( complexType > SMDSAbs_All &&
6333               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6334         --complexType;
6335       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6336
6337       double elemSize;
6338       if ( complexType == int( SMDSAbs_Node ))
6339       {
6340         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6341         elemSize = 1;
6342         if ( meshInfo.NbNodes() > 2 )
6343           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6344       }
6345       else
6346       {
6347         const SMDS_MeshElement* elem =
6348           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6349         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6350         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6351         while ( nodeIt->more() )
6352         {
6353           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6354           elemSize = max( dist, elemSize );
6355         }
6356       }
6357       _tolerance = 1e-6 * elemSize;
6358     }
6359   }
6360   return _tolerance;
6361 }
6362
6363 //================================================================================
6364 /*!
6365  * \brief Find intersection of the line and an edge of face and return parameter on line
6366  */
6367 //================================================================================
6368
6369 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6370                                                      const SMDS_MeshElement* face,
6371                                                      const double            tol,
6372                                                      double &                param)
6373 {
6374   int nbInts = 0;
6375   param = 0;
6376
6377   GeomAPI_ExtremaCurveCurve anExtCC;
6378   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6379   
6380   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6381   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6382   {
6383     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6384                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6385     anExtCC.Init( lineCurve, edge);
6386     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6387     {
6388       Quantity_Parameter pl, pe;
6389       anExtCC.LowerDistanceParameters( pl, pe );
6390       param += pl;
6391       if ( ++nbInts == 2 )
6392         break;
6393     }
6394   }
6395   if ( nbInts > 0 ) param /= nbInts;
6396   return nbInts > 0;
6397 }
6398 //================================================================================
6399 /*!
6400  * \brief Find all faces belonging to the outer boundary of mesh
6401  */
6402 //================================================================================
6403
6404 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6405 {
6406   if ( _outerFacesFound ) return;
6407
6408   // Collect all outer faces by passing from one outer face to another via their links
6409   // and BTW find out if there are internal faces at all.
6410
6411   // checked links and links where outer boundary meets internal one
6412   set< SMESH_TLink > visitedLinks, seamLinks;
6413
6414   // links to treat with already visited faces sharing them
6415   list < TFaceLink > startLinks;
6416
6417   // load startLinks with the first outerFace
6418   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6419   _outerFaces.insert( outerFace );
6420
6421   TIDSortedElemSet emptySet;
6422   while ( !startLinks.empty() )
6423   {
6424     const SMESH_TLink& link  = startLinks.front()._link;
6425     TIDSortedElemSet&  faces = startLinks.front()._faces;
6426
6427     outerFace = *faces.begin();
6428     // find other faces sharing the link
6429     const SMDS_MeshElement* f;
6430     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6431       faces.insert( f );
6432
6433     // select another outer face among the found 
6434     const SMDS_MeshElement* outerFace2 = 0;
6435     if ( faces.size() == 2 )
6436     {
6437       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6438     }
6439     else if ( faces.size() > 2 )
6440     {
6441       seamLinks.insert( link );
6442
6443       // link direction within the outerFace
6444       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6445                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6446       int i1 = outerFace->GetNodeIndex( link.node1() );
6447       int i2 = outerFace->GetNodeIndex( link.node2() );
6448       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6449       if ( rev ) n1n2.Reverse();
6450       // outerFace normal
6451       gp_XYZ ofNorm, fNorm;
6452       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6453       {
6454         // direction from the link inside outerFace
6455         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6456         // sort all other faces by angle with the dirInOF
6457         map< double, const SMDS_MeshElement* > angle2Face;
6458         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6459         for ( ; face != faces.end(); ++face )
6460         {
6461           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6462             continue;
6463           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6464           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6465           if ( angle < 0 ) angle += 2*PI;
6466           angle2Face.insert( make_pair( angle, *face ));
6467         }
6468         if ( !angle2Face.empty() )
6469           outerFace2 = angle2Face.begin()->second;
6470       }
6471     }
6472     // store the found outer face and add its links to continue seaching from
6473     if ( outerFace2 )
6474     {
6475       _outerFaces.insert( outerFace );
6476       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6477       for ( int i = 0; i < nbNodes; ++i )
6478       {
6479         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6480         if ( visitedLinks.insert( link2 ).second )
6481           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6482       }
6483     }
6484     startLinks.pop_front();
6485   }
6486   _outerFacesFound = true;
6487
6488   if ( !seamLinks.empty() )
6489   {
6490     // There are internal boundaries touching the outher one,
6491     // find all faces of internal boundaries in order to find
6492     // faces of boundaries of holes, if any.
6493     
6494   }
6495   else
6496   {
6497     _outerFaces.clear();
6498   }
6499 }
6500
6501 //=======================================================================
6502 /*!
6503  * \brief Find elements of given type where the given point is IN or ON.
6504  *        Returns nb of found elements and elements them-selves.
6505  *
6506  * 'ALL' type means elements of any type excluding nodes and 0D elements
6507  */
6508 //=======================================================================
6509
6510 int SMESH_ElementSearcherImpl::
6511 FindElementsByPoint(const gp_Pnt&                      point,
6512                     SMDSAbs_ElementType                type,
6513                     vector< const SMDS_MeshElement* >& foundElements)
6514 {
6515   foundElements.clear();
6516
6517   double tolerance = getTolerance();
6518
6519   // =================================================================================
6520   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6521   {
6522     if ( !_nodeSearcher )
6523       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6524
6525     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6526     if ( !closeNode ) return foundElements.size();
6527
6528     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6529       return foundElements.size(); // to far from any node
6530
6531     if ( type == SMDSAbs_Node )
6532     {
6533       foundElements.push_back( closeNode );
6534     }
6535     else
6536     {
6537       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6538       while ( elemIt->more() )
6539         foundElements.push_back( elemIt->next() );
6540     }
6541   }
6542   // =================================================================================
6543   else // elements more complex than 0D
6544   {
6545     if ( !_ebbTree || _elementType != type )
6546     {
6547       if ( _ebbTree ) delete _ebbTree;
6548       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6549     }
6550     TIDSortedElemSet suspectElems;
6551     _ebbTree->getElementsNearPoint( point, suspectElems );
6552     TIDSortedElemSet::iterator elem = suspectElems.begin();
6553     for ( ; elem != suspectElems.end(); ++elem )
6554       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6555         foundElements.push_back( *elem );
6556   }
6557   return foundElements.size();
6558 }
6559
6560 //================================================================================
6561 /*!
6562  * \brief Classify the given point in the closed 2D mesh
6563  */
6564 //================================================================================
6565
6566 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6567 {
6568   double tolerance = getTolerance();
6569   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6570   {
6571     if ( _ebbTree ) delete _ebbTree;
6572     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6573   }
6574   // Algo: analyse transition of a line starting at the point through mesh boundary;
6575   // try three lines parallel to axis of the coordinate system and perform rough
6576   // analysis. If solution is not clear perform thorough analysis.
6577
6578   const int nbAxes = 3;
6579   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6580   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6581   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6582   multimap< int, int > nbInt2Axis; // to find the simplest case
6583   for ( int axis = 0; axis < nbAxes; ++axis )
6584   {
6585     gp_Ax1 lineAxis( point, axisDir[axis]);
6586     gp_Lin line    ( lineAxis );
6587
6588     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6589     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6590
6591     // Intersect faces with the line
6592
6593     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6594     TIDSortedElemSet::iterator face = suspectFaces.begin();
6595     for ( ; face != suspectFaces.end(); ++face )
6596     {
6597       // get face plane
6598       gp_XYZ fNorm;
6599       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6600       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6601
6602       // perform intersection
6603       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6604       if ( !intersection.IsDone() )
6605         continue;
6606       if ( intersection.IsInQuadric() )
6607       {
6608         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6609       }
6610       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6611       {
6612         gp_Pnt intersectionPoint = intersection.Point(1);
6613         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6614           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6615       }
6616     }
6617     // Analyse intersections roughly
6618
6619     int nbInter = u2inters.size();
6620     if ( nbInter == 0 )
6621       return TopAbs_OUT; 
6622
6623     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6624     if ( nbInter == 1 ) // not closed mesh
6625       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6626
6627     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6628       return TopAbs_ON;
6629
6630     if ( (f<0) == (l<0) )
6631       return TopAbs_OUT;
6632
6633     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6634     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6635     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6636       return TopAbs_IN;
6637
6638     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6639
6640     if ( _outerFacesFound ) break; // pass to thorough analysis
6641
6642   } // three attempts - loop on CS axes
6643
6644   // Analyse intersections thoroughly.
6645   // We make two loops maximum, on the first one we only exclude touching intersections,
6646   // on the second, if situation is still unclear, we gather and use information on
6647   // position of faces (internal or outer). If faces position is already gathered,
6648   // we make the second loop right away.
6649
6650   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6651   {
6652     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6653     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6654     {
6655       int axis = nb_axis->second;
6656       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6657
6658       gp_Ax1 lineAxis( point, axisDir[axis]);
6659       gp_Lin line    ( lineAxis );
6660
6661       // add tangent intersections to u2inters
6662       double param;
6663       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6664       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6665         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6666           u2inters.insert(make_pair( param, *tgtInt ));
6667       tangentInters[ axis ].clear();
6668
6669       // Count intersections before and after the point excluding touching ones.
6670       // If hasPositionInfo we count intersections of outer boundary only
6671
6672       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6673       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6674       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6675       bool ok = ! u_int1->second._coincides;
6676       while ( ok && u_int1 != u2inters.end() )
6677       {
6678         double u = u_int1->first;
6679         bool touchingInt = false;
6680         if ( ++u_int2 != u2inters.end() )
6681         {
6682           // skip intersections at the same point (if the line passes through edge or node)
6683           int nbSamePnt = 0;
6684           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6685           {
6686             ++nbSamePnt;
6687             ++u_int2;
6688           }
6689
6690           // skip tangent intersections
6691           int nbTgt = 0;
6692           const SMDS_MeshElement* prevFace = u_int1->second._face;
6693           while ( ok && u_int2->second._coincides )
6694           {
6695             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6696               ok = false;
6697             else
6698             {
6699               nbTgt++;
6700               u_int2++;
6701               ok = ( u_int2 != u2inters.end() );
6702             }
6703           }
6704           if ( !ok ) break;
6705
6706           // skip intersections at the same point after tangent intersections
6707           if ( nbTgt > 0 )
6708           {
6709             double u2 = u_int2->first;
6710             ++u_int2;
6711             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6712             {
6713               ++nbSamePnt;
6714               ++u_int2;
6715             }
6716           }
6717           // decide if we skipped a touching intersection
6718           if ( nbSamePnt + nbTgt > 0 )
6719           {
6720             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6721             map< double, TInters >::iterator u_int = u_int1;
6722             for ( ; u_int != u_int2; ++u_int )
6723             {
6724               if ( u_int->second._coincides ) continue;
6725               double dot = u_int->second._faceNorm * line.Direction();
6726               if ( dot > maxDot ) maxDot = dot;
6727               if ( dot < minDot ) minDot = dot;
6728             }
6729             touchingInt = ( minDot*maxDot < 0 );
6730           }
6731         }
6732         if ( !touchingInt )
6733         {
6734           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6735           {
6736             if ( u < 0 )
6737               ++nbIntBeforePoint;
6738             else
6739               ++nbIntAfterPoint;
6740           }
6741           if ( u < f ) f = u;
6742           if ( u > l ) l = u;
6743         }
6744
6745         u_int1 = u_int2; // to next intersection
6746
6747       } // loop on intersections with one line
6748
6749       if ( ok )
6750       {
6751         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6752           return TopAbs_ON;
6753
6754         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6755           return TopAbs_OUT; 
6756
6757         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6758           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6759
6760         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6761           return TopAbs_IN;
6762
6763         if ( (f<0) == (l<0) )
6764           return TopAbs_OUT;
6765
6766         if ( hasPositionInfo )
6767           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6768       }
6769     } // loop on intersections of the tree lines - thorough analysis
6770
6771     if ( !hasPositionInfo )
6772     {
6773       // gather info on faces position - is face in the outer boundary or not
6774       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6775       findOuterBoundary( u2inters.begin()->second._face );
6776     }
6777
6778   } // two attempts - with and w/o faces position info in the mesh
6779
6780   return TopAbs_UNKNOWN;
6781 }
6782
6783 //=======================================================================
6784 /*!
6785  * \brief Return SMESH_ElementSearcher
6786  */
6787 //=======================================================================
6788
6789 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6790 {
6791   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6792 }
6793
6794 //=======================================================================
6795 /*!
6796  * \brief Return true if the point is IN or ON of the element
6797  */
6798 //=======================================================================
6799
6800 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6801 {
6802   if ( element->GetType() == SMDSAbs_Volume)
6803   {
6804     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6805   }
6806
6807   // get ordered nodes
6808
6809   vector< gp_XYZ > xyz;
6810
6811   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6812   if ( element->IsQuadratic() )
6813     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6814       nodeIt = f->interlacedNodesElemIterator();
6815     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6816       nodeIt = e->interlacedNodesElemIterator();
6817
6818   while ( nodeIt->more() )
6819     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6820
6821   int i, nbNodes = element->NbNodes();
6822
6823   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6824   {
6825     // compute face normal
6826     gp_Vec faceNorm(0,0,0);
6827     xyz.push_back( xyz.front() );
6828     for ( i = 0; i < nbNodes; ++i )
6829     {
6830       gp_Vec edge1( xyz[i+1], xyz[i]);
6831       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6832       faceNorm += edge1 ^ edge2;
6833     }
6834     double normSize = faceNorm.Magnitude();
6835     if ( normSize <= tol )
6836     {
6837       // degenerated face: point is out if it is out of all face edges
6838       for ( i = 0; i < nbNodes; ++i )
6839       {
6840         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6841         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6842         SMDS_MeshEdge edge( &n1, &n2 );
6843         if ( !isOut( &edge, point, tol ))
6844           return false;
6845       }
6846       return true;
6847     }
6848     faceNorm /= normSize;
6849
6850     // check if the point lays on face plane
6851     gp_Vec n2p( xyz[0], point );
6852     if ( fabs( n2p * faceNorm ) > tol )
6853       return true; // not on face plane
6854
6855     // check if point is out of face boundary:
6856     // define it by closest transition of a ray point->infinity through face boundary
6857     // on the face plane.
6858     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6859     // to find intersections of the ray with the boundary.
6860     gp_Vec ray = n2p;
6861     gp_Vec plnNorm = ray ^ faceNorm;
6862     normSize = plnNorm.Magnitude();
6863     if ( normSize <= tol ) return false; // point coincides with the first node
6864     plnNorm /= normSize;
6865     // for each node of the face, compute its signed distance to the plane
6866     vector<double> dist( nbNodes + 1);
6867     for ( i = 0; i < nbNodes; ++i )
6868     {
6869       gp_Vec n2p( xyz[i], point );
6870       dist[i] = n2p * plnNorm;
6871     }
6872     dist.back() = dist.front();
6873     // find the closest intersection
6874     int    iClosest = -1;
6875     double rClosest, distClosest = 1e100;;
6876     gp_Pnt pClosest;
6877     for ( i = 0; i < nbNodes; ++i )
6878     {
6879       double r;
6880       if ( fabs( dist[i]) < tol )
6881         r = 0.;
6882       else if ( fabs( dist[i+1]) < tol )
6883         r = 1.;
6884       else if ( dist[i] * dist[i+1] < 0 )
6885         r = dist[i] / ( dist[i] - dist[i+1] );
6886       else
6887         continue; // no intersection
6888       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6889       gp_Vec p2int ( point, pInt);
6890       if ( p2int * ray > -tol ) // right half-space
6891       {
6892         double intDist = p2int.SquareMagnitude();
6893         if ( intDist < distClosest )
6894         {
6895           iClosest = i;
6896           rClosest = r;
6897           pClosest = pInt;
6898           distClosest = intDist;
6899         }
6900       }
6901     }
6902     if ( iClosest < 0 )
6903       return true; // no intesections - out
6904
6905     // analyse transition
6906     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6907     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6908     gp_Vec p2int ( point, pClosest );
6909     bool out = (edgeNorm * p2int) < -tol;
6910     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6911       return out;
6912
6913     // ray pass through a face node; analyze transition through an adjacent edge
6914     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6915     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6916     gp_Vec edgeAdjacent( p1, p2 );
6917     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6918     bool out2 = (edgeNorm2 * p2int) < -tol;
6919
6920     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6921     return covexCorner ? (out || out2) : (out && out2);
6922   }
6923   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6924   {
6925     // point is out of edge if it is NOT ON any straight part of edge
6926     // (we consider quadratic edge as being composed of two straight parts)
6927     for ( i = 1; i < nbNodes; ++i )
6928     {
6929       gp_Vec edge( xyz[i-1], xyz[i]);
6930       gp_Vec n1p ( xyz[i-1], point);
6931       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6932       if ( dist > tol )
6933         continue;
6934       gp_Vec n2p( xyz[i], point );
6935       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6936         continue;
6937       return false; // point is ON this part
6938     }
6939     return true;
6940   }
6941   // Node or 0D element -------------------------------------------------------------------------
6942   {
6943     gp_Vec n2p ( xyz[0], point );
6944     return n2p.Magnitude() <= tol;
6945   }
6946   return true;
6947 }
6948
6949 //=======================================================================
6950 //function : SimplifyFace
6951 //purpose  :
6952 //=======================================================================
6953 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6954                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6955                                     vector<int>&                        quantities) const
6956 {
6957   int nbNodes = faceNodes.size();
6958
6959   if (nbNodes < 3)
6960     return 0;
6961
6962   set<const SMDS_MeshNode*> nodeSet;
6963
6964   // get simple seq of nodes
6965   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6966   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6967   int iSimple = 0, nbUnique = 0;
6968
6969   simpleNodes[iSimple++] = faceNodes[0];
6970   nbUnique++;
6971   for (int iCur = 1; iCur < nbNodes; iCur++) {
6972     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6973       simpleNodes[iSimple++] = faceNodes[iCur];
6974       if (nodeSet.insert( faceNodes[iCur] ).second)
6975         nbUnique++;
6976     }
6977   }
6978   int nbSimple = iSimple;
6979   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6980     nbSimple--;
6981     iSimple--;
6982   }
6983
6984   if (nbUnique < 3)
6985     return 0;
6986
6987   // separate loops
6988   int nbNew = 0;
6989   bool foundLoop = (nbSimple > nbUnique);
6990   while (foundLoop) {
6991     foundLoop = false;
6992     set<const SMDS_MeshNode*> loopSet;
6993     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6994       const SMDS_MeshNode* n = simpleNodes[iSimple];
6995       if (!loopSet.insert( n ).second) {
6996         foundLoop = true;
6997
6998         // separate loop
6999         int iC = 0, curLast = iSimple;
7000         for (; iC < curLast; iC++) {
7001           if (simpleNodes[iC] == n) break;
7002         }
7003         int loopLen = curLast - iC;
7004         if (loopLen > 2) {
7005           // create sub-element
7006           nbNew++;
7007           quantities.push_back(loopLen);
7008           for (; iC < curLast; iC++) {
7009             poly_nodes.push_back(simpleNodes[iC]);
7010           }
7011         }
7012         // shift the rest nodes (place from the first loop position)
7013         for (iC = curLast + 1; iC < nbSimple; iC++) {
7014           simpleNodes[iC - loopLen] = simpleNodes[iC];
7015         }
7016         nbSimple -= loopLen;
7017         iSimple -= loopLen;
7018       }
7019     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7020   } // while (foundLoop)
7021
7022   if (iSimple > 2) {
7023     nbNew++;
7024     quantities.push_back(iSimple);
7025     for (int i = 0; i < iSimple; i++)
7026       poly_nodes.push_back(simpleNodes[i]);
7027   }
7028
7029   return nbNew;
7030 }
7031
7032 //=======================================================================
7033 //function : MergeNodes
7034 //purpose  : In each group, the cdr of nodes are substituted by the first one
7035 //           in all elements.
7036 //=======================================================================
7037
7038 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7039 {
7040   myLastCreatedElems.Clear();
7041   myLastCreatedNodes.Clear();
7042
7043   SMESHDS_Mesh* aMesh = GetMeshDS();
7044
7045   TNodeNodeMap nodeNodeMap; // node to replace - new node
7046   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7047   list< int > rmElemIds, rmNodeIds;
7048
7049   // Fill nodeNodeMap and elems
7050
7051   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7052   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7053     list<const SMDS_MeshNode*>& nodes = *grIt;
7054     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7055     const SMDS_MeshNode* nToKeep = *nIt;
7056     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7057       const SMDS_MeshNode* nToRemove = *nIt;
7058       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7059       if ( nToRemove != nToKeep ) {
7060         rmNodeIds.push_back( nToRemove->GetID() );
7061         AddToSameGroups( nToKeep, nToRemove, aMesh );
7062       }
7063
7064       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7065       while ( invElemIt->more() ) {
7066         const SMDS_MeshElement* elem = invElemIt->next();
7067         elems.insert(elem);
7068       }
7069     }
7070   }
7071   // Change element nodes or remove an element
7072
7073   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7074   for ( ; eIt != elems.end(); eIt++ ) {
7075     const SMDS_MeshElement* elem = *eIt;
7076     int nbNodes = elem->NbNodes();
7077     int aShapeId = FindShape( elem );
7078
7079     set<const SMDS_MeshNode*> nodeSet;
7080     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7081     int iUnique = 0, iCur = 0, nbRepl = 0;
7082     vector<int> iRepl( nbNodes );
7083
7084     // get new seq of nodes
7085     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7086     while ( itN->more() ) {
7087       const SMDS_MeshNode* n =
7088         static_cast<const SMDS_MeshNode*>( itN->next() );
7089
7090       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7091       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7092         n = (*nnIt).second;
7093         // BUG 0020185: begin
7094         {
7095           bool stopRecur = false;
7096           set<const SMDS_MeshNode*> nodesRecur;
7097           nodesRecur.insert(n);
7098           while (!stopRecur) {
7099             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7100             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7101               n = (*nnIt_i).second;
7102               if (!nodesRecur.insert(n).second) {
7103                 // error: recursive dependancy
7104                 stopRecur = true;
7105               }
7106             }
7107             else
7108               stopRecur = true;
7109           }
7110         }
7111         // BUG 0020185: end
7112         iRepl[ nbRepl++ ] = iCur;
7113       }
7114       curNodes[ iCur ] = n;
7115       bool isUnique = nodeSet.insert( n ).second;
7116       if ( isUnique )
7117         uniqueNodes[ iUnique++ ] = n;
7118       iCur++;
7119     }
7120
7121     // Analyse element topology after replacement
7122
7123     bool isOk = true;
7124     int nbUniqueNodes = nodeSet.size();
7125     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7126       // Polygons and Polyhedral volumes
7127       if (elem->IsPoly()) {
7128
7129         if (elem->GetType() == SMDSAbs_Face) {
7130           // Polygon
7131           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7132           int inode = 0;
7133           for (; inode < nbNodes; inode++) {
7134             face_nodes[inode] = curNodes[inode];
7135           }
7136
7137           vector<const SMDS_MeshNode *> polygons_nodes;
7138           vector<int> quantities;
7139           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7140
7141           if (nbNew > 0) {
7142             inode = 0;
7143             for (int iface = 0; iface < nbNew - 1; iface++) {
7144               int nbNodes = quantities[iface];
7145               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7146               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7147                 poly_nodes[ii] = polygons_nodes[inode];
7148               }
7149               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7150               myLastCreatedElems.Append(newElem);
7151               if (aShapeId)
7152                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7153             }
7154             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7155           }
7156           else {
7157             rmElemIds.push_back(elem->GetID());
7158           }
7159
7160         }
7161         else if (elem->GetType() == SMDSAbs_Volume) {
7162           // Polyhedral volume
7163           if (nbUniqueNodes < 4) {
7164             rmElemIds.push_back(elem->GetID());
7165           }
7166           else {
7167             // each face has to be analized in order to check volume validity
7168             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7169               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7170             if (aPolyedre) {
7171               int nbFaces = aPolyedre->NbFaces();
7172
7173               vector<const SMDS_MeshNode *> poly_nodes;
7174               vector<int> quantities;
7175
7176               for (int iface = 1; iface <= nbFaces; iface++) {
7177                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7178                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7179
7180                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7181                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7182                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7183                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7184                     faceNode = (*nnIt).second;
7185                   }
7186                   faceNodes[inode - 1] = faceNode;
7187                 }
7188
7189                 SimplifyFace(faceNodes, poly_nodes, quantities);
7190               }
7191
7192               if (quantities.size() > 3) {
7193                 // to be done: remove coincident faces
7194               }
7195
7196               if (quantities.size() > 3)
7197                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7198               else
7199                 rmElemIds.push_back(elem->GetID());
7200
7201             }
7202             else {
7203               rmElemIds.push_back(elem->GetID());
7204             }
7205           }
7206         }
7207         else {
7208         }
7209
7210         continue;
7211       }
7212
7213       // Regular elements
7214       switch ( nbNodes ) {
7215       case 2: ///////////////////////////////////// EDGE
7216         isOk = false; break;
7217       case 3: ///////////////////////////////////// TRIANGLE
7218         isOk = false; break;
7219       case 4:
7220         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7221           isOk = false;
7222         else { //////////////////////////////////// QUADRANGLE
7223           if ( nbUniqueNodes < 3 )
7224             isOk = false;
7225           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7226             isOk = false; // opposite nodes stick
7227         }
7228         break;
7229       case 6: ///////////////////////////////////// PENTAHEDRON
7230         if ( nbUniqueNodes == 4 ) {
7231           // ---------------------------------> tetrahedron
7232           if (nbRepl == 3 &&
7233               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7234             // all top nodes stick: reverse a bottom
7235             uniqueNodes[ 0 ] = curNodes [ 1 ];
7236             uniqueNodes[ 1 ] = curNodes [ 0 ];
7237           }
7238           else if (nbRepl == 3 &&
7239                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7240             // all bottom nodes stick: set a top before
7241             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7242             uniqueNodes[ 0 ] = curNodes [ 3 ];
7243             uniqueNodes[ 1 ] = curNodes [ 4 ];
7244             uniqueNodes[ 2 ] = curNodes [ 5 ];
7245           }
7246           else if (nbRepl == 4 &&
7247                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7248             // a lateral face turns into a line: reverse a bottom
7249             uniqueNodes[ 0 ] = curNodes [ 1 ];
7250             uniqueNodes[ 1 ] = curNodes [ 0 ];
7251           }
7252           else
7253             isOk = false;
7254         }
7255         else if ( nbUniqueNodes == 5 ) {
7256           // PENTAHEDRON --------------------> 2 tetrahedrons
7257           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7258             // a bottom node sticks with a linked top one
7259             // 1.
7260             SMDS_MeshElement* newElem =
7261               aMesh->AddVolume(curNodes[ 3 ],
7262                                curNodes[ 4 ],
7263                                curNodes[ 5 ],
7264                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7265             myLastCreatedElems.Append(newElem);
7266             if ( aShapeId )
7267               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7268             // 2. : reverse a bottom
7269             uniqueNodes[ 0 ] = curNodes [ 1 ];
7270             uniqueNodes[ 1 ] = curNodes [ 0 ];
7271             nbUniqueNodes = 4;
7272           }
7273           else
7274             isOk = false;
7275         }
7276         else
7277           isOk = false;
7278         break;
7279       case 8: {
7280         if(elem->IsQuadratic()) { // Quadratic quadrangle
7281           //   1    5    2
7282           //    +---+---+
7283           //    |       |
7284           //    |       |
7285           //   4+       +6
7286           //    |       |
7287           //    |       |
7288           //    +---+---+
7289           //   0    7    3
7290           isOk = false;
7291           if(nbRepl==3) {
7292             nbUniqueNodes = 6;
7293             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7294               uniqueNodes[0] = curNodes[0];
7295               uniqueNodes[1] = curNodes[2];
7296               uniqueNodes[2] = curNodes[3];
7297               uniqueNodes[3] = curNodes[5];
7298               uniqueNodes[4] = curNodes[6];
7299               uniqueNodes[5] = curNodes[7];
7300               isOk = true;
7301             }
7302             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7303               uniqueNodes[0] = curNodes[0];
7304               uniqueNodes[1] = curNodes[1];
7305               uniqueNodes[2] = curNodes[2];
7306               uniqueNodes[3] = curNodes[4];
7307               uniqueNodes[4] = curNodes[5];
7308               uniqueNodes[5] = curNodes[6];
7309               isOk = true;
7310             }
7311             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7312               uniqueNodes[0] = curNodes[1];
7313               uniqueNodes[1] = curNodes[2];
7314               uniqueNodes[2] = curNodes[3];
7315               uniqueNodes[3] = curNodes[5];
7316               uniqueNodes[4] = curNodes[6];
7317               uniqueNodes[5] = curNodes[0];
7318               isOk = true;
7319             }
7320             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7321               uniqueNodes[0] = curNodes[0];
7322               uniqueNodes[1] = curNodes[1];
7323               uniqueNodes[2] = curNodes[3];
7324               uniqueNodes[3] = curNodes[4];
7325               uniqueNodes[4] = curNodes[6];
7326               uniqueNodes[5] = curNodes[7];
7327               isOk = true;
7328             }
7329             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7330               uniqueNodes[0] = curNodes[0];
7331               uniqueNodes[1] = curNodes[2];
7332               uniqueNodes[2] = curNodes[3];
7333               uniqueNodes[3] = curNodes[1];
7334               uniqueNodes[4] = curNodes[6];
7335               uniqueNodes[5] = curNodes[7];
7336               isOk = true;
7337             }
7338             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7339               uniqueNodes[0] = curNodes[0];
7340               uniqueNodes[1] = curNodes[1];
7341               uniqueNodes[2] = curNodes[2];
7342               uniqueNodes[3] = curNodes[4];
7343               uniqueNodes[4] = curNodes[5];
7344               uniqueNodes[5] = curNodes[7];
7345               isOk = true;
7346             }
7347             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7348               uniqueNodes[0] = curNodes[0];
7349               uniqueNodes[1] = curNodes[1];
7350               uniqueNodes[2] = curNodes[3];
7351               uniqueNodes[3] = curNodes[4];
7352               uniqueNodes[4] = curNodes[2];
7353               uniqueNodes[5] = curNodes[7];
7354               isOk = true;
7355             }
7356             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7357               uniqueNodes[0] = curNodes[0];
7358               uniqueNodes[1] = curNodes[1];
7359               uniqueNodes[2] = curNodes[2];
7360               uniqueNodes[3] = curNodes[4];
7361               uniqueNodes[4] = curNodes[5];
7362               uniqueNodes[5] = curNodes[3];
7363               isOk = true;
7364             }
7365           }
7366           break;
7367         }
7368         //////////////////////////////////// HEXAHEDRON
7369         isOk = false;
7370         SMDS_VolumeTool hexa (elem);
7371         hexa.SetExternalNormal();
7372         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7373           //////////////////////// ---> tetrahedron
7374           for ( int iFace = 0; iFace < 6; iFace++ ) {
7375             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7376             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7377                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7378                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7379               // one face turns into a point ...
7380               int iOppFace = hexa.GetOppFaceIndex( iFace );
7381               ind = hexa.GetFaceNodesIndices( iOppFace );
7382               int nbStick = 0;
7383               iUnique = 2; // reverse a tetrahedron bottom
7384               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7385                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7386                   nbStick++;
7387                 else if ( iUnique >= 0 )
7388                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7389               }
7390               if ( nbStick == 1 ) {
7391                 // ... and the opposite one - into a triangle.
7392                 // set a top node
7393                 ind = hexa.GetFaceNodesIndices( iFace );
7394                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7395                 isOk = true;
7396               }
7397               break;
7398             }
7399           }
7400         }
7401         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7402           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7403           for ( int iFace = 0; iFace < 6; iFace++ ) {
7404             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7405             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7406                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7407                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7408               // one face turns into a point ...
7409               int iOppFace = hexa.GetOppFaceIndex( iFace );
7410               ind = hexa.GetFaceNodesIndices( iOppFace );
7411               int nbStick = 0;
7412               iUnique = 2;  // reverse a tetrahedron 1 bottom
7413               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7414                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7415                   nbStick++;
7416                 else if ( iUnique >= 0 )
7417                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7418               }
7419               if ( nbStick == 0 ) {
7420                 // ... and the opposite one is a quadrangle
7421                 // set a top node
7422                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7423                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7424                 nbUniqueNodes = 4;
7425                 // tetrahedron 2
7426                 SMDS_MeshElement* newElem =
7427                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7428                                    curNodes[ind[ 3 ]],
7429                                    curNodes[ind[ 2 ]],
7430                                    curNodes[indTop[ 0 ]]);
7431                 myLastCreatedElems.Append(newElem);
7432                 if ( aShapeId )
7433                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7434                 isOk = true;
7435               }
7436               break;
7437             }
7438           }
7439         }
7440         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7441           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7442           // find indices of quad and tri faces
7443           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7444           for ( iFace = 0; iFace < 6; iFace++ ) {
7445             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7446             nodeSet.clear();
7447             for ( iCur = 0; iCur < 4; iCur++ )
7448               nodeSet.insert( curNodes[ind[ iCur ]] );
7449             nbUniqueNodes = nodeSet.size();
7450             if ( nbUniqueNodes == 3 )
7451               iTriFace[ nbTri++ ] = iFace;
7452             else if ( nbUniqueNodes == 4 )
7453               iQuadFace[ nbQuad++ ] = iFace;
7454           }
7455           if (nbQuad == 2 && nbTri == 4 &&
7456               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7457             // 2 opposite quadrangles stuck with a diagonal;
7458             // sample groups of merged indices: (0-4)(2-6)
7459             // --------------------------------------------> 2 tetrahedrons
7460             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7461             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7462             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7463             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7464                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7465               // stuck with 0-2 diagonal
7466               i0  = ind1[ 3 ];
7467               i1d = ind1[ 0 ];
7468               i2  = ind1[ 1 ];
7469               i3d = ind1[ 2 ];
7470               i0t = ind2[ 1 ];
7471               i2t = ind2[ 3 ];
7472             }
7473             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7474                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7475               // stuck with 1-3 diagonal
7476               i0  = ind1[ 0 ];
7477               i1d = ind1[ 1 ];
7478               i2  = ind1[ 2 ];
7479               i3d = ind1[ 3 ];
7480               i0t = ind2[ 0 ];
7481               i2t = ind2[ 1 ];
7482             }
7483             else {
7484               ASSERT(0);
7485             }
7486             // tetrahedron 1
7487             uniqueNodes[ 0 ] = curNodes [ i0 ];
7488             uniqueNodes[ 1 ] = curNodes [ i1d ];
7489             uniqueNodes[ 2 ] = curNodes [ i3d ];
7490             uniqueNodes[ 3 ] = curNodes [ i0t ];
7491             nbUniqueNodes = 4;
7492             // tetrahedron 2
7493             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7494                                                          curNodes[ i2 ],
7495                                                          curNodes[ i3d ],
7496                                                          curNodes[ i2t ]);
7497             myLastCreatedElems.Append(newElem);
7498             if ( aShapeId )
7499               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7500             isOk = true;
7501           }
7502           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7503                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7504             // --------------------------------------------> prism
7505             // find 2 opposite triangles
7506             nbUniqueNodes = 6;
7507             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7508               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7509                 // find indices of kept and replaced nodes
7510                 // and fill unique nodes of 2 opposite triangles
7511                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7512                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7513                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7514                 // fill unique nodes
7515                 iUnique = 0;
7516                 isOk = true;
7517                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7518                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7519                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7520                   if ( n == nInit ) {
7521                     // iCur of a linked node of the opposite face (make normals co-directed):
7522                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7523                     // check that correspondent corners of triangles are linked
7524                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7525                       isOk = false;
7526                     else {
7527                       uniqueNodes[ iUnique ] = n;
7528                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7529                       iUnique++;
7530                     }
7531                   }
7532                 }
7533                 break;
7534               }
7535             }
7536           }
7537         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7538         break;
7539       } // HEXAHEDRON
7540
7541       default:
7542         isOk = false;
7543       } // switch ( nbNodes )
7544
7545     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7546
7547     if ( isOk ) {
7548       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7549         // Change nodes of polyedre
7550         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7551           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7552         if (aPolyedre) {
7553           int nbFaces = aPolyedre->NbFaces();
7554
7555           vector<const SMDS_MeshNode *> poly_nodes;
7556           vector<int> quantities (nbFaces);
7557
7558           for (int iface = 1; iface <= nbFaces; iface++) {
7559             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7560             quantities[iface - 1] = nbFaceNodes;
7561
7562             for (inode = 1; inode <= nbFaceNodes; inode++) {
7563               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7564
7565               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7566               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7567                 curNode = (*nnIt).second;
7568               }
7569               poly_nodes.push_back(curNode);
7570             }
7571           }
7572           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7573         }
7574       }
7575       else {
7576         // Change regular element or polygon
7577         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7578       }
7579     }
7580     else {
7581       // Remove invalid regular element or invalid polygon
7582       rmElemIds.push_back( elem->GetID() );
7583     }
7584
7585   } // loop on elements
7586
7587   // Remove equal nodes and bad elements
7588
7589   Remove( rmNodeIds, true );
7590   Remove( rmElemIds, false );
7591
7592 }
7593
7594
7595 // ========================================================
7596 // class   : SortableElement
7597 // purpose : allow sorting elements basing on their nodes
7598 // ========================================================
7599 class SortableElement : public set <const SMDS_MeshElement*>
7600 {
7601 public:
7602
7603   SortableElement( const SMDS_MeshElement* theElem )
7604   {
7605     myElem = theElem;
7606     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7607     while ( nodeIt->more() )
7608       this->insert( nodeIt->next() );
7609   }
7610
7611   const SMDS_MeshElement* Get() const
7612   { return myElem; }
7613
7614   void Set(const SMDS_MeshElement* e) const
7615   { myElem = e; }
7616
7617
7618 private:
7619   mutable const SMDS_MeshElement* myElem;
7620 };
7621
7622 //=======================================================================
7623 //function : FindEqualElements
7624 //purpose  : Return list of group of elements built on the same nodes.
7625 //           Search among theElements or in the whole mesh if theElements is empty
7626 //=======================================================================
7627 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7628                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7629 {
7630   myLastCreatedElems.Clear();
7631   myLastCreatedNodes.Clear();
7632
7633   typedef set<const SMDS_MeshElement*> TElemsSet;
7634   typedef map< SortableElement, int > TMapOfNodeSet;
7635   typedef list<int> TGroupOfElems;
7636
7637   TElemsSet elems;
7638   if ( theElements.empty() )
7639   { // get all elements in the mesh
7640     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7641     while ( eIt->more() )
7642       elems.insert( elems.end(), eIt->next());
7643   }
7644   else
7645     elems = theElements;
7646
7647   vector< TGroupOfElems > arrayOfGroups;
7648   TGroupOfElems groupOfElems;
7649   TMapOfNodeSet mapOfNodeSet;
7650
7651   TElemsSet::iterator elemIt = elems.begin();
7652   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7653     const SMDS_MeshElement* curElem = *elemIt;
7654     SortableElement SE(curElem);
7655     int ind = -1;
7656     // check uniqueness
7657     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7658     if( !(pp.second) ) {
7659       TMapOfNodeSet::iterator& itSE = pp.first;
7660       ind = (*itSE).second;
7661       arrayOfGroups[ind].push_back(curElem->GetID());
7662     }
7663     else {
7664       groupOfElems.clear();
7665       groupOfElems.push_back(curElem->GetID());
7666       arrayOfGroups.push_back(groupOfElems);
7667       i++;
7668     }
7669   }
7670
7671   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7672   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7673     groupOfElems = *groupIt;
7674     if ( groupOfElems.size() > 1 ) {
7675       groupOfElems.sort();
7676       theGroupsOfElementsID.push_back(groupOfElems);
7677     }
7678   }
7679 }
7680
7681 //=======================================================================
7682 //function : MergeElements
7683 //purpose  : In each given group, substitute all elements by the first one.
7684 //=======================================================================
7685
7686 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7687 {
7688   myLastCreatedElems.Clear();
7689   myLastCreatedNodes.Clear();
7690
7691   typedef list<int> TListOfIDs;
7692   TListOfIDs rmElemIds; // IDs of elems to remove
7693
7694   SMESHDS_Mesh* aMesh = GetMeshDS();
7695
7696   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7697   while ( groupsIt != theGroupsOfElementsID.end() ) {
7698     TListOfIDs& aGroupOfElemID = *groupsIt;
7699     aGroupOfElemID.sort();
7700     int elemIDToKeep = aGroupOfElemID.front();
7701     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7702     aGroupOfElemID.pop_front();
7703     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7704     while ( idIt != aGroupOfElemID.end() ) {
7705       int elemIDToRemove = *idIt;
7706       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7707       // add the kept element in groups of removed one (PAL15188)
7708       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7709       rmElemIds.push_back( elemIDToRemove );
7710       ++idIt;
7711     }
7712     ++groupsIt;
7713   }
7714
7715   Remove( rmElemIds, false );
7716 }
7717
7718 //=======================================================================
7719 //function : MergeEqualElements
7720 //purpose  : Remove all but one of elements built on the same nodes.
7721 //=======================================================================
7722
7723 void SMESH_MeshEditor::MergeEqualElements()
7724 {
7725   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7726                                                  to merge equal elements in the whole mesh */
7727   TListOfListOfElementsID aGroupsOfElementsID;
7728   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7729   MergeElements(aGroupsOfElementsID);
7730 }
7731
7732 //=======================================================================
7733 //function : FindFaceInSet
7734 //purpose  : Return a face having linked nodes n1 and n2 and which is
7735 //           - not in avoidSet,
7736 //           - in elemSet provided that !elemSet.empty()
7737 //           i1 and i2 optionally returns indices of n1 and n2
7738 //=======================================================================
7739
7740 const SMDS_MeshElement*
7741 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7742                                 const SMDS_MeshNode*    n2,
7743                                 const TIDSortedElemSet& elemSet,
7744                                 const TIDSortedElemSet& avoidSet,
7745                                 int*                    n1ind,
7746                                 int*                    n2ind)
7747
7748 {
7749   int i1, i2;
7750   const SMDS_MeshElement* face = 0;
7751
7752   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7753   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7754   {
7755     const SMDS_MeshElement* elem = invElemIt->next();
7756     if (avoidSet.count( elem ))
7757       continue;
7758     if ( !elemSet.empty() && !elemSet.count( elem ))
7759       continue;
7760     // index of n1
7761     i1 = elem->GetNodeIndex( n1 );
7762     // find a n2 linked to n1
7763     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7764     for ( int di = -1; di < 2 && !face; di += 2 )
7765     {
7766       i2 = (i1+di+nbN) % nbN;
7767       if ( elem->GetNode( i2 ) == n2 )
7768         face = elem;
7769     }
7770     if ( !face && elem->IsQuadratic())
7771     {
7772       // analysis for quadratic elements using all nodes
7773       const SMDS_QuadraticFaceOfNodes* F =
7774         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7775       // use special nodes iterator
7776       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7777       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7778       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7779       {
7780         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7781         if ( n1 == prevN && n2 == n )
7782         {
7783           face = elem;
7784         }
7785         else if ( n2 == prevN && n1 == n )
7786         {
7787           face = elem; swap( i1, i2 );
7788         }
7789         prevN = n;
7790       }
7791     }
7792   }
7793   if ( n1ind ) *n1ind = i1;
7794   if ( n2ind ) *n2ind = i2;
7795   return face;
7796 }
7797
7798 //=======================================================================
7799 //function : findAdjacentFace
7800 //purpose  :
7801 //=======================================================================
7802
7803 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7804                                                 const SMDS_MeshNode* n2,
7805                                                 const SMDS_MeshElement* elem)
7806 {
7807   TIDSortedElemSet elemSet, avoidSet;
7808   if ( elem )
7809     avoidSet.insert ( elem );
7810   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7811 }
7812
7813 //=======================================================================
7814 //function : FindFreeBorder
7815 //purpose  :
7816 //=======================================================================
7817
7818 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7819
7820 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7821                                        const SMDS_MeshNode*             theSecondNode,
7822                                        const SMDS_MeshNode*             theLastNode,
7823                                        list< const SMDS_MeshNode* > &   theNodes,
7824                                        list< const SMDS_MeshElement* >& theFaces)
7825 {
7826   if ( !theFirstNode || !theSecondNode )
7827     return false;
7828   // find border face between theFirstNode and theSecondNode
7829   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7830   if ( !curElem )
7831     return false;
7832
7833   theFaces.push_back( curElem );
7834   theNodes.push_back( theFirstNode );
7835   theNodes.push_back( theSecondNode );
7836
7837   //vector<const SMDS_MeshNode*> nodes;
7838   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7839   TIDSortedElemSet foundElems;
7840   bool needTheLast = ( theLastNode != 0 );
7841
7842   while ( nStart != theLastNode ) {
7843     if ( nStart == theFirstNode )
7844       return !needTheLast;
7845
7846     // find all free border faces sharing form nStart
7847
7848     list< const SMDS_MeshElement* > curElemList;
7849     list< const SMDS_MeshNode* > nStartList;
7850     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7851     while ( invElemIt->more() ) {
7852       const SMDS_MeshElement* e = invElemIt->next();
7853       if ( e == curElem || foundElems.insert( e ).second ) {
7854         // get nodes
7855         int iNode = 0, nbNodes = e->NbNodes();
7856         //const SMDS_MeshNode* nodes[nbNodes+1];
7857         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7858
7859         if(e->IsQuadratic()) {
7860           const SMDS_QuadraticFaceOfNodes* F =
7861             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7862           // use special nodes iterator
7863           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7864           while( anIter->more() ) {
7865             nodes[ iNode++ ] = anIter->next();
7866           }
7867         }
7868         else {
7869           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7870           while ( nIt->more() )
7871             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7872         }
7873         nodes[ iNode ] = nodes[ 0 ];
7874         // check 2 links
7875         for ( iNode = 0; iNode < nbNodes; iNode++ )
7876           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7877                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7878               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7879           {
7880             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7881             curElemList.push_back( e );
7882           }
7883       }
7884     }
7885     // analyse the found
7886
7887     int nbNewBorders = curElemList.size();
7888     if ( nbNewBorders == 0 ) {
7889       // no free border furthermore
7890       return !needTheLast;
7891     }
7892     else if ( nbNewBorders == 1 ) {
7893       // one more element found
7894       nIgnore = nStart;
7895       nStart = nStartList.front();
7896       curElem = curElemList.front();
7897       theFaces.push_back( curElem );
7898       theNodes.push_back( nStart );
7899     }
7900     else {
7901       // several continuations found
7902       list< const SMDS_MeshElement* >::iterator curElemIt;
7903       list< const SMDS_MeshNode* >::iterator nStartIt;
7904       // check if one of them reached the last node
7905       if ( needTheLast ) {
7906         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7907              curElemIt!= curElemList.end();
7908              curElemIt++, nStartIt++ )
7909           if ( *nStartIt == theLastNode ) {
7910             theFaces.push_back( *curElemIt );
7911             theNodes.push_back( *nStartIt );
7912             return true;
7913           }
7914       }
7915       // find the best free border by the continuations
7916       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7917       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7918       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7919            curElemIt!= curElemList.end();
7920            curElemIt++, nStartIt++ )
7921       {
7922         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7923         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7924         // find one more free border
7925         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7926           cNL->clear();
7927           cFL->clear();
7928         }
7929         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7930           // choice: clear a worse one
7931           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7932           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7933           contNodes[ iWorse ].clear();
7934           contFaces[ iWorse ].clear();
7935         }
7936       }
7937       if ( contNodes[0].empty() && contNodes[1].empty() )
7938         return false;
7939
7940       // append the best free border
7941       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7942       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7943       theNodes.pop_back(); // remove nIgnore
7944       theNodes.pop_back(); // remove nStart
7945       theFaces.pop_back(); // remove curElem
7946       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7947       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7948       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7949       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7950       return true;
7951
7952     } // several continuations found
7953   } // while ( nStart != theLastNode )
7954
7955   return true;
7956 }
7957
7958 //=======================================================================
7959 //function : CheckFreeBorderNodes
7960 //purpose  : Return true if the tree nodes are on a free border
7961 //=======================================================================
7962
7963 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7964                                             const SMDS_MeshNode* theNode2,
7965                                             const SMDS_MeshNode* theNode3)
7966 {
7967   list< const SMDS_MeshNode* > nodes;
7968   list< const SMDS_MeshElement* > faces;
7969   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7970 }
7971
7972 //=======================================================================
7973 //function : SewFreeBorder
7974 //purpose  :
7975 //=======================================================================
7976
7977 SMESH_MeshEditor::Sew_Error
7978 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7979                                  const SMDS_MeshNode* theBordSecondNode,
7980                                  const SMDS_MeshNode* theBordLastNode,
7981                                  const SMDS_MeshNode* theSideFirstNode,
7982                                  const SMDS_MeshNode* theSideSecondNode,
7983                                  const SMDS_MeshNode* theSideThirdNode,
7984                                  const bool           theSideIsFreeBorder,
7985                                  const bool           toCreatePolygons,
7986                                  const bool           toCreatePolyedrs)
7987 {
7988   myLastCreatedElems.Clear();
7989   myLastCreatedNodes.Clear();
7990
7991   MESSAGE("::SewFreeBorder()");
7992   Sew_Error aResult = SEW_OK;
7993
7994   // ====================================
7995   //    find side nodes and elements
7996   // ====================================
7997
7998   list< const SMDS_MeshNode* > nSide[ 2 ];
7999   list< const SMDS_MeshElement* > eSide[ 2 ];
8000   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8001   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8002
8003   // Free border 1
8004   // --------------
8005   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8006                       nSide[0], eSide[0])) {
8007     MESSAGE(" Free Border 1 not found " );
8008     aResult = SEW_BORDER1_NOT_FOUND;
8009   }
8010   if (theSideIsFreeBorder) {
8011     // Free border 2
8012     // --------------
8013     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8014                         nSide[1], eSide[1])) {
8015       MESSAGE(" Free Border 2 not found " );
8016       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8017     }
8018   }
8019   if ( aResult != SEW_OK )
8020     return aResult;
8021
8022   if (!theSideIsFreeBorder) {
8023     // Side 2
8024     // --------------
8025
8026     // -------------------------------------------------------------------------
8027     // Algo:
8028     // 1. If nodes to merge are not coincident, move nodes of the free border
8029     //    from the coord sys defined by the direction from the first to last
8030     //    nodes of the border to the correspondent sys of the side 2
8031     // 2. On the side 2, find the links most co-directed with the correspondent
8032     //    links of the free border
8033     // -------------------------------------------------------------------------
8034
8035     // 1. Since sewing may brake if there are volumes to split on the side 2,
8036     //    we wont move nodes but just compute new coordinates for them
8037     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8038     TNodeXYZMap nBordXYZ;
8039     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8040     list< const SMDS_MeshNode* >::iterator nBordIt;
8041
8042     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8043     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8044     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8045     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8046     double tol2 = 1.e-8;
8047     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8048     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8049       // Need node movement.
8050
8051       // find X and Z axes to create trsf
8052       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8053       gp_Vec X = Zs ^ Zb;
8054       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8055         // Zb || Zs
8056         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8057
8058       // coord systems
8059       gp_Ax3 toBordAx( Pb1, Zb, X );
8060       gp_Ax3 fromSideAx( Ps1, Zs, X );
8061       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8062       // set trsf
8063       gp_Trsf toBordSys, fromSide2Sys;
8064       toBordSys.SetTransformation( toBordAx );
8065       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8066       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8067
8068       // move
8069       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8070         const SMDS_MeshNode* n = *nBordIt;
8071         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8072         toBordSys.Transforms( xyz );
8073         fromSide2Sys.Transforms( xyz );
8074         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8075       }
8076     }
8077     else {
8078       // just insert nodes XYZ in the nBordXYZ map
8079       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8080         const SMDS_MeshNode* n = *nBordIt;
8081         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8082       }
8083     }
8084
8085     // 2. On the side 2, find the links most co-directed with the correspondent
8086     //    links of the free border
8087
8088     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8089     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8090     sideNodes.push_back( theSideFirstNode );
8091
8092     bool hasVolumes = false;
8093     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8094     set<long> foundSideLinkIDs, checkedLinkIDs;
8095     SMDS_VolumeTool volume;
8096     //const SMDS_MeshNode* faceNodes[ 4 ];
8097
8098     const SMDS_MeshNode*    sideNode;
8099     const SMDS_MeshElement* sideElem;
8100     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8101     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8102     nBordIt = bordNodes.begin();
8103     nBordIt++;
8104     // border node position and border link direction to compare with
8105     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8106     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8107     // choose next side node by link direction or by closeness to
8108     // the current border node:
8109     bool searchByDir = ( *nBordIt != theBordLastNode );
8110     do {
8111       // find the next node on the Side 2
8112       sideNode = 0;
8113       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8114       long linkID;
8115       checkedLinkIDs.clear();
8116       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8117
8118       // loop on inverse elements of current node (prevSideNode) on the Side 2
8119       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8120       while ( invElemIt->more() )
8121       {
8122         const SMDS_MeshElement* elem = invElemIt->next();
8123         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8124         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8125         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8126         bool isVolume = volume.Set( elem );
8127         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8128         if ( isVolume ) // --volume
8129           hasVolumes = true;
8130         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8131           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8132           if(elem->IsQuadratic()) {
8133             const SMDS_QuadraticFaceOfNodes* F =
8134               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8135             // use special nodes iterator
8136             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8137             while( anIter->more() ) {
8138               nodes[ iNode ] = anIter->next();
8139               if ( nodes[ iNode++ ] == prevSideNode )
8140                 iPrevNode = iNode - 1;
8141             }
8142           }
8143           else {
8144             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8145             while ( nIt->more() ) {
8146               nodes[ iNode ] = cast2Node( nIt->next() );
8147               if ( nodes[ iNode++ ] == prevSideNode )
8148                 iPrevNode = iNode - 1;
8149             }
8150           }
8151           // there are 2 links to check
8152           nbNodes = 2;
8153         }
8154         else // --edge
8155           continue;
8156         // loop on links, to be precise, on the second node of links
8157         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8158           const SMDS_MeshNode* n = nodes[ iNode ];
8159           if ( isVolume ) {
8160             if ( !volume.IsLinked( n, prevSideNode ))
8161               continue;
8162           }
8163           else {
8164             if ( iNode ) // a node before prevSideNode
8165               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8166             else         // a node after prevSideNode
8167               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8168           }
8169           // check if this link was already used
8170           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8171           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8172           if (!isJustChecked &&
8173               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8174           {
8175             // test a link geometrically
8176             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8177             bool linkIsBetter = false;
8178             double dot = 0.0, dist = 0.0;
8179             if ( searchByDir ) { // choose most co-directed link
8180               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8181               linkIsBetter = ( dot > maxDot );
8182             }
8183             else { // choose link with the node closest to bordPos
8184               dist = ( nextXYZ - bordPos ).SquareModulus();
8185               linkIsBetter = ( dist < minDist );
8186             }
8187             if ( linkIsBetter ) {
8188               maxDot = dot;
8189               minDist = dist;
8190               linkID = iLink;
8191               sideNode = n;
8192               sideElem = elem;
8193             }
8194           }
8195         }
8196       } // loop on inverse elements of prevSideNode
8197
8198       if ( !sideNode ) {
8199         MESSAGE(" Cant find path by links of the Side 2 ");
8200         return SEW_BAD_SIDE_NODES;
8201       }
8202       sideNodes.push_back( sideNode );
8203       sideElems.push_back( sideElem );
8204       foundSideLinkIDs.insert ( linkID );
8205       prevSideNode = sideNode;
8206
8207       if ( *nBordIt == theBordLastNode )
8208         searchByDir = false;
8209       else {
8210         // find the next border link to compare with
8211         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8212         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8213         // move to next border node if sideNode is before forward border node (bordPos)
8214         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8215           prevBordNode = *nBordIt;
8216           nBordIt++;
8217           bordPos = nBordXYZ[ *nBordIt ];
8218           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8219           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8220         }
8221       }
8222     }
8223     while ( sideNode != theSideSecondNode );
8224
8225     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8226       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8227       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8228     }
8229   } // end nodes search on the side 2
8230
8231   // ============================
8232   // sew the border to the side 2
8233   // ============================
8234
8235   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8236   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8237
8238   TListOfListOfNodes nodeGroupsToMerge;
8239   if ( nbNodes[0] == nbNodes[1] ||
8240        ( theSideIsFreeBorder && !theSideThirdNode)) {
8241
8242     // all nodes are to be merged
8243
8244     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8245          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8246          nIt[0]++, nIt[1]++ )
8247     {
8248       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8249       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8250       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8251     }
8252   }
8253   else {
8254
8255     // insert new nodes into the border and the side to get equal nb of segments
8256
8257     // get normalized parameters of nodes on the borders
8258     //double param[ 2 ][ maxNbNodes ];
8259     double* param[ 2 ];
8260     param[0] = new double [ maxNbNodes ];
8261     param[1] = new double [ maxNbNodes ];
8262     int iNode, iBord;
8263     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8264       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8265       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8266       const SMDS_MeshNode* nPrev = *nIt;
8267       double bordLength = 0;
8268       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8269         const SMDS_MeshNode* nCur = *nIt;
8270         gp_XYZ segment (nCur->X() - nPrev->X(),
8271                         nCur->Y() - nPrev->Y(),
8272                         nCur->Z() - nPrev->Z());
8273         double segmentLen = segment.Modulus();
8274         bordLength += segmentLen;
8275         param[ iBord ][ iNode ] = bordLength;
8276         nPrev = nCur;
8277       }
8278       // normalize within [0,1]
8279       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8280         param[ iBord ][ iNode ] /= bordLength;
8281       }
8282     }
8283
8284     // loop on border segments
8285     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8286     int i[ 2 ] = { 0, 0 };
8287     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8288     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8289
8290     TElemOfNodeListMap insertMap;
8291     TElemOfNodeListMap::iterator insertMapIt;
8292     // insertMap is
8293     // key:   elem to insert nodes into
8294     // value: 2 nodes to insert between + nodes to be inserted
8295     do {
8296       bool next[ 2 ] = { false, false };
8297
8298       // find min adjacent segment length after sewing
8299       double nextParam = 10., prevParam = 0;
8300       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8301         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8302           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8303         if ( i[ iBord ] > 0 )
8304           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8305       }
8306       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8307       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8308       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8309
8310       // choose to insert or to merge nodes
8311       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8312       if ( Abs( du ) <= minSegLen * 0.2 ) {
8313         // merge
8314         // ------
8315         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8316         const SMDS_MeshNode* n0 = *nIt[0];
8317         const SMDS_MeshNode* n1 = *nIt[1];
8318         nodeGroupsToMerge.back().push_back( n1 );
8319         nodeGroupsToMerge.back().push_back( n0 );
8320         // position of node of the border changes due to merge
8321         param[ 0 ][ i[0] ] += du;
8322         // move n1 for the sake of elem shape evaluation during insertion.
8323         // n1 will be removed by MergeNodes() anyway
8324         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8325         next[0] = next[1] = true;
8326       }
8327       else {
8328         // insert
8329         // ------
8330         int intoBord = ( du < 0 ) ? 0 : 1;
8331         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8332         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8333         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8334         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8335         if ( intoBord == 1 ) {
8336           // move node of the border to be on a link of elem of the side
8337           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8338           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8339           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8340           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8341           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8342         }
8343         insertMapIt = insertMap.find( elem );
8344         bool notFound = ( insertMapIt == insertMap.end() );
8345         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8346         if ( otherLink ) {
8347           // insert into another link of the same element:
8348           // 1. perform insertion into the other link of the elem
8349           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8350           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8351           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8352           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8353           // 2. perform insertion into the link of adjacent faces
8354           while (true) {
8355             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8356             if ( adjElem )
8357               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8358             else
8359               break;
8360           }
8361           if (toCreatePolyedrs) {
8362             // perform insertion into the links of adjacent volumes
8363             UpdateVolumes(n12, n22, nodeList);
8364           }
8365           // 3. find an element appeared on n1 and n2 after the insertion
8366           insertMap.erase( elem );
8367           elem = findAdjacentFace( n1, n2, 0 );
8368         }
8369         if ( notFound || otherLink ) {
8370           // add element and nodes of the side into the insertMap
8371           insertMapIt = insertMap.insert
8372             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8373           (*insertMapIt).second.push_back( n1 );
8374           (*insertMapIt).second.push_back( n2 );
8375         }
8376         // add node to be inserted into elem
8377         (*insertMapIt).second.push_back( nIns );
8378         next[ 1 - intoBord ] = true;
8379       }
8380
8381       // go to the next segment
8382       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8383         if ( next[ iBord ] ) {
8384           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8385             eIt[ iBord ]++;
8386           nPrev[ iBord ] = *nIt[ iBord ];
8387           nIt[ iBord ]++; i[ iBord ]++;
8388         }
8389       }
8390     }
8391     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8392
8393     // perform insertion of nodes into elements
8394
8395     for (insertMapIt = insertMap.begin();
8396          insertMapIt != insertMap.end();
8397          insertMapIt++ )
8398     {
8399       const SMDS_MeshElement* elem = (*insertMapIt).first;
8400       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8401       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8402       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8403
8404       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8405
8406       if ( !theSideIsFreeBorder ) {
8407         // look for and insert nodes into the faces adjacent to elem
8408         while (true) {
8409           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8410           if ( adjElem )
8411             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8412           else
8413             break;
8414         }
8415       }
8416       if (toCreatePolyedrs) {
8417         // perform insertion into the links of adjacent volumes
8418         UpdateVolumes(n1, n2, nodeList);
8419       }
8420     }
8421
8422     delete param[0];
8423     delete param[1];
8424   } // end: insert new nodes
8425
8426   MergeNodes ( nodeGroupsToMerge );
8427
8428   return aResult;
8429 }
8430
8431 //=======================================================================
8432 //function : InsertNodesIntoLink
8433 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8434 //           and theBetweenNode2 and split theElement
8435 //=======================================================================
8436
8437 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8438                                            const SMDS_MeshNode*        theBetweenNode1,
8439                                            const SMDS_MeshNode*        theBetweenNode2,
8440                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8441                                            const bool                  toCreatePoly)
8442 {
8443   if ( theFace->GetType() != SMDSAbs_Face ) return;
8444
8445   // find indices of 2 link nodes and of the rest nodes
8446   int iNode = 0, il1, il2, i3, i4;
8447   il1 = il2 = i3 = i4 = -1;
8448   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8449   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8450
8451   if(theFace->IsQuadratic()) {
8452     const SMDS_QuadraticFaceOfNodes* F =
8453       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8454     // use special nodes iterator
8455     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8456     while( anIter->more() ) {
8457       const SMDS_MeshNode* n = anIter->next();
8458       if ( n == theBetweenNode1 )
8459         il1 = iNode;
8460       else if ( n == theBetweenNode2 )
8461         il2 = iNode;
8462       else if ( i3 < 0 )
8463         i3 = iNode;
8464       else
8465         i4 = iNode;
8466       nodes[ iNode++ ] = n;
8467     }
8468   }
8469   else {
8470     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8471     while ( nodeIt->more() ) {
8472       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8473       if ( n == theBetweenNode1 )
8474         il1 = iNode;
8475       else if ( n == theBetweenNode2 )
8476         il2 = iNode;
8477       else if ( i3 < 0 )
8478         i3 = iNode;
8479       else
8480         i4 = iNode;
8481       nodes[ iNode++ ] = n;
8482     }
8483   }
8484   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8485     return ;
8486
8487   // arrange link nodes to go one after another regarding the face orientation
8488   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8489   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8490   if ( reverse ) {
8491     iNode = il1;
8492     il1 = il2;
8493     il2 = iNode;
8494     aNodesToInsert.reverse();
8495   }
8496   // check that not link nodes of a quadrangles are in good order
8497   int nbFaceNodes = theFace->NbNodes();
8498   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8499     iNode = i3;
8500     i3 = i4;
8501     i4 = iNode;
8502   }
8503
8504   if (toCreatePoly || theFace->IsPoly()) {
8505
8506     iNode = 0;
8507     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8508
8509     // add nodes of face up to first node of link
8510     bool isFLN = false;
8511
8512     if(theFace->IsQuadratic()) {
8513       const SMDS_QuadraticFaceOfNodes* F =
8514         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8515       // use special nodes iterator
8516       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8517       while( anIter->more()  && !isFLN ) {
8518         const SMDS_MeshNode* n = anIter->next();
8519         poly_nodes[iNode++] = n;
8520         if (n == nodes[il1]) {
8521           isFLN = true;
8522         }
8523       }
8524       // add nodes to insert
8525       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8526       for (; nIt != aNodesToInsert.end(); nIt++) {
8527         poly_nodes[iNode++] = *nIt;
8528       }
8529       // add nodes of face starting from last node of link
8530       while ( anIter->more() ) {
8531         poly_nodes[iNode++] = anIter->next();
8532       }
8533     }
8534     else {
8535       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8536       while ( nodeIt->more() && !isFLN ) {
8537         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8538         poly_nodes[iNode++] = n;
8539         if (n == nodes[il1]) {
8540           isFLN = true;
8541         }
8542       }
8543       // add nodes to insert
8544       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8545       for (; nIt != aNodesToInsert.end(); nIt++) {
8546         poly_nodes[iNode++] = *nIt;
8547       }
8548       // add nodes of face starting from last node of link
8549       while ( nodeIt->more() ) {
8550         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8551         poly_nodes[iNode++] = n;
8552       }
8553     }
8554
8555     // edit or replace the face
8556     SMESHDS_Mesh *aMesh = GetMeshDS();
8557
8558     if (theFace->IsPoly()) {
8559       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8560     }
8561     else {
8562       int aShapeId = FindShape( theFace );
8563
8564       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8565       myLastCreatedElems.Append(newElem);
8566       if ( aShapeId && newElem )
8567         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8568
8569       aMesh->RemoveElement(theFace);
8570     }
8571     return;
8572   }
8573
8574   if( !theFace->IsQuadratic() ) {
8575
8576     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8577     int nbLinkNodes = 2 + aNodesToInsert.size();
8578     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8579     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8580     linkNodes[ 0 ] = nodes[ il1 ];
8581     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8582     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8583     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8584       linkNodes[ iNode++ ] = *nIt;
8585     }
8586     // decide how to split a quadrangle: compare possible variants
8587     // and choose which of splits to be a quadrangle
8588     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8589     if ( nbFaceNodes == 3 ) {
8590       iBestQuad = nbSplits;
8591       i4 = i3;
8592     }
8593     else if ( nbFaceNodes == 4 ) {
8594       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8595       double aBestRate = DBL_MAX;
8596       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8597         i1 = 0; i2 = 1;
8598         double aBadRate = 0;
8599         // evaluate elements quality
8600         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8601           if ( iSplit == iQuad ) {
8602             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8603                                    linkNodes[ i2++ ],
8604                                    nodes[ i3 ],
8605                                    nodes[ i4 ]);
8606             aBadRate += getBadRate( &quad, aCrit );
8607           }
8608           else {
8609             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8610                                    linkNodes[ i2++ ],
8611                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8612             aBadRate += getBadRate( &tria, aCrit );
8613           }
8614         }
8615         // choice
8616         if ( aBadRate < aBestRate ) {
8617           iBestQuad = iQuad;
8618           aBestRate = aBadRate;
8619         }
8620       }
8621     }
8622
8623     // create new elements
8624     SMESHDS_Mesh *aMesh = GetMeshDS();
8625     int aShapeId = FindShape( theFace );
8626
8627     i1 = 0; i2 = 1;
8628     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8629       SMDS_MeshElement* newElem = 0;
8630       if ( iSplit == iBestQuad )
8631         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8632                                   linkNodes[ i2++ ],
8633                                   nodes[ i3 ],
8634                                   nodes[ i4 ]);
8635       else
8636         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8637                                   linkNodes[ i2++ ],
8638                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8639       myLastCreatedElems.Append(newElem);
8640       if ( aShapeId && newElem )
8641         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8642     }
8643
8644     // change nodes of theFace
8645     const SMDS_MeshNode* newNodes[ 4 ];
8646     newNodes[ 0 ] = linkNodes[ i1 ];
8647     newNodes[ 1 ] = linkNodes[ i2 ];
8648     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8649     newNodes[ 3 ] = nodes[ i4 ];
8650     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8651   } // end if(!theFace->IsQuadratic())
8652   else { // theFace is quadratic
8653     // we have to split theFace on simple triangles and one simple quadrangle
8654     int tmp = il1/2;
8655     int nbshift = tmp*2;
8656     // shift nodes in nodes[] by nbshift
8657     int i,j;
8658     for(i=0; i<nbshift; i++) {
8659       const SMDS_MeshNode* n = nodes[0];
8660       for(j=0; j<nbFaceNodes-1; j++) {
8661         nodes[j] = nodes[j+1];
8662       }
8663       nodes[nbFaceNodes-1] = n;
8664     }
8665     il1 = il1 - nbshift;
8666     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8667     //   n0      n1     n2    n0      n1     n2
8668     //     +-----+-----+        +-----+-----+
8669     //      \         /         |           |
8670     //       \       /          |           |
8671     //      n5+     +n3       n7+           +n3
8672     //         \   /            |           |
8673     //          \ /             |           |
8674     //           +              +-----+-----+
8675     //           n4           n6      n5     n4
8676
8677     // create new elements
8678     SMESHDS_Mesh *aMesh = GetMeshDS();
8679     int aShapeId = FindShape( theFace );
8680
8681     int n1,n2,n3;
8682     if(nbFaceNodes==6) { // quadratic triangle
8683       SMDS_MeshElement* newElem =
8684         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8685       myLastCreatedElems.Append(newElem);
8686       if ( aShapeId && newElem )
8687         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8688       if(theFace->IsMediumNode(nodes[il1])) {
8689         // create quadrangle
8690         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8691         myLastCreatedElems.Append(newElem);
8692         if ( aShapeId && newElem )
8693           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8694         n1 = 1;
8695         n2 = 2;
8696         n3 = 3;
8697       }
8698       else {
8699         // create quadrangle
8700         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8701         myLastCreatedElems.Append(newElem);
8702         if ( aShapeId && newElem )
8703           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8704         n1 = 0;
8705         n2 = 1;
8706         n3 = 5;
8707       }
8708     }
8709     else { // nbFaceNodes==8 - quadratic quadrangle
8710       SMDS_MeshElement* newElem =
8711         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8712       myLastCreatedElems.Append(newElem);
8713       if ( aShapeId && newElem )
8714         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8715       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8716       myLastCreatedElems.Append(newElem);
8717       if ( aShapeId && newElem )
8718         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8719       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8720       myLastCreatedElems.Append(newElem);
8721       if ( aShapeId && newElem )
8722         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8723       if(theFace->IsMediumNode(nodes[il1])) {
8724         // create quadrangle
8725         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8726         myLastCreatedElems.Append(newElem);
8727         if ( aShapeId && newElem )
8728           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8729         n1 = 1;
8730         n2 = 2;
8731         n3 = 3;
8732       }
8733       else {
8734         // create quadrangle
8735         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8736         myLastCreatedElems.Append(newElem);
8737         if ( aShapeId && newElem )
8738           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8739         n1 = 0;
8740         n2 = 1;
8741         n3 = 7;
8742       }
8743     }
8744     // create needed triangles using n1,n2,n3 and inserted nodes
8745     int nbn = 2 + aNodesToInsert.size();
8746     //const SMDS_MeshNode* aNodes[nbn];
8747     vector<const SMDS_MeshNode*> aNodes(nbn);
8748     aNodes[0] = nodes[n1];
8749     aNodes[nbn-1] = nodes[n2];
8750     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8751     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8752       aNodes[iNode++] = *nIt;
8753     }
8754     for(i=1; i<nbn; i++) {
8755       SMDS_MeshElement* newElem =
8756         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8757       myLastCreatedElems.Append(newElem);
8758       if ( aShapeId && newElem )
8759         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8760     }
8761     // remove old quadratic face
8762     aMesh->RemoveElement(theFace);
8763   }
8764 }
8765
8766 //=======================================================================
8767 //function : UpdateVolumes
8768 //purpose  :
8769 //=======================================================================
8770 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8771                                       const SMDS_MeshNode*        theBetweenNode2,
8772                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8773 {
8774   myLastCreatedElems.Clear();
8775   myLastCreatedNodes.Clear();
8776
8777   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8778   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8779     const SMDS_MeshElement* elem = invElemIt->next();
8780
8781     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8782     SMDS_VolumeTool aVolume (elem);
8783     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8784       continue;
8785
8786     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8787     int iface, nbFaces = aVolume.NbFaces();
8788     vector<const SMDS_MeshNode *> poly_nodes;
8789     vector<int> quantities (nbFaces);
8790
8791     for (iface = 0; iface < nbFaces; iface++) {
8792       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8793       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8794       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8795
8796       for (int inode = 0; inode < nbFaceNodes; inode++) {
8797         poly_nodes.push_back(faceNodes[inode]);
8798
8799         if (nbInserted == 0) {
8800           if (faceNodes[inode] == theBetweenNode1) {
8801             if (faceNodes[inode + 1] == theBetweenNode2) {
8802               nbInserted = theNodesToInsert.size();
8803
8804               // add nodes to insert
8805               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8806               for (; nIt != theNodesToInsert.end(); nIt++) {
8807                 poly_nodes.push_back(*nIt);
8808               }
8809             }
8810           }
8811           else if (faceNodes[inode] == theBetweenNode2) {
8812             if (faceNodes[inode + 1] == theBetweenNode1) {
8813               nbInserted = theNodesToInsert.size();
8814
8815               // add nodes to insert in reversed order
8816               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8817               nIt--;
8818               for (; nIt != theNodesToInsert.begin(); nIt--) {
8819                 poly_nodes.push_back(*nIt);
8820               }
8821               poly_nodes.push_back(*nIt);
8822             }
8823           }
8824           else {
8825           }
8826         }
8827       }
8828       quantities[iface] = nbFaceNodes + nbInserted;
8829     }
8830
8831     // Replace or update the volume
8832     SMESHDS_Mesh *aMesh = GetMeshDS();
8833
8834     if (elem->IsPoly()) {
8835       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8836
8837     }
8838     else {
8839       int aShapeId = FindShape( elem );
8840
8841       SMDS_MeshElement* newElem =
8842         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8843       myLastCreatedElems.Append(newElem);
8844       if (aShapeId && newElem)
8845         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8846
8847       aMesh->RemoveElement(elem);
8848     }
8849   }
8850 }
8851
8852 //=======================================================================
8853 /*!
8854  * \brief Convert elements contained in a submesh to quadratic
8855  * \retval int - nb of checked elements
8856  */
8857 //=======================================================================
8858
8859 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8860                                              SMESH_MesherHelper& theHelper,
8861                                              const bool          theForce3d)
8862 {
8863   int nbElem = 0;
8864   if( !theSm ) return nbElem;
8865
8866   const bool notFromGroups = false;
8867   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8868   while(ElemItr->more())
8869   {
8870     nbElem++;
8871     const SMDS_MeshElement* elem = ElemItr->next();
8872     if( !elem || elem->IsQuadratic() ) continue;
8873
8874     int id = elem->GetID();
8875     int nbNodes = elem->NbNodes();
8876     vector<const SMDS_MeshNode *> aNds (nbNodes);
8877
8878     for(int i = 0; i < nbNodes; i++)
8879     {
8880       aNds[i] = elem->GetNode(i);
8881     }
8882     SMDSAbs_ElementType aType = elem->GetType();
8883
8884     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8885
8886     const SMDS_MeshElement* NewElem = 0;
8887
8888     switch( aType )
8889     {
8890     case SMDSAbs_Edge :
8891       {
8892         NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8893         break;
8894       }
8895     case SMDSAbs_Face :
8896       {
8897         switch(nbNodes)
8898         {
8899         case 3:
8900           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8901           break;
8902         case 4:
8903           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8904           break;
8905         default:
8906           continue;
8907         }
8908         break;
8909       }
8910     case SMDSAbs_Volume :
8911       {
8912         switch(nbNodes)
8913         {
8914         case 4:
8915           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8916           break;
8917         case 5:
8918           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8919           break;
8920         case 6:
8921           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8922           break;
8923         case 8:
8924           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8925                                         aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8926           break;
8927         default:
8928           continue;
8929         }
8930         break;
8931       }
8932     default :
8933       continue;
8934     }
8935     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8936     if( NewElem )
8937       theSm->AddElement( NewElem );
8938   }
8939   return nbElem;
8940 }
8941
8942 //=======================================================================
8943 //function : ConvertToQuadratic
8944 //purpose  :
8945 //=======================================================================
8946 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8947 {
8948   SMESHDS_Mesh* meshDS = GetMeshDS();
8949
8950   SMESH_MesherHelper aHelper(*myMesh);
8951   aHelper.SetIsQuadratic( true );
8952   const bool notFromGroups = false;
8953
8954   int nbCheckedElems = 0;
8955   if ( myMesh->HasShapeToMesh() )
8956   {
8957     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8958     {
8959       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8960       while ( smIt->more() ) {
8961         SMESH_subMesh* sm = smIt->next();
8962         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8963           aHelper.SetSubShape( sm->GetSubShape() );
8964           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8965         }
8966       }
8967     }
8968   }
8969   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8970   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8971   {
8972     SMESHDS_SubMesh *smDS = 0;
8973     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8974     while(aEdgeItr->more())
8975     {
8976       const SMDS_MeshEdge* edge = aEdgeItr->next();
8977       if(edge && !edge->IsQuadratic())
8978       {
8979         int id = edge->GetID();
8980         const SMDS_MeshNode* n1 = edge->GetNode(0);
8981         const SMDS_MeshNode* n2 = edge->GetNode(1);
8982
8983         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8984
8985         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8986         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8987       }
8988     }
8989     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8990     while(aFaceItr->more())
8991     {
8992       const SMDS_MeshFace* face = aFaceItr->next();
8993       if(!face || face->IsQuadratic() ) continue;
8994
8995       int id = face->GetID();
8996       int nbNodes = face->NbNodes();
8997       vector<const SMDS_MeshNode *> aNds (nbNodes);
8998
8999       for(int i = 0; i < nbNodes; i++)
9000       {
9001         aNds[i] = face->GetNode(i);
9002       }
9003
9004       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9005
9006       SMDS_MeshFace * NewFace = 0;
9007       switch(nbNodes)
9008       {
9009       case 3:
9010         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9011         break;
9012       case 4:
9013         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9014         break;
9015       default:
9016         continue;
9017       }
9018       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9019     }
9020     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9021     while(aVolumeItr->more())
9022     {
9023       const SMDS_MeshVolume* volume = aVolumeItr->next();
9024       if(!volume || volume->IsQuadratic() ) continue;
9025
9026       int id = volume->GetID();
9027       int nbNodes = volume->NbNodes();
9028       vector<const SMDS_MeshNode *> aNds (nbNodes);
9029
9030       for(int i = 0; i < nbNodes; i++)
9031       {
9032         aNds[i] = volume->GetNode(i);
9033       }
9034
9035       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9036
9037       SMDS_MeshVolume * NewVolume = 0;
9038       switch(nbNodes)
9039       {
9040       case 4:
9041         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9042                                       aNds[3], id, theForce3d );
9043         break;
9044       case 5:
9045         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9046                                       aNds[3], aNds[4], id, theForce3d);
9047         break;
9048       case 6:
9049         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9050                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
9051         break;
9052       case 8:
9053         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9054                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9055         break;
9056       default:
9057         continue;
9058       }
9059       ReplaceElemInGroups(volume, NewVolume, meshDS);
9060     }
9061   }
9062   if ( !theForce3d  && !getenv("NO_FixQuadraticElements")) {
9063     aHelper.SetSubShape(0); // apply to the whole mesh
9064     aHelper.FixQuadraticElements();
9065   }
9066 }
9067
9068 //=======================================================================
9069 /*!
9070  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9071  * \retval int - nb of checked elements
9072  */
9073 //=======================================================================
9074
9075 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9076                                      SMDS_ElemIteratorPtr theItr,
9077                                      const int            theShapeID)
9078 {
9079   int nbElem = 0;
9080   SMESHDS_Mesh* meshDS = GetMeshDS();
9081   const bool notFromGroups = false;
9082
9083   while( theItr->more() )
9084   {
9085     const SMDS_MeshElement* elem = theItr->next();
9086     nbElem++;
9087     if( elem && elem->IsQuadratic())
9088     {
9089       int id = elem->GetID();
9090       int nbNodes = elem->NbNodes();
9091       vector<const SMDS_MeshNode *> aNds, mediumNodes;
9092       aNds.reserve( nbNodes );
9093       mediumNodes.reserve( nbNodes );
9094
9095       for(int i = 0; i < nbNodes; i++)
9096       {
9097         const SMDS_MeshNode* n = elem->GetNode(i);
9098
9099         if( elem->IsMediumNode( n ) )
9100           mediumNodes.push_back( n );
9101         else
9102           aNds.push_back( n );
9103       }
9104       if( aNds.empty() ) continue;
9105       SMDSAbs_ElementType aType = elem->GetType();
9106
9107       //remove old quadratic element
9108       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9109
9110       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9111       ReplaceElemInGroups(elem, NewElem, meshDS);
9112       if( theSm && NewElem )
9113         theSm->AddElement( NewElem );
9114
9115       // remove medium nodes
9116       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9117       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9118         const SMDS_MeshNode* n = *nIt;
9119         if ( n->NbInverseElements() == 0 ) {
9120           if ( n->GetPosition()->GetShapeId() != theShapeID )
9121             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9122                                     ( n->GetPosition()->GetShapeId() ));
9123           else
9124             meshDS->RemoveFreeNode( n, theSm );
9125         }
9126       }
9127     }
9128   }
9129   return nbElem;
9130 }
9131
9132 //=======================================================================
9133 //function : ConvertFromQuadratic
9134 //purpose  :
9135 //=======================================================================
9136 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9137 {
9138   int nbCheckedElems = 0;
9139   if ( myMesh->HasShapeToMesh() )
9140   {
9141     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9142     {
9143       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9144       while ( smIt->more() ) {
9145         SMESH_subMesh* sm = smIt->next();
9146         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9147           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9148       }
9149     }
9150   }
9151
9152   int totalNbElems =
9153     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9154   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9155   {
9156     SMESHDS_SubMesh *aSM = 0;
9157     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9158   }
9159
9160   return true;
9161 }
9162
9163 //=======================================================================
9164 //function : SewSideElements
9165 //purpose  :
9166 //=======================================================================
9167
9168 SMESH_MeshEditor::Sew_Error
9169 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9170                                    TIDSortedElemSet&    theSide2,
9171                                    const SMDS_MeshNode* theFirstNode1,
9172                                    const SMDS_MeshNode* theFirstNode2,
9173                                    const SMDS_MeshNode* theSecondNode1,
9174                                    const SMDS_MeshNode* theSecondNode2)
9175 {
9176   myLastCreatedElems.Clear();
9177   myLastCreatedNodes.Clear();
9178
9179   MESSAGE ("::::SewSideElements()");
9180   if ( theSide1.size() != theSide2.size() )
9181     return SEW_DIFF_NB_OF_ELEMENTS;
9182
9183   Sew_Error aResult = SEW_OK;
9184   // Algo:
9185   // 1. Build set of faces representing each side
9186   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9187   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9188
9189   // =======================================================================
9190   // 1. Build set of faces representing each side:
9191   // =======================================================================
9192   // a. build set of nodes belonging to faces
9193   // b. complete set of faces: find missing fices whose nodes are in set of nodes
9194   // c. create temporary faces representing side of volumes if correspondent
9195   //    face does not exist
9196
9197   SMESHDS_Mesh* aMesh = GetMeshDS();
9198   SMDS_Mesh aTmpFacesMesh;
9199   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9200   set<const SMDS_MeshElement*> volSet1,  volSet2;
9201   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9202   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9203   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9204   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9205   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9206   int iSide, iFace, iNode;
9207
9208   for ( iSide = 0; iSide < 2; iSide++ ) {
9209     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9210     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9211     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9212     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9213     set<const SMDS_MeshElement*>::iterator vIt;
9214     TIDSortedElemSet::iterator eIt;
9215     set<const SMDS_MeshNode*>::iterator    nIt;
9216
9217     // check that given nodes belong to given elements
9218     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9219     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9220     int firstIndex = -1, secondIndex = -1;
9221     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9222       const SMDS_MeshElement* elem = *eIt;
9223       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9224       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9225       if ( firstIndex > -1 && secondIndex > -1 ) break;
9226     }
9227     if ( firstIndex < 0 || secondIndex < 0 ) {
9228       // we can simply return until temporary faces created
9229       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9230     }
9231
9232     // -----------------------------------------------------------
9233     // 1a. Collect nodes of existing faces
9234     //     and build set of face nodes in order to detect missing
9235     //     faces corresponing to sides of volumes
9236     // -----------------------------------------------------------
9237
9238     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9239
9240     // loop on the given element of a side
9241     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9242       //const SMDS_MeshElement* elem = *eIt;
9243       const SMDS_MeshElement* elem = *eIt;
9244       if ( elem->GetType() == SMDSAbs_Face ) {
9245         faceSet->insert( elem );
9246         set <const SMDS_MeshNode*> faceNodeSet;
9247         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9248         while ( nodeIt->more() ) {
9249           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9250           nodeSet->insert( n );
9251           faceNodeSet.insert( n );
9252         }
9253         setOfFaceNodeSet.insert( faceNodeSet );
9254       }
9255       else if ( elem->GetType() == SMDSAbs_Volume )
9256         volSet->insert( elem );
9257     }
9258     // ------------------------------------------------------------------------------
9259     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9260     // ------------------------------------------------------------------------------
9261
9262     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9263       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9264       while ( fIt->more() ) { // loop on faces sharing a node
9265         const SMDS_MeshElement* f = fIt->next();
9266         if ( faceSet->find( f ) == faceSet->end() ) {
9267           // check if all nodes are in nodeSet and
9268           // complete setOfFaceNodeSet if they are
9269           set <const SMDS_MeshNode*> faceNodeSet;
9270           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9271           bool allInSet = true;
9272           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9273             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9274             if ( nodeSet->find( n ) == nodeSet->end() )
9275               allInSet = false;
9276             else
9277               faceNodeSet.insert( n );
9278           }
9279           if ( allInSet ) {
9280             faceSet->insert( f );
9281             setOfFaceNodeSet.insert( faceNodeSet );
9282           }
9283         }
9284       }
9285     }
9286
9287     // -------------------------------------------------------------------------
9288     // 1c. Create temporary faces representing sides of volumes if correspondent
9289     //     face does not exist
9290     // -------------------------------------------------------------------------
9291
9292     if ( !volSet->empty() ) {
9293       //int nodeSetSize = nodeSet->size();
9294
9295       // loop on given volumes
9296       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9297         SMDS_VolumeTool vol (*vIt);
9298         // loop on volume faces: find free faces
9299         // --------------------------------------
9300         list<const SMDS_MeshElement* > freeFaceList;
9301         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9302           if ( !vol.IsFreeFace( iFace ))
9303             continue;
9304           // check if there is already a face with same nodes in a face set
9305           const SMDS_MeshElement* aFreeFace = 0;
9306           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9307           int nbNodes = vol.NbFaceNodes( iFace );
9308           set <const SMDS_MeshNode*> faceNodeSet;
9309           vol.GetFaceNodes( iFace, faceNodeSet );
9310           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9311           if ( isNewFace ) {
9312             // no such a face is given but it still can exist, check it
9313             if ( nbNodes == 3 ) {
9314               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9315             }
9316             else if ( nbNodes == 4 ) {
9317               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9318             }
9319             else {
9320               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9321               aFreeFace = aMesh->FindFace(poly_nodes);
9322             }
9323           }
9324           if ( !aFreeFace ) {
9325             // create a temporary face
9326             if ( nbNodes == 3 ) {
9327               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9328             }
9329             else if ( nbNodes == 4 ) {
9330               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9331             }
9332             else {
9333               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9334               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9335             }
9336           }
9337           if ( aFreeFace )
9338             freeFaceList.push_back( aFreeFace );
9339
9340         } // loop on faces of a volume
9341
9342         // choose one of several free faces
9343         // --------------------------------------
9344         if ( freeFaceList.size() > 1 ) {
9345           // choose a face having max nb of nodes shared by other elems of a side
9346           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9347           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9348           while ( fIt != freeFaceList.end() ) { // loop on free faces
9349             int nbSharedNodes = 0;
9350             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9351             while ( nodeIt->more() ) { // loop on free face nodes
9352               const SMDS_MeshNode* n =
9353                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9354               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9355               while ( invElemIt->more() ) {
9356                 const SMDS_MeshElement* e = invElemIt->next();
9357                 if ( faceSet->find( e ) != faceSet->end() )
9358                   nbSharedNodes++;
9359                 if ( elemSet->find( e ) != elemSet->end() )
9360                   nbSharedNodes++;
9361               }
9362             }
9363             if ( nbSharedNodes >= maxNbNodes ) {
9364               maxNbNodes = nbSharedNodes;
9365               fIt++;
9366             }
9367             else
9368               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9369           }
9370           if ( freeFaceList.size() > 1 )
9371           {
9372             // could not choose one face, use another way
9373             // choose a face most close to the bary center of the opposite side
9374             gp_XYZ aBC( 0., 0., 0. );
9375             set <const SMDS_MeshNode*> addedNodes;
9376             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9377             eIt = elemSet2->begin();
9378             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9379               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9380               while ( nodeIt->more() ) { // loop on free face nodes
9381                 const SMDS_MeshNode* n =
9382                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9383                 if ( addedNodes.insert( n ).second )
9384                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9385               }
9386             }
9387             aBC /= addedNodes.size();
9388             double minDist = DBL_MAX;
9389             fIt = freeFaceList.begin();
9390             while ( fIt != freeFaceList.end() ) { // loop on free faces
9391               double dist = 0;
9392               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9393               while ( nodeIt->more() ) { // loop on free face nodes
9394                 const SMDS_MeshNode* n =
9395                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9396                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9397                 dist += ( aBC - p ).SquareModulus();
9398               }
9399               if ( dist < minDist ) {
9400                 minDist = dist;
9401                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9402               }
9403               else
9404                 fIt = freeFaceList.erase( fIt++ );
9405             }
9406           }
9407         } // choose one of several free faces of a volume
9408
9409         if ( freeFaceList.size() == 1 ) {
9410           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9411           faceSet->insert( aFreeFace );
9412           // complete a node set with nodes of a found free face
9413           //           for ( iNode = 0; iNode < ; iNode++ )
9414           //             nodeSet->insert( fNodes[ iNode ] );
9415         }
9416
9417       } // loop on volumes of a side
9418
9419       //       // complete a set of faces if new nodes in a nodeSet appeared
9420       //       // ----------------------------------------------------------
9421       //       if ( nodeSetSize != nodeSet->size() ) {
9422       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9423       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9424       //           while ( fIt->more() ) { // loop on faces sharing a node
9425       //             const SMDS_MeshElement* f = fIt->next();
9426       //             if ( faceSet->find( f ) == faceSet->end() ) {
9427       //               // check if all nodes are in nodeSet and
9428       //               // complete setOfFaceNodeSet if they are
9429       //               set <const SMDS_MeshNode*> faceNodeSet;
9430       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9431       //               bool allInSet = true;
9432       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9433       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9434       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9435       //                   allInSet = false;
9436       //                 else
9437       //                   faceNodeSet.insert( n );
9438       //               }
9439       //               if ( allInSet ) {
9440       //                 faceSet->insert( f );
9441       //                 setOfFaceNodeSet.insert( faceNodeSet );
9442       //               }
9443       //             }
9444       //           }
9445       //         }
9446       //       }
9447     } // Create temporary faces, if there are volumes given
9448   } // loop on sides
9449
9450   if ( faceSet1.size() != faceSet2.size() ) {
9451     // delete temporary faces: they are in reverseElements of actual nodes
9452     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9453     while ( tmpFaceIt->more() )
9454       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9455     MESSAGE("Diff nb of faces");
9456     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9457   }
9458
9459   // ============================================================
9460   // 2. Find nodes to merge:
9461   //              bind a node to remove to a node to put instead
9462   // ============================================================
9463
9464   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9465   if ( theFirstNode1 != theFirstNode2 )
9466     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9467   if ( theSecondNode1 != theSecondNode2 )
9468     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9469
9470   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9471   set< long > linkIdSet; // links to process
9472   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9473
9474   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9475   list< NLink > linkList[2];
9476   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9477   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9478   // loop on links in linkList; find faces by links and append links
9479   // of the found faces to linkList
9480   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9481   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9482     NLink link[] = { *linkIt[0], *linkIt[1] };
9483     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9484     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9485       continue;
9486
9487     // by links, find faces in the face sets,
9488     // and find indices of link nodes in the found faces;
9489     // in a face set, there is only one or no face sharing a link
9490     // ---------------------------------------------------------------
9491
9492     const SMDS_MeshElement* face[] = { 0, 0 };
9493     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9494     vector<const SMDS_MeshNode*> fnodes1(9);
9495     vector<const SMDS_MeshNode*> fnodes2(9);
9496     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9497     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9498     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9499     int iLinkNode[2][2];
9500     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9501       const SMDS_MeshNode* n1 = link[iSide].first;
9502       const SMDS_MeshNode* n2 = link[iSide].second;
9503       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9504       set< const SMDS_MeshElement* > fMap;
9505       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9506         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9507         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9508         while ( fIt->more() ) { // loop on faces sharing a node
9509           const SMDS_MeshElement* f = fIt->next();
9510           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9511               ! fMap.insert( f ).second ) // f encounters twice
9512           {
9513             if ( face[ iSide ] ) {
9514               MESSAGE( "2 faces per link " );
9515               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9516               break;
9517             }
9518             face[ iSide ] = f;
9519             faceSet->erase( f );
9520             // get face nodes and find ones of a link
9521             iNode = 0;
9522             int nbl = -1;
9523             if(f->IsPoly()) {
9524               if(iSide==0) {
9525                 fnodes1.resize(f->NbNodes()+1);
9526                 notLinkNodes1.resize(f->NbNodes()-2);
9527               }
9528               else {
9529                 fnodes2.resize(f->NbNodes()+1);
9530                 notLinkNodes2.resize(f->NbNodes()-2);
9531               }
9532             }
9533             if(!f->IsQuadratic()) {
9534               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9535               while ( nIt->more() ) {
9536                 const SMDS_MeshNode* n =
9537                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9538                 if ( n == n1 ) {
9539                   iLinkNode[ iSide ][ 0 ] = iNode;
9540                 }
9541                 else if ( n == n2 ) {
9542                   iLinkNode[ iSide ][ 1 ] = iNode;
9543                 }
9544                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9545                 //  notLinkNodes[ iSide ][ 1 ] = n;
9546                 //else
9547                 //  notLinkNodes[ iSide ][ 0 ] = n;
9548                 else {
9549                   nbl++;
9550                   if(iSide==0)
9551                     notLinkNodes1[nbl] = n;
9552                   //notLinkNodes1.push_back(n);
9553                   else
9554                     notLinkNodes2[nbl] = n;
9555                   //notLinkNodes2.push_back(n);
9556                 }
9557                 //faceNodes[ iSide ][ iNode++ ] = n;
9558                 if(iSide==0) {
9559                   fnodes1[iNode++] = n;
9560                 }
9561                 else {
9562                   fnodes2[iNode++] = n;
9563                 }
9564               }
9565             }
9566             else { // f->IsQuadratic()
9567               const SMDS_QuadraticFaceOfNodes* F =
9568                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9569               // use special nodes iterator
9570               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9571               while ( anIter->more() ) {
9572                 const SMDS_MeshNode* n =
9573                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9574                 if ( n == n1 ) {
9575                   iLinkNode[ iSide ][ 0 ] = iNode;
9576                 }
9577                 else if ( n == n2 ) {
9578                   iLinkNode[ iSide ][ 1 ] = iNode;
9579                 }
9580                 else {
9581                   nbl++;
9582                   if(iSide==0) {
9583                     notLinkNodes1[nbl] = n;
9584                   }
9585                   else {
9586                     notLinkNodes2[nbl] = n;
9587                   }
9588                 }
9589                 if(iSide==0) {
9590                   fnodes1[iNode++] = n;
9591                 }
9592                 else {
9593                   fnodes2[iNode++] = n;
9594                 }
9595               }
9596             }
9597             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9598             if(iSide==0) {
9599               fnodes1[iNode] = fnodes1[0];
9600             }
9601             else {
9602               fnodes2[iNode] = fnodes1[0];
9603             }
9604           }
9605         }
9606       }
9607     }
9608
9609     // check similarity of elements of the sides
9610     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9611       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9612       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9613         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9614       }
9615       else {
9616         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9617       }
9618       break; // do not return because it s necessary to remove tmp faces
9619     }
9620
9621     // set nodes to merge
9622     // -------------------
9623
9624     if ( face[0] && face[1] )  {
9625       int nbNodes = face[0]->NbNodes();
9626       if ( nbNodes != face[1]->NbNodes() ) {
9627         MESSAGE("Diff nb of face nodes");
9628         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9629         break; // do not return because it s necessary to remove tmp faces
9630       }
9631       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9632       if ( nbNodes == 3 ) {
9633         //nReplaceMap.insert( TNodeNodeMap::value_type
9634         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9635         nReplaceMap.insert( TNodeNodeMap::value_type
9636                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9637       }
9638       else {
9639         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9640           // analyse link orientation in faces
9641           int i1 = iLinkNode[ iSide ][ 0 ];
9642           int i2 = iLinkNode[ iSide ][ 1 ];
9643           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9644           // if notLinkNodes are the first and the last ones, then
9645           // their order does not correspond to the link orientation
9646           if (( i1 == 1 && i2 == 2 ) ||
9647               ( i1 == 2 && i2 == 1 ))
9648             reverse[ iSide ] = !reverse[ iSide ];
9649         }
9650         if ( reverse[0] == reverse[1] ) {
9651           //nReplaceMap.insert( TNodeNodeMap::value_type
9652           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9653           //nReplaceMap.insert( TNodeNodeMap::value_type
9654           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9655           for(int nn=0; nn<nbNodes-2; nn++) {
9656             nReplaceMap.insert( TNodeNodeMap::value_type
9657                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9658           }
9659         }
9660         else {
9661           //nReplaceMap.insert( TNodeNodeMap::value_type
9662           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9663           //nReplaceMap.insert( TNodeNodeMap::value_type
9664           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9665           for(int nn=0; nn<nbNodes-2; nn++) {
9666             nReplaceMap.insert( TNodeNodeMap::value_type
9667                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9668           }
9669         }
9670       }
9671
9672       // add other links of the faces to linkList
9673       // -----------------------------------------
9674
9675       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9676       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9677         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9678         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9679         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9680         if ( !iter_isnew.second ) { // already in a set: no need to process
9681           linkIdSet.erase( iter_isnew.first );
9682         }
9683         else // new in set == encountered for the first time: add
9684         {
9685           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9686           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9687           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9688           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9689           linkList[0].push_back ( NLink( n1, n2 ));
9690           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9691         }
9692       }
9693     } // 2 faces found
9694   } // loop on link lists
9695
9696   if ( aResult == SEW_OK &&
9697        ( linkIt[0] != linkList[0].end() ||
9698          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9699     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9700              " " << (faceSetPtr[1]->empty()));
9701     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9702   }
9703
9704   // ====================================================================
9705   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9706   // ====================================================================
9707
9708   // delete temporary faces: they are in reverseElements of actual nodes
9709   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9710   while ( tmpFaceIt->more() )
9711     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9712
9713   if ( aResult != SEW_OK)
9714     return aResult;
9715
9716   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9717   // loop on nodes replacement map
9718   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9719   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9720     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9721       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9722       nodeIDsToRemove.push_back( nToRemove->GetID() );
9723       // loop on elements sharing nToRemove
9724       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9725       while ( invElemIt->more() ) {
9726         const SMDS_MeshElement* e = invElemIt->next();
9727         // get a new suite of nodes: make replacement
9728         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9729         vector< const SMDS_MeshNode*> nodes( nbNodes );
9730         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9731         while ( nIt->more() ) {
9732           const SMDS_MeshNode* n =
9733             static_cast<const SMDS_MeshNode*>( nIt->next() );
9734           nnIt = nReplaceMap.find( n );
9735           if ( nnIt != nReplaceMap.end() ) {
9736             nbReplaced++;
9737             n = (*nnIt).second;
9738           }
9739           nodes[ i++ ] = n;
9740         }
9741         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9742         //         elemIDsToRemove.push_back( e->GetID() );
9743         //       else
9744         if ( nbReplaced )
9745           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9746       }
9747     }
9748
9749   Remove( nodeIDsToRemove, true );
9750
9751   return aResult;
9752 }
9753
9754 //================================================================================
9755 /*!
9756  * \brief Find corresponding nodes in two sets of faces
9757  * \param theSide1 - first face set
9758  * \param theSide2 - second first face
9759  * \param theFirstNode1 - a boundary node of set 1
9760  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9761  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9762  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9763  * \param nReplaceMap - output map of corresponding nodes
9764  * \retval bool  - is a success or not
9765  */
9766 //================================================================================
9767
9768 #ifdef _DEBUG_
9769 //#define DEBUG_MATCHING_NODES
9770 #endif
9771
9772 SMESH_MeshEditor::Sew_Error
9773 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9774                                     set<const SMDS_MeshElement*>& theSide2,
9775                                     const SMDS_MeshNode*          theFirstNode1,
9776                                     const SMDS_MeshNode*          theFirstNode2,
9777                                     const SMDS_MeshNode*          theSecondNode1,
9778                                     const SMDS_MeshNode*          theSecondNode2,
9779                                     TNodeNodeMap &                nReplaceMap)
9780 {
9781   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9782
9783   nReplaceMap.clear();
9784   if ( theFirstNode1 != theFirstNode2 )
9785     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9786   if ( theSecondNode1 != theSecondNode2 )
9787     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9788
9789   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9790   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9791
9792   list< NLink > linkList[2];
9793   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9794   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9795
9796   // loop on links in linkList; find faces by links and append links
9797   // of the found faces to linkList
9798   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9799   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9800     NLink link[] = { *linkIt[0], *linkIt[1] };
9801     if ( linkSet.find( link[0] ) == linkSet.end() )
9802       continue;
9803
9804     // by links, find faces in the face sets,
9805     // and find indices of link nodes in the found faces;
9806     // in a face set, there is only one or no face sharing a link
9807     // ---------------------------------------------------------------
9808
9809     const SMDS_MeshElement* face[] = { 0, 0 };
9810     list<const SMDS_MeshNode*> notLinkNodes[2];
9811     //bool reverse[] = { false, false }; // order of notLinkNodes
9812     int nbNodes[2];
9813     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9814     {
9815       const SMDS_MeshNode* n1 = link[iSide].first;
9816       const SMDS_MeshNode* n2 = link[iSide].second;
9817       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9818       set< const SMDS_MeshElement* > facesOfNode1;
9819       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9820       {
9821         // during a loop of the first node, we find all faces around n1,
9822         // during a loop of the second node, we find one face sharing both n1 and n2
9823         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9824         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9825         while ( fIt->more() ) { // loop on faces sharing a node
9826           const SMDS_MeshElement* f = fIt->next();
9827           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9828               ! facesOfNode1.insert( f ).second ) // f encounters twice
9829           {
9830             if ( face[ iSide ] ) {
9831               MESSAGE( "2 faces per link " );
9832               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9833             }
9834             face[ iSide ] = f;
9835             faceSet->erase( f );
9836
9837             // get not link nodes
9838             int nbN = f->NbNodes();
9839             if ( f->IsQuadratic() )
9840               nbN /= 2;
9841             nbNodes[ iSide ] = nbN;
9842             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9843             int i1 = f->GetNodeIndex( n1 );
9844             int i2 = f->GetNodeIndex( n2 );
9845             int iEnd = nbN, iBeg = -1, iDelta = 1;
9846             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9847             if ( reverse ) {
9848               std::swap( iEnd, iBeg ); iDelta = -1;
9849             }
9850             int i = i2;
9851             while ( true ) {
9852               i += iDelta;
9853               if ( i == iEnd ) i = iBeg + iDelta;
9854               if ( i == i1 ) break;
9855               nodes.push_back ( f->GetNode( i ) );
9856             }
9857           }
9858         }
9859       }
9860     }
9861     // check similarity of elements of the sides
9862     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9863       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9864       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9865         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9866       }
9867       else {
9868         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9869       }
9870     }
9871
9872     // set nodes to merge
9873     // -------------------
9874
9875     if ( face[0] && face[1] )  {
9876       if ( nbNodes[0] != nbNodes[1] ) {
9877         MESSAGE("Diff nb of face nodes");
9878         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9879       }
9880 #ifdef DEBUG_MATCHING_NODES
9881       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9882                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9883                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9884 #endif
9885       int nbN = nbNodes[0];
9886       {
9887         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9888         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9889         for ( int i = 0 ; i < nbN - 2; ++i ) {
9890 #ifdef DEBUG_MATCHING_NODES
9891           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9892 #endif
9893           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9894         }
9895       }
9896
9897       // add other links of the face 1 to linkList
9898       // -----------------------------------------
9899
9900       const SMDS_MeshElement* f0 = face[0];
9901       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9902       for ( int i = 0; i < nbN; i++ )
9903       {
9904         const SMDS_MeshNode* n2 = f0->GetNode( i );
9905         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9906           linkSet.insert( SMESH_TLink( n1, n2 ));
9907         if ( !iter_isnew.second ) { // already in a set: no need to process
9908           linkSet.erase( iter_isnew.first );
9909         }
9910         else // new in set == encountered for the first time: add
9911         {
9912 #ifdef DEBUG_MATCHING_NODES
9913           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9914                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9915 #endif
9916           linkList[0].push_back ( NLink( n1, n2 ));
9917           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9918         }
9919         n1 = n2;
9920       }
9921     } // 2 faces found
9922   } // loop on link lists
9923
9924   return SEW_OK;
9925 }
9926
9927 //================================================================================
9928 /*!
9929   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9930   \param theElems - the list of elements (edges or faces) to be replicated
9931   The nodes for duplication could be found from these elements
9932   \param theNodesNot - list of nodes to NOT replicate
9933   \param theAffectedElems - the list of elements (cells and edges) to which the 
9934   replicated nodes should be associated to.
9935   \return TRUE if operation has been completed successfully, FALSE otherwise
9936 */
9937 //================================================================================
9938
9939 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9940                                     const TIDSortedElemSet& theNodesNot,
9941                                     const TIDSortedElemSet& theAffectedElems )
9942 {
9943   myLastCreatedElems.Clear();
9944   myLastCreatedNodes.Clear();
9945
9946   if ( theElems.size() == 0 )
9947     return false;
9948
9949   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9950   if ( !aMeshDS )
9951     return false;
9952
9953   bool res = false;
9954   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9955   // duplicate elements and nodes
9956   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9957   // replce nodes by duplications
9958   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9959   return res;
9960 }
9961
9962 //================================================================================
9963 /*!
9964   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9965   \param theMeshDS - mesh instance
9966   \param theElems - the elements replicated or modified (nodes should be changed)
9967   \param theNodesNot - nodes to NOT replicate
9968   \param theNodeNodeMap - relation of old node to new created node
9969   \param theIsDoubleElem - flag os to replicate element or modify
9970   \return TRUE if operation has been completed successfully, FALSE otherwise
9971 */
9972 //================================================================================
9973
9974 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9975                                     const TIDSortedElemSet& theElems,
9976                                     const TIDSortedElemSet& theNodesNot,
9977                                     std::map< const SMDS_MeshNode*,
9978                                     const SMDS_MeshNode* >& theNodeNodeMap,
9979                                     const bool theIsDoubleElem )
9980 {
9981   // iterate on through element and duplicate them (by nodes duplication)
9982   bool res = false;
9983   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9984   for ( ;  elemItr != theElems.end(); ++elemItr )
9985   {
9986     const SMDS_MeshElement* anElem = *elemItr;
9987     if (!anElem)
9988       continue;
9989
9990     bool isDuplicate = false;
9991     // duplicate nodes to duplicate element
9992     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9993     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9994     int ind = 0;
9995     while ( anIter->more() ) 
9996     { 
9997
9998       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9999       SMDS_MeshNode* aNewNode = aCurrNode;
10000       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10001         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10002       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10003       {
10004         // duplicate node
10005         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10006         theNodeNodeMap[ aCurrNode ] = aNewNode;
10007         myLastCreatedNodes.Append( aNewNode );
10008       }
10009       isDuplicate |= (aCurrNode != aNewNode);
10010       newNodes[ ind++ ] = aNewNode;
10011     }
10012     if ( !isDuplicate )
10013       continue;
10014
10015     if ( theIsDoubleElem )
10016       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10017     else
10018       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10019
10020     res = true;
10021   }
10022   return res;
10023 }
10024
10025 //================================================================================
10026 /*!
10027   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10028   \param theNodes - identifiers of nodes to be doubled
10029   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10030          nodes. If list of element identifiers is empty then nodes are doubled but 
10031          they not assigned to elements
10032   \return TRUE if operation has been completed successfully, FALSE otherwise
10033 */
10034 //================================================================================
10035
10036 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10037                                     const std::list< int >& theListOfModifiedElems )
10038 {
10039   myLastCreatedElems.Clear();
10040   myLastCreatedNodes.Clear();
10041
10042   if ( theListOfNodes.size() == 0 )
10043     return false;
10044
10045   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10046   if ( !aMeshDS )
10047     return false;
10048
10049   // iterate through nodes and duplicate them
10050
10051   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10052
10053   std::list< int >::const_iterator aNodeIter;
10054   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10055   {
10056     int aCurr = *aNodeIter;
10057     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10058     if ( !aNode )
10059       continue;
10060
10061     // duplicate node
10062
10063     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10064     if ( aNewNode )
10065     {
10066       anOldNodeToNewNode[ aNode ] = aNewNode;
10067       myLastCreatedNodes.Append( aNewNode );
10068     }
10069   }
10070
10071   // Create map of new nodes for modified elements
10072
10073   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10074
10075   std::list< int >::const_iterator anElemIter;
10076   for ( anElemIter = theListOfModifiedElems.begin(); 
10077         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10078   {
10079     int aCurr = *anElemIter;
10080     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10081     if ( !anElem )
10082       continue;
10083
10084     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10085
10086     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10087     int ind = 0;
10088     while ( anIter->more() ) 
10089     { 
10090       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10091       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10092       {
10093         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10094         aNodeArr[ ind++ ] = aNewNode;
10095       }
10096       else
10097         aNodeArr[ ind++ ] = aCurrNode;
10098     }
10099     anElemToNodes[ anElem ] = aNodeArr;
10100   }
10101
10102   // Change nodes of elements  
10103
10104   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10105     anElemToNodesIter = anElemToNodes.begin();
10106   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10107   {
10108     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10109     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10110     if ( anElem )
10111       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10112   }
10113
10114   return true;
10115 }
10116
10117 namespace {
10118
10119   //================================================================================
10120   /*!
10121   \brief Check if element located inside shape
10122   \return TRUE if IN or ON shape, FALSE otherwise
10123   */
10124   //================================================================================
10125
10126   template<class Classifier>
10127   bool isInside(const SMDS_MeshElement* theElem,
10128                 Classifier&             theClassifier,
10129                 const double            theTol)
10130   {
10131     gp_XYZ centerXYZ (0, 0, 0);
10132     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10133     while (aNodeItr->more())
10134       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10135
10136     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10137     theClassifier.Perform(aPnt, theTol);
10138     TopAbs_State aState = theClassifier.State();
10139     return (aState == TopAbs_IN || aState == TopAbs_ON );
10140   }
10141
10142   //================================================================================
10143   /*!
10144    * \brief Classifier of the 3D point on the TopoDS_Face
10145    *        with interaface suitable for isInside()
10146    */
10147   //================================================================================
10148
10149   struct _FaceClassifier
10150   {
10151     Extrema_ExtPS       _extremum;
10152     BRepAdaptor_Surface _surface;
10153     TopAbs_State        _state;
10154
10155     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10156     {
10157       _extremum.Initialize( _surface,
10158                             _surface.FirstUParameter(), _surface.LastUParameter(),
10159                             _surface.FirstVParameter(), _surface.LastVParameter(),
10160                             _surface.Tolerance(), _surface.Tolerance() );
10161     }
10162     void Perform(const gp_Pnt& aPnt, double theTol)
10163     {
10164       _state = TopAbs_OUT;
10165       _extremum.Perform(aPnt);
10166       if ( _extremum.IsDone() )
10167         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10168           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10169     }
10170     TopAbs_State State() const
10171     {
10172       return _state;
10173     }
10174   };
10175 }
10176
10177 //================================================================================
10178 /*!
10179   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10180   \param theElems - group of of elements (edges or faces) to be replicated
10181   \param theNodesNot - group of nodes not to replicate
10182   \param theShape - shape to detect affected elements (element which geometric center
10183   located on or inside shape).
10184   The replicated nodes should be associated to affected elements.
10185   \return TRUE if operation has been completed successfully, FALSE otherwise
10186 */
10187 //================================================================================
10188
10189 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10190                                             const TIDSortedElemSet& theNodesNot,
10191                                             const TopoDS_Shape&     theShape )
10192 {
10193   if ( theShape.IsNull() )
10194     return false;
10195
10196   const double aTol = Precision::Confusion();
10197   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10198   auto_ptr<_FaceClassifier>              aFaceClassifier;
10199   if ( theShape.ShapeType() == TopAbs_SOLID )
10200   {
10201     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10202     bsc3d->PerformInfinitePoint(aTol);
10203   }
10204   else if (theShape.ShapeType() == TopAbs_FACE )
10205   {
10206     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10207   }
10208
10209   // iterates on indicated elements and get elements by back references from their nodes
10210   TIDSortedElemSet anAffected;
10211   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10212   for ( ;  elemItr != theElems.end(); ++elemItr )
10213   {
10214     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10215     if (!anElem)
10216       continue;
10217
10218     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10219     while ( nodeItr->more() )
10220     {
10221       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10222       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10223         continue;
10224       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10225       while ( backElemItr->more() )
10226       {
10227         const SMDS_MeshElement* curElem = backElemItr->next();
10228         if ( curElem && theElems.find(curElem) == theElems.end() &&
10229              ( bsc3d.get() ?
10230                isInside( curElem, *bsc3d, aTol ) :
10231                isInside( curElem, *aFaceClassifier, aTol )))
10232           anAffected.insert( curElem );
10233       }
10234     }
10235   }
10236   return DoubleNodes( theElems, theNodesNot, anAffected );
10237 }
10238
10239 //================================================================================
10240 /*!
10241  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10242  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10243  * \return TRUE if operation has been completed successfully, FALSE otherwise
10244  */
10245 //================================================================================
10246
10247 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10248 {
10249   // iterates on volume elements and detect all free faces on them
10250   SMESHDS_Mesh* aMesh = GetMeshDS();
10251   if (!aMesh)
10252     return false;
10253   //bool res = false;
10254   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10255   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10256   while(vIt->more())
10257   {
10258     const SMDS_MeshVolume* volume = vIt->next();
10259     SMDS_VolumeTool vTool( volume );
10260     vTool.SetExternalNormal();
10261     const bool isPoly = volume->IsPoly();
10262     const bool isQuad = volume->IsQuadratic();
10263     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10264     {
10265       if (!vTool.IsFreeFace(iface))
10266         continue;
10267       nbFree++;
10268       vector<const SMDS_MeshNode *> nodes;
10269       int nbFaceNodes = vTool.NbFaceNodes(iface);
10270       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10271       int inode = 0;
10272       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10273         nodes.push_back(faceNodes[inode]);
10274       if (isQuad)
10275         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10276           nodes.push_back(faceNodes[inode]);
10277
10278       // add new face based on volume nodes
10279       if (aMesh->FindFace( nodes ) ) {
10280         nbExisted++;
10281         continue; // face already exsist
10282       }
10283       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10284       nbCreated++;
10285     }
10286   }
10287   return ( nbFree==(nbExisted+nbCreated) );
10288 }