Salome HOME
0020958: EDF 1529 SMESH : If some faces have been meshed with small
[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   void GetElementsNearLine( const gp_Ax1&                      line,
6275                             SMDSAbs_ElementType                type,
6276                             vector< const SMDS_MeshElement* >& foundElems);
6277   double getTolerance();
6278   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6279                             const double tolerance, double & param);
6280   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6281   bool isOuterBoundary(const SMDS_MeshElement* face) const
6282   {
6283     return _outerFaces.empty() || _outerFaces.count(face);
6284   }
6285   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6286   {
6287     const SMDS_MeshElement* _face;
6288     gp_Vec                  _faceNorm;
6289     bool                    _coincides; //!< the line lays in face plane
6290     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6291       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6292   };
6293   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6294   {
6295     SMESH_TLink      _link;
6296     TIDSortedElemSet _faces;
6297     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6298       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6299   };
6300 };
6301
6302 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6303 {
6304   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6305              << ", _coincides="<<i._coincides << ")";
6306 }
6307
6308 //=======================================================================
6309 /*!
6310  * \brief define tolerance for search
6311  */
6312 //=======================================================================
6313
6314 double SMESH_ElementSearcherImpl::getTolerance()
6315 {
6316   if ( _tolerance < 0 )
6317   {
6318     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6319
6320     _tolerance = 0;
6321     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6322     {
6323       double boxSize = _nodeSearcher->getTree()->maxSize();
6324       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6325     }
6326     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6327     {
6328       double boxSize = _ebbTree->maxSize();
6329       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6330     }
6331     if ( _tolerance == 0 )
6332     {
6333       // define tolerance by size of a most complex element
6334       int complexType = SMDSAbs_Volume;
6335       while ( complexType > SMDSAbs_All &&
6336               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6337         --complexType;
6338       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6339
6340       double elemSize;
6341       if ( complexType == int( SMDSAbs_Node ))
6342       {
6343         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6344         elemSize = 1;
6345         if ( meshInfo.NbNodes() > 2 )
6346           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6347       }
6348       else
6349       {
6350         const SMDS_MeshElement* elem =
6351           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6352         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6353         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6354         while ( nodeIt->more() )
6355         {
6356           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6357           elemSize = max( dist, elemSize );
6358         }
6359       }
6360       _tolerance = 1e-6 * elemSize;
6361     }
6362   }
6363   return _tolerance;
6364 }
6365
6366 //================================================================================
6367 /*!
6368  * \brief Find intersection of the line and an edge of face and return parameter on line
6369  */
6370 //================================================================================
6371
6372 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6373                                                      const SMDS_MeshElement* face,
6374                                                      const double            tol,
6375                                                      double &                param)
6376 {
6377   int nbInts = 0;
6378   param = 0;
6379
6380   GeomAPI_ExtremaCurveCurve anExtCC;
6381   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6382   
6383   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6384   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6385   {
6386     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6387                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6388     anExtCC.Init( lineCurve, edge);
6389     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6390     {
6391       Quantity_Parameter pl, pe;
6392       anExtCC.LowerDistanceParameters( pl, pe );
6393       param += pl;
6394       if ( ++nbInts == 2 )
6395         break;
6396     }
6397   }
6398   if ( nbInts > 0 ) param /= nbInts;
6399   return nbInts > 0;
6400 }
6401 //================================================================================
6402 /*!
6403  * \brief Find all faces belonging to the outer boundary of mesh
6404  */
6405 //================================================================================
6406
6407 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6408 {
6409   if ( _outerFacesFound ) return;
6410
6411   // Collect all outer faces by passing from one outer face to another via their links
6412   // and BTW find out if there are internal faces at all.
6413
6414   // checked links and links where outer boundary meets internal one
6415   set< SMESH_TLink > visitedLinks, seamLinks;
6416
6417   // links to treat with already visited faces sharing them
6418   list < TFaceLink > startLinks;
6419
6420   // load startLinks with the first outerFace
6421   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6422   _outerFaces.insert( outerFace );
6423
6424   TIDSortedElemSet emptySet;
6425   while ( !startLinks.empty() )
6426   {
6427     const SMESH_TLink& link  = startLinks.front()._link;
6428     TIDSortedElemSet&  faces = startLinks.front()._faces;
6429
6430     outerFace = *faces.begin();
6431     // find other faces sharing the link
6432     const SMDS_MeshElement* f;
6433     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6434       faces.insert( f );
6435
6436     // select another outer face among the found 
6437     const SMDS_MeshElement* outerFace2 = 0;
6438     if ( faces.size() == 2 )
6439     {
6440       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6441     }
6442     else if ( faces.size() > 2 )
6443     {
6444       seamLinks.insert( link );
6445
6446       // link direction within the outerFace
6447       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6448                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6449       int i1 = outerFace->GetNodeIndex( link.node1() );
6450       int i2 = outerFace->GetNodeIndex( link.node2() );
6451       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6452       if ( rev ) n1n2.Reverse();
6453       // outerFace normal
6454       gp_XYZ ofNorm, fNorm;
6455       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6456       {
6457         // direction from the link inside outerFace
6458         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6459         // sort all other faces by angle with the dirInOF
6460         map< double, const SMDS_MeshElement* > angle2Face;
6461         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6462         for ( ; face != faces.end(); ++face )
6463         {
6464           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6465             continue;
6466           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6467           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6468           if ( angle < 0 ) angle += 2*PI;
6469           angle2Face.insert( make_pair( angle, *face ));
6470         }
6471         if ( !angle2Face.empty() )
6472           outerFace2 = angle2Face.begin()->second;
6473       }
6474     }
6475     // store the found outer face and add its links to continue seaching from
6476     if ( outerFace2 )
6477     {
6478       _outerFaces.insert( outerFace );
6479       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6480       for ( int i = 0; i < nbNodes; ++i )
6481       {
6482         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6483         if ( visitedLinks.insert( link2 ).second )
6484           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6485       }
6486     }
6487     startLinks.pop_front();
6488   }
6489   _outerFacesFound = true;
6490
6491   if ( !seamLinks.empty() )
6492   {
6493     // There are internal boundaries touching the outher one,
6494     // find all faces of internal boundaries in order to find
6495     // faces of boundaries of holes, if any.
6496     
6497   }
6498   else
6499   {
6500     _outerFaces.clear();
6501   }
6502 }
6503
6504 //=======================================================================
6505 /*!
6506  * \brief Find elements of given type where the given point is IN or ON.
6507  *        Returns nb of found elements and elements them-selves.
6508  *
6509  * 'ALL' type means elements of any type excluding nodes and 0D elements
6510  */
6511 //=======================================================================
6512
6513 int SMESH_ElementSearcherImpl::
6514 FindElementsByPoint(const gp_Pnt&                      point,
6515                     SMDSAbs_ElementType                type,
6516                     vector< const SMDS_MeshElement* >& foundElements)
6517 {
6518   foundElements.clear();
6519
6520   double tolerance = getTolerance();
6521
6522   // =================================================================================
6523   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6524   {
6525     if ( !_nodeSearcher )
6526       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6527
6528     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6529     if ( !closeNode ) return foundElements.size();
6530
6531     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6532       return foundElements.size(); // to far from any node
6533
6534     if ( type == SMDSAbs_Node )
6535     {
6536       foundElements.push_back( closeNode );
6537     }
6538     else
6539     {
6540       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6541       while ( elemIt->more() )
6542         foundElements.push_back( elemIt->next() );
6543     }
6544   }
6545   // =================================================================================
6546   else // elements more complex than 0D
6547   {
6548     if ( !_ebbTree || _elementType != type )
6549     {
6550       if ( _ebbTree ) delete _ebbTree;
6551       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6552     }
6553     TIDSortedElemSet suspectElems;
6554     _ebbTree->getElementsNearPoint( point, suspectElems );
6555     TIDSortedElemSet::iterator elem = suspectElems.begin();
6556     for ( ; elem != suspectElems.end(); ++elem )
6557       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6558         foundElements.push_back( *elem );
6559   }
6560   return foundElements.size();
6561 }
6562
6563 //================================================================================
6564 /*!
6565  * \brief Classify the given point in the closed 2D mesh
6566  */
6567 //================================================================================
6568
6569 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6570 {
6571   double tolerance = getTolerance();
6572   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6573   {
6574     if ( _ebbTree ) delete _ebbTree;
6575     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6576   }
6577   // Algo: analyse transition of a line starting at the point through mesh boundary;
6578   // try three lines parallel to axis of the coordinate system and perform rough
6579   // analysis. If solution is not clear perform thorough analysis.
6580
6581   const int nbAxes = 3;
6582   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6583   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6584   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6585   multimap< int, int > nbInt2Axis; // to find the simplest case
6586   for ( int axis = 0; axis < nbAxes; ++axis )
6587   {
6588     gp_Ax1 lineAxis( point, axisDir[axis]);
6589     gp_Lin line    ( lineAxis );
6590
6591     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6592     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6593
6594     // Intersect faces with the line
6595
6596     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6597     TIDSortedElemSet::iterator face = suspectFaces.begin();
6598     for ( ; face != suspectFaces.end(); ++face )
6599     {
6600       // get face plane
6601       gp_XYZ fNorm;
6602       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6603       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6604
6605       // perform intersection
6606       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6607       if ( !intersection.IsDone() )
6608         continue;
6609       if ( intersection.IsInQuadric() )
6610       {
6611         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6612       }
6613       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6614       {
6615         gp_Pnt intersectionPoint = intersection.Point(1);
6616         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6617           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6618       }
6619     }
6620     // Analyse intersections roughly
6621
6622     int nbInter = u2inters.size();
6623     if ( nbInter == 0 )
6624       return TopAbs_OUT; 
6625
6626     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6627     if ( nbInter == 1 ) // not closed mesh
6628       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6629
6630     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6631       return TopAbs_ON;
6632
6633     if ( (f<0) == (l<0) )
6634       return TopAbs_OUT;
6635
6636     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6637     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6638     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6639       return TopAbs_IN;
6640
6641     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6642
6643     if ( _outerFacesFound ) break; // pass to thorough analysis
6644
6645   } // three attempts - loop on CS axes
6646
6647   // Analyse intersections thoroughly.
6648   // We make two loops maximum, on the first one we only exclude touching intersections,
6649   // on the second, if situation is still unclear, we gather and use information on
6650   // position of faces (internal or outer). If faces position is already gathered,
6651   // we make the second loop right away.
6652
6653   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6654   {
6655     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6656     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6657     {
6658       int axis = nb_axis->second;
6659       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6660
6661       gp_Ax1 lineAxis( point, axisDir[axis]);
6662       gp_Lin line    ( lineAxis );
6663
6664       // add tangent intersections to u2inters
6665       double param;
6666       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6667       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6668         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6669           u2inters.insert(make_pair( param, *tgtInt ));
6670       tangentInters[ axis ].clear();
6671
6672       // Count intersections before and after the point excluding touching ones.
6673       // If hasPositionInfo we count intersections of outer boundary only
6674
6675       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6676       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6677       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6678       bool ok = ! u_int1->second._coincides;
6679       while ( ok && u_int1 != u2inters.end() )
6680       {
6681         double u = u_int1->first;
6682         bool touchingInt = false;
6683         if ( ++u_int2 != u2inters.end() )
6684         {
6685           // skip intersections at the same point (if the line passes through edge or node)
6686           int nbSamePnt = 0;
6687           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6688           {
6689             ++nbSamePnt;
6690             ++u_int2;
6691           }
6692
6693           // skip tangent intersections
6694           int nbTgt = 0;
6695           const SMDS_MeshElement* prevFace = u_int1->second._face;
6696           while ( ok && u_int2->second._coincides )
6697           {
6698             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6699               ok = false;
6700             else
6701             {
6702               nbTgt++;
6703               u_int2++;
6704               ok = ( u_int2 != u2inters.end() );
6705             }
6706           }
6707           if ( !ok ) break;
6708
6709           // skip intersections at the same point after tangent intersections
6710           if ( nbTgt > 0 )
6711           {
6712             double u2 = u_int2->first;
6713             ++u_int2;
6714             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6715             {
6716               ++nbSamePnt;
6717               ++u_int2;
6718             }
6719           }
6720           // decide if we skipped a touching intersection
6721           if ( nbSamePnt + nbTgt > 0 )
6722           {
6723             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6724             map< double, TInters >::iterator u_int = u_int1;
6725             for ( ; u_int != u_int2; ++u_int )
6726             {
6727               if ( u_int->second._coincides ) continue;
6728               double dot = u_int->second._faceNorm * line.Direction();
6729               if ( dot > maxDot ) maxDot = dot;
6730               if ( dot < minDot ) minDot = dot;
6731             }
6732             touchingInt = ( minDot*maxDot < 0 );
6733           }
6734         }
6735         if ( !touchingInt )
6736         {
6737           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6738           {
6739             if ( u < 0 )
6740               ++nbIntBeforePoint;
6741             else
6742               ++nbIntAfterPoint;
6743           }
6744           if ( u < f ) f = u;
6745           if ( u > l ) l = u;
6746         }
6747
6748         u_int1 = u_int2; // to next intersection
6749
6750       } // loop on intersections with one line
6751
6752       if ( ok )
6753       {
6754         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6755           return TopAbs_ON;
6756
6757         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6758           return TopAbs_OUT; 
6759
6760         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6761           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6762
6763         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6764           return TopAbs_IN;
6765
6766         if ( (f<0) == (l<0) )
6767           return TopAbs_OUT;
6768
6769         if ( hasPositionInfo )
6770           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6771       }
6772     } // loop on intersections of the tree lines - thorough analysis
6773
6774     if ( !hasPositionInfo )
6775     {
6776       // gather info on faces position - is face in the outer boundary or not
6777       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6778       findOuterBoundary( u2inters.begin()->second._face );
6779     }
6780
6781   } // two attempts - with and w/o faces position info in the mesh
6782
6783   return TopAbs_UNKNOWN;
6784 }
6785
6786 //=======================================================================
6787 /*!
6788  * \brief Return elements possibly intersecting the line
6789  */
6790 //=======================================================================
6791
6792 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6793                                                      SMDSAbs_ElementType                type,
6794                                                      vector< const SMDS_MeshElement* >& foundElems)
6795 {
6796   if ( !_ebbTree || _elementType != type )
6797   {
6798     if ( _ebbTree ) delete _ebbTree;
6799     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6800   }
6801   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6802   _ebbTree->getElementsNearLine( line, suspectFaces );
6803   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6804 }
6805
6806 //=======================================================================
6807 /*!
6808  * \brief Return SMESH_ElementSearcher
6809  */
6810 //=======================================================================
6811
6812 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6813 {
6814   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6815 }
6816
6817 //=======================================================================
6818 /*!
6819  * \brief Return true if the point is IN or ON of the element
6820  */
6821 //=======================================================================
6822
6823 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6824 {
6825   if ( element->GetType() == SMDSAbs_Volume)
6826   {
6827     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6828   }
6829
6830   // get ordered nodes
6831
6832   vector< gp_XYZ > xyz;
6833
6834   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6835   if ( element->IsQuadratic() )
6836     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6837       nodeIt = f->interlacedNodesElemIterator();
6838     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6839       nodeIt = e->interlacedNodesElemIterator();
6840
6841   while ( nodeIt->more() )
6842     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6843
6844   int i, nbNodes = element->NbNodes();
6845
6846   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6847   {
6848     // compute face normal
6849     gp_Vec faceNorm(0,0,0);
6850     xyz.push_back( xyz.front() );
6851     for ( i = 0; i < nbNodes; ++i )
6852     {
6853       gp_Vec edge1( xyz[i+1], xyz[i]);
6854       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6855       faceNorm += edge1 ^ edge2;
6856     }
6857     double normSize = faceNorm.Magnitude();
6858     if ( normSize <= tol )
6859     {
6860       // degenerated face: point is out if it is out of all face edges
6861       for ( i = 0; i < nbNodes; ++i )
6862       {
6863         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6864         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6865         SMDS_MeshEdge edge( &n1, &n2 );
6866         if ( !isOut( &edge, point, tol ))
6867           return false;
6868       }
6869       return true;
6870     }
6871     faceNorm /= normSize;
6872
6873     // check if the point lays on face plane
6874     gp_Vec n2p( xyz[0], point );
6875     if ( fabs( n2p * faceNorm ) > tol )
6876       return true; // not on face plane
6877
6878     // check if point is out of face boundary:
6879     // define it by closest transition of a ray point->infinity through face boundary
6880     // on the face plane.
6881     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6882     // to find intersections of the ray with the boundary.
6883     gp_Vec ray = n2p;
6884     gp_Vec plnNorm = ray ^ faceNorm;
6885     normSize = plnNorm.Magnitude();
6886     if ( normSize <= tol ) return false; // point coincides with the first node
6887     plnNorm /= normSize;
6888     // for each node of the face, compute its signed distance to the plane
6889     vector<double> dist( nbNodes + 1);
6890     for ( i = 0; i < nbNodes; ++i )
6891     {
6892       gp_Vec n2p( xyz[i], point );
6893       dist[i] = n2p * plnNorm;
6894     }
6895     dist.back() = dist.front();
6896     // find the closest intersection
6897     int    iClosest = -1;
6898     double rClosest, distClosest = 1e100;;
6899     gp_Pnt pClosest;
6900     for ( i = 0; i < nbNodes; ++i )
6901     {
6902       double r;
6903       if ( fabs( dist[i]) < tol )
6904         r = 0.;
6905       else if ( fabs( dist[i+1]) < tol )
6906         r = 1.;
6907       else if ( dist[i] * dist[i+1] < 0 )
6908         r = dist[i] / ( dist[i] - dist[i+1] );
6909       else
6910         continue; // no intersection
6911       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6912       gp_Vec p2int ( point, pInt);
6913       if ( p2int * ray > -tol ) // right half-space
6914       {
6915         double intDist = p2int.SquareMagnitude();
6916         if ( intDist < distClosest )
6917         {
6918           iClosest = i;
6919           rClosest = r;
6920           pClosest = pInt;
6921           distClosest = intDist;
6922         }
6923       }
6924     }
6925     if ( iClosest < 0 )
6926       return true; // no intesections - out
6927
6928     // analyse transition
6929     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6930     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6931     gp_Vec p2int ( point, pClosest );
6932     bool out = (edgeNorm * p2int) < -tol;
6933     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6934       return out;
6935
6936     // ray pass through a face node; analyze transition through an adjacent edge
6937     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6938     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6939     gp_Vec edgeAdjacent( p1, p2 );
6940     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6941     bool out2 = (edgeNorm2 * p2int) < -tol;
6942
6943     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6944     return covexCorner ? (out || out2) : (out && out2);
6945   }
6946   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6947   {
6948     // point is out of edge if it is NOT ON any straight part of edge
6949     // (we consider quadratic edge as being composed of two straight parts)
6950     for ( i = 1; i < nbNodes; ++i )
6951     {
6952       gp_Vec edge( xyz[i-1], xyz[i]);
6953       gp_Vec n1p ( xyz[i-1], point);
6954       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6955       if ( dist > tol )
6956         continue;
6957       gp_Vec n2p( xyz[i], point );
6958       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6959         continue;
6960       return false; // point is ON this part
6961     }
6962     return true;
6963   }
6964   // Node or 0D element -------------------------------------------------------------------------
6965   {
6966     gp_Vec n2p ( xyz[0], point );
6967     return n2p.Magnitude() <= tol;
6968   }
6969   return true;
6970 }
6971
6972 //=======================================================================
6973 //function : SimplifyFace
6974 //purpose  :
6975 //=======================================================================
6976 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6977                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6978                                     vector<int>&                        quantities) const
6979 {
6980   int nbNodes = faceNodes.size();
6981
6982   if (nbNodes < 3)
6983     return 0;
6984
6985   set<const SMDS_MeshNode*> nodeSet;
6986
6987   // get simple seq of nodes
6988   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6989   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6990   int iSimple = 0, nbUnique = 0;
6991
6992   simpleNodes[iSimple++] = faceNodes[0];
6993   nbUnique++;
6994   for (int iCur = 1; iCur < nbNodes; iCur++) {
6995     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6996       simpleNodes[iSimple++] = faceNodes[iCur];
6997       if (nodeSet.insert( faceNodes[iCur] ).second)
6998         nbUnique++;
6999     }
7000   }
7001   int nbSimple = iSimple;
7002   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7003     nbSimple--;
7004     iSimple--;
7005   }
7006
7007   if (nbUnique < 3)
7008     return 0;
7009
7010   // separate loops
7011   int nbNew = 0;
7012   bool foundLoop = (nbSimple > nbUnique);
7013   while (foundLoop) {
7014     foundLoop = false;
7015     set<const SMDS_MeshNode*> loopSet;
7016     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7017       const SMDS_MeshNode* n = simpleNodes[iSimple];
7018       if (!loopSet.insert( n ).second) {
7019         foundLoop = true;
7020
7021         // separate loop
7022         int iC = 0, curLast = iSimple;
7023         for (; iC < curLast; iC++) {
7024           if (simpleNodes[iC] == n) break;
7025         }
7026         int loopLen = curLast - iC;
7027         if (loopLen > 2) {
7028           // create sub-element
7029           nbNew++;
7030           quantities.push_back(loopLen);
7031           for (; iC < curLast; iC++) {
7032             poly_nodes.push_back(simpleNodes[iC]);
7033           }
7034         }
7035         // shift the rest nodes (place from the first loop position)
7036         for (iC = curLast + 1; iC < nbSimple; iC++) {
7037           simpleNodes[iC - loopLen] = simpleNodes[iC];
7038         }
7039         nbSimple -= loopLen;
7040         iSimple -= loopLen;
7041       }
7042     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7043   } // while (foundLoop)
7044
7045   if (iSimple > 2) {
7046     nbNew++;
7047     quantities.push_back(iSimple);
7048     for (int i = 0; i < iSimple; i++)
7049       poly_nodes.push_back(simpleNodes[i]);
7050   }
7051
7052   return nbNew;
7053 }
7054
7055 //=======================================================================
7056 //function : MergeNodes
7057 //purpose  : In each group, the cdr of nodes are substituted by the first one
7058 //           in all elements.
7059 //=======================================================================
7060
7061 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7062 {
7063   myLastCreatedElems.Clear();
7064   myLastCreatedNodes.Clear();
7065
7066   SMESHDS_Mesh* aMesh = GetMeshDS();
7067
7068   TNodeNodeMap nodeNodeMap; // node to replace - new node
7069   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7070   list< int > rmElemIds, rmNodeIds;
7071
7072   // Fill nodeNodeMap and elems
7073
7074   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7075   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7076     list<const SMDS_MeshNode*>& nodes = *grIt;
7077     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7078     const SMDS_MeshNode* nToKeep = *nIt;
7079     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7080       const SMDS_MeshNode* nToRemove = *nIt;
7081       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7082       if ( nToRemove != nToKeep ) {
7083         rmNodeIds.push_back( nToRemove->GetID() );
7084         AddToSameGroups( nToKeep, nToRemove, aMesh );
7085       }
7086
7087       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7088       while ( invElemIt->more() ) {
7089         const SMDS_MeshElement* elem = invElemIt->next();
7090         elems.insert(elem);
7091       }
7092     }
7093   }
7094   // Change element nodes or remove an element
7095
7096   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7097   for ( ; eIt != elems.end(); eIt++ ) {
7098     const SMDS_MeshElement* elem = *eIt;
7099     int nbNodes = elem->NbNodes();
7100     int aShapeId = FindShape( elem );
7101
7102     set<const SMDS_MeshNode*> nodeSet;
7103     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7104     int iUnique = 0, iCur = 0, nbRepl = 0;
7105     vector<int> iRepl( nbNodes );
7106
7107     // get new seq of nodes
7108     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7109     while ( itN->more() ) {
7110       const SMDS_MeshNode* n =
7111         static_cast<const SMDS_MeshNode*>( itN->next() );
7112
7113       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7114       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7115         n = (*nnIt).second;
7116         // BUG 0020185: begin
7117         {
7118           bool stopRecur = false;
7119           set<const SMDS_MeshNode*> nodesRecur;
7120           nodesRecur.insert(n);
7121           while (!stopRecur) {
7122             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7123             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7124               n = (*nnIt_i).second;
7125               if (!nodesRecur.insert(n).second) {
7126                 // error: recursive dependancy
7127                 stopRecur = true;
7128               }
7129             }
7130             else
7131               stopRecur = true;
7132           }
7133         }
7134         // BUG 0020185: end
7135         iRepl[ nbRepl++ ] = iCur;
7136       }
7137       curNodes[ iCur ] = n;
7138       bool isUnique = nodeSet.insert( n ).second;
7139       if ( isUnique )
7140         uniqueNodes[ iUnique++ ] = n;
7141       iCur++;
7142     }
7143
7144     // Analyse element topology after replacement
7145
7146     bool isOk = true;
7147     int nbUniqueNodes = nodeSet.size();
7148     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7149       // Polygons and Polyhedral volumes
7150       if (elem->IsPoly()) {
7151
7152         if (elem->GetType() == SMDSAbs_Face) {
7153           // Polygon
7154           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7155           int inode = 0;
7156           for (; inode < nbNodes; inode++) {
7157             face_nodes[inode] = curNodes[inode];
7158           }
7159
7160           vector<const SMDS_MeshNode *> polygons_nodes;
7161           vector<int> quantities;
7162           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7163
7164           if (nbNew > 0) {
7165             inode = 0;
7166             for (int iface = 0; iface < nbNew - 1; iface++) {
7167               int nbNodes = quantities[iface];
7168               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7169               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7170                 poly_nodes[ii] = polygons_nodes[inode];
7171               }
7172               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7173               myLastCreatedElems.Append(newElem);
7174               if (aShapeId)
7175                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7176             }
7177             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7178           }
7179           else {
7180             rmElemIds.push_back(elem->GetID());
7181           }
7182
7183         }
7184         else if (elem->GetType() == SMDSAbs_Volume) {
7185           // Polyhedral volume
7186           if (nbUniqueNodes < 4) {
7187             rmElemIds.push_back(elem->GetID());
7188           }
7189           else {
7190             // each face has to be analized in order to check volume validity
7191             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7192               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7193             if (aPolyedre) {
7194               int nbFaces = aPolyedre->NbFaces();
7195
7196               vector<const SMDS_MeshNode *> poly_nodes;
7197               vector<int> quantities;
7198
7199               for (int iface = 1; iface <= nbFaces; iface++) {
7200                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7201                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7202
7203                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7204                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7205                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7206                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7207                     faceNode = (*nnIt).second;
7208                   }
7209                   faceNodes[inode - 1] = faceNode;
7210                 }
7211
7212                 SimplifyFace(faceNodes, poly_nodes, quantities);
7213               }
7214
7215               if (quantities.size() > 3) {
7216                 // to be done: remove coincident faces
7217               }
7218
7219               if (quantities.size() > 3)
7220                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7221               else
7222                 rmElemIds.push_back(elem->GetID());
7223
7224             }
7225             else {
7226               rmElemIds.push_back(elem->GetID());
7227             }
7228           }
7229         }
7230         else {
7231         }
7232
7233         continue;
7234       }
7235
7236       // Regular elements
7237       switch ( nbNodes ) {
7238       case 2: ///////////////////////////////////// EDGE
7239         isOk = false; break;
7240       case 3: ///////////////////////////////////// TRIANGLE
7241         isOk = false; break;
7242       case 4:
7243         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7244           isOk = false;
7245         else { //////////////////////////////////// QUADRANGLE
7246           if ( nbUniqueNodes < 3 )
7247             isOk = false;
7248           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7249             isOk = false; // opposite nodes stick
7250         }
7251         break;
7252       case 6: ///////////////////////////////////// PENTAHEDRON
7253         if ( nbUniqueNodes == 4 ) {
7254           // ---------------------------------> tetrahedron
7255           if (nbRepl == 3 &&
7256               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7257             // all top nodes stick: reverse a bottom
7258             uniqueNodes[ 0 ] = curNodes [ 1 ];
7259             uniqueNodes[ 1 ] = curNodes [ 0 ];
7260           }
7261           else if (nbRepl == 3 &&
7262                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7263             // all bottom nodes stick: set a top before
7264             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7265             uniqueNodes[ 0 ] = curNodes [ 3 ];
7266             uniqueNodes[ 1 ] = curNodes [ 4 ];
7267             uniqueNodes[ 2 ] = curNodes [ 5 ];
7268           }
7269           else if (nbRepl == 4 &&
7270                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7271             // a lateral face turns into a line: reverse a bottom
7272             uniqueNodes[ 0 ] = curNodes [ 1 ];
7273             uniqueNodes[ 1 ] = curNodes [ 0 ];
7274           }
7275           else
7276             isOk = false;
7277         }
7278         else if ( nbUniqueNodes == 5 ) {
7279           // PENTAHEDRON --------------------> 2 tetrahedrons
7280           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7281             // a bottom node sticks with a linked top one
7282             // 1.
7283             SMDS_MeshElement* newElem =
7284               aMesh->AddVolume(curNodes[ 3 ],
7285                                curNodes[ 4 ],
7286                                curNodes[ 5 ],
7287                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7288             myLastCreatedElems.Append(newElem);
7289             if ( aShapeId )
7290               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7291             // 2. : reverse a bottom
7292             uniqueNodes[ 0 ] = curNodes [ 1 ];
7293             uniqueNodes[ 1 ] = curNodes [ 0 ];
7294             nbUniqueNodes = 4;
7295           }
7296           else
7297             isOk = false;
7298         }
7299         else
7300           isOk = false;
7301         break;
7302       case 8: {
7303         if(elem->IsQuadratic()) { // Quadratic quadrangle
7304           //   1    5    2
7305           //    +---+---+
7306           //    |       |
7307           //    |       |
7308           //   4+       +6
7309           //    |       |
7310           //    |       |
7311           //    +---+---+
7312           //   0    7    3
7313           isOk = false;
7314           if(nbRepl==3) {
7315             nbUniqueNodes = 6;
7316             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7317               uniqueNodes[0] = curNodes[0];
7318               uniqueNodes[1] = curNodes[2];
7319               uniqueNodes[2] = curNodes[3];
7320               uniqueNodes[3] = curNodes[5];
7321               uniqueNodes[4] = curNodes[6];
7322               uniqueNodes[5] = curNodes[7];
7323               isOk = true;
7324             }
7325             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7326               uniqueNodes[0] = curNodes[0];
7327               uniqueNodes[1] = curNodes[1];
7328               uniqueNodes[2] = curNodes[2];
7329               uniqueNodes[3] = curNodes[4];
7330               uniqueNodes[4] = curNodes[5];
7331               uniqueNodes[5] = curNodes[6];
7332               isOk = true;
7333             }
7334             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7335               uniqueNodes[0] = curNodes[1];
7336               uniqueNodes[1] = curNodes[2];
7337               uniqueNodes[2] = curNodes[3];
7338               uniqueNodes[3] = curNodes[5];
7339               uniqueNodes[4] = curNodes[6];
7340               uniqueNodes[5] = curNodes[0];
7341               isOk = true;
7342             }
7343             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7344               uniqueNodes[0] = curNodes[0];
7345               uniqueNodes[1] = curNodes[1];
7346               uniqueNodes[2] = curNodes[3];
7347               uniqueNodes[3] = curNodes[4];
7348               uniqueNodes[4] = curNodes[6];
7349               uniqueNodes[5] = curNodes[7];
7350               isOk = true;
7351             }
7352             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7353               uniqueNodes[0] = curNodes[0];
7354               uniqueNodes[1] = curNodes[2];
7355               uniqueNodes[2] = curNodes[3];
7356               uniqueNodes[3] = curNodes[1];
7357               uniqueNodes[4] = curNodes[6];
7358               uniqueNodes[5] = curNodes[7];
7359               isOk = true;
7360             }
7361             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7362               uniqueNodes[0] = curNodes[0];
7363               uniqueNodes[1] = curNodes[1];
7364               uniqueNodes[2] = curNodes[2];
7365               uniqueNodes[3] = curNodes[4];
7366               uniqueNodes[4] = curNodes[5];
7367               uniqueNodes[5] = curNodes[7];
7368               isOk = true;
7369             }
7370             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7371               uniqueNodes[0] = curNodes[0];
7372               uniqueNodes[1] = curNodes[1];
7373               uniqueNodes[2] = curNodes[3];
7374               uniqueNodes[3] = curNodes[4];
7375               uniqueNodes[4] = curNodes[2];
7376               uniqueNodes[5] = curNodes[7];
7377               isOk = true;
7378             }
7379             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7380               uniqueNodes[0] = curNodes[0];
7381               uniqueNodes[1] = curNodes[1];
7382               uniqueNodes[2] = curNodes[2];
7383               uniqueNodes[3] = curNodes[4];
7384               uniqueNodes[4] = curNodes[5];
7385               uniqueNodes[5] = curNodes[3];
7386               isOk = true;
7387             }
7388           }
7389           break;
7390         }
7391         //////////////////////////////////// HEXAHEDRON
7392         isOk = false;
7393         SMDS_VolumeTool hexa (elem);
7394         hexa.SetExternalNormal();
7395         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7396           //////////////////////// ---> tetrahedron
7397           for ( int iFace = 0; iFace < 6; iFace++ ) {
7398             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7399             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7400                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7401                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7402               // one face turns into a point ...
7403               int iOppFace = hexa.GetOppFaceIndex( iFace );
7404               ind = hexa.GetFaceNodesIndices( iOppFace );
7405               int nbStick = 0;
7406               iUnique = 2; // reverse a tetrahedron bottom
7407               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7408                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7409                   nbStick++;
7410                 else if ( iUnique >= 0 )
7411                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7412               }
7413               if ( nbStick == 1 ) {
7414                 // ... and the opposite one - into a triangle.
7415                 // set a top node
7416                 ind = hexa.GetFaceNodesIndices( iFace );
7417                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7418                 isOk = true;
7419               }
7420               break;
7421             }
7422           }
7423         }
7424         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7425           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7426           for ( int iFace = 0; iFace < 6; iFace++ ) {
7427             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7428             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7429                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7430                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7431               // one face turns into a point ...
7432               int iOppFace = hexa.GetOppFaceIndex( iFace );
7433               ind = hexa.GetFaceNodesIndices( iOppFace );
7434               int nbStick = 0;
7435               iUnique = 2;  // reverse a tetrahedron 1 bottom
7436               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7437                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7438                   nbStick++;
7439                 else if ( iUnique >= 0 )
7440                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7441               }
7442               if ( nbStick == 0 ) {
7443                 // ... and the opposite one is a quadrangle
7444                 // set a top node
7445                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7446                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7447                 nbUniqueNodes = 4;
7448                 // tetrahedron 2
7449                 SMDS_MeshElement* newElem =
7450                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7451                                    curNodes[ind[ 3 ]],
7452                                    curNodes[ind[ 2 ]],
7453                                    curNodes[indTop[ 0 ]]);
7454                 myLastCreatedElems.Append(newElem);
7455                 if ( aShapeId )
7456                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7457                 isOk = true;
7458               }
7459               break;
7460             }
7461           }
7462         }
7463         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7464           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7465           // find indices of quad and tri faces
7466           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7467           for ( iFace = 0; iFace < 6; iFace++ ) {
7468             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7469             nodeSet.clear();
7470             for ( iCur = 0; iCur < 4; iCur++ )
7471               nodeSet.insert( curNodes[ind[ iCur ]] );
7472             nbUniqueNodes = nodeSet.size();
7473             if ( nbUniqueNodes == 3 )
7474               iTriFace[ nbTri++ ] = iFace;
7475             else if ( nbUniqueNodes == 4 )
7476               iQuadFace[ nbQuad++ ] = iFace;
7477           }
7478           if (nbQuad == 2 && nbTri == 4 &&
7479               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7480             // 2 opposite quadrangles stuck with a diagonal;
7481             // sample groups of merged indices: (0-4)(2-6)
7482             // --------------------------------------------> 2 tetrahedrons
7483             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7484             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7485             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7486             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7487                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7488               // stuck with 0-2 diagonal
7489               i0  = ind1[ 3 ];
7490               i1d = ind1[ 0 ];
7491               i2  = ind1[ 1 ];
7492               i3d = ind1[ 2 ];
7493               i0t = ind2[ 1 ];
7494               i2t = ind2[ 3 ];
7495             }
7496             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7497                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7498               // stuck with 1-3 diagonal
7499               i0  = ind1[ 0 ];
7500               i1d = ind1[ 1 ];
7501               i2  = ind1[ 2 ];
7502               i3d = ind1[ 3 ];
7503               i0t = ind2[ 0 ];
7504               i2t = ind2[ 1 ];
7505             }
7506             else {
7507               ASSERT(0);
7508             }
7509             // tetrahedron 1
7510             uniqueNodes[ 0 ] = curNodes [ i0 ];
7511             uniqueNodes[ 1 ] = curNodes [ i1d ];
7512             uniqueNodes[ 2 ] = curNodes [ i3d ];
7513             uniqueNodes[ 3 ] = curNodes [ i0t ];
7514             nbUniqueNodes = 4;
7515             // tetrahedron 2
7516             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7517                                                          curNodes[ i2 ],
7518                                                          curNodes[ i3d ],
7519                                                          curNodes[ i2t ]);
7520             myLastCreatedElems.Append(newElem);
7521             if ( aShapeId )
7522               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7523             isOk = true;
7524           }
7525           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7526                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7527             // --------------------------------------------> prism
7528             // find 2 opposite triangles
7529             nbUniqueNodes = 6;
7530             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7531               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7532                 // find indices of kept and replaced nodes
7533                 // and fill unique nodes of 2 opposite triangles
7534                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7535                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7536                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7537                 // fill unique nodes
7538                 iUnique = 0;
7539                 isOk = true;
7540                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7541                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7542                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7543                   if ( n == nInit ) {
7544                     // iCur of a linked node of the opposite face (make normals co-directed):
7545                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7546                     // check that correspondent corners of triangles are linked
7547                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7548                       isOk = false;
7549                     else {
7550                       uniqueNodes[ iUnique ] = n;
7551                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7552                       iUnique++;
7553                     }
7554                   }
7555                 }
7556                 break;
7557               }
7558             }
7559           }
7560         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7561         break;
7562       } // HEXAHEDRON
7563
7564       default:
7565         isOk = false;
7566       } // switch ( nbNodes )
7567
7568     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7569
7570     if ( isOk ) {
7571       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7572         // Change nodes of polyedre
7573         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7574           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7575         if (aPolyedre) {
7576           int nbFaces = aPolyedre->NbFaces();
7577
7578           vector<const SMDS_MeshNode *> poly_nodes;
7579           vector<int> quantities (nbFaces);
7580
7581           for (int iface = 1; iface <= nbFaces; iface++) {
7582             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7583             quantities[iface - 1] = nbFaceNodes;
7584
7585             for (inode = 1; inode <= nbFaceNodes; inode++) {
7586               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7587
7588               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7589               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7590                 curNode = (*nnIt).second;
7591               }
7592               poly_nodes.push_back(curNode);
7593             }
7594           }
7595           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7596         }
7597       }
7598       else {
7599         // Change regular element or polygon
7600         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7601       }
7602     }
7603     else {
7604       // Remove invalid regular element or invalid polygon
7605       rmElemIds.push_back( elem->GetID() );
7606     }
7607
7608   } // loop on elements
7609
7610   // Remove equal nodes and bad elements
7611
7612   Remove( rmNodeIds, true );
7613   Remove( rmElemIds, false );
7614
7615 }
7616
7617
7618 // ========================================================
7619 // class   : SortableElement
7620 // purpose : allow sorting elements basing on their nodes
7621 // ========================================================
7622 class SortableElement : public set <const SMDS_MeshElement*>
7623 {
7624 public:
7625
7626   SortableElement( const SMDS_MeshElement* theElem )
7627   {
7628     myElem = theElem;
7629     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7630     while ( nodeIt->more() )
7631       this->insert( nodeIt->next() );
7632   }
7633
7634   const SMDS_MeshElement* Get() const
7635   { return myElem; }
7636
7637   void Set(const SMDS_MeshElement* e) const
7638   { myElem = e; }
7639
7640
7641 private:
7642   mutable const SMDS_MeshElement* myElem;
7643 };
7644
7645 //=======================================================================
7646 //function : FindEqualElements
7647 //purpose  : Return list of group of elements built on the same nodes.
7648 //           Search among theElements or in the whole mesh if theElements is empty
7649 //=======================================================================
7650 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7651                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7652 {
7653   myLastCreatedElems.Clear();
7654   myLastCreatedNodes.Clear();
7655
7656   typedef set<const SMDS_MeshElement*> TElemsSet;
7657   typedef map< SortableElement, int > TMapOfNodeSet;
7658   typedef list<int> TGroupOfElems;
7659
7660   TElemsSet elems;
7661   if ( theElements.empty() )
7662   { // get all elements in the mesh
7663     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7664     while ( eIt->more() )
7665       elems.insert( elems.end(), eIt->next());
7666   }
7667   else
7668     elems = theElements;
7669
7670   vector< TGroupOfElems > arrayOfGroups;
7671   TGroupOfElems groupOfElems;
7672   TMapOfNodeSet mapOfNodeSet;
7673
7674   TElemsSet::iterator elemIt = elems.begin();
7675   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7676     const SMDS_MeshElement* curElem = *elemIt;
7677     SortableElement SE(curElem);
7678     int ind = -1;
7679     // check uniqueness
7680     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7681     if( !(pp.second) ) {
7682       TMapOfNodeSet::iterator& itSE = pp.first;
7683       ind = (*itSE).second;
7684       arrayOfGroups[ind].push_back(curElem->GetID());
7685     }
7686     else {
7687       groupOfElems.clear();
7688       groupOfElems.push_back(curElem->GetID());
7689       arrayOfGroups.push_back(groupOfElems);
7690       i++;
7691     }
7692   }
7693
7694   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7695   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7696     groupOfElems = *groupIt;
7697     if ( groupOfElems.size() > 1 ) {
7698       groupOfElems.sort();
7699       theGroupsOfElementsID.push_back(groupOfElems);
7700     }
7701   }
7702 }
7703
7704 //=======================================================================
7705 //function : MergeElements
7706 //purpose  : In each given group, substitute all elements by the first one.
7707 //=======================================================================
7708
7709 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7710 {
7711   myLastCreatedElems.Clear();
7712   myLastCreatedNodes.Clear();
7713
7714   typedef list<int> TListOfIDs;
7715   TListOfIDs rmElemIds; // IDs of elems to remove
7716
7717   SMESHDS_Mesh* aMesh = GetMeshDS();
7718
7719   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7720   while ( groupsIt != theGroupsOfElementsID.end() ) {
7721     TListOfIDs& aGroupOfElemID = *groupsIt;
7722     aGroupOfElemID.sort();
7723     int elemIDToKeep = aGroupOfElemID.front();
7724     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7725     aGroupOfElemID.pop_front();
7726     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7727     while ( idIt != aGroupOfElemID.end() ) {
7728       int elemIDToRemove = *idIt;
7729       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7730       // add the kept element in groups of removed one (PAL15188)
7731       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7732       rmElemIds.push_back( elemIDToRemove );
7733       ++idIt;
7734     }
7735     ++groupsIt;
7736   }
7737
7738   Remove( rmElemIds, false );
7739 }
7740
7741 //=======================================================================
7742 //function : MergeEqualElements
7743 //purpose  : Remove all but one of elements built on the same nodes.
7744 //=======================================================================
7745
7746 void SMESH_MeshEditor::MergeEqualElements()
7747 {
7748   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7749                                                  to merge equal elements in the whole mesh */
7750   TListOfListOfElementsID aGroupsOfElementsID;
7751   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7752   MergeElements(aGroupsOfElementsID);
7753 }
7754
7755 //=======================================================================
7756 //function : FindFaceInSet
7757 //purpose  : Return a face having linked nodes n1 and n2 and which is
7758 //           - not in avoidSet,
7759 //           - in elemSet provided that !elemSet.empty()
7760 //           i1 and i2 optionally returns indices of n1 and n2
7761 //=======================================================================
7762
7763 const SMDS_MeshElement*
7764 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7765                                 const SMDS_MeshNode*    n2,
7766                                 const TIDSortedElemSet& elemSet,
7767                                 const TIDSortedElemSet& avoidSet,
7768                                 int*                    n1ind,
7769                                 int*                    n2ind)
7770
7771 {
7772   int i1, i2;
7773   const SMDS_MeshElement* face = 0;
7774
7775   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7776   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7777   {
7778     const SMDS_MeshElement* elem = invElemIt->next();
7779     if (avoidSet.count( elem ))
7780       continue;
7781     if ( !elemSet.empty() && !elemSet.count( elem ))
7782       continue;
7783     // index of n1
7784     i1 = elem->GetNodeIndex( n1 );
7785     // find a n2 linked to n1
7786     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7787     for ( int di = -1; di < 2 && !face; di += 2 )
7788     {
7789       i2 = (i1+di+nbN) % nbN;
7790       if ( elem->GetNode( i2 ) == n2 )
7791         face = elem;
7792     }
7793     if ( !face && elem->IsQuadratic())
7794     {
7795       // analysis for quadratic elements using all nodes
7796       const SMDS_QuadraticFaceOfNodes* F =
7797         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7798       // use special nodes iterator
7799       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7800       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7801       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7802       {
7803         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7804         if ( n1 == prevN && n2 == n )
7805         {
7806           face = elem;
7807         }
7808         else if ( n2 == prevN && n1 == n )
7809         {
7810           face = elem; swap( i1, i2 );
7811         }
7812         prevN = n;
7813       }
7814     }
7815   }
7816   if ( n1ind ) *n1ind = i1;
7817   if ( n2ind ) *n2ind = i2;
7818   return face;
7819 }
7820
7821 //=======================================================================
7822 //function : findAdjacentFace
7823 //purpose  :
7824 //=======================================================================
7825
7826 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7827                                                 const SMDS_MeshNode* n2,
7828                                                 const SMDS_MeshElement* elem)
7829 {
7830   TIDSortedElemSet elemSet, avoidSet;
7831   if ( elem )
7832     avoidSet.insert ( elem );
7833   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7834 }
7835
7836 //=======================================================================
7837 //function : FindFreeBorder
7838 //purpose  :
7839 //=======================================================================
7840
7841 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7842
7843 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7844                                        const SMDS_MeshNode*             theSecondNode,
7845                                        const SMDS_MeshNode*             theLastNode,
7846                                        list< const SMDS_MeshNode* > &   theNodes,
7847                                        list< const SMDS_MeshElement* >& theFaces)
7848 {
7849   if ( !theFirstNode || !theSecondNode )
7850     return false;
7851   // find border face between theFirstNode and theSecondNode
7852   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7853   if ( !curElem )
7854     return false;
7855
7856   theFaces.push_back( curElem );
7857   theNodes.push_back( theFirstNode );
7858   theNodes.push_back( theSecondNode );
7859
7860   //vector<const SMDS_MeshNode*> nodes;
7861   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7862   TIDSortedElemSet foundElems;
7863   bool needTheLast = ( theLastNode != 0 );
7864
7865   while ( nStart != theLastNode ) {
7866     if ( nStart == theFirstNode )
7867       return !needTheLast;
7868
7869     // find all free border faces sharing form nStart
7870
7871     list< const SMDS_MeshElement* > curElemList;
7872     list< const SMDS_MeshNode* > nStartList;
7873     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7874     while ( invElemIt->more() ) {
7875       const SMDS_MeshElement* e = invElemIt->next();
7876       if ( e == curElem || foundElems.insert( e ).second ) {
7877         // get nodes
7878         int iNode = 0, nbNodes = e->NbNodes();
7879         //const SMDS_MeshNode* nodes[nbNodes+1];
7880         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7881
7882         if(e->IsQuadratic()) {
7883           const SMDS_QuadraticFaceOfNodes* F =
7884             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7885           // use special nodes iterator
7886           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7887           while( anIter->more() ) {
7888             nodes[ iNode++ ] = anIter->next();
7889           }
7890         }
7891         else {
7892           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7893           while ( nIt->more() )
7894             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7895         }
7896         nodes[ iNode ] = nodes[ 0 ];
7897         // check 2 links
7898         for ( iNode = 0; iNode < nbNodes; iNode++ )
7899           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7900                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7901               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7902           {
7903             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7904             curElemList.push_back( e );
7905           }
7906       }
7907     }
7908     // analyse the found
7909
7910     int nbNewBorders = curElemList.size();
7911     if ( nbNewBorders == 0 ) {
7912       // no free border furthermore
7913       return !needTheLast;
7914     }
7915     else if ( nbNewBorders == 1 ) {
7916       // one more element found
7917       nIgnore = nStart;
7918       nStart = nStartList.front();
7919       curElem = curElemList.front();
7920       theFaces.push_back( curElem );
7921       theNodes.push_back( nStart );
7922     }
7923     else {
7924       // several continuations found
7925       list< const SMDS_MeshElement* >::iterator curElemIt;
7926       list< const SMDS_MeshNode* >::iterator nStartIt;
7927       // check if one of them reached the last node
7928       if ( needTheLast ) {
7929         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7930              curElemIt!= curElemList.end();
7931              curElemIt++, nStartIt++ )
7932           if ( *nStartIt == theLastNode ) {
7933             theFaces.push_back( *curElemIt );
7934             theNodes.push_back( *nStartIt );
7935             return true;
7936           }
7937       }
7938       // find the best free border by the continuations
7939       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7940       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7941       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7942            curElemIt!= curElemList.end();
7943            curElemIt++, nStartIt++ )
7944       {
7945         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7946         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7947         // find one more free border
7948         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7949           cNL->clear();
7950           cFL->clear();
7951         }
7952         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7953           // choice: clear a worse one
7954           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7955           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7956           contNodes[ iWorse ].clear();
7957           contFaces[ iWorse ].clear();
7958         }
7959       }
7960       if ( contNodes[0].empty() && contNodes[1].empty() )
7961         return false;
7962
7963       // append the best free border
7964       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7965       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7966       theNodes.pop_back(); // remove nIgnore
7967       theNodes.pop_back(); // remove nStart
7968       theFaces.pop_back(); // remove curElem
7969       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7970       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7971       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7972       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7973       return true;
7974
7975     } // several continuations found
7976   } // while ( nStart != theLastNode )
7977
7978   return true;
7979 }
7980
7981 //=======================================================================
7982 //function : CheckFreeBorderNodes
7983 //purpose  : Return true if the tree nodes are on a free border
7984 //=======================================================================
7985
7986 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7987                                             const SMDS_MeshNode* theNode2,
7988                                             const SMDS_MeshNode* theNode3)
7989 {
7990   list< const SMDS_MeshNode* > nodes;
7991   list< const SMDS_MeshElement* > faces;
7992   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7993 }
7994
7995 //=======================================================================
7996 //function : SewFreeBorder
7997 //purpose  :
7998 //=======================================================================
7999
8000 SMESH_MeshEditor::Sew_Error
8001 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8002                                  const SMDS_MeshNode* theBordSecondNode,
8003                                  const SMDS_MeshNode* theBordLastNode,
8004                                  const SMDS_MeshNode* theSideFirstNode,
8005                                  const SMDS_MeshNode* theSideSecondNode,
8006                                  const SMDS_MeshNode* theSideThirdNode,
8007                                  const bool           theSideIsFreeBorder,
8008                                  const bool           toCreatePolygons,
8009                                  const bool           toCreatePolyedrs)
8010 {
8011   myLastCreatedElems.Clear();
8012   myLastCreatedNodes.Clear();
8013
8014   MESSAGE("::SewFreeBorder()");
8015   Sew_Error aResult = SEW_OK;
8016
8017   // ====================================
8018   //    find side nodes and elements
8019   // ====================================
8020
8021   list< const SMDS_MeshNode* > nSide[ 2 ];
8022   list< const SMDS_MeshElement* > eSide[ 2 ];
8023   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8024   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8025
8026   // Free border 1
8027   // --------------
8028   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8029                       nSide[0], eSide[0])) {
8030     MESSAGE(" Free Border 1 not found " );
8031     aResult = SEW_BORDER1_NOT_FOUND;
8032   }
8033   if (theSideIsFreeBorder) {
8034     // Free border 2
8035     // --------------
8036     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8037                         nSide[1], eSide[1])) {
8038       MESSAGE(" Free Border 2 not found " );
8039       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8040     }
8041   }
8042   if ( aResult != SEW_OK )
8043     return aResult;
8044
8045   if (!theSideIsFreeBorder) {
8046     // Side 2
8047     // --------------
8048
8049     // -------------------------------------------------------------------------
8050     // Algo:
8051     // 1. If nodes to merge are not coincident, move nodes of the free border
8052     //    from the coord sys defined by the direction from the first to last
8053     //    nodes of the border to the correspondent sys of the side 2
8054     // 2. On the side 2, find the links most co-directed with the correspondent
8055     //    links of the free border
8056     // -------------------------------------------------------------------------
8057
8058     // 1. Since sewing may brake if there are volumes to split on the side 2,
8059     //    we wont move nodes but just compute new coordinates for them
8060     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8061     TNodeXYZMap nBordXYZ;
8062     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8063     list< const SMDS_MeshNode* >::iterator nBordIt;
8064
8065     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8066     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8067     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8068     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8069     double tol2 = 1.e-8;
8070     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8071     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8072       // Need node movement.
8073
8074       // find X and Z axes to create trsf
8075       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8076       gp_Vec X = Zs ^ Zb;
8077       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8078         // Zb || Zs
8079         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8080
8081       // coord systems
8082       gp_Ax3 toBordAx( Pb1, Zb, X );
8083       gp_Ax3 fromSideAx( Ps1, Zs, X );
8084       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8085       // set trsf
8086       gp_Trsf toBordSys, fromSide2Sys;
8087       toBordSys.SetTransformation( toBordAx );
8088       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8089       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8090
8091       // move
8092       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8093         const SMDS_MeshNode* n = *nBordIt;
8094         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8095         toBordSys.Transforms( xyz );
8096         fromSide2Sys.Transforms( xyz );
8097         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8098       }
8099     }
8100     else {
8101       // just insert nodes XYZ in the nBordXYZ map
8102       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8103         const SMDS_MeshNode* n = *nBordIt;
8104         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8105       }
8106     }
8107
8108     // 2. On the side 2, find the links most co-directed with the correspondent
8109     //    links of the free border
8110
8111     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8112     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8113     sideNodes.push_back( theSideFirstNode );
8114
8115     bool hasVolumes = false;
8116     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8117     set<long> foundSideLinkIDs, checkedLinkIDs;
8118     SMDS_VolumeTool volume;
8119     //const SMDS_MeshNode* faceNodes[ 4 ];
8120
8121     const SMDS_MeshNode*    sideNode;
8122     const SMDS_MeshElement* sideElem;
8123     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8124     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8125     nBordIt = bordNodes.begin();
8126     nBordIt++;
8127     // border node position and border link direction to compare with
8128     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8129     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8130     // choose next side node by link direction or by closeness to
8131     // the current border node:
8132     bool searchByDir = ( *nBordIt != theBordLastNode );
8133     do {
8134       // find the next node on the Side 2
8135       sideNode = 0;
8136       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8137       long linkID;
8138       checkedLinkIDs.clear();
8139       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8140
8141       // loop on inverse elements of current node (prevSideNode) on the Side 2
8142       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8143       while ( invElemIt->more() )
8144       {
8145         const SMDS_MeshElement* elem = invElemIt->next();
8146         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8147         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8148         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8149         bool isVolume = volume.Set( elem );
8150         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8151         if ( isVolume ) // --volume
8152           hasVolumes = true;
8153         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8154           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8155           if(elem->IsQuadratic()) {
8156             const SMDS_QuadraticFaceOfNodes* F =
8157               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8158             // use special nodes iterator
8159             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8160             while( anIter->more() ) {
8161               nodes[ iNode ] = anIter->next();
8162               if ( nodes[ iNode++ ] == prevSideNode )
8163                 iPrevNode = iNode - 1;
8164             }
8165           }
8166           else {
8167             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8168             while ( nIt->more() ) {
8169               nodes[ iNode ] = cast2Node( nIt->next() );
8170               if ( nodes[ iNode++ ] == prevSideNode )
8171                 iPrevNode = iNode - 1;
8172             }
8173           }
8174           // there are 2 links to check
8175           nbNodes = 2;
8176         }
8177         else // --edge
8178           continue;
8179         // loop on links, to be precise, on the second node of links
8180         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8181           const SMDS_MeshNode* n = nodes[ iNode ];
8182           if ( isVolume ) {
8183             if ( !volume.IsLinked( n, prevSideNode ))
8184               continue;
8185           }
8186           else {
8187             if ( iNode ) // a node before prevSideNode
8188               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8189             else         // a node after prevSideNode
8190               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8191           }
8192           // check if this link was already used
8193           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8194           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8195           if (!isJustChecked &&
8196               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8197           {
8198             // test a link geometrically
8199             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8200             bool linkIsBetter = false;
8201             double dot = 0.0, dist = 0.0;
8202             if ( searchByDir ) { // choose most co-directed link
8203               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8204               linkIsBetter = ( dot > maxDot );
8205             }
8206             else { // choose link with the node closest to bordPos
8207               dist = ( nextXYZ - bordPos ).SquareModulus();
8208               linkIsBetter = ( dist < minDist );
8209             }
8210             if ( linkIsBetter ) {
8211               maxDot = dot;
8212               minDist = dist;
8213               linkID = iLink;
8214               sideNode = n;
8215               sideElem = elem;
8216             }
8217           }
8218         }
8219       } // loop on inverse elements of prevSideNode
8220
8221       if ( !sideNode ) {
8222         MESSAGE(" Cant find path by links of the Side 2 ");
8223         return SEW_BAD_SIDE_NODES;
8224       }
8225       sideNodes.push_back( sideNode );
8226       sideElems.push_back( sideElem );
8227       foundSideLinkIDs.insert ( linkID );
8228       prevSideNode = sideNode;
8229
8230       if ( *nBordIt == theBordLastNode )
8231         searchByDir = false;
8232       else {
8233         // find the next border link to compare with
8234         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8235         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8236         // move to next border node if sideNode is before forward border node (bordPos)
8237         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8238           prevBordNode = *nBordIt;
8239           nBordIt++;
8240           bordPos = nBordXYZ[ *nBordIt ];
8241           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8242           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8243         }
8244       }
8245     }
8246     while ( sideNode != theSideSecondNode );
8247
8248     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8249       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8250       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8251     }
8252   } // end nodes search on the side 2
8253
8254   // ============================
8255   // sew the border to the side 2
8256   // ============================
8257
8258   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8259   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8260
8261   TListOfListOfNodes nodeGroupsToMerge;
8262   if ( nbNodes[0] == nbNodes[1] ||
8263        ( theSideIsFreeBorder && !theSideThirdNode)) {
8264
8265     // all nodes are to be merged
8266
8267     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8268          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8269          nIt[0]++, nIt[1]++ )
8270     {
8271       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8272       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8273       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8274     }
8275   }
8276   else {
8277
8278     // insert new nodes into the border and the side to get equal nb of segments
8279
8280     // get normalized parameters of nodes on the borders
8281     //double param[ 2 ][ maxNbNodes ];
8282     double* param[ 2 ];
8283     param[0] = new double [ maxNbNodes ];
8284     param[1] = new double [ maxNbNodes ];
8285     int iNode, iBord;
8286     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8287       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8288       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8289       const SMDS_MeshNode* nPrev = *nIt;
8290       double bordLength = 0;
8291       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8292         const SMDS_MeshNode* nCur = *nIt;
8293         gp_XYZ segment (nCur->X() - nPrev->X(),
8294                         nCur->Y() - nPrev->Y(),
8295                         nCur->Z() - nPrev->Z());
8296         double segmentLen = segment.Modulus();
8297         bordLength += segmentLen;
8298         param[ iBord ][ iNode ] = bordLength;
8299         nPrev = nCur;
8300       }
8301       // normalize within [0,1]
8302       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8303         param[ iBord ][ iNode ] /= bordLength;
8304       }
8305     }
8306
8307     // loop on border segments
8308     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8309     int i[ 2 ] = { 0, 0 };
8310     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8311     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8312
8313     TElemOfNodeListMap insertMap;
8314     TElemOfNodeListMap::iterator insertMapIt;
8315     // insertMap is
8316     // key:   elem to insert nodes into
8317     // value: 2 nodes to insert between + nodes to be inserted
8318     do {
8319       bool next[ 2 ] = { false, false };
8320
8321       // find min adjacent segment length after sewing
8322       double nextParam = 10., prevParam = 0;
8323       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8324         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8325           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8326         if ( i[ iBord ] > 0 )
8327           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8328       }
8329       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8330       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8331       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8332
8333       // choose to insert or to merge nodes
8334       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8335       if ( Abs( du ) <= minSegLen * 0.2 ) {
8336         // merge
8337         // ------
8338         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8339         const SMDS_MeshNode* n0 = *nIt[0];
8340         const SMDS_MeshNode* n1 = *nIt[1];
8341         nodeGroupsToMerge.back().push_back( n1 );
8342         nodeGroupsToMerge.back().push_back( n0 );
8343         // position of node of the border changes due to merge
8344         param[ 0 ][ i[0] ] += du;
8345         // move n1 for the sake of elem shape evaluation during insertion.
8346         // n1 will be removed by MergeNodes() anyway
8347         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8348         next[0] = next[1] = true;
8349       }
8350       else {
8351         // insert
8352         // ------
8353         int intoBord = ( du < 0 ) ? 0 : 1;
8354         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8355         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8356         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8357         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8358         if ( intoBord == 1 ) {
8359           // move node of the border to be on a link of elem of the side
8360           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8361           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8362           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8363           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8364           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8365         }
8366         insertMapIt = insertMap.find( elem );
8367         bool notFound = ( insertMapIt == insertMap.end() );
8368         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8369         if ( otherLink ) {
8370           // insert into another link of the same element:
8371           // 1. perform insertion into the other link of the elem
8372           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8373           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8374           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8375           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8376           // 2. perform insertion into the link of adjacent faces
8377           while (true) {
8378             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8379             if ( adjElem )
8380               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8381             else
8382               break;
8383           }
8384           if (toCreatePolyedrs) {
8385             // perform insertion into the links of adjacent volumes
8386             UpdateVolumes(n12, n22, nodeList);
8387           }
8388           // 3. find an element appeared on n1 and n2 after the insertion
8389           insertMap.erase( elem );
8390           elem = findAdjacentFace( n1, n2, 0 );
8391         }
8392         if ( notFound || otherLink ) {
8393           // add element and nodes of the side into the insertMap
8394           insertMapIt = insertMap.insert
8395             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8396           (*insertMapIt).second.push_back( n1 );
8397           (*insertMapIt).second.push_back( n2 );
8398         }
8399         // add node to be inserted into elem
8400         (*insertMapIt).second.push_back( nIns );
8401         next[ 1 - intoBord ] = true;
8402       }
8403
8404       // go to the next segment
8405       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8406         if ( next[ iBord ] ) {
8407           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8408             eIt[ iBord ]++;
8409           nPrev[ iBord ] = *nIt[ iBord ];
8410           nIt[ iBord ]++; i[ iBord ]++;
8411         }
8412       }
8413     }
8414     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8415
8416     // perform insertion of nodes into elements
8417
8418     for (insertMapIt = insertMap.begin();
8419          insertMapIt != insertMap.end();
8420          insertMapIt++ )
8421     {
8422       const SMDS_MeshElement* elem = (*insertMapIt).first;
8423       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8424       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8425       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8426
8427       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8428
8429       if ( !theSideIsFreeBorder ) {
8430         // look for and insert nodes into the faces adjacent to elem
8431         while (true) {
8432           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8433           if ( adjElem )
8434             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8435           else
8436             break;
8437         }
8438       }
8439       if (toCreatePolyedrs) {
8440         // perform insertion into the links of adjacent volumes
8441         UpdateVolumes(n1, n2, nodeList);
8442       }
8443     }
8444
8445     delete param[0];
8446     delete param[1];
8447   } // end: insert new nodes
8448
8449   MergeNodes ( nodeGroupsToMerge );
8450
8451   return aResult;
8452 }
8453
8454 //=======================================================================
8455 //function : InsertNodesIntoLink
8456 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8457 //           and theBetweenNode2 and split theElement
8458 //=======================================================================
8459
8460 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8461                                            const SMDS_MeshNode*        theBetweenNode1,
8462                                            const SMDS_MeshNode*        theBetweenNode2,
8463                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8464                                            const bool                  toCreatePoly)
8465 {
8466   if ( theFace->GetType() != SMDSAbs_Face ) return;
8467
8468   // find indices of 2 link nodes and of the rest nodes
8469   int iNode = 0, il1, il2, i3, i4;
8470   il1 = il2 = i3 = i4 = -1;
8471   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8472   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8473
8474   if(theFace->IsQuadratic()) {
8475     const SMDS_QuadraticFaceOfNodes* F =
8476       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8477     // use special nodes iterator
8478     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8479     while( anIter->more() ) {
8480       const SMDS_MeshNode* n = anIter->next();
8481       if ( n == theBetweenNode1 )
8482         il1 = iNode;
8483       else if ( n == theBetweenNode2 )
8484         il2 = iNode;
8485       else if ( i3 < 0 )
8486         i3 = iNode;
8487       else
8488         i4 = iNode;
8489       nodes[ iNode++ ] = n;
8490     }
8491   }
8492   else {
8493     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8494     while ( nodeIt->more() ) {
8495       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8496       if ( n == theBetweenNode1 )
8497         il1 = iNode;
8498       else if ( n == theBetweenNode2 )
8499         il2 = iNode;
8500       else if ( i3 < 0 )
8501         i3 = iNode;
8502       else
8503         i4 = iNode;
8504       nodes[ iNode++ ] = n;
8505     }
8506   }
8507   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8508     return ;
8509
8510   // arrange link nodes to go one after another regarding the face orientation
8511   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8512   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8513   if ( reverse ) {
8514     iNode = il1;
8515     il1 = il2;
8516     il2 = iNode;
8517     aNodesToInsert.reverse();
8518   }
8519   // check that not link nodes of a quadrangles are in good order
8520   int nbFaceNodes = theFace->NbNodes();
8521   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8522     iNode = i3;
8523     i3 = i4;
8524     i4 = iNode;
8525   }
8526
8527   if (toCreatePoly || theFace->IsPoly()) {
8528
8529     iNode = 0;
8530     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8531
8532     // add nodes of face up to first node of link
8533     bool isFLN = false;
8534
8535     if(theFace->IsQuadratic()) {
8536       const SMDS_QuadraticFaceOfNodes* F =
8537         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8538       // use special nodes iterator
8539       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8540       while( anIter->more()  && !isFLN ) {
8541         const SMDS_MeshNode* n = anIter->next();
8542         poly_nodes[iNode++] = n;
8543         if (n == nodes[il1]) {
8544           isFLN = true;
8545         }
8546       }
8547       // add nodes to insert
8548       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8549       for (; nIt != aNodesToInsert.end(); nIt++) {
8550         poly_nodes[iNode++] = *nIt;
8551       }
8552       // add nodes of face starting from last node of link
8553       while ( anIter->more() ) {
8554         poly_nodes[iNode++] = anIter->next();
8555       }
8556     }
8557     else {
8558       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8559       while ( nodeIt->more() && !isFLN ) {
8560         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8561         poly_nodes[iNode++] = n;
8562         if (n == nodes[il1]) {
8563           isFLN = true;
8564         }
8565       }
8566       // add nodes to insert
8567       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8568       for (; nIt != aNodesToInsert.end(); nIt++) {
8569         poly_nodes[iNode++] = *nIt;
8570       }
8571       // add nodes of face starting from last node of link
8572       while ( nodeIt->more() ) {
8573         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8574         poly_nodes[iNode++] = n;
8575       }
8576     }
8577
8578     // edit or replace the face
8579     SMESHDS_Mesh *aMesh = GetMeshDS();
8580
8581     if (theFace->IsPoly()) {
8582       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8583     }
8584     else {
8585       int aShapeId = FindShape( theFace );
8586
8587       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8588       myLastCreatedElems.Append(newElem);
8589       if ( aShapeId && newElem )
8590         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8591
8592       aMesh->RemoveElement(theFace);
8593     }
8594     return;
8595   }
8596
8597   if( !theFace->IsQuadratic() ) {
8598
8599     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8600     int nbLinkNodes = 2 + aNodesToInsert.size();
8601     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8602     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8603     linkNodes[ 0 ] = nodes[ il1 ];
8604     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8605     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8606     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8607       linkNodes[ iNode++ ] = *nIt;
8608     }
8609     // decide how to split a quadrangle: compare possible variants
8610     // and choose which of splits to be a quadrangle
8611     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8612     if ( nbFaceNodes == 3 ) {
8613       iBestQuad = nbSplits;
8614       i4 = i3;
8615     }
8616     else if ( nbFaceNodes == 4 ) {
8617       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8618       double aBestRate = DBL_MAX;
8619       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8620         i1 = 0; i2 = 1;
8621         double aBadRate = 0;
8622         // evaluate elements quality
8623         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8624           if ( iSplit == iQuad ) {
8625             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8626                                    linkNodes[ i2++ ],
8627                                    nodes[ i3 ],
8628                                    nodes[ i4 ]);
8629             aBadRate += getBadRate( &quad, aCrit );
8630           }
8631           else {
8632             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8633                                    linkNodes[ i2++ ],
8634                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8635             aBadRate += getBadRate( &tria, aCrit );
8636           }
8637         }
8638         // choice
8639         if ( aBadRate < aBestRate ) {
8640           iBestQuad = iQuad;
8641           aBestRate = aBadRate;
8642         }
8643       }
8644     }
8645
8646     // create new elements
8647     SMESHDS_Mesh *aMesh = GetMeshDS();
8648     int aShapeId = FindShape( theFace );
8649
8650     i1 = 0; i2 = 1;
8651     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8652       SMDS_MeshElement* newElem = 0;
8653       if ( iSplit == iBestQuad )
8654         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8655                                   linkNodes[ i2++ ],
8656                                   nodes[ i3 ],
8657                                   nodes[ i4 ]);
8658       else
8659         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8660                                   linkNodes[ i2++ ],
8661                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8662       myLastCreatedElems.Append(newElem);
8663       if ( aShapeId && newElem )
8664         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8665     }
8666
8667     // change nodes of theFace
8668     const SMDS_MeshNode* newNodes[ 4 ];
8669     newNodes[ 0 ] = linkNodes[ i1 ];
8670     newNodes[ 1 ] = linkNodes[ i2 ];
8671     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8672     newNodes[ 3 ] = nodes[ i4 ];
8673     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8674   } // end if(!theFace->IsQuadratic())
8675   else { // theFace is quadratic
8676     // we have to split theFace on simple triangles and one simple quadrangle
8677     int tmp = il1/2;
8678     int nbshift = tmp*2;
8679     // shift nodes in nodes[] by nbshift
8680     int i,j;
8681     for(i=0; i<nbshift; i++) {
8682       const SMDS_MeshNode* n = nodes[0];
8683       for(j=0; j<nbFaceNodes-1; j++) {
8684         nodes[j] = nodes[j+1];
8685       }
8686       nodes[nbFaceNodes-1] = n;
8687     }
8688     il1 = il1 - nbshift;
8689     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8690     //   n0      n1     n2    n0      n1     n2
8691     //     +-----+-----+        +-----+-----+
8692     //      \         /         |           |
8693     //       \       /          |           |
8694     //      n5+     +n3       n7+           +n3
8695     //         \   /            |           |
8696     //          \ /             |           |
8697     //           +              +-----+-----+
8698     //           n4           n6      n5     n4
8699
8700     // create new elements
8701     SMESHDS_Mesh *aMesh = GetMeshDS();
8702     int aShapeId = FindShape( theFace );
8703
8704     int n1,n2,n3;
8705     if(nbFaceNodes==6) { // quadratic triangle
8706       SMDS_MeshElement* newElem =
8707         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8708       myLastCreatedElems.Append(newElem);
8709       if ( aShapeId && newElem )
8710         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8711       if(theFace->IsMediumNode(nodes[il1])) {
8712         // create quadrangle
8713         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8714         myLastCreatedElems.Append(newElem);
8715         if ( aShapeId && newElem )
8716           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8717         n1 = 1;
8718         n2 = 2;
8719         n3 = 3;
8720       }
8721       else {
8722         // create quadrangle
8723         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8724         myLastCreatedElems.Append(newElem);
8725         if ( aShapeId && newElem )
8726           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8727         n1 = 0;
8728         n2 = 1;
8729         n3 = 5;
8730       }
8731     }
8732     else { // nbFaceNodes==8 - quadratic quadrangle
8733       SMDS_MeshElement* newElem =
8734         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8735       myLastCreatedElems.Append(newElem);
8736       if ( aShapeId && newElem )
8737         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8738       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8739       myLastCreatedElems.Append(newElem);
8740       if ( aShapeId && newElem )
8741         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8742       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8743       myLastCreatedElems.Append(newElem);
8744       if ( aShapeId && newElem )
8745         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8746       if(theFace->IsMediumNode(nodes[il1])) {
8747         // create quadrangle
8748         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8749         myLastCreatedElems.Append(newElem);
8750         if ( aShapeId && newElem )
8751           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8752         n1 = 1;
8753         n2 = 2;
8754         n3 = 3;
8755       }
8756       else {
8757         // create quadrangle
8758         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8759         myLastCreatedElems.Append(newElem);
8760         if ( aShapeId && newElem )
8761           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8762         n1 = 0;
8763         n2 = 1;
8764         n3 = 7;
8765       }
8766     }
8767     // create needed triangles using n1,n2,n3 and inserted nodes
8768     int nbn = 2 + aNodesToInsert.size();
8769     //const SMDS_MeshNode* aNodes[nbn];
8770     vector<const SMDS_MeshNode*> aNodes(nbn);
8771     aNodes[0] = nodes[n1];
8772     aNodes[nbn-1] = nodes[n2];
8773     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8774     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8775       aNodes[iNode++] = *nIt;
8776     }
8777     for(i=1; i<nbn; i++) {
8778       SMDS_MeshElement* newElem =
8779         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8780       myLastCreatedElems.Append(newElem);
8781       if ( aShapeId && newElem )
8782         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8783     }
8784     // remove old quadratic face
8785     aMesh->RemoveElement(theFace);
8786   }
8787 }
8788
8789 //=======================================================================
8790 //function : UpdateVolumes
8791 //purpose  :
8792 //=======================================================================
8793 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8794                                       const SMDS_MeshNode*        theBetweenNode2,
8795                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8796 {
8797   myLastCreatedElems.Clear();
8798   myLastCreatedNodes.Clear();
8799
8800   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8801   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8802     const SMDS_MeshElement* elem = invElemIt->next();
8803
8804     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8805     SMDS_VolumeTool aVolume (elem);
8806     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8807       continue;
8808
8809     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8810     int iface, nbFaces = aVolume.NbFaces();
8811     vector<const SMDS_MeshNode *> poly_nodes;
8812     vector<int> quantities (nbFaces);
8813
8814     for (iface = 0; iface < nbFaces; iface++) {
8815       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8816       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8817       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8818
8819       for (int inode = 0; inode < nbFaceNodes; inode++) {
8820         poly_nodes.push_back(faceNodes[inode]);
8821
8822         if (nbInserted == 0) {
8823           if (faceNodes[inode] == theBetweenNode1) {
8824             if (faceNodes[inode + 1] == theBetweenNode2) {
8825               nbInserted = theNodesToInsert.size();
8826
8827               // add nodes to insert
8828               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8829               for (; nIt != theNodesToInsert.end(); nIt++) {
8830                 poly_nodes.push_back(*nIt);
8831               }
8832             }
8833           }
8834           else if (faceNodes[inode] == theBetweenNode2) {
8835             if (faceNodes[inode + 1] == theBetweenNode1) {
8836               nbInserted = theNodesToInsert.size();
8837
8838               // add nodes to insert in reversed order
8839               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8840               nIt--;
8841               for (; nIt != theNodesToInsert.begin(); nIt--) {
8842                 poly_nodes.push_back(*nIt);
8843               }
8844               poly_nodes.push_back(*nIt);
8845             }
8846           }
8847           else {
8848           }
8849         }
8850       }
8851       quantities[iface] = nbFaceNodes + nbInserted;
8852     }
8853
8854     // Replace or update the volume
8855     SMESHDS_Mesh *aMesh = GetMeshDS();
8856
8857     if (elem->IsPoly()) {
8858       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8859
8860     }
8861     else {
8862       int aShapeId = FindShape( elem );
8863
8864       SMDS_MeshElement* newElem =
8865         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8866       myLastCreatedElems.Append(newElem);
8867       if (aShapeId && newElem)
8868         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8869
8870       aMesh->RemoveElement(elem);
8871     }
8872   }
8873 }
8874
8875 //=======================================================================
8876 /*!
8877  * \brief Convert elements contained in a submesh to quadratic
8878  * \retval int - nb of checked elements
8879  */
8880 //=======================================================================
8881
8882 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8883                                              SMESH_MesherHelper& theHelper,
8884                                              const bool          theForce3d)
8885 {
8886   int nbElem = 0;
8887   if( !theSm ) return nbElem;
8888
8889   const bool notFromGroups = false;
8890   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8891   while(ElemItr->more())
8892   {
8893     nbElem++;
8894     const SMDS_MeshElement* elem = ElemItr->next();
8895     if( !elem || elem->IsQuadratic() ) continue;
8896
8897     int id = elem->GetID();
8898     int nbNodes = elem->NbNodes();
8899     vector<const SMDS_MeshNode *> aNds (nbNodes);
8900
8901     for(int i = 0; i < nbNodes; i++)
8902     {
8903       aNds[i] = elem->GetNode(i);
8904     }
8905     SMDSAbs_ElementType aType = elem->GetType();
8906
8907     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8908
8909     const SMDS_MeshElement* NewElem = 0;
8910
8911     switch( aType )
8912     {
8913     case SMDSAbs_Edge :
8914       {
8915         NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8916         break;
8917       }
8918     case SMDSAbs_Face :
8919       {
8920         switch(nbNodes)
8921         {
8922         case 3:
8923           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8924           break;
8925         case 4:
8926           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8927           break;
8928         default:
8929           continue;
8930         }
8931         break;
8932       }
8933     case SMDSAbs_Volume :
8934       {
8935         switch(nbNodes)
8936         {
8937         case 4:
8938           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8939           break;
8940         case 5:
8941           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8942           break;
8943         case 6:
8944           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8945           break;
8946         case 8:
8947           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8948                                         aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8949           break;
8950         default:
8951           continue;
8952         }
8953         break;
8954       }
8955     default :
8956       continue;
8957     }
8958     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8959     if( NewElem )
8960       theSm->AddElement( NewElem );
8961   }
8962   return nbElem;
8963 }
8964
8965 //=======================================================================
8966 //function : ConvertToQuadratic
8967 //purpose  :
8968 //=======================================================================
8969 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8970 {
8971   SMESHDS_Mesh* meshDS = GetMeshDS();
8972
8973   SMESH_MesherHelper aHelper(*myMesh);
8974   aHelper.SetIsQuadratic( true );
8975   const bool notFromGroups = false;
8976
8977   int nbCheckedElems = 0;
8978   if ( myMesh->HasShapeToMesh() )
8979   {
8980     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8981     {
8982       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8983       while ( smIt->more() ) {
8984         SMESH_subMesh* sm = smIt->next();
8985         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8986           aHelper.SetSubShape( sm->GetSubShape() );
8987           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8988         }
8989       }
8990     }
8991   }
8992   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8993   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8994   {
8995     SMESHDS_SubMesh *smDS = 0;
8996     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8997     while(aEdgeItr->more())
8998     {
8999       const SMDS_MeshEdge* edge = aEdgeItr->next();
9000       if(edge && !edge->IsQuadratic())
9001       {
9002         int id = edge->GetID();
9003         const SMDS_MeshNode* n1 = edge->GetNode(0);
9004         const SMDS_MeshNode* n2 = edge->GetNode(1);
9005
9006         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
9007
9008         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9009         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9010       }
9011     }
9012     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9013     while(aFaceItr->more())
9014     {
9015       const SMDS_MeshFace* face = aFaceItr->next();
9016       if(!face || face->IsQuadratic() ) continue;
9017
9018       int id = face->GetID();
9019       int nbNodes = face->NbNodes();
9020       vector<const SMDS_MeshNode *> aNds (nbNodes);
9021
9022       for(int i = 0; i < nbNodes; i++)
9023       {
9024         aNds[i] = face->GetNode(i);
9025       }
9026
9027       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9028
9029       SMDS_MeshFace * NewFace = 0;
9030       switch(nbNodes)
9031       {
9032       case 3:
9033         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9034         break;
9035       case 4:
9036         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9037         break;
9038       default:
9039         continue;
9040       }
9041       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9042     }
9043     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9044     while(aVolumeItr->more())
9045     {
9046       const SMDS_MeshVolume* volume = aVolumeItr->next();
9047       if(!volume || volume->IsQuadratic() ) continue;
9048
9049       int id = volume->GetID();
9050       int nbNodes = volume->NbNodes();
9051       vector<const SMDS_MeshNode *> aNds (nbNodes);
9052
9053       for(int i = 0; i < nbNodes; i++)
9054       {
9055         aNds[i] = volume->GetNode(i);
9056       }
9057
9058       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9059
9060       SMDS_MeshVolume * NewVolume = 0;
9061       switch(nbNodes)
9062       {
9063       case 4:
9064         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9065                                       aNds[3], id, theForce3d );
9066         break;
9067       case 5:
9068         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9069                                       aNds[3], aNds[4], id, theForce3d);
9070         break;
9071       case 6:
9072         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9073                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
9074         break;
9075       case 8:
9076         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9077                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9078         break;
9079       default:
9080         continue;
9081       }
9082       ReplaceElemInGroups(volume, NewVolume, meshDS);
9083     }
9084   }
9085   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9086   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9087     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9088     aHelper.FixQuadraticElements();
9089   }
9090 }
9091
9092 //=======================================================================
9093 /*!
9094  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9095  * \retval int - nb of checked elements
9096  */
9097 //=======================================================================
9098
9099 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9100                                      SMDS_ElemIteratorPtr theItr,
9101                                      const int            theShapeID)
9102 {
9103   int nbElem = 0;
9104   SMESHDS_Mesh* meshDS = GetMeshDS();
9105   const bool notFromGroups = false;
9106
9107   while( theItr->more() )
9108   {
9109     const SMDS_MeshElement* elem = theItr->next();
9110     nbElem++;
9111     if( elem && elem->IsQuadratic())
9112     {
9113       int id = elem->GetID();
9114       int nbNodes = elem->NbNodes();
9115       vector<const SMDS_MeshNode *> aNds, mediumNodes;
9116       aNds.reserve( nbNodes );
9117       mediumNodes.reserve( nbNodes );
9118
9119       for(int i = 0; i < nbNodes; i++)
9120       {
9121         const SMDS_MeshNode* n = elem->GetNode(i);
9122
9123         if( elem->IsMediumNode( n ) )
9124           mediumNodes.push_back( n );
9125         else
9126           aNds.push_back( n );
9127       }
9128       if( aNds.empty() ) continue;
9129       SMDSAbs_ElementType aType = elem->GetType();
9130
9131       //remove old quadratic element
9132       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9133
9134       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9135       ReplaceElemInGroups(elem, NewElem, meshDS);
9136       if( theSm && NewElem )
9137         theSm->AddElement( NewElem );
9138
9139       // remove medium nodes
9140       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9141       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9142         const SMDS_MeshNode* n = *nIt;
9143         if ( n->NbInverseElements() == 0 ) {
9144           if ( n->GetPosition()->GetShapeId() != theShapeID )
9145             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9146                                     ( n->GetPosition()->GetShapeId() ));
9147           else
9148             meshDS->RemoveFreeNode( n, theSm );
9149         }
9150       }
9151     }
9152   }
9153   return nbElem;
9154 }
9155
9156 //=======================================================================
9157 //function : ConvertFromQuadratic
9158 //purpose  :
9159 //=======================================================================
9160 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9161 {
9162   int nbCheckedElems = 0;
9163   if ( myMesh->HasShapeToMesh() )
9164   {
9165     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9166     {
9167       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9168       while ( smIt->more() ) {
9169         SMESH_subMesh* sm = smIt->next();
9170         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9171           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9172       }
9173     }
9174   }
9175
9176   int totalNbElems =
9177     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9178   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9179   {
9180     SMESHDS_SubMesh *aSM = 0;
9181     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9182   }
9183
9184   return true;
9185 }
9186
9187 //=======================================================================
9188 //function : SewSideElements
9189 //purpose  :
9190 //=======================================================================
9191
9192 SMESH_MeshEditor::Sew_Error
9193 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9194                                    TIDSortedElemSet&    theSide2,
9195                                    const SMDS_MeshNode* theFirstNode1,
9196                                    const SMDS_MeshNode* theFirstNode2,
9197                                    const SMDS_MeshNode* theSecondNode1,
9198                                    const SMDS_MeshNode* theSecondNode2)
9199 {
9200   myLastCreatedElems.Clear();
9201   myLastCreatedNodes.Clear();
9202
9203   MESSAGE ("::::SewSideElements()");
9204   if ( theSide1.size() != theSide2.size() )
9205     return SEW_DIFF_NB_OF_ELEMENTS;
9206
9207   Sew_Error aResult = SEW_OK;
9208   // Algo:
9209   // 1. Build set of faces representing each side
9210   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9211   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9212
9213   // =======================================================================
9214   // 1. Build set of faces representing each side:
9215   // =======================================================================
9216   // a. build set of nodes belonging to faces
9217   // b. complete set of faces: find missing fices whose nodes are in set of nodes
9218   // c. create temporary faces representing side of volumes if correspondent
9219   //    face does not exist
9220
9221   SMESHDS_Mesh* aMesh = GetMeshDS();
9222   SMDS_Mesh aTmpFacesMesh;
9223   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9224   set<const SMDS_MeshElement*> volSet1,  volSet2;
9225   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9226   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9227   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9228   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9229   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9230   int iSide, iFace, iNode;
9231
9232   for ( iSide = 0; iSide < 2; iSide++ ) {
9233     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9234     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9235     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9236     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9237     set<const SMDS_MeshElement*>::iterator vIt;
9238     TIDSortedElemSet::iterator eIt;
9239     set<const SMDS_MeshNode*>::iterator    nIt;
9240
9241     // check that given nodes belong to given elements
9242     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9243     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9244     int firstIndex = -1, secondIndex = -1;
9245     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9246       const SMDS_MeshElement* elem = *eIt;
9247       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9248       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9249       if ( firstIndex > -1 && secondIndex > -1 ) break;
9250     }
9251     if ( firstIndex < 0 || secondIndex < 0 ) {
9252       // we can simply return until temporary faces created
9253       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9254     }
9255
9256     // -----------------------------------------------------------
9257     // 1a. Collect nodes of existing faces
9258     //     and build set of face nodes in order to detect missing
9259     //     faces corresponing to sides of volumes
9260     // -----------------------------------------------------------
9261
9262     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9263
9264     // loop on the given element of a side
9265     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9266       //const SMDS_MeshElement* elem = *eIt;
9267       const SMDS_MeshElement* elem = *eIt;
9268       if ( elem->GetType() == SMDSAbs_Face ) {
9269         faceSet->insert( elem );
9270         set <const SMDS_MeshNode*> faceNodeSet;
9271         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9272         while ( nodeIt->more() ) {
9273           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9274           nodeSet->insert( n );
9275           faceNodeSet.insert( n );
9276         }
9277         setOfFaceNodeSet.insert( faceNodeSet );
9278       }
9279       else if ( elem->GetType() == SMDSAbs_Volume )
9280         volSet->insert( elem );
9281     }
9282     // ------------------------------------------------------------------------------
9283     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9284     // ------------------------------------------------------------------------------
9285
9286     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9287       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9288       while ( fIt->more() ) { // loop on faces sharing a node
9289         const SMDS_MeshElement* f = fIt->next();
9290         if ( faceSet->find( f ) == faceSet->end() ) {
9291           // check if all nodes are in nodeSet and
9292           // complete setOfFaceNodeSet if they are
9293           set <const SMDS_MeshNode*> faceNodeSet;
9294           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9295           bool allInSet = true;
9296           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9297             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9298             if ( nodeSet->find( n ) == nodeSet->end() )
9299               allInSet = false;
9300             else
9301               faceNodeSet.insert( n );
9302           }
9303           if ( allInSet ) {
9304             faceSet->insert( f );
9305             setOfFaceNodeSet.insert( faceNodeSet );
9306           }
9307         }
9308       }
9309     }
9310
9311     // -------------------------------------------------------------------------
9312     // 1c. Create temporary faces representing sides of volumes if correspondent
9313     //     face does not exist
9314     // -------------------------------------------------------------------------
9315
9316     if ( !volSet->empty() ) {
9317       //int nodeSetSize = nodeSet->size();
9318
9319       // loop on given volumes
9320       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9321         SMDS_VolumeTool vol (*vIt);
9322         // loop on volume faces: find free faces
9323         // --------------------------------------
9324         list<const SMDS_MeshElement* > freeFaceList;
9325         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9326           if ( !vol.IsFreeFace( iFace ))
9327             continue;
9328           // check if there is already a face with same nodes in a face set
9329           const SMDS_MeshElement* aFreeFace = 0;
9330           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9331           int nbNodes = vol.NbFaceNodes( iFace );
9332           set <const SMDS_MeshNode*> faceNodeSet;
9333           vol.GetFaceNodes( iFace, faceNodeSet );
9334           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9335           if ( isNewFace ) {
9336             // no such a face is given but it still can exist, check it
9337             if ( nbNodes == 3 ) {
9338               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9339             }
9340             else if ( nbNodes == 4 ) {
9341               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9342             }
9343             else {
9344               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9345               aFreeFace = aMesh->FindFace(poly_nodes);
9346             }
9347           }
9348           if ( !aFreeFace ) {
9349             // create a temporary face
9350             if ( nbNodes == 3 ) {
9351               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9352             }
9353             else if ( nbNodes == 4 ) {
9354               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9355             }
9356             else {
9357               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9358               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9359             }
9360           }
9361           if ( aFreeFace )
9362             freeFaceList.push_back( aFreeFace );
9363
9364         } // loop on faces of a volume
9365
9366         // choose one of several free faces
9367         // --------------------------------------
9368         if ( freeFaceList.size() > 1 ) {
9369           // choose a face having max nb of nodes shared by other elems of a side
9370           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9371           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9372           while ( fIt != freeFaceList.end() ) { // loop on free faces
9373             int nbSharedNodes = 0;
9374             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9375             while ( nodeIt->more() ) { // loop on free face nodes
9376               const SMDS_MeshNode* n =
9377                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9378               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9379               while ( invElemIt->more() ) {
9380                 const SMDS_MeshElement* e = invElemIt->next();
9381                 if ( faceSet->find( e ) != faceSet->end() )
9382                   nbSharedNodes++;
9383                 if ( elemSet->find( e ) != elemSet->end() )
9384                   nbSharedNodes++;
9385               }
9386             }
9387             if ( nbSharedNodes >= maxNbNodes ) {
9388               maxNbNodes = nbSharedNodes;
9389               fIt++;
9390             }
9391             else
9392               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9393           }
9394           if ( freeFaceList.size() > 1 )
9395           {
9396             // could not choose one face, use another way
9397             // choose a face most close to the bary center of the opposite side
9398             gp_XYZ aBC( 0., 0., 0. );
9399             set <const SMDS_MeshNode*> addedNodes;
9400             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9401             eIt = elemSet2->begin();
9402             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9403               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9404               while ( nodeIt->more() ) { // loop on free face nodes
9405                 const SMDS_MeshNode* n =
9406                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9407                 if ( addedNodes.insert( n ).second )
9408                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9409               }
9410             }
9411             aBC /= addedNodes.size();
9412             double minDist = DBL_MAX;
9413             fIt = freeFaceList.begin();
9414             while ( fIt != freeFaceList.end() ) { // loop on free faces
9415               double dist = 0;
9416               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9417               while ( nodeIt->more() ) { // loop on free face nodes
9418                 const SMDS_MeshNode* n =
9419                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9420                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9421                 dist += ( aBC - p ).SquareModulus();
9422               }
9423               if ( dist < minDist ) {
9424                 minDist = dist;
9425                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9426               }
9427               else
9428                 fIt = freeFaceList.erase( fIt++ );
9429             }
9430           }
9431         } // choose one of several free faces of a volume
9432
9433         if ( freeFaceList.size() == 1 ) {
9434           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9435           faceSet->insert( aFreeFace );
9436           // complete a node set with nodes of a found free face
9437           //           for ( iNode = 0; iNode < ; iNode++ )
9438           //             nodeSet->insert( fNodes[ iNode ] );
9439         }
9440
9441       } // loop on volumes of a side
9442
9443       //       // complete a set of faces if new nodes in a nodeSet appeared
9444       //       // ----------------------------------------------------------
9445       //       if ( nodeSetSize != nodeSet->size() ) {
9446       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9447       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9448       //           while ( fIt->more() ) { // loop on faces sharing a node
9449       //             const SMDS_MeshElement* f = fIt->next();
9450       //             if ( faceSet->find( f ) == faceSet->end() ) {
9451       //               // check if all nodes are in nodeSet and
9452       //               // complete setOfFaceNodeSet if they are
9453       //               set <const SMDS_MeshNode*> faceNodeSet;
9454       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9455       //               bool allInSet = true;
9456       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9457       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9458       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9459       //                   allInSet = false;
9460       //                 else
9461       //                   faceNodeSet.insert( n );
9462       //               }
9463       //               if ( allInSet ) {
9464       //                 faceSet->insert( f );
9465       //                 setOfFaceNodeSet.insert( faceNodeSet );
9466       //               }
9467       //             }
9468       //           }
9469       //         }
9470       //       }
9471     } // Create temporary faces, if there are volumes given
9472   } // loop on sides
9473
9474   if ( faceSet1.size() != faceSet2.size() ) {
9475     // delete temporary faces: they are in reverseElements of actual nodes
9476     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9477     while ( tmpFaceIt->more() )
9478       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9479     MESSAGE("Diff nb of faces");
9480     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9481   }
9482
9483   // ============================================================
9484   // 2. Find nodes to merge:
9485   //              bind a node to remove to a node to put instead
9486   // ============================================================
9487
9488   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9489   if ( theFirstNode1 != theFirstNode2 )
9490     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9491   if ( theSecondNode1 != theSecondNode2 )
9492     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9493
9494   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9495   set< long > linkIdSet; // links to process
9496   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9497
9498   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9499   list< NLink > linkList[2];
9500   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9501   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9502   // loop on links in linkList; find faces by links and append links
9503   // of the found faces to linkList
9504   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9505   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9506     NLink link[] = { *linkIt[0], *linkIt[1] };
9507     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9508     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9509       continue;
9510
9511     // by links, find faces in the face sets,
9512     // and find indices of link nodes in the found faces;
9513     // in a face set, there is only one or no face sharing a link
9514     // ---------------------------------------------------------------
9515
9516     const SMDS_MeshElement* face[] = { 0, 0 };
9517     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9518     vector<const SMDS_MeshNode*> fnodes1(9);
9519     vector<const SMDS_MeshNode*> fnodes2(9);
9520     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9521     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9522     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9523     int iLinkNode[2][2];
9524     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9525       const SMDS_MeshNode* n1 = link[iSide].first;
9526       const SMDS_MeshNode* n2 = link[iSide].second;
9527       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9528       set< const SMDS_MeshElement* > fMap;
9529       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9530         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9531         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9532         while ( fIt->more() ) { // loop on faces sharing a node
9533           const SMDS_MeshElement* f = fIt->next();
9534           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9535               ! fMap.insert( f ).second ) // f encounters twice
9536           {
9537             if ( face[ iSide ] ) {
9538               MESSAGE( "2 faces per link " );
9539               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9540               break;
9541             }
9542             face[ iSide ] = f;
9543             faceSet->erase( f );
9544             // get face nodes and find ones of a link
9545             iNode = 0;
9546             int nbl = -1;
9547             if(f->IsPoly()) {
9548               if(iSide==0) {
9549                 fnodes1.resize(f->NbNodes()+1);
9550                 notLinkNodes1.resize(f->NbNodes()-2);
9551               }
9552               else {
9553                 fnodes2.resize(f->NbNodes()+1);
9554                 notLinkNodes2.resize(f->NbNodes()-2);
9555               }
9556             }
9557             if(!f->IsQuadratic()) {
9558               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9559               while ( nIt->more() ) {
9560                 const SMDS_MeshNode* n =
9561                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9562                 if ( n == n1 ) {
9563                   iLinkNode[ iSide ][ 0 ] = iNode;
9564                 }
9565                 else if ( n == n2 ) {
9566                   iLinkNode[ iSide ][ 1 ] = iNode;
9567                 }
9568                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9569                 //  notLinkNodes[ iSide ][ 1 ] = n;
9570                 //else
9571                 //  notLinkNodes[ iSide ][ 0 ] = n;
9572                 else {
9573                   nbl++;
9574                   if(iSide==0)
9575                     notLinkNodes1[nbl] = n;
9576                   //notLinkNodes1.push_back(n);
9577                   else
9578                     notLinkNodes2[nbl] = n;
9579                   //notLinkNodes2.push_back(n);
9580                 }
9581                 //faceNodes[ iSide ][ iNode++ ] = n;
9582                 if(iSide==0) {
9583                   fnodes1[iNode++] = n;
9584                 }
9585                 else {
9586                   fnodes2[iNode++] = n;
9587                 }
9588               }
9589             }
9590             else { // f->IsQuadratic()
9591               const SMDS_QuadraticFaceOfNodes* F =
9592                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9593               // use special nodes iterator
9594               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9595               while ( anIter->more() ) {
9596                 const SMDS_MeshNode* n =
9597                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9598                 if ( n == n1 ) {
9599                   iLinkNode[ iSide ][ 0 ] = iNode;
9600                 }
9601                 else if ( n == n2 ) {
9602                   iLinkNode[ iSide ][ 1 ] = iNode;
9603                 }
9604                 else {
9605                   nbl++;
9606                   if(iSide==0) {
9607                     notLinkNodes1[nbl] = n;
9608                   }
9609                   else {
9610                     notLinkNodes2[nbl] = n;
9611                   }
9612                 }
9613                 if(iSide==0) {
9614                   fnodes1[iNode++] = n;
9615                 }
9616                 else {
9617                   fnodes2[iNode++] = n;
9618                 }
9619               }
9620             }
9621             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9622             if(iSide==0) {
9623               fnodes1[iNode] = fnodes1[0];
9624             }
9625             else {
9626               fnodes2[iNode] = fnodes1[0];
9627             }
9628           }
9629         }
9630       }
9631     }
9632
9633     // check similarity of elements of the sides
9634     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9635       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9636       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9637         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9638       }
9639       else {
9640         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9641       }
9642       break; // do not return because it s necessary to remove tmp faces
9643     }
9644
9645     // set nodes to merge
9646     // -------------------
9647
9648     if ( face[0] && face[1] )  {
9649       int nbNodes = face[0]->NbNodes();
9650       if ( nbNodes != face[1]->NbNodes() ) {
9651         MESSAGE("Diff nb of face nodes");
9652         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9653         break; // do not return because it s necessary to remove tmp faces
9654       }
9655       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9656       if ( nbNodes == 3 ) {
9657         //nReplaceMap.insert( TNodeNodeMap::value_type
9658         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9659         nReplaceMap.insert( TNodeNodeMap::value_type
9660                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9661       }
9662       else {
9663         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9664           // analyse link orientation in faces
9665           int i1 = iLinkNode[ iSide ][ 0 ];
9666           int i2 = iLinkNode[ iSide ][ 1 ];
9667           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9668           // if notLinkNodes are the first and the last ones, then
9669           // their order does not correspond to the link orientation
9670           if (( i1 == 1 && i2 == 2 ) ||
9671               ( i1 == 2 && i2 == 1 ))
9672             reverse[ iSide ] = !reverse[ iSide ];
9673         }
9674         if ( reverse[0] == reverse[1] ) {
9675           //nReplaceMap.insert( TNodeNodeMap::value_type
9676           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9677           //nReplaceMap.insert( TNodeNodeMap::value_type
9678           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9679           for(int nn=0; nn<nbNodes-2; nn++) {
9680             nReplaceMap.insert( TNodeNodeMap::value_type
9681                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9682           }
9683         }
9684         else {
9685           //nReplaceMap.insert( TNodeNodeMap::value_type
9686           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9687           //nReplaceMap.insert( TNodeNodeMap::value_type
9688           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9689           for(int nn=0; nn<nbNodes-2; nn++) {
9690             nReplaceMap.insert( TNodeNodeMap::value_type
9691                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9692           }
9693         }
9694       }
9695
9696       // add other links of the faces to linkList
9697       // -----------------------------------------
9698
9699       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9700       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9701         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9702         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9703         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9704         if ( !iter_isnew.second ) { // already in a set: no need to process
9705           linkIdSet.erase( iter_isnew.first );
9706         }
9707         else // new in set == encountered for the first time: add
9708         {
9709           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9710           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9711           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9712           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9713           linkList[0].push_back ( NLink( n1, n2 ));
9714           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9715         }
9716       }
9717     } // 2 faces found
9718   } // loop on link lists
9719
9720   if ( aResult == SEW_OK &&
9721        ( linkIt[0] != linkList[0].end() ||
9722          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9723     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9724              " " << (faceSetPtr[1]->empty()));
9725     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9726   }
9727
9728   // ====================================================================
9729   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9730   // ====================================================================
9731
9732   // delete temporary faces: they are in reverseElements of actual nodes
9733   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9734   while ( tmpFaceIt->more() )
9735     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9736
9737   if ( aResult != SEW_OK)
9738     return aResult;
9739
9740   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9741   // loop on nodes replacement map
9742   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9743   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9744     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9745       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9746       nodeIDsToRemove.push_back( nToRemove->GetID() );
9747       // loop on elements sharing nToRemove
9748       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9749       while ( invElemIt->more() ) {
9750         const SMDS_MeshElement* e = invElemIt->next();
9751         // get a new suite of nodes: make replacement
9752         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9753         vector< const SMDS_MeshNode*> nodes( nbNodes );
9754         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9755         while ( nIt->more() ) {
9756           const SMDS_MeshNode* n =
9757             static_cast<const SMDS_MeshNode*>( nIt->next() );
9758           nnIt = nReplaceMap.find( n );
9759           if ( nnIt != nReplaceMap.end() ) {
9760             nbReplaced++;
9761             n = (*nnIt).second;
9762           }
9763           nodes[ i++ ] = n;
9764         }
9765         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9766         //         elemIDsToRemove.push_back( e->GetID() );
9767         //       else
9768         if ( nbReplaced )
9769           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9770       }
9771     }
9772
9773   Remove( nodeIDsToRemove, true );
9774
9775   return aResult;
9776 }
9777
9778 //================================================================================
9779 /*!
9780  * \brief Find corresponding nodes in two sets of faces
9781  * \param theSide1 - first face set
9782  * \param theSide2 - second first face
9783  * \param theFirstNode1 - a boundary node of set 1
9784  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9785  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9786  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9787  * \param nReplaceMap - output map of corresponding nodes
9788  * \retval bool  - is a success or not
9789  */
9790 //================================================================================
9791
9792 #ifdef _DEBUG_
9793 //#define DEBUG_MATCHING_NODES
9794 #endif
9795
9796 SMESH_MeshEditor::Sew_Error
9797 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9798                                     set<const SMDS_MeshElement*>& theSide2,
9799                                     const SMDS_MeshNode*          theFirstNode1,
9800                                     const SMDS_MeshNode*          theFirstNode2,
9801                                     const SMDS_MeshNode*          theSecondNode1,
9802                                     const SMDS_MeshNode*          theSecondNode2,
9803                                     TNodeNodeMap &                nReplaceMap)
9804 {
9805   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9806
9807   nReplaceMap.clear();
9808   if ( theFirstNode1 != theFirstNode2 )
9809     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9810   if ( theSecondNode1 != theSecondNode2 )
9811     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9812
9813   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9814   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9815
9816   list< NLink > linkList[2];
9817   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9818   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9819
9820   // loop on links in linkList; find faces by links and append links
9821   // of the found faces to linkList
9822   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9823   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9824     NLink link[] = { *linkIt[0], *linkIt[1] };
9825     if ( linkSet.find( link[0] ) == linkSet.end() )
9826       continue;
9827
9828     // by links, find faces in the face sets,
9829     // and find indices of link nodes in the found faces;
9830     // in a face set, there is only one or no face sharing a link
9831     // ---------------------------------------------------------------
9832
9833     const SMDS_MeshElement* face[] = { 0, 0 };
9834     list<const SMDS_MeshNode*> notLinkNodes[2];
9835     //bool reverse[] = { false, false }; // order of notLinkNodes
9836     int nbNodes[2];
9837     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9838     {
9839       const SMDS_MeshNode* n1 = link[iSide].first;
9840       const SMDS_MeshNode* n2 = link[iSide].second;
9841       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9842       set< const SMDS_MeshElement* > facesOfNode1;
9843       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9844       {
9845         // during a loop of the first node, we find all faces around n1,
9846         // during a loop of the second node, we find one face sharing both n1 and n2
9847         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9848         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9849         while ( fIt->more() ) { // loop on faces sharing a node
9850           const SMDS_MeshElement* f = fIt->next();
9851           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9852               ! facesOfNode1.insert( f ).second ) // f encounters twice
9853           {
9854             if ( face[ iSide ] ) {
9855               MESSAGE( "2 faces per link " );
9856               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9857             }
9858             face[ iSide ] = f;
9859             faceSet->erase( f );
9860
9861             // get not link nodes
9862             int nbN = f->NbNodes();
9863             if ( f->IsQuadratic() )
9864               nbN /= 2;
9865             nbNodes[ iSide ] = nbN;
9866             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9867             int i1 = f->GetNodeIndex( n1 );
9868             int i2 = f->GetNodeIndex( n2 );
9869             int iEnd = nbN, iBeg = -1, iDelta = 1;
9870             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9871             if ( reverse ) {
9872               std::swap( iEnd, iBeg ); iDelta = -1;
9873             }
9874             int i = i2;
9875             while ( true ) {
9876               i += iDelta;
9877               if ( i == iEnd ) i = iBeg + iDelta;
9878               if ( i == i1 ) break;
9879               nodes.push_back ( f->GetNode( i ) );
9880             }
9881           }
9882         }
9883       }
9884     }
9885     // check similarity of elements of the sides
9886     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9887       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9888       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9889         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9890       }
9891       else {
9892         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9893       }
9894     }
9895
9896     // set nodes to merge
9897     // -------------------
9898
9899     if ( face[0] && face[1] )  {
9900       if ( nbNodes[0] != nbNodes[1] ) {
9901         MESSAGE("Diff nb of face nodes");
9902         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9903       }
9904 #ifdef DEBUG_MATCHING_NODES
9905       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9906                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9907                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9908 #endif
9909       int nbN = nbNodes[0];
9910       {
9911         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9912         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9913         for ( int i = 0 ; i < nbN - 2; ++i ) {
9914 #ifdef DEBUG_MATCHING_NODES
9915           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9916 #endif
9917           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9918         }
9919       }
9920
9921       // add other links of the face 1 to linkList
9922       // -----------------------------------------
9923
9924       const SMDS_MeshElement* f0 = face[0];
9925       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9926       for ( int i = 0; i < nbN; i++ )
9927       {
9928         const SMDS_MeshNode* n2 = f0->GetNode( i );
9929         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9930           linkSet.insert( SMESH_TLink( n1, n2 ));
9931         if ( !iter_isnew.second ) { // already in a set: no need to process
9932           linkSet.erase( iter_isnew.first );
9933         }
9934         else // new in set == encountered for the first time: add
9935         {
9936 #ifdef DEBUG_MATCHING_NODES
9937           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9938                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9939 #endif
9940           linkList[0].push_back ( NLink( n1, n2 ));
9941           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9942         }
9943         n1 = n2;
9944       }
9945     } // 2 faces found
9946   } // loop on link lists
9947
9948   return SEW_OK;
9949 }
9950
9951 //================================================================================
9952 /*!
9953   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9954   \param theElems - the list of elements (edges or faces) to be replicated
9955   The nodes for duplication could be found from these elements
9956   \param theNodesNot - list of nodes to NOT replicate
9957   \param theAffectedElems - the list of elements (cells and edges) to which the 
9958   replicated nodes should be associated to.
9959   \return TRUE if operation has been completed successfully, FALSE otherwise
9960 */
9961 //================================================================================
9962
9963 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9964                                     const TIDSortedElemSet& theNodesNot,
9965                                     const TIDSortedElemSet& theAffectedElems )
9966 {
9967   myLastCreatedElems.Clear();
9968   myLastCreatedNodes.Clear();
9969
9970   if ( theElems.size() == 0 )
9971     return false;
9972
9973   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9974   if ( !aMeshDS )
9975     return false;
9976
9977   bool res = false;
9978   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9979   // duplicate elements and nodes
9980   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9981   // replce nodes by duplications
9982   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9983   return res;
9984 }
9985
9986 //================================================================================
9987 /*!
9988   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9989   \param theMeshDS - mesh instance
9990   \param theElems - the elements replicated or modified (nodes should be changed)
9991   \param theNodesNot - nodes to NOT replicate
9992   \param theNodeNodeMap - relation of old node to new created node
9993   \param theIsDoubleElem - flag os to replicate element or modify
9994   \return TRUE if operation has been completed successfully, FALSE otherwise
9995 */
9996 //================================================================================
9997
9998 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9999                                     const TIDSortedElemSet& theElems,
10000                                     const TIDSortedElemSet& theNodesNot,
10001                                     std::map< const SMDS_MeshNode*,
10002                                     const SMDS_MeshNode* >& theNodeNodeMap,
10003                                     const bool theIsDoubleElem )
10004 {
10005   // iterate on through element and duplicate them (by nodes duplication)
10006   bool res = false;
10007   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10008   for ( ;  elemItr != theElems.end(); ++elemItr )
10009   {
10010     const SMDS_MeshElement* anElem = *elemItr;
10011     if (!anElem)
10012       continue;
10013
10014     bool isDuplicate = false;
10015     // duplicate nodes to duplicate element
10016     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10017     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10018     int ind = 0;
10019     while ( anIter->more() ) 
10020     { 
10021
10022       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10023       SMDS_MeshNode* aNewNode = aCurrNode;
10024       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10025         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10026       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10027       {
10028         // duplicate node
10029         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10030         theNodeNodeMap[ aCurrNode ] = aNewNode;
10031         myLastCreatedNodes.Append( aNewNode );
10032       }
10033       isDuplicate |= (aCurrNode != aNewNode);
10034       newNodes[ ind++ ] = aNewNode;
10035     }
10036     if ( !isDuplicate )
10037       continue;
10038
10039     if ( theIsDoubleElem )
10040       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10041     else
10042       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10043
10044     res = true;
10045   }
10046   return res;
10047 }
10048
10049 //================================================================================
10050 /*!
10051   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10052   \param theNodes - identifiers of nodes to be doubled
10053   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10054          nodes. If list of element identifiers is empty then nodes are doubled but 
10055          they not assigned to elements
10056   \return TRUE if operation has been completed successfully, FALSE otherwise
10057 */
10058 //================================================================================
10059
10060 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10061                                     const std::list< int >& theListOfModifiedElems )
10062 {
10063   myLastCreatedElems.Clear();
10064   myLastCreatedNodes.Clear();
10065
10066   if ( theListOfNodes.size() == 0 )
10067     return false;
10068
10069   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10070   if ( !aMeshDS )
10071     return false;
10072
10073   // iterate through nodes and duplicate them
10074
10075   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10076
10077   std::list< int >::const_iterator aNodeIter;
10078   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10079   {
10080     int aCurr = *aNodeIter;
10081     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10082     if ( !aNode )
10083       continue;
10084
10085     // duplicate node
10086
10087     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10088     if ( aNewNode )
10089     {
10090       anOldNodeToNewNode[ aNode ] = aNewNode;
10091       myLastCreatedNodes.Append( aNewNode );
10092     }
10093   }
10094
10095   // Create map of new nodes for modified elements
10096
10097   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10098
10099   std::list< int >::const_iterator anElemIter;
10100   for ( anElemIter = theListOfModifiedElems.begin(); 
10101         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10102   {
10103     int aCurr = *anElemIter;
10104     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10105     if ( !anElem )
10106       continue;
10107
10108     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10109
10110     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10111     int ind = 0;
10112     while ( anIter->more() ) 
10113     { 
10114       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10115       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10116       {
10117         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10118         aNodeArr[ ind++ ] = aNewNode;
10119       }
10120       else
10121         aNodeArr[ ind++ ] = aCurrNode;
10122     }
10123     anElemToNodes[ anElem ] = aNodeArr;
10124   }
10125
10126   // Change nodes of elements  
10127
10128   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10129     anElemToNodesIter = anElemToNodes.begin();
10130   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10131   {
10132     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10133     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10134     if ( anElem )
10135       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10136   }
10137
10138   return true;
10139 }
10140
10141 namespace {
10142
10143   //================================================================================
10144   /*!
10145   \brief Check if element located inside shape
10146   \return TRUE if IN or ON shape, FALSE otherwise
10147   */
10148   //================================================================================
10149
10150   template<class Classifier>
10151   bool isInside(const SMDS_MeshElement* theElem,
10152                 Classifier&             theClassifier,
10153                 const double            theTol)
10154   {
10155     gp_XYZ centerXYZ (0, 0, 0);
10156     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10157     while (aNodeItr->more())
10158       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10159
10160     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10161     theClassifier.Perform(aPnt, theTol);
10162     TopAbs_State aState = theClassifier.State();
10163     return (aState == TopAbs_IN || aState == TopAbs_ON );
10164   }
10165
10166   //================================================================================
10167   /*!
10168    * \brief Classifier of the 3D point on the TopoDS_Face
10169    *        with interaface suitable for isInside()
10170    */
10171   //================================================================================
10172
10173   struct _FaceClassifier
10174   {
10175     Extrema_ExtPS       _extremum;
10176     BRepAdaptor_Surface _surface;
10177     TopAbs_State        _state;
10178
10179     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10180     {
10181       _extremum.Initialize( _surface,
10182                             _surface.FirstUParameter(), _surface.LastUParameter(),
10183                             _surface.FirstVParameter(), _surface.LastVParameter(),
10184                             _surface.Tolerance(), _surface.Tolerance() );
10185     }
10186     void Perform(const gp_Pnt& aPnt, double theTol)
10187     {
10188       _state = TopAbs_OUT;
10189       _extremum.Perform(aPnt);
10190       if ( _extremum.IsDone() )
10191         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10192           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10193     }
10194     TopAbs_State State() const
10195     {
10196       return _state;
10197     }
10198   };
10199 }
10200
10201 //================================================================================
10202 /*!
10203   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10204   \param theElems - group of of elements (edges or faces) to be replicated
10205   \param theNodesNot - group of nodes not to replicate
10206   \param theShape - shape to detect affected elements (element which geometric center
10207   located on or inside shape).
10208   The replicated nodes should be associated to affected elements.
10209   \return TRUE if operation has been completed successfully, FALSE otherwise
10210 */
10211 //================================================================================
10212
10213 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10214                                             const TIDSortedElemSet& theNodesNot,
10215                                             const TopoDS_Shape&     theShape )
10216 {
10217   if ( theShape.IsNull() )
10218     return false;
10219
10220   const double aTol = Precision::Confusion();
10221   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10222   auto_ptr<_FaceClassifier>              aFaceClassifier;
10223   if ( theShape.ShapeType() == TopAbs_SOLID )
10224   {
10225     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10226     bsc3d->PerformInfinitePoint(aTol);
10227   }
10228   else if (theShape.ShapeType() == TopAbs_FACE )
10229   {
10230     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10231   }
10232
10233   // iterates on indicated elements and get elements by back references from their nodes
10234   TIDSortedElemSet anAffected;
10235   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10236   for ( ;  elemItr != theElems.end(); ++elemItr )
10237   {
10238     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10239     if (!anElem)
10240       continue;
10241
10242     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10243     while ( nodeItr->more() )
10244     {
10245       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10246       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10247         continue;
10248       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10249       while ( backElemItr->more() )
10250       {
10251         const SMDS_MeshElement* curElem = backElemItr->next();
10252         if ( curElem && theElems.find(curElem) == theElems.end() &&
10253              ( bsc3d.get() ?
10254                isInside( curElem, *bsc3d, aTol ) :
10255                isInside( curElem, *aFaceClassifier, aTol )))
10256           anAffected.insert( curElem );
10257       }
10258     }
10259   }
10260   return DoubleNodes( theElems, theNodesNot, anAffected );
10261 }
10262
10263 //================================================================================
10264 /*!
10265  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10266  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10267  * \return TRUE if operation has been completed successfully, FALSE otherwise
10268  */
10269 //================================================================================
10270
10271 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10272 {
10273   // iterates on volume elements and detect all free faces on them
10274   SMESHDS_Mesh* aMesh = GetMeshDS();
10275   if (!aMesh)
10276     return false;
10277   //bool res = false;
10278   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10279   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10280   while(vIt->more())
10281   {
10282     const SMDS_MeshVolume* volume = vIt->next();
10283     SMDS_VolumeTool vTool( volume );
10284     vTool.SetExternalNormal();
10285     const bool isPoly = volume->IsPoly();
10286     const bool isQuad = volume->IsQuadratic();
10287     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10288     {
10289       if (!vTool.IsFreeFace(iface))
10290         continue;
10291       nbFree++;
10292       vector<const SMDS_MeshNode *> nodes;
10293       int nbFaceNodes = vTool.NbFaceNodes(iface);
10294       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10295       int inode = 0;
10296       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10297         nodes.push_back(faceNodes[inode]);
10298       if (isQuad)
10299         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10300           nodes.push_back(faceNodes[inode]);
10301
10302       // add new face based on volume nodes
10303       if (aMesh->FindFace( nodes ) ) {
10304         nbExisted++;
10305         continue; // face already exsist
10306       }
10307       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10308       nbCreated++;
10309     }
10310   }
10311   return ( nbFree==(nbExisted+nbCreated) );
10312 }