Salome HOME
0020725: EDF 1242 SMESH : Crash avec Convert lin--> quad avec BLSURF/GHS3D on 64bits
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26 //
27 #include "SMESH_MeshEditor.hxx"
28
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_QuadraticFaceOfNodes.hxx"
36 #include "SMDS_MeshGroup.hxx"
37
38 #include "SMESHDS_Group.hxx"
39 #include "SMESHDS_Mesh.hxx"
40
41 #include "SMESH_Algo.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_Group.hxx"
44 #include "SMESH_MesherHelper.hxx"
45 #include "SMESH_OctreeNode.hxx"
46 #include "SMESH_subMesh.hxx"
47
48 #include "utilities.h"
49
50 #include <BRepAdaptor_Surface.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <BRep_Tool.hxx>
53 #include <ElCLib.hxx>
54 #include <Extrema_GenExtPS.hxx>
55 #include <Extrema_POnCurv.hxx>
56 #include <Extrema_POnSurf.hxx>
57 #include <GC_MakeSegment.hxx>
58 #include <Geom2d_Curve.hxx>
59 #include <GeomAPI_ExtremaCurveCurve.hxx>
60 #include <GeomAdaptor_Surface.hxx>
61 #include <Geom_Curve.hxx>
62 #include <Geom_Line.hxx>
63 #include <Geom_Surface.hxx>
64 #include <IntAna_IntConicQuad.hxx>
65 #include <IntAna_Quadric.hxx>
66 #include <Precision.hxx>
67 #include <TColStd_ListOfInteger.hxx>
68 #include <TopAbs_State.hxx>
69 #include <TopExp.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_ListIteratorOfListOfShape.hxx>
72 #include <TopTools_ListOfShape.hxx>
73 #include <TopTools_SequenceOfShape.hxx>
74 #include <TopoDS.hxx>
75 #include <TopoDS_Face.hxx>
76 #include <gp.hxx>
77 #include <gp_Ax1.hxx>
78 #include <gp_Dir.hxx>
79 #include <gp_Lin.hxx>
80 #include <gp_Pln.hxx>
81 #include <gp_Trsf.hxx>
82 #include <gp_Vec.hxx>
83 #include <gp_XY.hxx>
84 #include <gp_XYZ.hxx>
85
86 #include <math.h>
87
88 #include <map>
89 #include <set>
90 #include <numeric>
91 #include <limits>
92
93 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
94
95 using namespace std;
96 using namespace SMESH::Controls;
97
98 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
100
101 //=======================================================================
102 //function : SMESH_MeshEditor
103 //purpose  :
104 //=======================================================================
105
106 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
107   :myMesh( theMesh ) // theMesh may be NULL
108 {
109 }
110
111 //=======================================================================
112 /*!
113  * \brief Add element
114  */
115 //=======================================================================
116
117 SMDS_MeshElement*
118 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
119                              const SMDSAbs_ElementType            type,
120                              const bool                           isPoly,
121                              const int                            ID)
122 {
123   SMDS_MeshElement* e = 0;
124   int nbnode = node.size();
125   SMESHDS_Mesh* mesh = GetMeshDS();
126   switch ( type ) {
127   case SMDSAbs_Edge:
128     if ( nbnode == 2 )
129       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
130       else      e = mesh->AddEdge      (node[0], node[1] );
131     else if ( nbnode == 3 )
132       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
133       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
134     break;
135   case SMDSAbs_Face:
136     if ( !isPoly ) {
137       if      (nbnode == 3)
138         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
139         else      e = mesh->AddFace      (node[0], node[1], node[2] );
140       else if (nbnode == 4) 
141         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
142         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
143       else if (nbnode == 6)
144         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
145                                           node[4], node[5], ID);
146         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
147                                           node[4], node[5] );
148       else if (nbnode == 8)
149         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
150                                           node[4], node[5], node[6], node[7], ID);
151         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
152                                           node[4], node[5], node[6], node[7] );
153     } else {
154       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
155       else      e = mesh->AddPolygonalFace      (node    );
156     }
157     break;
158   case SMDSAbs_Volume:
159     if ( !isPoly ) {
160       if      (nbnode == 4)
161         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
162         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
163       else if (nbnode == 5)
164         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
165                                             node[4], ID);
166         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
167                                             node[4] );
168       else if (nbnode == 6)
169         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
170                                             node[4], node[5], ID);
171         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
172                                             node[4], node[5] );
173       else if (nbnode == 8)
174         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175                                             node[4], node[5], node[6], node[7], ID);
176         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
177                                             node[4], node[5], node[6], node[7] );
178       else if (nbnode == 10)
179         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180                                             node[4], node[5], node[6], node[7],
181                                             node[8], node[9], ID);
182         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
183                                             node[4], node[5], node[6], node[7],
184                                             node[8], node[9] );
185       else if (nbnode == 13)
186         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
187                                             node[4], node[5], node[6], node[7],
188                                             node[8], node[9], node[10],node[11],
189                                             node[12],ID);
190         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
191                                             node[4], node[5], node[6], node[7],
192                                             node[8], node[9], node[10],node[11],
193                                             node[12] );
194       else if (nbnode == 15)
195         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
196                                             node[4], node[5], node[6], node[7],
197                                             node[8], node[9], node[10],node[11],
198                                             node[12],node[13],node[14],ID);
199         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
200                                             node[4], node[5], node[6], node[7],
201                                             node[8], node[9], node[10],node[11],
202                                             node[12],node[13],node[14] );
203       else if (nbnode == 20)
204         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
205                                             node[4], node[5], node[6], node[7],
206                                             node[8], node[9], node[10],node[11],
207                                             node[12],node[13],node[14],node[15],
208                                             node[16],node[17],node[18],node[19],ID);
209         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
210                                             node[4], node[5], node[6], node[7],
211                                             node[8], node[9], node[10],node[11],
212                                             node[12],node[13],node[14],node[15],
213                                             node[16],node[17],node[18],node[19] );
214     }
215   }
216   return e;
217 }
218
219 //=======================================================================
220 /*!
221  * \brief Add element
222  */
223 //=======================================================================
224
225 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
226                                                const SMDSAbs_ElementType type,
227                                                const bool                isPoly,
228                                                const int                 ID)
229 {
230   vector<const SMDS_MeshNode*> nodes;
231   nodes.reserve( nodeIDs.size() );
232   vector<int>::const_iterator id = nodeIDs.begin();
233   while ( id != nodeIDs.end() ) {
234     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
235       nodes.push_back( node );
236     else
237       return 0;
238   }
239   return AddElement( nodes, type, isPoly, ID );
240 }
241
242 //=======================================================================
243 //function : Remove
244 //purpose  : Remove a node or an element.
245 //           Modify a compute state of sub-meshes which become empty
246 //=======================================================================
247
248 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
249                                const bool         isNodes )
250 {
251   myLastCreatedElems.Clear();
252   myLastCreatedNodes.Clear();
253
254   SMESHDS_Mesh* aMesh = GetMeshDS();
255   set< SMESH_subMesh *> smmap;
256
257   list<int>::const_iterator it = theIDs.begin();
258   for ( ; it != theIDs.end(); it++ ) {
259     const SMDS_MeshElement * elem;
260     if ( isNodes )
261       elem = aMesh->FindNode( *it );
262     else
263       elem = aMesh->FindElement( *it );
264     if ( !elem )
265       continue;
266
267     // Notify VERTEX sub-meshes about modification
268     if ( isNodes ) {
269       const SMDS_MeshNode* node = cast2Node( elem );
270       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
271         if ( int aShapeID = node->GetPosition()->GetShapeId() )
272           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
273             smmap.insert( sm );
274     }
275     // Find sub-meshes to notify about modification
276     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
277     //     while ( nodeIt->more() ) {
278     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
279     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
280     //       if ( aPosition.get() ) {
281     //         if ( int aShapeID = aPosition->GetShapeId() ) {
282     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
283     //             smmap.insert( sm );
284     //         }
285     //       }
286     //     }
287
288     // Do remove
289     if ( isNodes )
290       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
291     else
292       aMesh->RemoveElement( elem );
293   }
294
295   // Notify sub-meshes about modification
296   if ( !smmap.empty() ) {
297     set< SMESH_subMesh *>::iterator smIt;
298     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
299       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
300   }
301
302   //   // Check if the whole mesh becomes empty
303   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
304   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
305
306   return true;
307 }
308
309 //=======================================================================
310 //function : FindShape
311 //purpose  : Return an index of the shape theElem is on
312 //           or zero if a shape not found
313 //=======================================================================
314
315 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
316 {
317   myLastCreatedElems.Clear();
318   myLastCreatedNodes.Clear();
319
320   SMESHDS_Mesh * aMesh = GetMeshDS();
321   if ( aMesh->ShapeToMesh().IsNull() )
322     return 0;
323
324   if ( theElem->GetType() == SMDSAbs_Node ) {
325     const SMDS_PositionPtr& aPosition =
326       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
327     if ( aPosition.get() )
328       return aPosition->GetShapeId();
329     else
330       return 0;
331   }
332
333   TopoDS_Shape aShape; // the shape a node is on
334   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
335   while ( nodeIt->more() ) {
336     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
337     const SMDS_PositionPtr& aPosition = node->GetPosition();
338     if ( aPosition.get() ) {
339       int aShapeID = aPosition->GetShapeId();
340       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
341       if ( sm ) {
342         if ( sm->Contains( theElem ))
343           return aShapeID;
344         if ( aShape.IsNull() )
345           aShape = aMesh->IndexToShape( aShapeID );
346       }
347       else {
348         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
349       }
350     }
351   }
352
353   // None of nodes is on a proper shape,
354   // find the shape among ancestors of aShape on which a node is
355   if ( aShape.IsNull() ) {
356     //MESSAGE ("::FindShape() - NONE node is on shape")
357     return 0;
358   }
359   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
360   for ( ; ancIt.More(); ancIt.Next() ) {
361     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
362     if ( sm && sm->Contains( theElem ))
363       return aMesh->ShapeToIndex( ancIt.Value() );
364   }
365
366   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
367   return 0;
368 }
369
370 //=======================================================================
371 //function : IsMedium
372 //purpose  :
373 //=======================================================================
374
375 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
376                                 const SMDSAbs_ElementType typeToCheck)
377 {
378   bool isMedium = false;
379   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
380   while (it->more() && !isMedium ) {
381     const SMDS_MeshElement* elem = it->next();
382     isMedium = elem->IsMediumNode(node);
383   }
384   return isMedium;
385 }
386
387 //=======================================================================
388 //function : ShiftNodesQuadTria
389 //purpose  : auxilary
390 //           Shift nodes in the array corresponded to quadratic triangle
391 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
392 //=======================================================================
393 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
394 {
395   const SMDS_MeshNode* nd1 = aNodes[0];
396   aNodes[0] = aNodes[1];
397   aNodes[1] = aNodes[2];
398   aNodes[2] = nd1;
399   const SMDS_MeshNode* nd2 = aNodes[3];
400   aNodes[3] = aNodes[4];
401   aNodes[4] = aNodes[5];
402   aNodes[5] = nd2;
403 }
404
405 //=======================================================================
406 //function : GetNodesFromTwoTria
407 //purpose  : auxilary
408 //           Shift nodes in the array corresponded to quadratic triangle
409 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
410 //=======================================================================
411 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
412                                 const SMDS_MeshElement * theTria2,
413                                 const SMDS_MeshNode* N1[],
414                                 const SMDS_MeshNode* N2[])
415 {
416   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
417   int i=0;
418   while(i<6) {
419     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
420     i++;
421   }
422   if(it->more()) return false;
423   it = theTria2->nodesIterator();
424   i=0;
425   while(i<6) {
426     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
427     i++;
428   }
429   if(it->more()) return false;
430
431   int sames[3] = {-1,-1,-1};
432   int nbsames = 0;
433   int j;
434   for(i=0; i<3; i++) {
435     for(j=0; j<3; j++) {
436       if(N1[i]==N2[j]) {
437         sames[i] = j;
438         nbsames++;
439         break;
440       }
441     }
442   }
443   if(nbsames!=2) return false;
444   if(sames[0]>-1) {
445     ShiftNodesQuadTria(N1);
446     if(sames[1]>-1) {
447       ShiftNodesQuadTria(N1);
448     }
449   }
450   i = sames[0] + sames[1] + sames[2];
451   for(; i<2; i++) {
452     ShiftNodesQuadTria(N2);
453   }
454   // now we receive following N1 and N2 (using numeration as above image)
455   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
456   // i.e. first nodes from both arrays determ new diagonal
457   return true;
458 }
459
460 //=======================================================================
461 //function : InverseDiag
462 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
463 //           but having other common link.
464 //           Return False if args are improper
465 //=======================================================================
466
467 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
468                                     const SMDS_MeshElement * theTria2 )
469 {
470   myLastCreatedElems.Clear();
471   myLastCreatedNodes.Clear();
472
473   if (!theTria1 || !theTria2)
474     return false;
475
476   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
477   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
478   if (F1 && F2) {
479
480     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
481     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
482     //    |/ |                                         | \|
483     //  B +--+ 2                                     B +--+ 2
484
485     // put nodes in array and find out indices of the same ones
486     const SMDS_MeshNode* aNodes [6];
487     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
488     int i = 0;
489     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
490     while ( it->more() ) {
491       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
492
493       if ( i > 2 ) // theTria2
494         // find same node of theTria1
495         for ( int j = 0; j < 3; j++ )
496           if ( aNodes[ i ] == aNodes[ j ]) {
497             sameInd[ j ] = i;
498             sameInd[ i ] = j;
499             break;
500           }
501       // next
502       i++;
503       if ( i == 3 ) {
504         if ( it->more() )
505           return false; // theTria1 is not a triangle
506         it = theTria2->nodesIterator();
507       }
508       if ( i == 6 && it->more() )
509         return false; // theTria2 is not a triangle
510     }
511
512     // find indices of 1,2 and of A,B in theTria1
513     int iA = 0, iB = 0, i1 = 0, i2 = 0;
514     for ( i = 0; i < 6; i++ ) {
515       if ( sameInd [ i ] == 0 )
516         if ( i < 3 ) i1 = i;
517         else         i2 = i;
518       else if (i < 3)
519         if ( iA ) iB = i;
520         else      iA = i;
521     }
522     // nodes 1 and 2 should not be the same
523     if ( aNodes[ i1 ] == aNodes[ i2 ] )
524       return false;
525
526     // theTria1: A->2
527     aNodes[ iA ] = aNodes[ i2 ];
528     // theTria2: B->1
529     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
530
531     //MESSAGE( theTria1 << theTria2 );
532
533     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
534     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
535
536     //MESSAGE( theTria1 << theTria2 );
537
538     return true;
539
540   } // end if(F1 && F2)
541
542   // check case of quadratic faces
543   const SMDS_QuadraticFaceOfNodes* QF1 =
544     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
545   if(!QF1) return false;
546   const SMDS_QuadraticFaceOfNodes* QF2 =
547     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
548   if(!QF2) return false;
549
550   //       5
551   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
552   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
553   //    |   / |
554   //  7 +  +  + 6
555   //    | /9  |
556   //    |/    |
557   //  4 +--+--+ 3
558   //       8
559
560   const SMDS_MeshNode* N1 [6];
561   const SMDS_MeshNode* N2 [6];
562   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
563     return false;
564   // now we receive following N1 and N2 (using numeration as above image)
565   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
566   // i.e. first nodes from both arrays determ new diagonal
567
568   const SMDS_MeshNode* N1new [6];
569   const SMDS_MeshNode* N2new [6];
570   N1new[0] = N1[0];
571   N1new[1] = N2[0];
572   N1new[2] = N2[1];
573   N1new[3] = N1[4];
574   N1new[4] = N2[3];
575   N1new[5] = N1[5];
576   N2new[0] = N1[0];
577   N2new[1] = N1[1];
578   N2new[2] = N2[0];
579   N2new[3] = N1[3];
580   N2new[4] = N2[5];
581   N2new[5] = N1[4];
582   // replaces nodes in faces
583   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
584   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
585
586   return true;
587 }
588
589 //=======================================================================
590 //function : findTriangles
591 //purpose  : find triangles sharing theNode1-theNode2 link
592 //=======================================================================
593
594 static bool findTriangles(const SMDS_MeshNode *    theNode1,
595                           const SMDS_MeshNode *    theNode2,
596                           const SMDS_MeshElement*& theTria1,
597                           const SMDS_MeshElement*& theTria2)
598 {
599   if ( !theNode1 || !theNode2 ) return false;
600
601   theTria1 = theTria2 = 0;
602
603   set< const SMDS_MeshElement* > emap;
604   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
605   while (it->more()) {
606     const SMDS_MeshElement* elem = it->next();
607     if ( elem->NbNodes() == 3 )
608       emap.insert( elem );
609   }
610   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
611   while (it->more()) {
612     const SMDS_MeshElement* elem = it->next();
613     if ( emap.find( elem ) != emap.end() )
614       if ( theTria1 ) {
615         // theTria1 must be element with minimum ID
616         if( theTria1->GetID() < elem->GetID() ) {
617           theTria2 = elem;
618         }
619         else {
620           theTria2 = theTria1;
621           theTria1 = elem;
622         }
623         break;
624       }
625       else {
626         theTria1 = elem;
627       }
628   }
629   return ( theTria1 && theTria2 );
630 }
631
632 //=======================================================================
633 //function : InverseDiag
634 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
635 //           with ones built on the same 4 nodes but having other common link.
636 //           Return false if proper faces not found
637 //=======================================================================
638
639 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
640                                     const SMDS_MeshNode * theNode2)
641 {
642   myLastCreatedElems.Clear();
643   myLastCreatedNodes.Clear();
644
645   MESSAGE( "::InverseDiag()" );
646
647   const SMDS_MeshElement *tr1, *tr2;
648   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
649     return false;
650
651   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
652   //if (!F1) return false;
653   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
654   //if (!F2) return false;
655   if (F1 && F2) {
656
657     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
658     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
659     //    |/ |                                    | \|
660     //  B +--+ 2                                B +--+ 2
661
662     // put nodes in array
663     // and find indices of 1,2 and of A in tr1 and of B in tr2
664     int i, iA1 = 0, i1 = 0;
665     const SMDS_MeshNode* aNodes1 [3];
666     SMDS_ElemIteratorPtr it;
667     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
668       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
669       if ( aNodes1[ i ] == theNode1 )
670         iA1 = i; // node A in tr1
671       else if ( aNodes1[ i ] != theNode2 )
672         i1 = i;  // node 1
673     }
674     int iB2 = 0, i2 = 0;
675     const SMDS_MeshNode* aNodes2 [3];
676     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
677       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
678       if ( aNodes2[ i ] == theNode2 )
679         iB2 = i; // node B in tr2
680       else if ( aNodes2[ i ] != theNode1 )
681         i2 = i;  // node 2
682     }
683
684     // nodes 1 and 2 should not be the same
685     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
686       return false;
687
688     // tr1: A->2
689     aNodes1[ iA1 ] = aNodes2[ i2 ];
690     // tr2: B->1
691     aNodes2[ iB2 ] = aNodes1[ i1 ];
692
693     //MESSAGE( tr1 << tr2 );
694
695     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
696     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
697
698     //MESSAGE( tr1 << tr2 );
699
700     return true;
701   }
702
703   // check case of quadratic faces
704   const SMDS_QuadraticFaceOfNodes* QF1 =
705     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
706   if(!QF1) return false;
707   const SMDS_QuadraticFaceOfNodes* QF2 =
708     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
709   if(!QF2) return false;
710   return InverseDiag(tr1,tr2);
711 }
712
713 //=======================================================================
714 //function : getQuadrangleNodes
715 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
716 //           fusion of triangles tr1 and tr2 having shared link on
717 //           theNode1 and theNode2
718 //=======================================================================
719
720 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
721                         const SMDS_MeshNode *    theNode1,
722                         const SMDS_MeshNode *    theNode2,
723                         const SMDS_MeshElement * tr1,
724                         const SMDS_MeshElement * tr2 )
725 {
726   if( tr1->NbNodes() != tr2->NbNodes() )
727     return false;
728   // find the 4-th node to insert into tr1
729   const SMDS_MeshNode* n4 = 0;
730   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
731   int i=0;
732   while ( !n4 && i<3 ) {
733     const SMDS_MeshNode * n = cast2Node( it->next() );
734     i++;
735     bool isDiag = ( n == theNode1 || n == theNode2 );
736     if ( !isDiag )
737       n4 = n;
738   }
739   // Make an array of nodes to be in a quadrangle
740   int iNode = 0, iFirstDiag = -1;
741   it = tr1->nodesIterator();
742   i=0;
743   while ( i<3 ) {
744     const SMDS_MeshNode * n = cast2Node( it->next() );
745     i++;
746     bool isDiag = ( n == theNode1 || n == theNode2 );
747     if ( isDiag ) {
748       if ( iFirstDiag < 0 )
749         iFirstDiag = iNode;
750       else if ( iNode - iFirstDiag == 1 )
751         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
752     }
753     else if ( n == n4 ) {
754       return false; // tr1 and tr2 should not have all the same nodes
755     }
756     theQuadNodes[ iNode++ ] = n;
757   }
758   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
759     theQuadNodes[ iNode ] = n4;
760
761   return true;
762 }
763
764 //=======================================================================
765 //function : DeleteDiag
766 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
767 //           with a quadrangle built on the same 4 nodes.
768 //           Return false if proper faces not found
769 //=======================================================================
770
771 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
772                                    const SMDS_MeshNode * theNode2)
773 {
774   myLastCreatedElems.Clear();
775   myLastCreatedNodes.Clear();
776
777   MESSAGE( "::DeleteDiag()" );
778
779   const SMDS_MeshElement *tr1, *tr2;
780   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
781     return false;
782
783   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
784   //if (!F1) return false;
785   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
786   //if (!F2) return false;
787   if (F1 && F2) {
788
789     const SMDS_MeshNode* aNodes [ 4 ];
790     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
791       return false;
792
793     //MESSAGE( endl << tr1 << tr2 );
794
795     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
796     myLastCreatedElems.Append(tr1);
797     GetMeshDS()->RemoveElement( tr2 );
798
799     //MESSAGE( endl << tr1 );
800
801     return true;
802   }
803
804   // check case of quadratic faces
805   const SMDS_QuadraticFaceOfNodes* QF1 =
806     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
807   if(!QF1) return false;
808   const SMDS_QuadraticFaceOfNodes* QF2 =
809     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
810   if(!QF2) return false;
811
812   //       5
813   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
814   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
815   //    |   / |
816   //  7 +  +  + 6
817   //    | /9  |
818   //    |/    |
819   //  4 +--+--+ 3
820   //       8
821
822   const SMDS_MeshNode* N1 [6];
823   const SMDS_MeshNode* N2 [6];
824   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
825     return false;
826   // now we receive following N1 and N2 (using numeration as above image)
827   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
828   // i.e. first nodes from both arrays determ new diagonal
829
830   const SMDS_MeshNode* aNodes[8];
831   aNodes[0] = N1[0];
832   aNodes[1] = N1[1];
833   aNodes[2] = N2[0];
834   aNodes[3] = N2[1];
835   aNodes[4] = N1[3];
836   aNodes[5] = N2[5];
837   aNodes[6] = N2[3];
838   aNodes[7] = N1[5];
839
840   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
841   myLastCreatedElems.Append(tr1);
842   GetMeshDS()->RemoveElement( tr2 );
843
844   // remove middle node (9)
845   GetMeshDS()->RemoveNode( N1[4] );
846
847   return true;
848 }
849
850 //=======================================================================
851 //function : Reorient
852 //purpose  : Reverse theElement orientation
853 //=======================================================================
854
855 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
856 {
857   myLastCreatedElems.Clear();
858   myLastCreatedNodes.Clear();
859
860   if (!theElem)
861     return false;
862   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
863   if ( !it || !it->more() )
864     return false;
865
866   switch ( theElem->GetType() ) {
867
868   case SMDSAbs_Edge:
869   case SMDSAbs_Face: {
870     if(!theElem->IsQuadratic()) {
871       int i = theElem->NbNodes();
872       vector<const SMDS_MeshNode*> aNodes( i );
873       while ( it->more() )
874         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
875       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
876     }
877     else {
878       // quadratic elements
879       if(theElem->GetType()==SMDSAbs_Edge) {
880         vector<const SMDS_MeshNode*> aNodes(3);
881         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
882         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
883         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
884         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
885       }
886       else {
887         int nbn = theElem->NbNodes();
888         vector<const SMDS_MeshNode*> aNodes(nbn);
889         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
890         int i=1;
891         for(; i<nbn/2; i++) {
892           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
893         }
894         for(i=0; i<nbn/2; i++) {
895           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
896         }
897         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
898       }
899     }
900   }
901   case SMDSAbs_Volume: {
902     if (theElem->IsPoly()) {
903       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
904         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
905       if (!aPolyedre) {
906         MESSAGE("Warning: bad volumic element");
907         return false;
908       }
909
910       int nbFaces = aPolyedre->NbFaces();
911       vector<const SMDS_MeshNode *> poly_nodes;
912       vector<int> quantities (nbFaces);
913
914       // reverse each face of the polyedre
915       for (int iface = 1; iface <= nbFaces; iface++) {
916         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
917         quantities[iface - 1] = nbFaceNodes;
918
919         for (inode = nbFaceNodes; inode >= 1; inode--) {
920           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
921           poly_nodes.push_back(curNode);
922         }
923       }
924
925       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
926
927     }
928     else {
929       SMDS_VolumeTool vTool;
930       if ( !vTool.Set( theElem ))
931         return false;
932       vTool.Inverse();
933       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
934     }
935   }
936   default:;
937   }
938
939   return false;
940 }
941
942 //=======================================================================
943 //function : getBadRate
944 //purpose  :
945 //=======================================================================
946
947 static double getBadRate (const SMDS_MeshElement*               theElem,
948                           SMESH::Controls::NumericalFunctorPtr& theCrit)
949 {
950   SMESH::Controls::TSequenceOfXYZ P;
951   if ( !theElem || !theCrit->GetPoints( theElem, P ))
952     return 1e100;
953   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
954   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
955 }
956
957 //=======================================================================
958 //function : QuadToTri
959 //purpose  : Cut quadrangles into triangles.
960 //           theCrit is used to select a diagonal to cut
961 //=======================================================================
962
963 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
964                                   SMESH::Controls::NumericalFunctorPtr theCrit)
965 {
966   myLastCreatedElems.Clear();
967   myLastCreatedNodes.Clear();
968
969   MESSAGE( "::QuadToTri()" );
970
971   if ( !theCrit.get() )
972     return false;
973
974   SMESHDS_Mesh * aMesh = GetMeshDS();
975
976   Handle(Geom_Surface) surface;
977   SMESH_MesherHelper   helper( *GetMesh() );
978
979   TIDSortedElemSet::iterator itElem;
980   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
981     const SMDS_MeshElement* elem = *itElem;
982     if ( !elem || elem->GetType() != SMDSAbs_Face )
983       continue;
984     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
985       continue;
986
987     // retrieve element nodes
988     const SMDS_MeshNode* aNodes [8];
989     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
990     int i = 0;
991     while ( itN->more() )
992       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
993
994     // compare two sets of possible triangles
995     double aBadRate1, aBadRate2; // to what extent a set is bad
996     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
997     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
998     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
999
1000     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1001     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1002     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1003
1004     int aShapeId = FindShape( elem );
1005     const SMDS_MeshElement* newElem = 0;
1006
1007     if( !elem->IsQuadratic() ) {
1008
1009       // split liner quadrangle
1010
1011       if ( aBadRate1 <= aBadRate2 ) {
1012         // tr1 + tr2 is better
1013         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1014         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1015       }
1016       else {
1017         // tr3 + tr4 is better
1018         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1019         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1020       }
1021     }
1022     else {
1023
1024       // split quadratic quadrangle
1025
1026       // get surface elem is on
1027       if ( aShapeId != helper.GetSubShapeID() ) {
1028         surface.Nullify();
1029         TopoDS_Shape shape;
1030         if ( aShapeId > 0 )
1031           shape = aMesh->IndexToShape( aShapeId );
1032         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1033           TopoDS_Face face = TopoDS::Face( shape );
1034           surface = BRep_Tool::Surface( face );
1035           if ( !surface.IsNull() )
1036             helper.SetSubShape( shape );
1037         }
1038       }
1039       // get elem nodes
1040       const SMDS_MeshNode* aNodes [8];
1041       const SMDS_MeshNode* inFaceNode = 0;
1042       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1043       int i = 0;
1044       while ( itN->more() ) {
1045         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1046         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1047              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1048         {
1049           inFaceNode = aNodes[ i-1 ];
1050         }
1051       }
1052       // find middle point for (0,1,2,3)
1053       // and create a node in this point;
1054       gp_XYZ p( 0,0,0 );
1055       if ( surface.IsNull() ) {
1056         for(i=0; i<4; i++)
1057           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1058         p /= 4;
1059       }
1060       else {
1061         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1062         gp_XY uv( 0,0 );
1063         for(i=0; i<4; i++)
1064           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1065         uv /= 4.;
1066         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1067       }
1068       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1069       myLastCreatedNodes.Append(newN);
1070
1071       // create a new element
1072       const SMDS_MeshNode* N[6];
1073       if ( aBadRate1 <= aBadRate2 ) {
1074         N[0] = aNodes[0];
1075         N[1] = aNodes[1];
1076         N[2] = aNodes[2];
1077         N[3] = aNodes[4];
1078         N[4] = aNodes[5];
1079         N[5] = newN;
1080         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1081                                  aNodes[6], aNodes[7], newN );
1082       }
1083       else {
1084         N[0] = aNodes[1];
1085         N[1] = aNodes[2];
1086         N[2] = aNodes[3];
1087         N[3] = aNodes[5];
1088         N[4] = aNodes[6];
1089         N[5] = newN;
1090         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1091                                  aNodes[7], aNodes[4], newN );
1092       }
1093       aMesh->ChangeElementNodes( elem, N, 6 );
1094
1095     } // quadratic case
1096
1097     // care of a new element
1098
1099     myLastCreatedElems.Append(newElem);
1100     AddToSameGroups( newElem, elem, aMesh );
1101
1102     // put a new triangle on the same shape
1103     if ( aShapeId )
1104       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1105   }
1106   return true;
1107 }
1108
1109 //=======================================================================
1110 //function : BestSplit
1111 //purpose  : Find better diagonal for cutting.
1112 //=======================================================================
1113
1114 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1115                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1116 {
1117   myLastCreatedElems.Clear();
1118   myLastCreatedNodes.Clear();
1119
1120   if (!theCrit.get())
1121     return -1;
1122
1123   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1124     return -1;
1125
1126   if( theQuad->NbNodes()==4 ||
1127       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1128
1129     // retrieve element nodes
1130     const SMDS_MeshNode* aNodes [4];
1131     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1132     int i = 0;
1133     //while (itN->more())
1134     while (i<4) {
1135       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1136     }
1137     // compare two sets of possible triangles
1138     double aBadRate1, aBadRate2; // to what extent a set is bad
1139     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1140     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1141     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1142
1143     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1144     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1145     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1146
1147     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1148       return 1; // diagonal 1-3
1149
1150     return 2; // diagonal 2-4
1151   }
1152   return -1;
1153 }
1154
1155 namespace
1156 {
1157   // Methods of splitting volumes into tetra
1158
1159   const int theHexTo5[5*4] =
1160     {
1161       0, 1, 5, 2,
1162       0, 4, 5, 7,
1163       0, 3, 7, 2,
1164       5, 6, 7, 2,
1165       0, 2, 5, 7
1166     };
1167   const int theHexTo6[6*4] =
1168     {
1169       0, 1, 5, 2,
1170       0, 4, 5, 7,
1171       0, 3, 7, 2,
1172       5, 6, 7, 2,
1173       0, 2, 5, 7
1174     };
1175   const int thePyraTo2[2*4] =
1176     {
1177       0, 1, 2, 4,
1178       0, 2, 3, 4
1179     };
1180
1181   const int thePentaTo8[8*4] =
1182     {
1183       0, 1, 2, 6,
1184       3, 5, 4, 6,
1185       0, 3, 4, 6,
1186       0, 4, 1, 6,
1187       1, 4, 5, 6,
1188       1, 5, 2, 6,
1189       2, 5, 3, 6,
1190       2, 3, 0, 6
1191     };
1192
1193   struct TSplitMethod
1194   {
1195     int        _nbTetra;
1196     const int* _connectivity;
1197     bool       _addNode; // additional node is to be created
1198     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1199       : _nbTetra(nbTet), _connectivity(conn), _addNode(addNode) {}
1200   };
1201
1202   /*!
1203    * \brief return TSplitMethod for the given element
1204    */
1205   TSplitMethod getSplitMethod( const SMDS_MeshElement* vol, const int theMethodFlags)
1206   {
1207     TSplitMethod method;
1208     if ( vol->GetType() == SMDSAbs_Volume && !vol->IsPoly())
1209       switch ( vol->NbNodes() )
1210       {
1211       case 8:
1212       case 20:
1213         if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1214           method = TSplitMethod( 5, theHexTo5 );
1215         else
1216           method = TSplitMethod( 6, theHexTo6 );
1217         break;
1218       case 5:
1219       case 13:
1220         method = TSplitMethod( 2, thePyraTo2 );
1221         break;
1222       case 6:
1223       case 15:
1224         method = TSplitMethod( 8, thePentaTo8, /*addNode=*/true );
1225         break;
1226       default:;
1227       }
1228     return method;
1229   }
1230 }
1231
1232 //=======================================================================
1233 //function : SplitVolumesIntoTetra
1234 //purpose  : Split volumic elements into tetrahedra.
1235 //=======================================================================
1236
1237 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1238                                               const int                theMethodFlags)
1239 {
1240   // sdt-like iterator on coordinates of nodes of mesh element
1241   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1242   NXyzIterator xyzEnd;
1243
1244   SMESH_MesherHelper helper( *GetMesh());
1245
1246   TIDSortedElemSet::const_iterator elem = theElems.begin();
1247   for ( ; elem != theElems.end(); ++elem )
1248   {
1249     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1250     if ( geomType <= SMDSEntity_Quad_Tetra )
1251       continue; // tetra or face or edge
1252
1253     if ( (*elem)->IsQuadratic() )
1254     {
1255       // add quadratic links to the helper
1256       SMDS_VolumeTool vol( *elem );
1257       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1258       {
1259         const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1260         for ( int iN = 0; iN < vol.NbFaceNodes( iF ); iN += 2)
1261           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1262       }
1263       helper.SetIsQuadratic( true );
1264     }
1265     else
1266     {
1267       helper.SetIsQuadratic( false );
1268     }
1269
1270     vector<const SMDS_MeshElement* > tetras; // splits of a volume
1271
1272     if ( geomType == SMDSEntity_Polyhedra )
1273     {
1274       // Each face of a polyhedron is split into triangles and
1275       // each of triangles and a cell barycenter form a tetrahedron.
1276
1277       SMDS_VolumeTool vol( *elem );
1278
1279       // make a node at barycenter
1280       gp_XYZ gc = std::accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd,gp_XYZ(0,0,0));
1281       gc /= vol.NbNodes();
1282       SMDS_MeshNode* gcNode = GetMeshDS()->AddNode( gc.X(), gc.Y(), gc.Z() );
1283
1284       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1285       {
1286         const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1287         int nbFNodes = vol.NbFaceNodes( iF );
1288         int nbTria = nbFNodes - 2;
1289         bool extFace =  vol.IsFaceExternal( iF );
1290         SMDS_MeshElement* tet;
1291         for ( int i = 0; i < nbTria; ++i )
1292         {
1293           if ( extFace )
1294             tet = helper.AddVolume( fNodes[0], fNodes[i+1], fNodes[i+2], gcNode );
1295           else
1296             tet = helper.AddVolume( fNodes[0], fNodes[i+2], fNodes[i+1], gcNode );
1297           tetras.push_back( tet );
1298         }
1299       }
1300
1301     }
1302     else
1303     {
1304
1305       TSplitMethod splitMethod = getSplitMethod( *elem, theMethodFlags );
1306       if ( splitMethod._nbTetra < 1 ) continue;
1307
1308       vector<const SMDS_MeshNode*> volNodes( (*elem)->begin_nodes(), (*elem)->end_nodes());
1309     }
1310   }
1311 }
1312
1313 //=======================================================================
1314 //function : AddToSameGroups
1315 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1316 //=======================================================================
1317
1318 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1319                                         const SMDS_MeshElement* elemInGroups,
1320                                         SMESHDS_Mesh *          aMesh)
1321 {
1322   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1323   if (!groups.empty()) {
1324     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1325     for ( ; grIt != groups.end(); grIt++ ) {
1326       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1327       if ( group && group->Contains( elemInGroups ))
1328         group->SMDSGroup().Add( elemToAdd );
1329     }
1330   }
1331 }
1332
1333
1334 //=======================================================================
1335 //function : RemoveElemFromGroups
1336 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1337 //=======================================================================
1338 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1339                                              SMESHDS_Mesh *          aMesh)
1340 {
1341   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1342   if (!groups.empty())
1343   {
1344     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1345     for (; GrIt != groups.end(); GrIt++)
1346     {
1347       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1348       if (!grp || grp->IsEmpty()) continue;
1349       grp->SMDSGroup().Remove(removeelem);
1350     }
1351   }
1352 }
1353
1354 //=======================================================================
1355 //function : ReplaceElemInGroups
1356 //purpose  : replace elemToRm by elemToAdd in the all groups
1357 //=======================================================================
1358
1359 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1360                                             const SMDS_MeshElement* elemToAdd,
1361                                             SMESHDS_Mesh *          aMesh)
1362 {
1363   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1364   if (!groups.empty()) {
1365     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1366     for ( ; grIt != groups.end(); grIt++ ) {
1367       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1368       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1369         group->SMDSGroup().Add( elemToAdd );
1370     }
1371   }
1372 }
1373
1374 //=======================================================================
1375 //function : QuadToTri
1376 //purpose  : Cut quadrangles into triangles.
1377 //           theCrit is used to select a diagonal to cut
1378 //=======================================================================
1379
1380 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1381                                   const bool         the13Diag)
1382 {
1383   myLastCreatedElems.Clear();
1384   myLastCreatedNodes.Clear();
1385
1386   MESSAGE( "::QuadToTri()" );
1387
1388   SMESHDS_Mesh * aMesh = GetMeshDS();
1389
1390   Handle(Geom_Surface) surface;
1391   SMESH_MesherHelper   helper( *GetMesh() );
1392
1393   TIDSortedElemSet::iterator itElem;
1394   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1395     const SMDS_MeshElement* elem = *itElem;
1396     if ( !elem || elem->GetType() != SMDSAbs_Face )
1397       continue;
1398     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1399     if(!isquad) continue;
1400
1401     if(elem->NbNodes()==4) {
1402       // retrieve element nodes
1403       const SMDS_MeshNode* aNodes [4];
1404       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1405       int i = 0;
1406       while ( itN->more() )
1407         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1408
1409       int aShapeId = FindShape( elem );
1410       const SMDS_MeshElement* newElem = 0;
1411       if ( the13Diag ) {
1412         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1413         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1414       }
1415       else {
1416         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1417         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1418       }
1419       myLastCreatedElems.Append(newElem);
1420       // put a new triangle on the same shape and add to the same groups
1421       if ( aShapeId )
1422         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1423       AddToSameGroups( newElem, elem, aMesh );
1424     }
1425
1426     // Quadratic quadrangle
1427
1428     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1429
1430       // get surface elem is on
1431       int aShapeId = FindShape( elem );
1432       if ( aShapeId != helper.GetSubShapeID() ) {
1433         surface.Nullify();
1434         TopoDS_Shape shape;
1435         if ( aShapeId > 0 )
1436           shape = aMesh->IndexToShape( aShapeId );
1437         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1438           TopoDS_Face face = TopoDS::Face( shape );
1439           surface = BRep_Tool::Surface( face );
1440           if ( !surface.IsNull() )
1441             helper.SetSubShape( shape );
1442         }
1443       }
1444
1445       const SMDS_MeshNode* aNodes [8];
1446       const SMDS_MeshNode* inFaceNode = 0;
1447       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1448       int i = 0;
1449       while ( itN->more() ) {
1450         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1451         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1452              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1453         {
1454           inFaceNode = aNodes[ i-1 ];
1455         }
1456       }
1457
1458       // find middle point for (0,1,2,3)
1459       // and create a node in this point;
1460       gp_XYZ p( 0,0,0 );
1461       if ( surface.IsNull() ) {
1462         for(i=0; i<4; i++)
1463           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1464         p /= 4;
1465       }
1466       else {
1467         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1468         gp_XY uv( 0,0 );
1469         for(i=0; i<4; i++)
1470           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1471         uv /= 4.;
1472         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1473       }
1474       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1475       myLastCreatedNodes.Append(newN);
1476
1477       // create a new element
1478       const SMDS_MeshElement* newElem = 0;
1479       const SMDS_MeshNode* N[6];
1480       if ( the13Diag ) {
1481         N[0] = aNodes[0];
1482         N[1] = aNodes[1];
1483         N[2] = aNodes[2];
1484         N[3] = aNodes[4];
1485         N[4] = aNodes[5];
1486         N[5] = newN;
1487         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1488                                  aNodes[6], aNodes[7], newN );
1489       }
1490       else {
1491         N[0] = aNodes[1];
1492         N[1] = aNodes[2];
1493         N[2] = aNodes[3];
1494         N[3] = aNodes[5];
1495         N[4] = aNodes[6];
1496         N[5] = newN;
1497         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1498                                  aNodes[7], aNodes[4], newN );
1499       }
1500       myLastCreatedElems.Append(newElem);
1501       aMesh->ChangeElementNodes( elem, N, 6 );
1502       // put a new triangle on the same shape and add to the same groups
1503       if ( aShapeId )
1504         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1505       AddToSameGroups( newElem, elem, aMesh );
1506     }
1507   }
1508
1509   return true;
1510 }
1511
1512 //=======================================================================
1513 //function : getAngle
1514 //purpose  :
1515 //=======================================================================
1516
1517 double getAngle(const SMDS_MeshElement * tr1,
1518                 const SMDS_MeshElement * tr2,
1519                 const SMDS_MeshNode *    n1,
1520                 const SMDS_MeshNode *    n2)
1521 {
1522   double angle = 2*PI; // bad angle
1523
1524   // get normals
1525   SMESH::Controls::TSequenceOfXYZ P1, P2;
1526   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1527        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1528     return angle;
1529   gp_Vec N1,N2;
1530   if(!tr1->IsQuadratic())
1531     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1532   else
1533     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1534   if ( N1.SquareMagnitude() <= gp::Resolution() )
1535     return angle;
1536   if(!tr2->IsQuadratic())
1537     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1538   else
1539     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1540   if ( N2.SquareMagnitude() <= gp::Resolution() )
1541     return angle;
1542
1543   // find the first diagonal node n1 in the triangles:
1544   // take in account a diagonal link orientation
1545   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1546   for ( int t = 0; t < 2; t++ ) {
1547     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1548     int i = 0, iDiag = -1;
1549     while ( it->more()) {
1550       const SMDS_MeshElement *n = it->next();
1551       if ( n == n1 || n == n2 )
1552         if ( iDiag < 0)
1553           iDiag = i;
1554         else {
1555           if ( i - iDiag == 1 )
1556             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1557           else
1558             nFirst[ t ] = n;
1559           break;
1560         }
1561       i++;
1562     }
1563   }
1564   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1565     N2.Reverse();
1566
1567   angle = N1.Angle( N2 );
1568   //SCRUTE( angle );
1569   return angle;
1570 }
1571
1572 // =================================================
1573 // class generating a unique ID for a pair of nodes
1574 // and able to return nodes by that ID
1575 // =================================================
1576 class LinkID_Gen {
1577 public:
1578
1579   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1580     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1581   {}
1582
1583   long GetLinkID (const SMDS_MeshNode * n1,
1584                   const SMDS_MeshNode * n2) const
1585   {
1586     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1587   }
1588
1589   bool GetNodes (const long             theLinkID,
1590                  const SMDS_MeshNode* & theNode1,
1591                  const SMDS_MeshNode* & theNode2) const
1592   {
1593     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1594     if ( !theNode1 ) return false;
1595     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1596     if ( !theNode2 ) return false;
1597     return true;
1598   }
1599
1600 private:
1601   LinkID_Gen();
1602   const SMESHDS_Mesh* myMesh;
1603   long                myMaxID;
1604 };
1605
1606
1607 //=======================================================================
1608 //function : TriToQuad
1609 //purpose  : Fuse neighbour triangles into quadrangles.
1610 //           theCrit is used to select a neighbour to fuse with.
1611 //           theMaxAngle is a max angle between element normals at which
1612 //           fusion is still performed.
1613 //=======================================================================
1614
1615 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1616                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1617                                   const double                         theMaxAngle)
1618 {
1619   myLastCreatedElems.Clear();
1620   myLastCreatedNodes.Clear();
1621
1622   MESSAGE( "::TriToQuad()" );
1623
1624   if ( !theCrit.get() )
1625     return false;
1626
1627   SMESHDS_Mesh * aMesh = GetMeshDS();
1628
1629   // Prepare data for algo: build
1630   // 1. map of elements with their linkIDs
1631   // 2. map of linkIDs with their elements
1632
1633   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1634   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1635   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
1636   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1637
1638   TIDSortedElemSet::iterator itElem;
1639   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1640     const SMDS_MeshElement* elem = *itElem;
1641     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1642     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1643     if(!IsTria) continue;
1644
1645     // retrieve element nodes
1646     const SMDS_MeshNode* aNodes [4];
1647     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1648     int i = 0;
1649     while ( i<3 )
1650       aNodes[ i++ ] = cast2Node( itN->next() );
1651     aNodes[ 3 ] = aNodes[ 0 ];
1652
1653     // fill maps
1654     for ( i = 0; i < 3; i++ ) {
1655       SMESH_TLink link( aNodes[i], aNodes[i+1] );
1656       // check if elements sharing a link can be fused
1657       itLE = mapLi_listEl.find( link );
1658       if ( itLE != mapLi_listEl.end() ) {
1659         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1660           continue;
1661         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1662         //if ( FindShape( elem ) != FindShape( elem2 ))
1663         //  continue; // do not fuse triangles laying on different shapes
1664         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1665           continue; // avoid making badly shaped quads
1666         (*itLE).second.push_back( elem );
1667       }
1668       else {
1669         mapLi_listEl[ link ].push_back( elem );
1670       }
1671       mapEl_setLi [ elem ].insert( link );
1672     }
1673   }
1674   // Clean the maps from the links shared by a sole element, ie
1675   // links to which only one element is bound in mapLi_listEl
1676
1677   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1678     int nbElems = (*itLE).second.size();
1679     if ( nbElems < 2  ) {
1680       const SMDS_MeshElement* elem = (*itLE).second.front();
1681       SMESH_TLink link = (*itLE).first;
1682       mapEl_setLi[ elem ].erase( link );
1683       if ( mapEl_setLi[ elem ].empty() )
1684         mapEl_setLi.erase( elem );
1685     }
1686   }
1687
1688   // Algo: fuse triangles into quadrangles
1689
1690   while ( ! mapEl_setLi.empty() ) {
1691     // Look for the start element:
1692     // the element having the least nb of shared links
1693     const SMDS_MeshElement* startElem = 0;
1694     int minNbLinks = 4;
1695     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1696       int nbLinks = (*itEL).second.size();
1697       if ( nbLinks < minNbLinks ) {
1698         startElem = (*itEL).first;
1699         minNbLinks = nbLinks;
1700         if ( minNbLinks == 1 )
1701           break;
1702       }
1703     }
1704
1705     // search elements to fuse starting from startElem or links of elements
1706     // fused earlyer - startLinks
1707     list< SMESH_TLink > startLinks;
1708     while ( startElem || !startLinks.empty() ) {
1709       while ( !startElem && !startLinks.empty() ) {
1710         // Get an element to start, by a link
1711         SMESH_TLink linkId = startLinks.front();
1712         startLinks.pop_front();
1713         itLE = mapLi_listEl.find( linkId );
1714         if ( itLE != mapLi_listEl.end() ) {
1715           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1716           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1717           for ( ; itE != listElem.end() ; itE++ )
1718             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1719               startElem = (*itE);
1720           mapLi_listEl.erase( itLE );
1721         }
1722       }
1723
1724       if ( startElem ) {
1725         // Get candidates to be fused
1726         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1727         const SMESH_TLink *link12, *link13;
1728         startElem = 0;
1729         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1730         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1731         ASSERT( !setLi.empty() );
1732         set< SMESH_TLink >::iterator itLi;
1733         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1734         {
1735           const SMESH_TLink & link = (*itLi);
1736           itLE = mapLi_listEl.find( link );
1737           if ( itLE == mapLi_listEl.end() )
1738             continue;
1739
1740           const SMDS_MeshElement* elem = (*itLE).second.front();
1741           if ( elem == tr1 )
1742             elem = (*itLE).second.back();
1743           mapLi_listEl.erase( itLE );
1744           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1745             continue;
1746           if ( tr2 ) {
1747             tr3 = elem;
1748             link13 = &link;
1749           }
1750           else {
1751             tr2 = elem;
1752             link12 = &link;
1753           }
1754
1755           // add other links of elem to list of links to re-start from
1756           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1757           set< SMESH_TLink >::iterator it;
1758           for ( it = links.begin(); it != links.end(); it++ ) {
1759             const SMESH_TLink& link2 = (*it);
1760             if ( link2 != link )
1761               startLinks.push_back( link2 );
1762           }
1763         }
1764
1765         // Get nodes of possible quadrangles
1766         const SMDS_MeshNode *n12 [4], *n13 [4];
1767         bool Ok12 = false, Ok13 = false;
1768         const SMDS_MeshNode *linkNode1, *linkNode2;
1769         if(tr2) {
1770           linkNode1 = link12->first;
1771           linkNode2 = link12->second;
1772           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1773             Ok12 = true;
1774         }
1775         if(tr3) {
1776           linkNode1 = link13->first;
1777           linkNode2 = link13->second;
1778           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1779             Ok13 = true;
1780         }
1781
1782         // Choose a pair to fuse
1783         if ( Ok12 && Ok13 ) {
1784           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1785           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1786           double aBadRate12 = getBadRate( &quad12, theCrit );
1787           double aBadRate13 = getBadRate( &quad13, theCrit );
1788           if (  aBadRate13 < aBadRate12 )
1789             Ok12 = false;
1790           else
1791             Ok13 = false;
1792         }
1793
1794         // Make quadrangles
1795         // and remove fused elems and removed links from the maps
1796         mapEl_setLi.erase( tr1 );
1797         if ( Ok12 ) {
1798           mapEl_setLi.erase( tr2 );
1799           mapLi_listEl.erase( *link12 );
1800           if(tr1->NbNodes()==3) {
1801             if( tr1->GetID() < tr2->GetID() ) {
1802               aMesh->ChangeElementNodes( tr1, n12, 4 );
1803               myLastCreatedElems.Append(tr1);
1804               aMesh->RemoveElement( tr2 );
1805             }
1806             else {
1807               aMesh->ChangeElementNodes( tr2, n12, 4 );
1808               myLastCreatedElems.Append(tr2);
1809               aMesh->RemoveElement( tr1);
1810             }
1811           }
1812           else {
1813             const SMDS_MeshNode* N1 [6];
1814             const SMDS_MeshNode* N2 [6];
1815             GetNodesFromTwoTria(tr1,tr2,N1,N2);
1816             // now we receive following N1 and N2 (using numeration as above image)
1817             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1818             // i.e. first nodes from both arrays determ new diagonal
1819             const SMDS_MeshNode* aNodes[8];
1820             aNodes[0] = N1[0];
1821             aNodes[1] = N1[1];
1822             aNodes[2] = N2[0];
1823             aNodes[3] = N2[1];
1824             aNodes[4] = N1[3];
1825             aNodes[5] = N2[5];
1826             aNodes[6] = N2[3];
1827             aNodes[7] = N1[5];
1828             if( tr1->GetID() < tr2->GetID() ) {
1829               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1830               myLastCreatedElems.Append(tr1);
1831               GetMeshDS()->RemoveElement( tr2 );
1832             }
1833             else {
1834               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1835               myLastCreatedElems.Append(tr2);
1836               GetMeshDS()->RemoveElement( tr1 );
1837             }
1838             // remove middle node (9)
1839             GetMeshDS()->RemoveNode( N1[4] );
1840           }
1841         }
1842         else if ( Ok13 ) {
1843           mapEl_setLi.erase( tr3 );
1844           mapLi_listEl.erase( *link13 );
1845           if(tr1->NbNodes()==3) {
1846             if( tr1->GetID() < tr2->GetID() ) {
1847               aMesh->ChangeElementNodes( tr1, n13, 4 );
1848               myLastCreatedElems.Append(tr1);
1849               aMesh->RemoveElement( tr3 );
1850             }
1851             else {
1852               aMesh->ChangeElementNodes( tr3, n13, 4 );
1853               myLastCreatedElems.Append(tr3);
1854               aMesh->RemoveElement( tr1 );
1855             }
1856           }
1857           else {
1858             const SMDS_MeshNode* N1 [6];
1859             const SMDS_MeshNode* N2 [6];
1860             GetNodesFromTwoTria(tr1,tr3,N1,N2);
1861             // now we receive following N1 and N2 (using numeration as above image)
1862             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1863             // i.e. first nodes from both arrays determ new diagonal
1864             const SMDS_MeshNode* aNodes[8];
1865             aNodes[0] = N1[0];
1866             aNodes[1] = N1[1];
1867             aNodes[2] = N2[0];
1868             aNodes[3] = N2[1];
1869             aNodes[4] = N1[3];
1870             aNodes[5] = N2[5];
1871             aNodes[6] = N2[3];
1872             aNodes[7] = N1[5];
1873             if( tr1->GetID() < tr2->GetID() ) {
1874               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1875               myLastCreatedElems.Append(tr1);
1876               GetMeshDS()->RemoveElement( tr3 );
1877             }
1878             else {
1879               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1880               myLastCreatedElems.Append(tr3);
1881               GetMeshDS()->RemoveElement( tr1 );
1882             }
1883             // remove middle node (9)
1884             GetMeshDS()->RemoveNode( N1[4] );
1885           }
1886         }
1887
1888         // Next element to fuse: the rejected one
1889         if ( tr3 )
1890           startElem = Ok12 ? tr3 : tr2;
1891
1892       } // if ( startElem )
1893     } // while ( startElem || !startLinks.empty() )
1894   } // while ( ! mapEl_setLi.empty() )
1895
1896   return true;
1897 }
1898
1899
1900 /*#define DUMPSO(txt) \
1901 //  cout << txt << endl;
1902 //=============================================================================
1903 //
1904 //
1905 //
1906 //=============================================================================
1907 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1908 {
1909 if ( i1 == i2 )
1910 return;
1911 int tmp = idNodes[ i1 ];
1912 idNodes[ i1 ] = idNodes[ i2 ];
1913 idNodes[ i2 ] = tmp;
1914 gp_Pnt Ptmp = P[ i1 ];
1915 P[ i1 ] = P[ i2 ];
1916 P[ i2 ] = Ptmp;
1917 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1918 }
1919
1920 //=======================================================================
1921 //function : SortQuadNodes
1922 //purpose  : Set 4 nodes of a quadrangle face in a good order.
1923 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
1924 //           1 or 2 else 0.
1925 //=======================================================================
1926
1927 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1928 int               idNodes[] )
1929 {
1930   gp_Pnt P[4];
1931   int i;
1932   for ( i = 0; i < 4; i++ ) {
1933     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1934     if ( !n ) return 0;
1935     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1936   }
1937
1938   gp_Vec V1(P[0], P[1]);
1939   gp_Vec V2(P[0], P[2]);
1940   gp_Vec V3(P[0], P[3]);
1941
1942   gp_Vec Cross1 = V1 ^ V2;
1943   gp_Vec Cross2 = V2 ^ V3;
1944
1945   i = 0;
1946   if (Cross1.Dot(Cross2) < 0)
1947   {
1948     Cross1 = V2 ^ V1;
1949     Cross2 = V1 ^ V3;
1950
1951     if (Cross1.Dot(Cross2) < 0)
1952       i = 2;
1953     else
1954       i = 1;
1955     swap ( i, i + 1, idNodes, P );
1956
1957     //     for ( int ii = 0; ii < 4; ii++ ) {
1958     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1959     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1960     //     }
1961   }
1962   return i;
1963 }
1964
1965 //=======================================================================
1966 //function : SortHexaNodes
1967 //purpose  : Set 8 nodes of a hexahedron in a good order.
1968 //           Return success status
1969 //=======================================================================
1970
1971 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1972                                       int               idNodes[] )
1973 {
1974   gp_Pnt P[8];
1975   int i;
1976   DUMPSO( "INPUT: ========================================");
1977   for ( i = 0; i < 8; i++ ) {
1978     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1979     if ( !n ) return false;
1980     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1981     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1982   }
1983   DUMPSO( "========================================");
1984
1985
1986   set<int> faceNodes;  // ids of bottom face nodes, to be found
1987   set<int> checkedId1; // ids of tried 2-nd nodes
1988   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1989   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
1990   int iMin, iLoop1 = 0;
1991
1992   // Loop to try the 2-nd nodes
1993
1994   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1995   {
1996     // Find not checked 2-nd node
1997     for ( i = 1; i < 8; i++ )
1998       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1999         int id1 = idNodes[i];
2000         swap ( 1, i, idNodes, P );
2001         checkedId1.insert ( id1 );
2002         break;
2003       }
2004
2005     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2006     // ie that all but meybe one (id3 which is on the same face) nodes
2007     // lay on the same side from the triangle plane.
2008
2009     bool manyInPlane = false; // more than 4 nodes lay in plane
2010     int iLoop2 = 0;
2011     while ( ++iLoop2 < 6 ) {
2012
2013       // get 1-2-3 plane coeffs
2014       Standard_Real A, B, C, D;
2015       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2016       if ( N.SquareMagnitude() > gp::Resolution() )
2017       {
2018         gp_Pln pln ( P[0], N );
2019         pln.Coefficients( A, B, C, D );
2020
2021         // find the node (iMin) closest to pln
2022         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2023         set<int> idInPln;
2024         for ( i = 3; i < 8; i++ ) {
2025           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2026           if ( fabs( dist[i] ) < minDist ) {
2027             minDist = fabs( dist[i] );
2028             iMin = i;
2029           }
2030           if ( fabs( dist[i] ) <= tol )
2031             idInPln.insert( idNodes[i] );
2032         }
2033
2034         // there should not be more than 4 nodes in bottom plane
2035         if ( idInPln.size() > 1 )
2036         {
2037           DUMPSO( "### idInPln.size() = " << idInPln.size());
2038           // idInPlane does not contain the first 3 nodes
2039           if ( manyInPlane || idInPln.size() == 5)
2040             return false; // all nodes in one plane
2041           manyInPlane = true;
2042
2043           // set the 1-st node to be not in plane
2044           for ( i = 3; i < 8; i++ ) {
2045             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2046               DUMPSO( "### Reset 0-th node");
2047               swap( 0, i, idNodes, P );
2048               break;
2049             }
2050           }
2051
2052           // reset to re-check second nodes
2053           leastDist = DBL_MAX;
2054           faceNodes.clear();
2055           checkedId1.clear();
2056           iLoop1 = 0;
2057           break; // from iLoop2;
2058         }
2059
2060         // check that the other 4 nodes are on the same side
2061         bool sameSide = true;
2062         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2063         for ( i = 3; sameSide && i < 8; i++ ) {
2064           if ( i != iMin )
2065             sameSide = ( isNeg == dist[i] <= 0.);
2066         }
2067
2068         // keep best solution
2069         if ( sameSide && minDist < leastDist ) {
2070           leastDist = minDist;
2071           faceNodes.clear();
2072           faceNodes.insert( idNodes[ 1 ] );
2073           faceNodes.insert( idNodes[ 2 ] );
2074           faceNodes.insert( idNodes[ iMin ] );
2075           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2076                   << " leastDist = " << leastDist);
2077           if ( leastDist <= DBL_MIN )
2078             break;
2079         }
2080       }
2081
2082       // set next 3-d node to check
2083       int iNext = 2 + iLoop2;
2084       if ( iNext < 8 ) {
2085         DUMPSO( "Try 2-nd");
2086         swap ( 2, iNext, idNodes, P );
2087       }
2088     } // while ( iLoop2 < 6 )
2089   } // iLoop1
2090
2091   if ( faceNodes.empty() ) return false;
2092
2093   // Put the faceNodes in proper places
2094   for ( i = 4; i < 8; i++ ) {
2095     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2096       // find a place to put
2097       int iTo = 1;
2098       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2099         iTo++;
2100       DUMPSO( "Set faceNodes");
2101       swap ( iTo, i, idNodes, P );
2102     }
2103   }
2104
2105
2106   // Set nodes of the found bottom face in good order
2107   DUMPSO( " Found bottom face: ");
2108   i = SortQuadNodes( theMesh, idNodes );
2109   if ( i ) {
2110     gp_Pnt Ptmp = P[ i ];
2111     P[ i ] = P[ i+1 ];
2112     P[ i+1 ] = Ptmp;
2113   }
2114   //   else
2115   //     for ( int ii = 0; ii < 4; ii++ ) {
2116   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2117   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2118   //    }
2119
2120   // Gravity center of the top and bottom faces
2121   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2122   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2123
2124   // Get direction from the bottom to the top face
2125   gp_Vec upDir ( aGCb, aGCt );
2126   Standard_Real upDirSize = upDir.Magnitude();
2127   if ( upDirSize <= gp::Resolution() ) return false;
2128   upDir / upDirSize;
2129
2130   // Assure that the bottom face normal points up
2131   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2132   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2133   if ( Nb.Dot( upDir ) < 0 ) {
2134     DUMPSO( "Reverse bottom face");
2135     swap( 1, 3, idNodes, P );
2136   }
2137
2138   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2139   Standard_Real minDist = DBL_MAX;
2140   for ( i = 4; i < 8; i++ ) {
2141     // projection of P[i] to the plane defined by P[0] and upDir
2142     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2143     Standard_Real sqDist = P[0].SquareDistance( Pp );
2144     if ( sqDist < minDist ) {
2145       minDist = sqDist;
2146       iMin = i;
2147     }
2148   }
2149   DUMPSO( "Set 4-th");
2150   swap ( 4, iMin, idNodes, P );
2151
2152   // Set nodes of the top face in good order
2153   DUMPSO( "Sort top face");
2154   i = SortQuadNodes( theMesh, &idNodes[4] );
2155   if ( i ) {
2156     i += 4;
2157     gp_Pnt Ptmp = P[ i ];
2158     P[ i ] = P[ i+1 ];
2159     P[ i+1 ] = Ptmp;
2160   }
2161
2162   // Assure that direction of the top face normal is from the bottom face
2163   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2164   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2165   if ( Nt.Dot( upDir ) < 0 ) {
2166     DUMPSO( "Reverse top face");
2167     swap( 5, 7, idNodes, P );
2168   }
2169
2170   //   DUMPSO( "OUTPUT: ========================================");
2171   //   for ( i = 0; i < 8; i++ ) {
2172   //     float *p = ugrid->GetPoint(idNodes[i]);
2173   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2174   //   }
2175
2176   return true;
2177 }*/
2178
2179 //================================================================================
2180 /*!
2181  * \brief Return nodes linked to the given one
2182  * \param theNode - the node
2183  * \param linkedNodes - the found nodes
2184  * \param type - the type of elements to check
2185  *
2186  * Medium nodes are ignored
2187  */
2188 //================================================================================
2189
2190 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2191                                        TIDSortedElemSet &   linkedNodes,
2192                                        SMDSAbs_ElementType  type )
2193 {
2194   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2195   while ( elemIt->more() )
2196   {
2197     const SMDS_MeshElement* elem = elemIt->next();
2198     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2199     if ( elem->GetType() == SMDSAbs_Volume )
2200     {
2201       SMDS_VolumeTool vol( elem );
2202       while ( nodeIt->more() ) {
2203         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2204         if ( theNode != n && vol.IsLinked( theNode, n ))
2205           linkedNodes.insert( n );
2206       }
2207     }
2208     else
2209     {
2210       for ( int i = 0; nodeIt->more(); ++i ) {
2211         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2212         if ( n == theNode ) {
2213           int iBefore = i - 1;
2214           int iAfter  = i + 1;
2215           if ( elem->IsQuadratic() ) {
2216             int nb = elem->NbNodes() / 2;
2217             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2218             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2219           }
2220           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2221           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2222         }
2223       }
2224     }
2225   }
2226 }
2227
2228 //=======================================================================
2229 //function : laplacianSmooth
2230 //purpose  : pulls theNode toward the center of surrounding nodes directly
2231 //           connected to that node along an element edge
2232 //=======================================================================
2233
2234 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2235                      const Handle(Geom_Surface)&          theSurface,
2236                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2237 {
2238   // find surrounding nodes
2239
2240   TIDSortedElemSet nodeSet;
2241   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2242
2243   // compute new coodrs
2244
2245   double coord[] = { 0., 0., 0. };
2246   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2247   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2248     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2249     if ( theSurface.IsNull() ) { // smooth in 3D
2250       coord[0] += node->X();
2251       coord[1] += node->Y();
2252       coord[2] += node->Z();
2253     }
2254     else { // smooth in 2D
2255       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2256       gp_XY* uv = theUVMap[ node ];
2257       coord[0] += uv->X();
2258       coord[1] += uv->Y();
2259     }
2260   }
2261   int nbNodes = nodeSet.size();
2262   if ( !nbNodes )
2263     return;
2264   coord[0] /= nbNodes;
2265   coord[1] /= nbNodes;
2266
2267   if ( !theSurface.IsNull() ) {
2268     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2269     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2270     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2271     coord[0] = p3d.X();
2272     coord[1] = p3d.Y();
2273     coord[2] = p3d.Z();
2274   }
2275   else
2276     coord[2] /= nbNodes;
2277
2278   // move node
2279
2280   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2281 }
2282
2283 //=======================================================================
2284 //function : centroidalSmooth
2285 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2286 //           surrounding elements
2287 //=======================================================================
2288
2289 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2290                       const Handle(Geom_Surface)&          theSurface,
2291                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2292 {
2293   gp_XYZ aNewXYZ(0.,0.,0.);
2294   SMESH::Controls::Area anAreaFunc;
2295   double totalArea = 0.;
2296   int nbElems = 0;
2297
2298   // compute new XYZ
2299
2300   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2301   while ( elemIt->more() )
2302   {
2303     const SMDS_MeshElement* elem = elemIt->next();
2304     nbElems++;
2305
2306     gp_XYZ elemCenter(0.,0.,0.);
2307     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2308     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2309     int nn = elem->NbNodes();
2310     if(elem->IsQuadratic()) nn = nn/2;
2311     int i=0;
2312     //while ( itN->more() ) {
2313     while ( i<nn ) {
2314       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2315       i++;
2316       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2317       aNodePoints.push_back( aP );
2318       if ( !theSurface.IsNull() ) { // smooth in 2D
2319         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2320         gp_XY* uv = theUVMap[ aNode ];
2321         aP.SetCoord( uv->X(), uv->Y(), 0. );
2322       }
2323       elemCenter += aP;
2324     }
2325     double elemArea = anAreaFunc.GetValue( aNodePoints );
2326     totalArea += elemArea;
2327     elemCenter /= nn;
2328     aNewXYZ += elemCenter * elemArea;
2329   }
2330   aNewXYZ /= totalArea;
2331   if ( !theSurface.IsNull() ) {
2332     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2333     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2334   }
2335
2336   // move node
2337
2338   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2339 }
2340
2341 //=======================================================================
2342 //function : getClosestUV
2343 //purpose  : return UV of closest projection
2344 //=======================================================================
2345
2346 static bool getClosestUV (Extrema_GenExtPS& projector,
2347                           const gp_Pnt&     point,
2348                           gp_XY &           result)
2349 {
2350   projector.Perform( point );
2351   if ( projector.IsDone() ) {
2352     double u, v, minVal = DBL_MAX;
2353     for ( int i = projector.NbExt(); i > 0; i-- )
2354       if ( projector.Value( i ) < minVal ) {
2355         minVal = projector.Value( i );
2356         projector.Point( i ).Parameter( u, v );
2357       }
2358     result.SetCoord( u, v );
2359     return true;
2360   }
2361   return false;
2362 }
2363
2364 //=======================================================================
2365 //function : Smooth
2366 //purpose  : Smooth theElements during theNbIterations or until a worst
2367 //           element has aspect ratio <= theTgtAspectRatio.
2368 //           Aspect Ratio varies in range [1.0, inf].
2369 //           If theElements is empty, the whole mesh is smoothed.
2370 //           theFixedNodes contains additionally fixed nodes. Nodes built
2371 //           on edges and boundary nodes are always fixed.
2372 //=======================================================================
2373
2374 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2375                                set<const SMDS_MeshNode*> & theFixedNodes,
2376                                const SmoothMethod          theSmoothMethod,
2377                                const int                   theNbIterations,
2378                                double                      theTgtAspectRatio,
2379                                const bool                  the2D)
2380 {
2381   myLastCreatedElems.Clear();
2382   myLastCreatedNodes.Clear();
2383
2384   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2385
2386   if ( theTgtAspectRatio < 1.0 )
2387     theTgtAspectRatio = 1.0;
2388
2389   const double disttol = 1.e-16;
2390
2391   SMESH::Controls::AspectRatio aQualityFunc;
2392
2393   SMESHDS_Mesh* aMesh = GetMeshDS();
2394
2395   if ( theElems.empty() ) {
2396     // add all faces to theElems
2397     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2398     while ( fIt->more() ) {
2399       const SMDS_MeshElement* face = fIt->next();
2400       theElems.insert( face );
2401     }
2402   }
2403   // get all face ids theElems are on
2404   set< int > faceIdSet;
2405   TIDSortedElemSet::iterator itElem;
2406   if ( the2D )
2407     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2408       int fId = FindShape( *itElem );
2409       // check that corresponding submesh exists and a shape is face
2410       if (fId &&
2411           faceIdSet.find( fId ) == faceIdSet.end() &&
2412           aMesh->MeshElements( fId )) {
2413         TopoDS_Shape F = aMesh->IndexToShape( fId );
2414         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2415           faceIdSet.insert( fId );
2416       }
2417     }
2418   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2419
2420   // ===============================================
2421   // smooth elements on each TopoDS_Face separately
2422   // ===============================================
2423
2424   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2425   for ( ; fId != faceIdSet.rend(); ++fId ) {
2426     // get face surface and submesh
2427     Handle(Geom_Surface) surface;
2428     SMESHDS_SubMesh* faceSubMesh = 0;
2429     TopoDS_Face face;
2430     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2431     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2432     bool isUPeriodic = false, isVPeriodic = false;
2433     if ( *fId ) {
2434       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2435       surface = BRep_Tool::Surface( face );
2436       faceSubMesh = aMesh->MeshElements( *fId );
2437       fToler2 = BRep_Tool::Tolerance( face );
2438       fToler2 *= fToler2 * 10.;
2439       isUPeriodic = surface->IsUPeriodic();
2440       if ( isUPeriodic )
2441         vPeriod = surface->UPeriod();
2442       isVPeriodic = surface->IsVPeriodic();
2443       if ( isVPeriodic )
2444         uPeriod = surface->VPeriod();
2445       surface->Bounds( u1, u2, v1, v2 );
2446     }
2447     // ---------------------------------------------------------
2448     // for elements on a face, find movable and fixed nodes and
2449     // compute UV for them
2450     // ---------------------------------------------------------
2451     bool checkBoundaryNodes = false;
2452     bool isQuadratic = false;
2453     set<const SMDS_MeshNode*> setMovableNodes;
2454     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2455     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2456     list< const SMDS_MeshElement* > elemsOnFace;
2457
2458     Extrema_GenExtPS projector;
2459     GeomAdaptor_Surface surfAdaptor;
2460     if ( !surface.IsNull() ) {
2461       surfAdaptor.Load( surface );
2462       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2463     }
2464     int nbElemOnFace = 0;
2465     itElem = theElems.begin();
2466     // loop on not yet smoothed elements: look for elems on a face
2467     while ( itElem != theElems.end() ) {
2468       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2469         break; // all elements found
2470
2471       const SMDS_MeshElement* elem = *itElem;
2472       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2473            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2474         ++itElem;
2475         continue;
2476       }
2477       elemsOnFace.push_back( elem );
2478       theElems.erase( itElem++ );
2479       nbElemOnFace++;
2480
2481       if ( !isQuadratic )
2482         isQuadratic = elem->IsQuadratic();
2483
2484       // get movable nodes of elem
2485       const SMDS_MeshNode* node;
2486       SMDS_TypeOfPosition posType;
2487       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2488       int nn = 0, nbn =  elem->NbNodes();
2489       if(elem->IsQuadratic())
2490         nbn = nbn/2;
2491       while ( nn++ < nbn ) {
2492         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2493         const SMDS_PositionPtr& pos = node->GetPosition();
2494         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2495         if (posType != SMDS_TOP_EDGE &&
2496             posType != SMDS_TOP_VERTEX &&
2497             theFixedNodes.find( node ) == theFixedNodes.end())
2498         {
2499           // check if all faces around the node are on faceSubMesh
2500           // because a node on edge may be bound to face
2501           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2502           bool all = true;
2503           if ( faceSubMesh ) {
2504             while ( eIt->more() && all ) {
2505               const SMDS_MeshElement* e = eIt->next();
2506               all = faceSubMesh->Contains( e );
2507             }
2508           }
2509           if ( all )
2510             setMovableNodes.insert( node );
2511           else
2512             checkBoundaryNodes = true;
2513         }
2514         if ( posType == SMDS_TOP_3DSPACE )
2515           checkBoundaryNodes = true;
2516       }
2517
2518       if ( surface.IsNull() )
2519         continue;
2520
2521       // get nodes to check UV
2522       list< const SMDS_MeshNode* > uvCheckNodes;
2523       itN = elem->nodesIterator();
2524       nn = 0; nbn =  elem->NbNodes();
2525       if(elem->IsQuadratic())
2526         nbn = nbn/2;
2527       while ( nn++ < nbn ) {
2528         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2529         if ( uvMap.find( node ) == uvMap.end() )
2530           uvCheckNodes.push_back( node );
2531         // add nodes of elems sharing node
2532         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2533         //         while ( eIt->more() ) {
2534         //           const SMDS_MeshElement* e = eIt->next();
2535         //           if ( e != elem ) {
2536         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2537         //             while ( nIt->more() ) {
2538         //               const SMDS_MeshNode* n =
2539         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2540         //               if ( uvMap.find( n ) == uvMap.end() )
2541         //                 uvCheckNodes.push_back( n );
2542         //             }
2543         //           }
2544         //         }
2545       }
2546       // check UV on face
2547       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2548       for ( ; n != uvCheckNodes.end(); ++n ) {
2549         node = *n;
2550         gp_XY uv( 0, 0 );
2551         const SMDS_PositionPtr& pos = node->GetPosition();
2552         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2553         // get existing UV
2554         switch ( posType ) {
2555         case SMDS_TOP_FACE: {
2556           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2557           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2558           break;
2559         }
2560         case SMDS_TOP_EDGE: {
2561           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2562           Handle(Geom2d_Curve) pcurve;
2563           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2564             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2565           if ( !pcurve.IsNull() ) {
2566             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2567             uv = pcurve->Value( u ).XY();
2568           }
2569           break;
2570         }
2571         case SMDS_TOP_VERTEX: {
2572           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2573           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2574             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2575           break;
2576         }
2577         default:;
2578         }
2579         // check existing UV
2580         bool project = true;
2581         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2582         double dist1 = DBL_MAX, dist2 = 0;
2583         if ( posType != SMDS_TOP_3DSPACE ) {
2584           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2585           project = dist1 > fToler2;
2586         }
2587         if ( project ) { // compute new UV
2588           gp_XY newUV;
2589           if ( !getClosestUV( projector, pNode, newUV )) {
2590             MESSAGE("Node Projection Failed " << node);
2591           }
2592           else {
2593             if ( isUPeriodic )
2594               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2595             if ( isVPeriodic )
2596               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2597             // check new UV
2598             if ( posType != SMDS_TOP_3DSPACE )
2599               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2600             if ( dist2 < dist1 )
2601               uv = newUV;
2602           }
2603         }
2604         // store UV in the map
2605         listUV.push_back( uv );
2606         uvMap.insert( make_pair( node, &listUV.back() ));
2607       }
2608     } // loop on not yet smoothed elements
2609
2610     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2611       checkBoundaryNodes = true;
2612
2613     // fix nodes on mesh boundary
2614
2615     if ( checkBoundaryNodes ) {
2616       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2617       map< NLink, int >::iterator link_nb;
2618       // put all elements links to linkNbMap
2619       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2620       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2621         const SMDS_MeshElement* elem = (*elemIt);
2622         int nbn =  elem->NbNodes();
2623         if(elem->IsQuadratic())
2624           nbn = nbn/2;
2625         // loop on elem links: insert them in linkNbMap
2626         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2627         for ( int iN = 0; iN < nbn; ++iN ) {
2628           curNode = elem->GetNode( iN );
2629           NLink link;
2630           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2631           else                      link = make_pair( prevNode , curNode );
2632           prevNode = curNode;
2633           link_nb = linkNbMap.find( link );
2634           if ( link_nb == linkNbMap.end() )
2635             linkNbMap.insert( make_pair ( link, 1 ));
2636           else
2637             link_nb->second++;
2638         }
2639       }
2640       // remove nodes that are in links encountered only once from setMovableNodes
2641       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2642         if ( link_nb->second == 1 ) {
2643           setMovableNodes.erase( link_nb->first.first );
2644           setMovableNodes.erase( link_nb->first.second );
2645         }
2646       }
2647     }
2648
2649     // -----------------------------------------------------
2650     // for nodes on seam edge, compute one more UV ( uvMap2 );
2651     // find movable nodes linked to nodes on seam and which
2652     // are to be smoothed using the second UV ( uvMap2 )
2653     // -----------------------------------------------------
2654
2655     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2656     if ( !surface.IsNull() ) {
2657       TopExp_Explorer eExp( face, TopAbs_EDGE );
2658       for ( ; eExp.More(); eExp.Next() ) {
2659         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2660         if ( !BRep_Tool::IsClosed( edge, face ))
2661           continue;
2662         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2663         if ( !sm ) continue;
2664         // find out which parameter varies for a node on seam
2665         double f,l;
2666         gp_Pnt2d uv1, uv2;
2667         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2668         if ( pcurve.IsNull() ) continue;
2669         uv1 = pcurve->Value( f );
2670         edge.Reverse();
2671         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2672         if ( pcurve.IsNull() ) continue;
2673         uv2 = pcurve->Value( f );
2674         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2675         // assure uv1 < uv2
2676         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2677           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2678         }
2679         // get nodes on seam and its vertices
2680         list< const SMDS_MeshNode* > seamNodes;
2681         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2682         while ( nSeamIt->more() ) {
2683           const SMDS_MeshNode* node = nSeamIt->next();
2684           if ( !isQuadratic || !IsMedium( node ))
2685             seamNodes.push_back( node );
2686         }
2687         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2688         for ( ; vExp.More(); vExp.Next() ) {
2689           sm = aMesh->MeshElements( vExp.Current() );
2690           if ( sm ) {
2691             nSeamIt = sm->GetNodes();
2692             while ( nSeamIt->more() )
2693               seamNodes.push_back( nSeamIt->next() );
2694           }
2695         }
2696         // loop on nodes on seam
2697         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2698         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2699           const SMDS_MeshNode* nSeam = *noSeIt;
2700           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2701           if ( n_uv == uvMap.end() )
2702             continue;
2703           // set the first UV
2704           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2705           // set the second UV
2706           listUV.push_back( *n_uv->second );
2707           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2708           if ( uvMap2.empty() )
2709             uvMap2 = uvMap; // copy the uvMap contents
2710           uvMap2[ nSeam ] = &listUV.back();
2711
2712           // collect movable nodes linked to ones on seam in nodesNearSeam
2713           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2714           while ( eIt->more() ) {
2715             const SMDS_MeshElement* e = eIt->next();
2716             int nbUseMap1 = 0, nbUseMap2 = 0;
2717             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2718             int nn = 0, nbn =  e->NbNodes();
2719             if(e->IsQuadratic()) nbn = nbn/2;
2720             while ( nn++ < nbn )
2721             {
2722               const SMDS_MeshNode* n =
2723                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2724               if (n == nSeam ||
2725                   setMovableNodes.find( n ) == setMovableNodes.end() )
2726                 continue;
2727               // add only nodes being closer to uv2 than to uv1
2728               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2729                            0.5 * ( n->Y() + nSeam->Y() ),
2730                            0.5 * ( n->Z() + nSeam->Z() ));
2731               gp_XY uv;
2732               getClosestUV( projector, pMid, uv );
2733               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2734                 nodesNearSeam.insert( n );
2735                 nbUseMap2++;
2736               }
2737               else
2738                 nbUseMap1++;
2739             }
2740             // for centroidalSmooth all element nodes must
2741             // be on one side of a seam
2742             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2743               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2744               nn = 0;
2745               while ( nn++ < nbn ) {
2746                 const SMDS_MeshNode* n =
2747                   static_cast<const SMDS_MeshNode*>( nIt->next() );
2748                 setMovableNodes.erase( n );
2749               }
2750             }
2751           }
2752         } // loop on nodes on seam
2753       } // loop on edge of a face
2754     } // if ( !face.IsNull() )
2755
2756     if ( setMovableNodes.empty() ) {
2757       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2758       continue; // goto next face
2759     }
2760
2761     // -------------
2762     // SMOOTHING //
2763     // -------------
2764
2765     int it = -1;
2766     double maxRatio = -1., maxDisplacement = -1.;
2767     set<const SMDS_MeshNode*>::iterator nodeToMove;
2768     for ( it = 0; it < theNbIterations; it++ ) {
2769       maxDisplacement = 0.;
2770       nodeToMove = setMovableNodes.begin();
2771       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2772         const SMDS_MeshNode* node = (*nodeToMove);
2773         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2774
2775         // smooth
2776         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2777         if ( theSmoothMethod == LAPLACIAN )
2778           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2779         else
2780           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2781
2782         // node displacement
2783         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2784         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2785         if ( aDispl > maxDisplacement )
2786           maxDisplacement = aDispl;
2787       }
2788       // no node movement => exit
2789       //if ( maxDisplacement < 1.e-16 ) {
2790       if ( maxDisplacement < disttol ) {
2791         MESSAGE("-- no node movement --");
2792         break;
2793       }
2794
2795       // check elements quality
2796       maxRatio  = 0;
2797       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2798       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2799         const SMDS_MeshElement* elem = (*elemIt);
2800         if ( !elem || elem->GetType() != SMDSAbs_Face )
2801           continue;
2802         SMESH::Controls::TSequenceOfXYZ aPoints;
2803         if ( aQualityFunc.GetPoints( elem, aPoints )) {
2804           double aValue = aQualityFunc.GetValue( aPoints );
2805           if ( aValue > maxRatio )
2806             maxRatio = aValue;
2807         }
2808       }
2809       if ( maxRatio <= theTgtAspectRatio ) {
2810         MESSAGE("-- quality achived --");
2811         break;
2812       }
2813       if (it+1 == theNbIterations) {
2814         MESSAGE("-- Iteration limit exceeded --");
2815       }
2816     } // smoothing iterations
2817
2818     MESSAGE(" Face id: " << *fId <<
2819             " Nb iterstions: " << it <<
2820             " Displacement: " << maxDisplacement <<
2821             " Aspect Ratio " << maxRatio);
2822
2823     // ---------------------------------------
2824     // new nodes positions are computed,
2825     // record movement in DS and set new UV
2826     // ---------------------------------------
2827     nodeToMove = setMovableNodes.begin();
2828     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2829       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2830       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2831       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2832       if ( node_uv != uvMap.end() ) {
2833         gp_XY* uv = node_uv->second;
2834         node->SetPosition
2835           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2836       }
2837     }
2838
2839     // move medium nodes of quadratic elements
2840     if ( isQuadratic )
2841     {
2842       SMESH_MesherHelper helper( *GetMesh() );
2843       if ( !face.IsNull() )
2844         helper.SetSubShape( face );
2845       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2846       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2847         const SMDS_QuadraticFaceOfNodes* QF =
2848           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2849         if(QF) {
2850           vector<const SMDS_MeshNode*> Ns;
2851           Ns.reserve(QF->NbNodes()+1);
2852           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2853           while ( anIter->more() )
2854             Ns.push_back( anIter->next() );
2855           Ns.push_back( Ns[0] );
2856           double x, y, z;
2857           for(int i=0; i<QF->NbNodes(); i=i+2) {
2858             if ( !surface.IsNull() ) {
2859               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2860               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2861               gp_XY uv = ( uv1 + uv2 ) / 2.;
2862               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2863               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2864             }
2865             else {
2866               x = (Ns[i]->X() + Ns[i+2]->X())/2;
2867               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2868               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2869             }
2870             if( fabs( Ns[i+1]->X() - x ) > disttol ||
2871                 fabs( Ns[i+1]->Y() - y ) > disttol ||
2872                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2873               // we have to move i+1 node
2874               aMesh->MoveNode( Ns[i+1], x, y, z );
2875             }
2876           }
2877         }
2878       }
2879     }
2880
2881   } // loop on face ids
2882
2883 }
2884
2885 //=======================================================================
2886 //function : isReverse
2887 //purpose  : Return true if normal of prevNodes is not co-directied with
2888 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2889 //           iNotSame is where prevNodes and nextNodes are different
2890 //=======================================================================
2891
2892 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2893                       vector<const SMDS_MeshNode*> nextNodes,
2894                       const int            nbNodes,
2895                       const int            iNotSame)
2896 {
2897   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2898   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2899
2900   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2901   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2902   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2903   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2904
2905   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2906   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2907   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2908   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2909
2910   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2911
2912   return (vA ^ vB) * vN < 0.0;
2913 }
2914
2915 //=======================================================================
2916 /*!
2917  * \brief Create elements by sweeping an element
2918  * \param elem - element to sweep
2919  * \param newNodesItVec - nodes generated from each node of the element
2920  * \param newElems - generated elements
2921  * \param nbSteps - number of sweeping steps
2922  * \param srcElements - to append elem for each generated element
2923  */
2924 //=======================================================================
2925
2926 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
2927                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2928                                     list<const SMDS_MeshElement*>&        newElems,
2929                                     const int                             nbSteps,
2930                                     SMESH_SequenceOfElemPtr&              srcElements)
2931 {
2932   SMESHDS_Mesh* aMesh = GetMeshDS();
2933
2934   // Loop on elem nodes:
2935   // find new nodes and detect same nodes indices
2936   int nbNodes = elem->NbNodes();
2937   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2938   vector<const SMDS_MeshNode*> prevNod( nbNodes );
2939   vector<const SMDS_MeshNode*> nextNod( nbNodes );
2940   vector<const SMDS_MeshNode*> midlNod( nbNodes );
2941
2942   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2943   vector<int> sames(nbNodes);
2944   vector<bool> issimple(nbNodes);
2945
2946   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2947     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2948     const SMDS_MeshNode*                 node         = nnIt->first;
2949     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2950     if ( listNewNodes.empty() ) {
2951       return;
2952     }
2953
2954     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
2955
2956     itNN[ iNode ] = listNewNodes.begin();
2957     prevNod[ iNode ] = node;
2958     nextNod[ iNode ] = listNewNodes.front();
2959     if( !elem->IsQuadratic() || !issimple[iNode] ) {
2960       if ( prevNod[ iNode ] != nextNod [ iNode ])
2961         iNotSameNode = iNode;
2962       else {
2963         iSameNode = iNode;
2964         //nbSame++;
2965         sames[nbSame++] = iNode;
2966       }
2967     }
2968   }
2969
2970   //cout<<"  nbSame = "<<nbSame<<endl;
2971   if ( nbSame == nbNodes || nbSame > 2) {
2972     MESSAGE( " Too many same nodes of element " << elem->GetID() );
2973     //INFOS( " Too many same nodes of element " << elem->GetID() );
2974     return;
2975   }
2976
2977   //  if( elem->IsQuadratic() && nbSame>0 ) {
2978   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2979   //    return;
2980   //  }
2981
2982   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2983   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2984   if ( nbSame > 0 ) {
2985     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2986     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2987     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
2988   }
2989
2990   //if(nbNodes==8)
2991   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2992   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2993   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2994   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2995
2996   // check element orientation
2997   int i0 = 0, i2 = 2;
2998   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2999     //MESSAGE("Reversed elem " << elem );
3000     i0 = 2;
3001     i2 = 0;
3002     if ( nbSame > 0 )
3003       std::swap( iBeforeSame, iAfterSame );
3004   }
3005
3006   // make new elements
3007   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3008     // get next nodes
3009     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3010       if(issimple[iNode]) {
3011         nextNod[ iNode ] = *itNN[ iNode ];
3012         itNN[ iNode ]++;
3013       }
3014       else {
3015         if( elem->GetType()==SMDSAbs_Node ) {
3016           // we have to use two nodes
3017           midlNod[ iNode ] = *itNN[ iNode ];
3018           itNN[ iNode ]++;
3019           nextNod[ iNode ] = *itNN[ iNode ];
3020           itNN[ iNode ]++;
3021         }
3022         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3023           // we have to use each second node
3024           //itNN[ iNode ]++;
3025           nextNod[ iNode ] = *itNN[ iNode ];
3026           itNN[ iNode ]++;
3027         }
3028         else {
3029           // we have to use two nodes
3030           midlNod[ iNode ] = *itNN[ iNode ];
3031           itNN[ iNode ]++;
3032           nextNod[ iNode ] = *itNN[ iNode ];
3033           itNN[ iNode ]++;
3034         }
3035       }
3036     }
3037     SMDS_MeshElement* aNewElem = 0;
3038     if(!elem->IsPoly()) {
3039       switch ( nbNodes ) {
3040       case 0:
3041         return;
3042       case 1: { // NODE
3043         if ( nbSame == 0 ) {
3044           if(issimple[0])
3045             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3046           else
3047             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3048         }
3049         break;
3050       }
3051       case 2: { // EDGE
3052         if ( nbSame == 0 )
3053           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3054                                     nextNod[ 1 ], nextNod[ 0 ] );
3055         else
3056           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3057                                     nextNod[ iNotSameNode ] );
3058         break;
3059       }
3060
3061       case 3: { // TRIANGLE or quadratic edge
3062         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3063
3064           if ( nbSame == 0 )       // --- pentahedron
3065             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3066                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3067
3068           else if ( nbSame == 1 )  // --- pyramid
3069             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3070                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3071                                          nextNod[ iSameNode ]);
3072
3073           else // 2 same nodes:      --- tetrahedron
3074             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3075                                          nextNod[ iNotSameNode ]);
3076         }
3077         else { // quadratic edge
3078           if(nbSame==0) {     // quadratic quadrangle
3079             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3080                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3081           }
3082           else if(nbSame==1) { // quadratic triangle
3083             if(sames[0]==2) {
3084               return; // medium node on axis
3085             }
3086             else if(sames[0]==0) {
3087               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3088                                         nextNod[2], midlNod[1], prevNod[2]);
3089             }
3090             else { // sames[0]==1
3091               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3092                                         midlNod[0], nextNod[2], prevNod[2]);
3093             }
3094           }
3095           else {
3096             return;
3097           }
3098         }
3099         break;
3100       }
3101       case 4: { // QUADRANGLE
3102
3103         if ( nbSame == 0 )       // --- hexahedron
3104           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3105                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3106
3107         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3108           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3109                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3110                                        nextNod[ iSameNode ]);
3111           newElems.push_back( aNewElem );
3112           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3113                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3114                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3115         }
3116         else if ( nbSame == 2 ) { // pentahedron
3117           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3118             // iBeforeSame is same too
3119             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3120                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3121                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3122           else
3123             // iAfterSame is same too
3124             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3125                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3126                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3127         }
3128         break;
3129       }
3130       case 6: { // quadratic triangle
3131         // create pentahedron with 15 nodes
3132         if(nbSame==0) {
3133           if(i0>0) { // reversed case
3134             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3135                                          nextNod[0], nextNod[2], nextNod[1],
3136                                          prevNod[5], prevNod[4], prevNod[3],
3137                                          nextNod[5], nextNod[4], nextNod[3],
3138                                          midlNod[0], midlNod[2], midlNod[1]);
3139           }
3140           else { // not reversed case
3141             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3142                                          nextNod[0], nextNod[1], nextNod[2],
3143                                          prevNod[3], prevNod[4], prevNod[5],
3144                                          nextNod[3], nextNod[4], nextNod[5],
3145                                          midlNod[0], midlNod[1], midlNod[2]);
3146           }
3147         }
3148         else if(nbSame==1) {
3149           // 2d order pyramid of 13 nodes
3150           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3151           //                                 int n12,int n23,int n34,int n41,
3152           //                                 int n15,int n25,int n35,int n45, int ID);
3153           int n5 = iSameNode;
3154           int n1,n4,n41,n15,n45;
3155           if(i0>0) { // reversed case
3156             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3157             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3158             n41 = n1 + 3;
3159             n15 = n5 + 3;
3160             n45 = n4 + 3;
3161           }
3162           else {
3163             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3164             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3165             n41 = n4 + 3;
3166             n15 = n1 + 3;
3167             n45 = n5 + 3;
3168           }
3169           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3170                                       nextNod[n4], prevNod[n4], prevNod[n5],
3171                                       midlNod[n1], nextNod[n41],
3172                                       midlNod[n4], prevNod[n41],
3173                                       prevNod[n15], nextNod[n15],
3174                                       nextNod[n45], prevNod[n45]);
3175         }
3176         else if(nbSame==2) {
3177           // 2d order tetrahedron of 10 nodes
3178           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3179           //                                 int n12,int n23,int n31,
3180           //                                 int n14,int n24,int n34, int ID);
3181           int n1 = iNotSameNode;
3182           int n2,n3,n12,n23,n31;
3183           if(i0>0) { // reversed case
3184             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3185             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3186             n12 = n2 + 3;
3187             n23 = n3 + 3;
3188             n31 = n1 + 3;
3189           }
3190           else {
3191             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3192             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3193             n12 = n1 + 3;
3194             n23 = n2 + 3;
3195             n31 = n3 + 3;
3196           }
3197           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3198                                        prevNod[n12], prevNod[n23], prevNod[n31],
3199                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3200         }
3201         break;
3202       }
3203       case 8: { // quadratic quadrangle
3204         if(nbSame==0) {
3205           // create hexahedron with 20 nodes
3206           if(i0>0) { // reversed case
3207             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3208                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3209                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3210                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3211                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3212           }
3213           else { // not reversed case
3214             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3215                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3216                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3217                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3218                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3219           }
3220         }
3221         else if(nbSame==1) { 
3222           // --- pyramid + pentahedron - can not be created since it is needed 
3223           // additional middle node ot the center of face
3224           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3225           return;
3226         }
3227         else if(nbSame==2) {
3228           // 2d order Pentahedron with 15 nodes
3229           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3230           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3231           //                                 int n14,int n25,int n36, int ID);
3232           int n1,n2,n4,n5;
3233           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3234             // iBeforeSame is same too
3235             n1 = iBeforeSame;
3236             n2 = iOpposSame;
3237             n4 = iSameNode;
3238             n5 = iAfterSame;
3239           }
3240           else {
3241             // iAfterSame is same too
3242             n1 = iSameNode;
3243             n2 = iBeforeSame;
3244             n4 = iAfterSame;
3245             n5 = iOpposSame;
3246           }
3247           int n12,n45,n14,n25;
3248           if(i0>0) { //reversed case
3249             n12 = n1 + 4;
3250             n45 = n5 + 4;
3251             n14 = n4 + 4;
3252             n25 = n2 + 4;
3253           }
3254           else {
3255             n12 = n2 + 4;
3256             n45 = n4 + 4;
3257             n14 = n1 + 4;
3258             n25 = n5 + 4;
3259           }
3260           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3261                                        prevNod[n4], prevNod[n5], nextNod[n5],
3262                                        prevNod[n12], midlNod[n2], nextNod[n12],
3263                                        prevNod[n45], midlNod[n5], nextNod[n45],
3264                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3265         }
3266         break;
3267       }
3268       default: {
3269         // realized for extrusion only
3270         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3271         //vector<int> quantities (nbNodes + 2);
3272
3273         //quantities[0] = nbNodes; // bottom of prism
3274         //for (int inode = 0; inode < nbNodes; inode++) {
3275         //  polyedre_nodes[inode] = prevNod[inode];
3276         //}
3277
3278         //quantities[1] = nbNodes; // top of prism
3279         //for (int inode = 0; inode < nbNodes; inode++) {
3280         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3281         //}
3282
3283         //for (int iface = 0; iface < nbNodes; iface++) {
3284         //  quantities[iface + 2] = 4;
3285         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3286         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3287         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3288         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3289         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3290         //}
3291         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3292         break;
3293       }
3294       }
3295     }
3296
3297     if(!aNewElem) {
3298       // realized for extrusion only
3299       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3300       vector<int> quantities (nbNodes + 2);
3301
3302       quantities[0] = nbNodes; // bottom of prism
3303       for (int inode = 0; inode < nbNodes; inode++) {
3304         polyedre_nodes[inode] = prevNod[inode];
3305       }
3306
3307       quantities[1] = nbNodes; // top of prism
3308       for (int inode = 0; inode < nbNodes; inode++) {
3309         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3310       }
3311
3312       for (int iface = 0; iface < nbNodes; iface++) {
3313         quantities[iface + 2] = 4;
3314         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3315         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3316         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3317         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3318         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3319       }
3320       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3321     }
3322
3323     if ( aNewElem ) {
3324       newElems.push_back( aNewElem );
3325       myLastCreatedElems.Append(aNewElem);
3326       srcElements.Append( elem );
3327     }
3328
3329     // set new prev nodes
3330     for ( iNode = 0; iNode < nbNodes; iNode++ )
3331       prevNod[ iNode ] = nextNod[ iNode ];
3332
3333   } // for steps
3334 }
3335
3336 //=======================================================================
3337 /*!
3338  * \brief Create 1D and 2D elements around swept elements
3339  * \param mapNewNodes - source nodes and ones generated from them
3340  * \param newElemsMap - source elements and ones generated from them
3341  * \param elemNewNodesMap - nodes generated from each node of each element
3342  * \param elemSet - all swept elements
3343  * \param nbSteps - number of sweeping steps
3344  * \param srcElements - to append elem for each generated element
3345  */
3346 //=======================================================================
3347
3348 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3349                                   TElemOfElemListMap &     newElemsMap,
3350                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3351                                   TIDSortedElemSet&        elemSet,
3352                                   const int                nbSteps,
3353                                   SMESH_SequenceOfElemPtr& srcElements)
3354 {
3355   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3356   SMESHDS_Mesh* aMesh = GetMeshDS();
3357
3358   // Find nodes belonging to only one initial element - sweep them to get edges.
3359
3360   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3361   for ( ; nList != mapNewNodes.end(); nList++ ) {
3362     const SMDS_MeshNode* node =
3363       static_cast<const SMDS_MeshNode*>( nList->first );
3364     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3365     int nbInitElems = 0;
3366     const SMDS_MeshElement* el = 0;
3367     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3368     while ( eIt->more() && nbInitElems < 2 ) {
3369       el = eIt->next();
3370       SMDSAbs_ElementType type = el->GetType();
3371       if ( type == SMDSAbs_Volume || type < highType ) continue;
3372       if ( type > highType ) {
3373         nbInitElems = 0;
3374         highType = type;
3375       }
3376       if ( elemSet.find(el) != elemSet.end() )
3377         nbInitElems++;
3378     }
3379     if ( nbInitElems < 2 ) {
3380       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3381       if(!NotCreateEdge) {
3382         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3383         list<const SMDS_MeshElement*> newEdges;
3384         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3385       }
3386     }
3387   }
3388
3389   // Make a ceiling for each element ie an equal element of last new nodes.
3390   // Find free links of faces - make edges and sweep them into faces.
3391
3392   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3393   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3394   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3395     const SMDS_MeshElement* elem = itElem->first;
3396     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3397
3398     if ( elem->GetType() == SMDSAbs_Edge ) {
3399       // create a ceiling edge
3400       if (!elem->IsQuadratic()) {
3401         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3402                                vecNewNodes[ 1 ]->second.back())) {
3403           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3404                                                    vecNewNodes[ 1 ]->second.back()));
3405           srcElements.Append( myLastCreatedElems.Last() );
3406         }
3407       }
3408       else {
3409         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3410                                vecNewNodes[ 1 ]->second.back(),
3411                                vecNewNodes[ 2 ]->second.back())) {
3412           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3413                                                    vecNewNodes[ 1 ]->second.back(),
3414                                                    vecNewNodes[ 2 ]->second.back()));
3415           srcElements.Append( myLastCreatedElems.Last() );
3416         }
3417       }
3418     }
3419     if ( elem->GetType() != SMDSAbs_Face )
3420       continue;
3421
3422     if(itElem->second.size()==0) continue;
3423
3424     bool hasFreeLinks = false;
3425
3426     TIDSortedElemSet avoidSet;
3427     avoidSet.insert( elem );
3428
3429     set<const SMDS_MeshNode*> aFaceLastNodes;
3430     int iNode, nbNodes = vecNewNodes.size();
3431     if(!elem->IsQuadratic()) {
3432       // loop on the face nodes
3433       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3434         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3435         // look for free links of the face
3436         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3437         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3438         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3439         // check if a link is free
3440         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3441           hasFreeLinks = true;
3442           // make an edge and a ceiling for a new edge
3443           if ( !aMesh->FindEdge( n1, n2 )) {
3444             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3445             srcElements.Append( myLastCreatedElems.Last() );
3446           }
3447           n1 = vecNewNodes[ iNode ]->second.back();
3448           n2 = vecNewNodes[ iNext ]->second.back();
3449           if ( !aMesh->FindEdge( n1, n2 )) {
3450             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3451             srcElements.Append( myLastCreatedElems.Last() );
3452           }
3453         }
3454       }
3455     }
3456     else { // elem is quadratic face
3457       int nbn = nbNodes/2;
3458       for ( iNode = 0; iNode < nbn; iNode++ ) {
3459         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3460         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3461         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3462         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3463         // check if a link is free
3464         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3465           hasFreeLinks = true;
3466           // make an edge and a ceiling for a new edge
3467           // find medium node
3468           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3469           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3470             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3471             srcElements.Append( myLastCreatedElems.Last() );
3472           }
3473           n1 = vecNewNodes[ iNode ]->second.back();
3474           n2 = vecNewNodes[ iNext ]->second.back();
3475           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3476           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3477             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3478             srcElements.Append( myLastCreatedElems.Last() );
3479           }
3480         }
3481       }
3482       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3483         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3484       }
3485     }
3486
3487     // sweep free links into faces
3488
3489     if ( hasFreeLinks )  {
3490       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3491       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3492
3493       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3494       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3495         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3496         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3497       }
3498       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3499         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3500         iVol = 0;
3501         while ( iVol++ < volNb ) v++;
3502         // find indices of free faces of a volume and their source edges
3503         list< int > freeInd;
3504         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3505         SMDS_VolumeTool vTool( *v );
3506         int iF, nbF = vTool.NbFaces();
3507         for ( iF = 0; iF < nbF; iF ++ ) {
3508           if (vTool.IsFreeFace( iF ) &&
3509               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3510               initNodeSet != faceNodeSet) // except an initial face
3511           {
3512             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3513               continue;
3514             freeInd.push_back( iF );
3515             // find source edge of a free face iF
3516             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3517             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3518             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3519                                    initNodeSet.begin(), initNodeSet.end(),
3520                                    commonNodes.begin());
3521             if ( (*v)->IsQuadratic() )
3522               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3523             else
3524               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3525 #ifdef _DEBUG_
3526             if ( !srcEdges.back() )
3527             {
3528               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3529                    << iF << " of volume #" << vTool.ID() << endl;
3530             }
3531 #endif
3532           }
3533         }
3534         if ( freeInd.empty() )
3535           continue;
3536
3537         // create faces for all steps;
3538         // if such a face has been already created by sweep of edge,
3539         // assure that its orientation is OK
3540         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3541           vTool.Set( *v );
3542           vTool.SetExternalNormal();
3543           list< int >::iterator ind = freeInd.begin();
3544           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3545           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3546           {
3547             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3548             int nbn = vTool.NbFaceNodes( *ind );
3549             switch ( nbn ) {
3550             case 3: { ///// triangle
3551               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3552               if ( !f )
3553                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3554               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3555                 aMesh->ChangeElementNodes( f, nodes, nbn );
3556               break;
3557             }
3558             case 4: { ///// quadrangle
3559               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3560               if ( !f )
3561                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3562               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3563                 aMesh->ChangeElementNodes( f, nodes, nbn );
3564               break;
3565             }
3566             default:
3567               if( (*v)->IsQuadratic() ) {
3568                 if(nbn==6) { /////// quadratic triangle
3569                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3570                                                              nodes[1], nodes[3], nodes[5] );
3571                   if ( !f ) {
3572                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3573                                                              nodes[1], nodes[3], nodes[5]));
3574                   }
3575                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3576                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3577                     tmpnodes[0] = nodes[0];
3578                     tmpnodes[1] = nodes[2];
3579                     tmpnodes[2] = nodes[4];
3580                     tmpnodes[3] = nodes[1];
3581                     tmpnodes[4] = nodes[3];
3582                     tmpnodes[5] = nodes[5];
3583                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3584                   }
3585                 }
3586                 else {       /////// quadratic quadrangle
3587                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3588                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3589                   if ( !f ) {
3590                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3591                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3592                   }
3593                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3594                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3595                     tmpnodes[0] = nodes[0];
3596                     tmpnodes[1] = nodes[2];
3597                     tmpnodes[2] = nodes[4];
3598                     tmpnodes[3] = nodes[6];
3599                     tmpnodes[4] = nodes[1];
3600                     tmpnodes[5] = nodes[3];
3601                     tmpnodes[6] = nodes[5];
3602                     tmpnodes[7] = nodes[7];
3603                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3604                   }
3605                 }
3606               }
3607               else { //////// polygon
3608                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3609                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3610                 if ( !f )
3611                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3612                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3613                   aMesh->ChangeElementNodes( f, nodes, nbn );
3614               }
3615             }
3616             while ( srcElements.Length() < myLastCreatedElems.Length() )
3617               srcElements.Append( *srcEdge );
3618
3619           }  // loop on free faces
3620
3621           // go to the next volume
3622           iVol = 0;
3623           while ( iVol++ < nbVolumesByStep ) v++;
3624         }
3625       }
3626     } // sweep free links into faces
3627
3628     // Make a ceiling face with a normal external to a volume
3629
3630     SMDS_VolumeTool lastVol( itElem->second.back() );
3631
3632     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3633     if ( iF >= 0 ) {
3634       lastVol.SetExternalNormal();
3635       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3636       int nbn = lastVol.NbFaceNodes( iF );
3637       switch ( nbn ) {
3638       case 3:
3639         if (!hasFreeLinks ||
3640             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3641           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3642         break;
3643       case 4:
3644         if (!hasFreeLinks ||
3645             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3646           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3647         break;
3648       default:
3649         if(itElem->second.back()->IsQuadratic()) {
3650           if(nbn==6) {
3651             if (!hasFreeLinks ||
3652                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3653                                  nodes[1], nodes[3], nodes[5]) ) {
3654               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3655                                                        nodes[1], nodes[3], nodes[5]));
3656             }
3657           }
3658           else { // nbn==8
3659             if (!hasFreeLinks ||
3660                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3661                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3662               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3663                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3664           }
3665         }
3666         else {
3667           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3668           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3669             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3670         }
3671       } // switch
3672
3673       while ( srcElements.Length() < myLastCreatedElems.Length() )
3674         srcElements.Append( myLastCreatedElems.Last() );
3675     }
3676   } // loop on swept elements
3677 }
3678
3679 //=======================================================================
3680 //function : RotationSweep
3681 //purpose  :
3682 //=======================================================================
3683
3684 SMESH_MeshEditor::PGroupIDs
3685 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3686                                 const gp_Ax1&      theAxis,
3687                                 const double       theAngle,
3688                                 const int          theNbSteps,
3689                                 const double       theTol,
3690                                 const bool         theMakeGroups,
3691                                 const bool         theMakeWalls)
3692 {
3693   myLastCreatedElems.Clear();
3694   myLastCreatedNodes.Clear();
3695
3696   // source elements for each generated one
3697   SMESH_SequenceOfElemPtr srcElems, srcNodes;
3698
3699   MESSAGE( "RotationSweep()");
3700   gp_Trsf aTrsf;
3701   aTrsf.SetRotation( theAxis, theAngle );
3702   gp_Trsf aTrsf2;
3703   aTrsf2.SetRotation( theAxis, theAngle/2. );
3704
3705   gp_Lin aLine( theAxis );
3706   double aSqTol = theTol * theTol;
3707
3708   SMESHDS_Mesh* aMesh = GetMeshDS();
3709
3710   TNodeOfNodeListMap mapNewNodes;
3711   TElemOfVecOfNnlmiMap mapElemNewNodes;
3712   TElemOfElemListMap newElemsMap;
3713
3714   // loop on theElems
3715   TIDSortedElemSet::iterator itElem;
3716   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3717     const SMDS_MeshElement* elem = *itElem;
3718     if ( !elem || elem->GetType() == SMDSAbs_Volume )
3719       continue;
3720     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3721     newNodesItVec.reserve( elem->NbNodes() );
3722
3723     // loop on elem nodes
3724     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3725     while ( itN->more() ) {
3726       // check if a node has been already sweeped
3727       const SMDS_MeshNode* node = cast2Node( itN->next() );
3728
3729       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3730       double coord[3];
3731       aXYZ.Coord( coord[0], coord[1], coord[2] );
3732       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3733
3734       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3735       if ( nIt == mapNewNodes.end() ) {
3736         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3737         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3738
3739         // make new nodes
3740         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3741         //double coord[3];
3742         //aXYZ.Coord( coord[0], coord[1], coord[2] );
3743         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3744         const SMDS_MeshNode * newNode = node;
3745         for ( int i = 0; i < theNbSteps; i++ ) {
3746           if ( !isOnAxis ) {
3747             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3748               // create two nodes
3749               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3750               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3751               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3752               myLastCreatedNodes.Append(newNode);
3753               srcNodes.Append( node );
3754               listNewNodes.push_back( newNode );
3755               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3756               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3757             }
3758             else {
3759               aTrsf.Transforms( coord[0], coord[1], coord[2] );
3760             }
3761             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3762             myLastCreatedNodes.Append(newNode);
3763             srcNodes.Append( node );
3764             listNewNodes.push_back( newNode );
3765           }
3766           else {
3767             listNewNodes.push_back( newNode );
3768             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3769               listNewNodes.push_back( newNode );
3770             }
3771           }
3772         }
3773       }
3774       /*
3775         else {
3776         // if current elem is quadratic and current node is not medium
3777         // we have to check - may be it is needed to insert additional nodes
3778         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3779         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3780         if(listNewNodes.size()==theNbSteps) {
3781         listNewNodes.clear();
3782         // make new nodes
3783         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3784         //double coord[3];
3785         //aXYZ.Coord( coord[0], coord[1], coord[2] );
3786         const SMDS_MeshNode * newNode = node;
3787         if ( !isOnAxis ) {
3788         for(int i = 0; i<theNbSteps; i++) {
3789         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3790         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3791         cout<<"    3 AddNode:  "<<newNode;
3792         myLastCreatedNodes.Append(newNode);
3793         listNewNodes.push_back( newNode );
3794         srcNodes.Append( node );
3795         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3796         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3797         cout<<"    4 AddNode:  "<<newNode;
3798         myLastCreatedNodes.Append(newNode);
3799         srcNodes.Append( node );
3800         listNewNodes.push_back( newNode );
3801         }
3802         }
3803         else {
3804         listNewNodes.push_back( newNode );
3805         }
3806         }
3807         }
3808         }
3809       */
3810       newNodesItVec.push_back( nIt );
3811     }
3812     // make new elements
3813     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3814   }
3815
3816   if ( theMakeWalls )
3817     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3818
3819   PGroupIDs newGroupIDs;
3820   if ( theMakeGroups )
3821     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3822
3823   return newGroupIDs;
3824 }
3825
3826
3827 //=======================================================================
3828 //function : CreateNode
3829 //purpose  :
3830 //=======================================================================
3831 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3832                                                   const double y,
3833                                                   const double z,
3834                                                   const double tolnode,
3835                                                   SMESH_SequenceOfNode& aNodes)
3836 {
3837   myLastCreatedElems.Clear();
3838   myLastCreatedNodes.Clear();
3839
3840   gp_Pnt P1(x,y,z);
3841   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3842
3843   // try to search in sequence of existing nodes
3844   // if aNodes.Length()>0 we 'nave to use given sequence
3845   // else - use all nodes of mesh
3846   if(aNodes.Length()>0) {
3847     int i;
3848     for(i=1; i<=aNodes.Length(); i++) {
3849       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3850       if(P1.Distance(P2)<tolnode)
3851         return aNodes.Value(i);
3852     }
3853   }
3854   else {
3855     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3856     while(itn->more()) {
3857       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3858       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3859       if(P1.Distance(P2)<tolnode)
3860         return aN;
3861     }
3862   }
3863
3864   // create new node and return it
3865   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3866   myLastCreatedNodes.Append(NewNode);
3867   return NewNode;
3868 }
3869
3870
3871 //=======================================================================
3872 //function : ExtrusionSweep
3873 //purpose  :
3874 //=======================================================================
3875
3876 SMESH_MeshEditor::PGroupIDs
3877 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
3878                                   const gp_Vec&       theStep,
3879                                   const int           theNbSteps,
3880                                   TElemOfElemListMap& newElemsMap,
3881                                   const bool          theMakeGroups,
3882                                   const int           theFlags,
3883                                   const double        theTolerance)
3884 {
3885   ExtrusParam aParams;
3886   aParams.myDir = gp_Dir(theStep);
3887   aParams.myNodes.Clear();
3888   aParams.mySteps = new TColStd_HSequenceOfReal;
3889   int i;
3890   for(i=1; i<=theNbSteps; i++)
3891     aParams.mySteps->Append(theStep.Magnitude());
3892
3893   return
3894     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3895 }
3896
3897
3898 //=======================================================================
3899 //function : ExtrusionSweep
3900 //purpose  :
3901 //=======================================================================
3902
3903 SMESH_MeshEditor::PGroupIDs
3904 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
3905                                   ExtrusParam&        theParams,
3906                                   TElemOfElemListMap& newElemsMap,
3907                                   const bool          theMakeGroups,
3908                                   const int           theFlags,
3909                                   const double        theTolerance)
3910 {
3911   myLastCreatedElems.Clear();
3912   myLastCreatedNodes.Clear();
3913
3914   // source elements for each generated one
3915   SMESH_SequenceOfElemPtr srcElems, srcNodes;
3916
3917   SMESHDS_Mesh* aMesh = GetMeshDS();
3918
3919   int nbsteps = theParams.mySteps->Length();
3920
3921   TNodeOfNodeListMap mapNewNodes;
3922   //TNodeOfNodeVecMap mapNewNodes;
3923   TElemOfVecOfNnlmiMap mapElemNewNodes;
3924   //TElemOfVecOfMapNodesMap mapElemNewNodes;
3925
3926   // loop on theElems
3927   TIDSortedElemSet::iterator itElem;
3928   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3929     // check element type
3930     const SMDS_MeshElement* elem = *itElem;
3931     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
3932       continue;
3933
3934     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3935     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3936     newNodesItVec.reserve( elem->NbNodes() );
3937
3938     // loop on elem nodes
3939     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3940     while ( itN->more() )
3941     {
3942       // check if a node has been already sweeped
3943       const SMDS_MeshNode* node = cast2Node( itN->next() );
3944       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3945       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3946       if ( nIt == mapNewNodes.end() ) {
3947         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3948         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3949         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3950         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3951         //vecNewNodes.reserve(nbsteps);
3952
3953         // make new nodes
3954         double coord[] = { node->X(), node->Y(), node->Z() };
3955         //int nbsteps = theParams.mySteps->Length();
3956         for ( int i = 0; i < nbsteps; i++ ) {
3957           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3958             // create additional node
3959             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3960             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3961             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3962             if( theFlags & EXTRUSION_FLAG_SEW ) {
3963               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3964                                                          theTolerance, theParams.myNodes);
3965               listNewNodes.push_back( newNode );
3966             }
3967             else {
3968               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3969               myLastCreatedNodes.Append(newNode);
3970               srcNodes.Append( node );
3971               listNewNodes.push_back( newNode );
3972             }
3973           }
3974           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3975           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3976           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3977           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3978           if( theFlags & EXTRUSION_FLAG_SEW ) {
3979             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3980                                                        theTolerance, theParams.myNodes);
3981             listNewNodes.push_back( newNode );
3982             //vecNewNodes[i]=newNode;
3983           }
3984           else {
3985             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3986             myLastCreatedNodes.Append(newNode);
3987             srcNodes.Append( node );
3988             listNewNodes.push_back( newNode );
3989             //vecNewNodes[i]=newNode;
3990           }
3991         }
3992       }
3993       else {
3994         // if current elem is quadratic and current node is not medium
3995         // we have to check - may be it is needed to insert additional nodes
3996         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3997           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3998           if(listNewNodes.size()==nbsteps) {
3999             listNewNodes.clear();
4000             double coord[] = { node->X(), node->Y(), node->Z() };
4001             for ( int i = 0; i < nbsteps; i++ ) {
4002               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4003               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4004               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4005               if( theFlags & EXTRUSION_FLAG_SEW ) {
4006                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4007                                                            theTolerance, theParams.myNodes);
4008                 listNewNodes.push_back( newNode );
4009               }
4010               else {
4011                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4012                 myLastCreatedNodes.Append(newNode);
4013                 srcNodes.Append( node );
4014                 listNewNodes.push_back( newNode );
4015               }
4016               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4017               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4018               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4019               if( theFlags & EXTRUSION_FLAG_SEW ) {
4020                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4021                                                            theTolerance, theParams.myNodes);
4022                 listNewNodes.push_back( newNode );
4023               }
4024               else {
4025                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4026                 myLastCreatedNodes.Append(newNode);
4027                 srcNodes.Append( node );
4028                 listNewNodes.push_back( newNode );
4029               }
4030             }
4031           }
4032         }
4033       }
4034       newNodesItVec.push_back( nIt );
4035     }
4036     // make new elements
4037     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4038   }
4039
4040   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4041     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4042   }
4043   PGroupIDs newGroupIDs;
4044   if ( theMakeGroups )
4045     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4046
4047   return newGroupIDs;
4048 }
4049
4050 /*
4051 //=======================================================================
4052 //class    : SMESH_MeshEditor_PathPoint
4053 //purpose  : auxiliary class
4054 //=======================================================================
4055 class SMESH_MeshEditor_PathPoint {
4056 public:
4057 SMESH_MeshEditor_PathPoint() {
4058 myPnt.SetCoord(99., 99., 99.);
4059 myTgt.SetCoord(1.,0.,0.);
4060 myAngle=0.;
4061 myPrm=0.;
4062 }
4063 void SetPnt(const gp_Pnt& aP3D){
4064 myPnt=aP3D;
4065 }
4066 void SetTangent(const gp_Dir& aTgt){
4067 myTgt=aTgt;
4068 }
4069 void SetAngle(const double& aBeta){
4070 myAngle=aBeta;
4071 }
4072 void SetParameter(const double& aPrm){
4073 myPrm=aPrm;
4074 }
4075 const gp_Pnt& Pnt()const{
4076 return myPnt;
4077 }
4078 const gp_Dir& Tangent()const{
4079 return myTgt;
4080 }
4081 double Angle()const{
4082 return myAngle;
4083 }
4084 double Parameter()const{
4085 return myPrm;
4086 }
4087
4088 protected:
4089 gp_Pnt myPnt;
4090 gp_Dir myTgt;
4091 double myAngle;
4092 double myPrm;
4093 };
4094 */
4095
4096 //=======================================================================
4097 //function : ExtrusionAlongTrack
4098 //purpose  :
4099 //=======================================================================
4100 SMESH_MeshEditor::Extrusion_Error
4101 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4102                                        SMESH_subMesh*       theTrack,
4103                                        const SMDS_MeshNode* theN1,
4104                                        const bool           theHasAngles,
4105                                        list<double>&        theAngles,
4106                                        const bool           theLinearVariation,
4107                                        const bool           theHasRefPoint,
4108                                        const gp_Pnt&        theRefPoint,
4109                                        const bool           theMakeGroups)
4110 {
4111   myLastCreatedElems.Clear();
4112   myLastCreatedNodes.Clear();
4113
4114   int aNbE;
4115   std::list<double> aPrms;
4116   TIDSortedElemSet::iterator itElem;
4117
4118   gp_XYZ aGC;
4119   TopoDS_Edge aTrackEdge;
4120   TopoDS_Vertex aV1, aV2;
4121
4122   SMDS_ElemIteratorPtr aItE;
4123   SMDS_NodeIteratorPtr aItN;
4124   SMDSAbs_ElementType aTypeE;
4125
4126   TNodeOfNodeListMap mapNewNodes;
4127
4128   // 1. Check data
4129   aNbE = theElements.size();
4130   // nothing to do
4131   if ( !aNbE )
4132     return EXTR_NO_ELEMENTS;
4133
4134   // 1.1 Track Pattern
4135   ASSERT( theTrack );
4136
4137   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4138
4139   aItE = pSubMeshDS->GetElements();
4140   while ( aItE->more() ) {
4141     const SMDS_MeshElement* pE = aItE->next();
4142     aTypeE = pE->GetType();
4143     // Pattern must contain links only
4144     if ( aTypeE != SMDSAbs_Edge )
4145       return EXTR_PATH_NOT_EDGE;
4146   }
4147
4148   list<SMESH_MeshEditor_PathPoint> fullList;
4149
4150   const TopoDS_Shape& aS = theTrack->GetSubShape();
4151   // Sub shape for the Pattern must be an Edge or Wire
4152   if( aS.ShapeType() == TopAbs_EDGE ) {
4153     aTrackEdge = TopoDS::Edge( aS );
4154     // the Edge must not be degenerated
4155     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4156       return EXTR_BAD_PATH_SHAPE;
4157     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4158     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4159     const SMDS_MeshNode* aN1 = aItN->next();
4160     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4161     const SMDS_MeshNode* aN2 = aItN->next();
4162     // starting node must be aN1 or aN2
4163     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4164       return EXTR_BAD_STARTING_NODE;
4165     aItN = pSubMeshDS->GetNodes();
4166     while ( aItN->more() ) {
4167       const SMDS_MeshNode* pNode = aItN->next();
4168       const SMDS_EdgePosition* pEPos =
4169         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4170       double aT = pEPos->GetUParameter();
4171       aPrms.push_back( aT );
4172     }
4173     //Extrusion_Error err =
4174     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4175   }
4176   else if( aS.ShapeType() == TopAbs_WIRE ) {
4177     list< SMESH_subMesh* > LSM;
4178     TopTools_SequenceOfShape Edges;
4179     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4180     while(itSM->more()) {
4181       SMESH_subMesh* SM = itSM->next();
4182       LSM.push_back(SM);
4183       const TopoDS_Shape& aS = SM->GetSubShape();
4184       Edges.Append(aS);
4185     }
4186     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4187     int startNid = theN1->GetID();
4188     TColStd_MapOfInteger UsedNums;
4189     int NbEdges = Edges.Length();
4190     int i = 1;
4191     for(; i<=NbEdges; i++) {
4192       int k = 0;
4193       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4194       for(; itLSM!=LSM.end(); itLSM++) {
4195         k++;
4196         if(UsedNums.Contains(k)) continue;
4197         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4198         SMESH_subMesh* locTrack = *itLSM;
4199         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4200         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4201         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4202         const SMDS_MeshNode* aN1 = aItN->next();
4203         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4204         const SMDS_MeshNode* aN2 = aItN->next();
4205         // starting node must be aN1 or aN2
4206         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4207         // 2. Collect parameters on the track edge
4208         aPrms.clear();
4209         aItN = locMeshDS->GetNodes();
4210         while ( aItN->more() ) {
4211           const SMDS_MeshNode* pNode = aItN->next();
4212           const SMDS_EdgePosition* pEPos =
4213             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4214           double aT = pEPos->GetUParameter();
4215           aPrms.push_back( aT );
4216         }
4217         list<SMESH_MeshEditor_PathPoint> LPP;
4218         //Extrusion_Error err =
4219         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4220         LLPPs.push_back(LPP);
4221         UsedNums.Add(k);
4222         // update startN for search following egde
4223         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4224         else startNid = aN1->GetID();
4225         break;
4226       }
4227     }
4228     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4229     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4230     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4231     for(; itPP!=firstList.end(); itPP++) {
4232       fullList.push_back( *itPP );
4233     }
4234     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4235     fullList.pop_back();
4236     itLLPP++;
4237     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4238       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4239       itPP = currList.begin();
4240       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4241       gp_Dir D1 = PP1.Tangent();
4242       gp_Dir D2 = PP2.Tangent();
4243       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4244                            (D1.Z()+D2.Z())/2 ) );
4245       PP1.SetTangent(Dnew);
4246       fullList.push_back(PP1);
4247       itPP++;
4248       for(; itPP!=firstList.end(); itPP++) {
4249         fullList.push_back( *itPP );
4250       }
4251       PP1 = fullList.back();
4252       fullList.pop_back();
4253     }
4254     // if wire not closed
4255     fullList.push_back(PP1);
4256     // else ???
4257   }
4258   else {
4259     return EXTR_BAD_PATH_SHAPE;
4260   }
4261
4262   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4263                           theHasRefPoint, theRefPoint, theMakeGroups);
4264 }
4265
4266
4267 //=======================================================================
4268 //function : ExtrusionAlongTrack
4269 //purpose  :
4270 //=======================================================================
4271 SMESH_MeshEditor::Extrusion_Error
4272 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4273                                        SMESH_Mesh*          theTrack,
4274                                        const SMDS_MeshNode* theN1,
4275                                        const bool           theHasAngles,
4276                                        list<double>&        theAngles,
4277                                        const bool           theLinearVariation,
4278                                        const bool           theHasRefPoint,
4279                                        const gp_Pnt&        theRefPoint,
4280                                        const bool           theMakeGroups)
4281 {
4282   myLastCreatedElems.Clear();
4283   myLastCreatedNodes.Clear();
4284
4285   int aNbE;
4286   std::list<double> aPrms;
4287   TIDSortedElemSet::iterator itElem;
4288
4289   gp_XYZ aGC;
4290   TopoDS_Edge aTrackEdge;
4291   TopoDS_Vertex aV1, aV2;
4292
4293   SMDS_ElemIteratorPtr aItE;
4294   SMDS_NodeIteratorPtr aItN;
4295   SMDSAbs_ElementType aTypeE;
4296
4297   TNodeOfNodeListMap mapNewNodes;
4298
4299   // 1. Check data
4300   aNbE = theElements.size();
4301   // nothing to do
4302   if ( !aNbE )
4303     return EXTR_NO_ELEMENTS;
4304
4305   // 1.1 Track Pattern
4306   ASSERT( theTrack );
4307
4308   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4309
4310   aItE = pMeshDS->elementsIterator();
4311   while ( aItE->more() ) {
4312     const SMDS_MeshElement* pE = aItE->next();
4313     aTypeE = pE->GetType();
4314     // Pattern must contain links only
4315     if ( aTypeE != SMDSAbs_Edge )
4316       return EXTR_PATH_NOT_EDGE;
4317   }
4318
4319   list<SMESH_MeshEditor_PathPoint> fullList;
4320
4321   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4322   // Sub shape for the Pattern must be an Edge or Wire
4323   if( aS.ShapeType() == TopAbs_EDGE ) {
4324     aTrackEdge = TopoDS::Edge( aS );
4325     // the Edge must not be degenerated
4326     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4327       return EXTR_BAD_PATH_SHAPE;
4328     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4329     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4330     const SMDS_MeshNode* aN1 = aItN->next();
4331     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4332     const SMDS_MeshNode* aN2 = aItN->next();
4333     // starting node must be aN1 or aN2
4334     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4335       return EXTR_BAD_STARTING_NODE;
4336     aItN = pMeshDS->nodesIterator();
4337     while ( aItN->more() ) {
4338       const SMDS_MeshNode* pNode = aItN->next();
4339       if( pNode==aN1 || pNode==aN2 ) continue;
4340       const SMDS_EdgePosition* pEPos =
4341         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4342       double aT = pEPos->GetUParameter();
4343       aPrms.push_back( aT );
4344     }
4345     //Extrusion_Error err =
4346     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4347   }
4348   else if( aS.ShapeType() == TopAbs_WIRE ) {
4349     list< SMESH_subMesh* > LSM;
4350     TopTools_SequenceOfShape Edges;
4351     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4352     for(; eExp.More(); eExp.Next()) {
4353       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4354       if( BRep_Tool::Degenerated(E) ) continue;
4355       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4356       if(SM) {
4357         LSM.push_back(SM);
4358         Edges.Append(E);
4359       }
4360     }
4361     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4362     int startNid = theN1->GetID();
4363     TColStd_MapOfInteger UsedNums;
4364     int NbEdges = Edges.Length();
4365     int i = 1;
4366     for(; i<=NbEdges; i++) {
4367       int k = 0;
4368       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4369       for(; itLSM!=LSM.end(); itLSM++) {
4370         k++;
4371         if(UsedNums.Contains(k)) continue;
4372         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4373         SMESH_subMesh* locTrack = *itLSM;
4374         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4375         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4376         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4377         const SMDS_MeshNode* aN1 = aItN->next();
4378         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4379         const SMDS_MeshNode* aN2 = aItN->next();
4380         // starting node must be aN1 or aN2
4381         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4382         // 2. Collect parameters on the track edge
4383         aPrms.clear();
4384         aItN = locMeshDS->GetNodes();
4385         while ( aItN->more() ) {
4386           const SMDS_MeshNode* pNode = aItN->next();
4387           const SMDS_EdgePosition* pEPos =
4388             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4389           double aT = pEPos->GetUParameter();
4390           aPrms.push_back( aT );
4391         }
4392         list<SMESH_MeshEditor_PathPoint> LPP;
4393         //Extrusion_Error err =
4394         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4395         LLPPs.push_back(LPP);
4396         UsedNums.Add(k);
4397         // update startN for search following egde
4398         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4399         else startNid = aN1->GetID();
4400         break;
4401       }
4402     }
4403     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4404     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4405     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4406     for(; itPP!=firstList.end(); itPP++) {
4407       fullList.push_back( *itPP );
4408     }
4409     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4410     fullList.pop_back();
4411     itLLPP++;
4412     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4413       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4414       itPP = currList.begin();
4415       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4416       gp_Pnt P1 = PP1.Pnt();
4417       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4418       gp_Pnt P2 = PP2.Pnt();
4419       gp_Dir D1 = PP1.Tangent();
4420       gp_Dir D2 = PP2.Tangent();
4421       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4422                            (D1.Z()+D2.Z())/2 ) );
4423       PP1.SetTangent(Dnew);
4424       fullList.push_back(PP1);
4425       itPP++;
4426       for(; itPP!=currList.end(); itPP++) {
4427         fullList.push_back( *itPP );
4428       }
4429       PP1 = fullList.back();
4430       fullList.pop_back();
4431     }
4432     // if wire not closed
4433     fullList.push_back(PP1);
4434     // else ???
4435   }
4436   else {
4437     return EXTR_BAD_PATH_SHAPE;
4438   }
4439
4440   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4441                           theHasRefPoint, theRefPoint, theMakeGroups);
4442 }
4443
4444
4445 //=======================================================================
4446 //function : MakeEdgePathPoints
4447 //purpose  : auxilary for ExtrusionAlongTrack
4448 //=======================================================================
4449 SMESH_MeshEditor::Extrusion_Error
4450 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4451                                      const TopoDS_Edge& aTrackEdge,
4452                                      bool FirstIsStart,
4453                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4454 {
4455   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4456   aTolVec=1.e-7;
4457   aTolVec2=aTolVec*aTolVec;
4458   double aT1, aT2;
4459   TopoDS_Vertex aV1, aV2;
4460   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4461   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4462   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4463   // 2. Collect parameters on the track edge
4464   aPrms.push_front( aT1 );
4465   aPrms.push_back( aT2 );
4466   // sort parameters
4467   aPrms.sort();
4468   if( FirstIsStart ) {
4469     if ( aT1 > aT2 ) {
4470       aPrms.reverse();
4471     }
4472   }
4473   else {
4474     if ( aT2 > aT1 ) {
4475       aPrms.reverse();
4476     }
4477   }
4478   // 3. Path Points
4479   SMESH_MeshEditor_PathPoint aPP;
4480   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4481   std::list<double>::iterator aItD = aPrms.begin();
4482   for(; aItD != aPrms.end(); ++aItD) {
4483     double aT = *aItD;
4484     gp_Pnt aP3D;
4485     gp_Vec aVec;
4486     aC3D->D1( aT, aP3D, aVec );
4487     aL2 = aVec.SquareMagnitude();
4488     if ( aL2 < aTolVec2 )
4489       return EXTR_CANT_GET_TANGENT;
4490     gp_Dir aTgt( aVec );
4491     aPP.SetPnt( aP3D );
4492     aPP.SetTangent( aTgt );
4493     aPP.SetParameter( aT );
4494     LPP.push_back(aPP);
4495   }
4496   return EXTR_OK;
4497 }
4498
4499
4500 //=======================================================================
4501 //function : MakeExtrElements
4502 //purpose  : auxilary for ExtrusionAlongTrack
4503 //=======================================================================
4504 SMESH_MeshEditor::Extrusion_Error
4505 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4506                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4507                                    const bool theHasAngles,
4508                                    list<double>& theAngles,
4509                                    const bool theLinearVariation,
4510                                    const bool theHasRefPoint,
4511                                    const gp_Pnt& theRefPoint,
4512                                    const bool theMakeGroups)
4513 {
4514   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4515   int aNbTP = fullList.size();
4516   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4517   // Angles
4518   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4519     LinearAngleVariation(aNbTP-1, theAngles);
4520   }
4521   vector<double> aAngles( aNbTP );
4522   int j = 0;
4523   for(; j<aNbTP; ++j) {
4524     aAngles[j] = 0.;
4525   }
4526   if ( theHasAngles ) {
4527     double anAngle;;
4528     std::list<double>::iterator aItD = theAngles.begin();
4529     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4530       anAngle = *aItD;
4531       aAngles[j] = anAngle;
4532     }
4533   }
4534   // fill vector of path points with angles
4535   //aPPs.resize(fullList.size());
4536   j = -1;
4537   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4538   for(; itPP!=fullList.end(); itPP++) {
4539     j++;
4540     SMESH_MeshEditor_PathPoint PP = *itPP;
4541     PP.SetAngle(aAngles[j]);
4542     aPPs[j] = PP;
4543   }
4544
4545   TNodeOfNodeListMap mapNewNodes;
4546   TElemOfVecOfNnlmiMap mapElemNewNodes;
4547   TElemOfElemListMap newElemsMap;
4548   TIDSortedElemSet::iterator itElem;
4549   double aX, aY, aZ;
4550   int aNb;
4551   SMDSAbs_ElementType aTypeE;
4552   // source elements for each generated one
4553   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4554
4555   // 3. Center of rotation aV0
4556   gp_Pnt aV0 = theRefPoint;
4557   gp_XYZ aGC;
4558   if ( !theHasRefPoint ) {
4559     aNb = 0;
4560     aGC.SetCoord( 0.,0.,0. );
4561
4562     itElem = theElements.begin();
4563     for ( ; itElem != theElements.end(); itElem++ ) {
4564       const SMDS_MeshElement* elem = *itElem;
4565
4566       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4567       while ( itN->more() ) {
4568         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4569         aX = node->X();
4570         aY = node->Y();
4571         aZ = node->Z();
4572
4573         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4574           list<const SMDS_MeshNode*> aLNx;
4575           mapNewNodes[node] = aLNx;
4576           //
4577           gp_XYZ aXYZ( aX, aY, aZ );
4578           aGC += aXYZ;
4579           ++aNb;
4580         }
4581       }
4582     }
4583     aGC /= aNb;
4584     aV0.SetXYZ( aGC );
4585   } // if (!theHasRefPoint) {
4586   mapNewNodes.clear();
4587
4588   // 4. Processing the elements
4589   SMESHDS_Mesh* aMesh = GetMeshDS();
4590
4591   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4592     // check element type
4593     const SMDS_MeshElement* elem = *itElem;
4594     aTypeE = elem->GetType();
4595     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4596       continue;
4597
4598     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4599     newNodesItVec.reserve( elem->NbNodes() );
4600
4601     // loop on elem nodes
4602     int nodeIndex = -1;
4603     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4604     while ( itN->more() )
4605     {
4606       ++nodeIndex;
4607       // check if a node has been already processed
4608       const SMDS_MeshNode* node =
4609         static_cast<const SMDS_MeshNode*>( itN->next() );
4610       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4611       if ( nIt == mapNewNodes.end() ) {
4612         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4613         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4614
4615         // make new nodes
4616         aX = node->X();  aY = node->Y(); aZ = node->Z();
4617
4618         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4619         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4620         gp_Ax1 anAx1, anAxT1T0;
4621         gp_Dir aDT1x, aDT0x, aDT1T0;
4622
4623         aTolAng=1.e-4;
4624
4625         aV0x = aV0;
4626         aPN0.SetCoord(aX, aY, aZ);
4627
4628         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4629         aP0x = aPP0.Pnt();
4630         aDT0x= aPP0.Tangent();
4631         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4632
4633         for ( j = 1; j < aNbTP; ++j ) {
4634           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4635           aP1x = aPP1.Pnt();
4636           aDT1x = aPP1.Tangent();
4637           aAngle1x = aPP1.Angle();
4638
4639           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4640           // Translation
4641           gp_Vec aV01x( aP0x, aP1x );
4642           aTrsf.SetTranslation( aV01x );
4643
4644           // traslated point
4645           aV1x = aV0x.Transformed( aTrsf );
4646           aPN1 = aPN0.Transformed( aTrsf );
4647
4648           // rotation 1 [ T1,T0 ]
4649           aAngleT1T0=-aDT1x.Angle( aDT0x );
4650           if (fabs(aAngleT1T0) > aTolAng) {
4651             aDT1T0=aDT1x^aDT0x;
4652             anAxT1T0.SetLocation( aV1x );
4653             anAxT1T0.SetDirection( aDT1T0 );
4654             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4655
4656             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4657           }
4658
4659           // rotation 2
4660           if ( theHasAngles ) {
4661             anAx1.SetLocation( aV1x );
4662             anAx1.SetDirection( aDT1x );
4663             aTrsfRot.SetRotation( anAx1, aAngle1x );
4664
4665             aPN1 = aPN1.Transformed( aTrsfRot );
4666           }
4667
4668           // make new node
4669           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4670             // create additional node
4671             double x = ( aPN1.X() + aPN0.X() )/2.;
4672             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4673             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4674             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4675             myLastCreatedNodes.Append(newNode);
4676             srcNodes.Append( node );
4677             listNewNodes.push_back( newNode );
4678           }
4679           aX = aPN1.X();
4680           aY = aPN1.Y();
4681           aZ = aPN1.Z();
4682           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4683           myLastCreatedNodes.Append(newNode);
4684           srcNodes.Append( node );
4685           listNewNodes.push_back( newNode );
4686
4687           aPN0 = aPN1;
4688           aP0x = aP1x;
4689           aV0x = aV1x;
4690           aDT0x = aDT1x;
4691         }
4692       }
4693
4694       else {
4695         // if current elem is quadratic and current node is not medium
4696         // we have to check - may be it is needed to insert additional nodes
4697         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4698           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4699           if(listNewNodes.size()==aNbTP-1) {
4700             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4701             gp_XYZ P(node->X(), node->Y(), node->Z());
4702             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4703             int i;
4704             for(i=0; i<aNbTP-1; i++) {
4705               const SMDS_MeshNode* N = *it;
4706               double x = ( N->X() + P.X() )/2.;
4707               double y = ( N->Y() + P.Y() )/2.;
4708               double z = ( N->Z() + P.Z() )/2.;
4709               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4710               srcNodes.Append( node );
4711               myLastCreatedNodes.Append(newN);
4712               aNodes[2*i] = newN;
4713               aNodes[2*i+1] = N;
4714               P = gp_XYZ(N->X(),N->Y(),N->Z());
4715             }
4716             listNewNodes.clear();
4717             for(i=0; i<2*(aNbTP-1); i++) {
4718               listNewNodes.push_back(aNodes[i]);
4719             }
4720           }
4721         }
4722       }
4723
4724       newNodesItVec.push_back( nIt );
4725     }
4726     // make new elements
4727     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4728     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
4729     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4730   }
4731
4732   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4733
4734   if ( theMakeGroups )
4735     generateGroups( srcNodes, srcElems, "extruded");
4736
4737   return EXTR_OK;
4738 }
4739
4740
4741 //=======================================================================
4742 //function : LinearAngleVariation
4743 //purpose  : auxilary for ExtrusionAlongTrack
4744 //=======================================================================
4745 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4746                                             list<double>& Angles)
4747 {
4748   int nbAngles = Angles.size();
4749   if( nbSteps > nbAngles ) {
4750     vector<double> theAngles(nbAngles);
4751     list<double>::iterator it = Angles.begin();
4752     int i = -1;
4753     for(; it!=Angles.end(); it++) {
4754       i++;
4755       theAngles[i] = (*it);
4756     }
4757     list<double> res;
4758     double rAn2St = double( nbAngles ) / double( nbSteps );
4759     double angPrev = 0, angle;
4760     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4761       double angCur = rAn2St * ( iSt+1 );
4762       double angCurFloor  = floor( angCur );
4763       double angPrevFloor = floor( angPrev );
4764       if ( angPrevFloor == angCurFloor )
4765         angle = rAn2St * theAngles[ int( angCurFloor ) ];
4766       else {
4767         int iP = int( angPrevFloor );
4768         double angPrevCeil = ceil(angPrev);
4769         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4770
4771         int iC = int( angCurFloor );
4772         if ( iC < nbAngles )
4773           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4774
4775         iP = int( angPrevCeil );
4776         while ( iC-- > iP )
4777           angle += theAngles[ iC ];
4778       }
4779       res.push_back(angle);
4780       angPrev = angCur;
4781     }
4782     Angles.clear();
4783     it = res.begin();
4784     for(; it!=res.end(); it++)
4785       Angles.push_back( *it );
4786   }
4787 }
4788
4789
4790 //=======================================================================
4791 //function : Transform
4792 //purpose  :
4793 //=======================================================================
4794
4795 SMESH_MeshEditor::PGroupIDs
4796 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4797                              const gp_Trsf&     theTrsf,
4798                              const bool         theCopy,
4799                              const bool         theMakeGroups,
4800                              SMESH_Mesh*        theTargetMesh)
4801 {
4802   myLastCreatedElems.Clear();
4803   myLastCreatedNodes.Clear();
4804
4805   bool needReverse = false;
4806   string groupPostfix;
4807   switch ( theTrsf.Form() ) {
4808   case gp_PntMirror:
4809   case gp_Ax1Mirror:
4810   case gp_Ax2Mirror:
4811     needReverse = true;
4812     groupPostfix = "mirrored";
4813     break;
4814   case gp_Rotation:
4815     groupPostfix = "rotated";
4816     break;
4817   case gp_Translation:
4818     groupPostfix = "translated";
4819     break;
4820   case gp_Scale:
4821     groupPostfix = "scaled";
4822     break;
4823   default:
4824     needReverse = false;
4825     groupPostfix = "transformed";
4826   }
4827
4828   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4829   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4830   SMESHDS_Mesh* aMesh    = GetMeshDS();
4831
4832
4833   // map old node to new one
4834   TNodeNodeMap nodeMap;
4835
4836   // elements sharing moved nodes; those of them which have all
4837   // nodes mirrored but are not in theElems are to be reversed
4838   TIDSortedElemSet inverseElemSet;
4839
4840   // source elements for each generated one
4841   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4842
4843   // loop on theElems
4844   TIDSortedElemSet::iterator itElem;
4845   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4846     const SMDS_MeshElement* elem = *itElem;
4847     if ( !elem )
4848       continue;
4849
4850     // loop on elem nodes
4851     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4852     while ( itN->more() ) {
4853
4854       // check if a node has been already transformed
4855       const SMDS_MeshNode* node = cast2Node( itN->next() );
4856       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4857         nodeMap.insert( make_pair ( node, node ));
4858       if ( !n2n_isnew.second )
4859         continue;
4860
4861       double coord[3];
4862       coord[0] = node->X();
4863       coord[1] = node->Y();
4864       coord[2] = node->Z();
4865       theTrsf.Transforms( coord[0], coord[1], coord[2] );
4866       if ( theTargetMesh ) {
4867         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4868         n2n_isnew.first->second = newNode;
4869         myLastCreatedNodes.Append(newNode);
4870         srcNodes.Append( node );
4871       }
4872       else if ( theCopy ) {
4873         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4874         n2n_isnew.first->second = newNode;
4875         myLastCreatedNodes.Append(newNode);
4876         srcNodes.Append( node );
4877       }
4878       else {
4879         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4880         // node position on shape becomes invalid
4881         const_cast< SMDS_MeshNode* > ( node )->SetPosition
4882           ( SMDS_SpacePosition::originSpacePosition() );
4883       }
4884
4885       // keep inverse elements
4886       if ( !theCopy && !theTargetMesh && needReverse ) {
4887         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4888         while ( invElemIt->more() ) {
4889           const SMDS_MeshElement* iel = invElemIt->next();
4890           inverseElemSet.insert( iel );
4891         }
4892       }
4893     }
4894   }
4895
4896   // either create new elements or reverse mirrored ones
4897   if ( !theCopy && !needReverse && !theTargetMesh )
4898     return PGroupIDs();
4899
4900   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4901   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4902     theElems.insert( *invElemIt );
4903
4904   // replicate or reverse elements
4905
4906   enum {
4907     REV_TETRA   = 0,  //  = nbNodes - 4
4908     REV_PYRAMID = 1,  //  = nbNodes - 4
4909     REV_PENTA   = 2,  //  = nbNodes - 4
4910     REV_FACE    = 3,
4911     REV_HEXA    = 4,  //  = nbNodes - 4
4912     FORWARD     = 5
4913   };
4914   int index[][8] = {
4915     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
4916     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
4917     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
4918     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
4919     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
4920     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
4921   };
4922
4923   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4924   {
4925     const SMDS_MeshElement* elem = *itElem;
4926     if ( !elem || elem->GetType() == SMDSAbs_Node )
4927       continue;
4928
4929     int nbNodes = elem->NbNodes();
4930     int elemType = elem->GetType();
4931
4932     if (elem->IsPoly()) {
4933       // Polygon or Polyhedral Volume
4934       switch ( elemType ) {
4935       case SMDSAbs_Face:
4936         {
4937           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4938           int iNode = 0;
4939           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4940           while (itN->more()) {
4941             const SMDS_MeshNode* node =
4942               static_cast<const SMDS_MeshNode*>(itN->next());
4943             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4944             if (nodeMapIt == nodeMap.end())
4945               break; // not all nodes transformed
4946             if (needReverse) {
4947               // reverse mirrored faces and volumes
4948               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4949             } else {
4950               poly_nodes[iNode] = (*nodeMapIt).second;
4951             }
4952             iNode++;
4953           }
4954           if ( iNode != nbNodes )
4955             continue; // not all nodes transformed
4956
4957           if ( theTargetMesh ) {
4958             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4959             srcElems.Append( elem );
4960           }
4961           else if ( theCopy ) {
4962             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4963             srcElems.Append( elem );
4964           }
4965           else {
4966             aMesh->ChangePolygonNodes(elem, poly_nodes);
4967           }
4968         }
4969         break;
4970       case SMDSAbs_Volume:
4971         {
4972           // ATTENTION: Reversing is not yet done!!!
4973           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4974             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4975           if (!aPolyedre) {
4976             MESSAGE("Warning: bad volumic element");
4977             continue;
4978           }
4979
4980           vector<const SMDS_MeshNode*> poly_nodes;
4981           vector<int> quantities;
4982
4983           bool allTransformed = true;
4984           int nbFaces = aPolyedre->NbFaces();
4985           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4986             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4987             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4988               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4989               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4990               if (nodeMapIt == nodeMap.end()) {
4991                 allTransformed = false; // not all nodes transformed
4992               } else {
4993                 poly_nodes.push_back((*nodeMapIt).second);
4994               }
4995             }
4996             quantities.push_back(nbFaceNodes);
4997           }
4998           if ( !allTransformed )
4999             continue; // not all nodes transformed
5000
5001           if ( theTargetMesh ) {
5002             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5003             srcElems.Append( elem );
5004           }
5005           else if ( theCopy ) {
5006             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5007             srcElems.Append( elem );
5008           }
5009           else {
5010             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5011           }
5012         }
5013         break;
5014       default:;
5015       }
5016       continue;
5017     }
5018
5019     // Regular elements
5020     int* i = index[ FORWARD ];
5021     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5022       if ( elemType == SMDSAbs_Face )
5023         i = index[ REV_FACE ];
5024       else
5025         i = index[ nbNodes - 4 ];
5026
5027     if(elem->IsQuadratic()) {
5028       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5029       i = anIds;
5030       if(needReverse) {
5031         if(nbNodes==3) { // quadratic edge
5032           static int anIds[] = {1,0,2};
5033           i = anIds;
5034         }
5035         else if(nbNodes==6) { // quadratic triangle
5036           static int anIds[] = {0,2,1,5,4,3};
5037           i = anIds;
5038         }
5039         else if(nbNodes==8) { // quadratic quadrangle
5040           static int anIds[] = {0,3,2,1,7,6,5,4};
5041           i = anIds;
5042         }
5043         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5044           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5045           i = anIds;
5046         }
5047         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5048           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5049           i = anIds;
5050         }
5051         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5052           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5053           i = anIds;
5054         }
5055         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5056           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5057           i = anIds;
5058         }
5059       }
5060     }
5061
5062     // find transformed nodes
5063     vector<const SMDS_MeshNode*> nodes(nbNodes);
5064     int iNode = 0;
5065     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5066     while ( itN->more() ) {
5067       const SMDS_MeshNode* node =
5068         static_cast<const SMDS_MeshNode*>( itN->next() );
5069       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5070       if ( nodeMapIt == nodeMap.end() )
5071         break; // not all nodes transformed
5072       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5073     }
5074     if ( iNode != nbNodes )
5075       continue; // not all nodes transformed
5076
5077     if ( theTargetMesh ) {
5078       if ( SMDS_MeshElement* copy =
5079            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5080         myLastCreatedElems.Append( copy );
5081         srcElems.Append( elem );
5082       }
5083     }
5084     else if ( theCopy ) {
5085       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5086         myLastCreatedElems.Append( copy );
5087         srcElems.Append( elem );
5088       }
5089     }
5090     else {
5091       // reverse element as it was reversed by transformation
5092       if ( nbNodes > 2 )
5093         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5094     }
5095   }
5096
5097   PGroupIDs newGroupIDs;
5098
5099   if ( theMakeGroups && theCopy ||
5100        theMakeGroups && theTargetMesh )
5101     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5102
5103   return newGroupIDs;
5104 }
5105
5106
5107 //=======================================================================
5108 //function : Scale
5109 //purpose  :
5110 //=======================================================================
5111
5112 SMESH_MeshEditor::PGroupIDs
5113 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5114                          const gp_Pnt&            thePoint,
5115                          const std::list<double>& theScaleFact,
5116                          const bool         theCopy,
5117                          const bool         theMakeGroups,
5118                          SMESH_Mesh*        theTargetMesh)
5119 {
5120   myLastCreatedElems.Clear();
5121   myLastCreatedNodes.Clear();
5122
5123   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5124   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5125   SMESHDS_Mesh* aMesh    = GetMeshDS();
5126
5127   double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5128   std::list<double>::const_iterator itS = theScaleFact.begin();
5129   scaleX = (*itS);
5130   if(theScaleFact.size()==1) {
5131     scaleY = (*itS);
5132     scaleZ= (*itS);
5133   }
5134   if(theScaleFact.size()==2) {
5135     itS++;
5136     scaleY = (*itS);
5137     scaleZ= (*itS);
5138   }
5139   if(theScaleFact.size()>2) {
5140     itS++;
5141     scaleY = (*itS);
5142     itS++;
5143     scaleZ= (*itS);
5144   }
5145   
5146   // map old node to new one
5147   TNodeNodeMap nodeMap;
5148
5149   // elements sharing moved nodes; those of them which have all
5150   // nodes mirrored but are not in theElems are to be reversed
5151   TIDSortedElemSet inverseElemSet;
5152
5153   // source elements for each generated one
5154   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5155
5156   // loop on theElems
5157   TIDSortedElemSet::iterator itElem;
5158   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5159     const SMDS_MeshElement* elem = *itElem;
5160     if ( !elem )
5161       continue;
5162
5163     // loop on elem nodes
5164     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5165     while ( itN->more() ) {
5166
5167       // check if a node has been already transformed
5168       const SMDS_MeshNode* node = cast2Node( itN->next() );
5169       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5170         nodeMap.insert( make_pair ( node, node ));
5171       if ( !n2n_isnew.second )
5172         continue;
5173
5174       //double coord[3];
5175       //coord[0] = node->X();
5176       //coord[1] = node->Y();
5177       //coord[2] = node->Z();
5178       //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5179       double dx = (node->X() - thePoint.X()) * scaleX;
5180       double dy = (node->Y() - thePoint.Y()) * scaleY;
5181       double dz = (node->Z() - thePoint.Z()) * scaleZ;
5182       if ( theTargetMesh ) {
5183         //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5184         const SMDS_MeshNode * newNode =
5185           aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5186         n2n_isnew.first->second = newNode;
5187         myLastCreatedNodes.Append(newNode);
5188         srcNodes.Append( node );
5189       }
5190       else if ( theCopy ) {
5191         //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5192         const SMDS_MeshNode * newNode =
5193           aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5194         n2n_isnew.first->second = newNode;
5195         myLastCreatedNodes.Append(newNode);
5196         srcNodes.Append( node );
5197       }
5198       else {
5199         //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5200         aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
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   if ( !theCopy && !theTargetMesh )
5220     return PGroupIDs();
5221
5222   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5223   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5224     theElems.insert( *invElemIt );
5225
5226   // replicate or reverse elements
5227
5228   enum {
5229     REV_TETRA   = 0,  //  = nbNodes - 4
5230     REV_PYRAMID = 1,  //  = nbNodes - 4
5231     REV_PENTA   = 2,  //  = nbNodes - 4
5232     REV_FACE    = 3,
5233     REV_HEXA    = 4,  //  = nbNodes - 4
5234     FORWARD     = 5
5235   };
5236   int index[][8] = {
5237     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5238     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5239     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5240     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5241     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5242     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5243   };
5244
5245   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5246   {
5247     const SMDS_MeshElement* elem = *itElem;
5248     if ( !elem || elem->GetType() == SMDSAbs_Node )
5249       continue;
5250
5251     int nbNodes = elem->NbNodes();
5252     int elemType = elem->GetType();
5253
5254     if (elem->IsPoly()) {
5255       // Polygon or Polyhedral Volume
5256       switch ( elemType ) {
5257       case SMDSAbs_Face:
5258         {
5259           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5260           int iNode = 0;
5261           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5262           while (itN->more()) {
5263             const SMDS_MeshNode* node =
5264               static_cast<const SMDS_MeshNode*>(itN->next());
5265             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5266             if (nodeMapIt == nodeMap.end())
5267               break; // not all nodes transformed
5268             //if (needReverse) {
5269             //  // reverse mirrored faces and volumes
5270             //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5271             //} else {
5272             poly_nodes[iNode] = (*nodeMapIt).second;
5273             //}
5274             iNode++;
5275           }
5276           if ( iNode != nbNodes )
5277             continue; // not all nodes transformed
5278
5279           if ( theTargetMesh ) {
5280             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5281             srcElems.Append( elem );
5282           }
5283           else if ( theCopy ) {
5284             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5285             srcElems.Append( elem );
5286           }
5287           else {
5288             aMesh->ChangePolygonNodes(elem, poly_nodes);
5289           }
5290         }
5291         break;
5292       case SMDSAbs_Volume:
5293         {
5294           // ATTENTION: Reversing is not yet done!!!
5295           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5296             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5297           if (!aPolyedre) {
5298             MESSAGE("Warning: bad volumic element");
5299             continue;
5300           }
5301
5302           vector<const SMDS_MeshNode*> poly_nodes;
5303           vector<int> quantities;
5304
5305           bool allTransformed = true;
5306           int nbFaces = aPolyedre->NbFaces();
5307           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5308             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5309             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5310               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5311               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5312               if (nodeMapIt == nodeMap.end()) {
5313                 allTransformed = false; // not all nodes transformed
5314               } else {
5315                 poly_nodes.push_back((*nodeMapIt).second);
5316               }
5317             }
5318             quantities.push_back(nbFaceNodes);
5319           }
5320           if ( !allTransformed )
5321             continue; // not all nodes transformed
5322
5323           if ( theTargetMesh ) {
5324             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5325             srcElems.Append( elem );
5326           }
5327           else if ( theCopy ) {
5328             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5329             srcElems.Append( elem );
5330           }
5331           else {
5332             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5333           }
5334         }
5335         break;
5336       default:;
5337       }
5338       continue;
5339     }
5340
5341     // Regular elements
5342     int* i = index[ FORWARD ];
5343     //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5344     //  if ( elemType == SMDSAbs_Face )
5345     //    i = index[ REV_FACE ];
5346     //  else
5347     //    i = index[ nbNodes - 4 ];
5348
5349     if(elem->IsQuadratic()) {
5350       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5351       i = anIds;
5352       //if(needReverse) {
5353       //  if(nbNodes==3) { // quadratic edge
5354       //    static int anIds[] = {1,0,2};
5355       //    i = anIds;
5356       //  }
5357       //  else if(nbNodes==6) { // quadratic triangle
5358       //    static int anIds[] = {0,2,1,5,4,3};
5359       //    i = anIds;
5360       //  }
5361       //  else if(nbNodes==8) { // quadratic quadrangle
5362       //    static int anIds[] = {0,3,2,1,7,6,5,4};
5363       //    i = anIds;
5364       //  }
5365       //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5366       //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5367       //    i = anIds;
5368       //  }
5369       //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5370       //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5371       //    i = anIds;
5372       //  }
5373       //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5374       //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5375       //    i = anIds;
5376       //  }
5377       //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5378       //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5379       //    i = anIds;
5380       //  }
5381       //}
5382     }
5383
5384     // find transformed nodes
5385     vector<const SMDS_MeshNode*> nodes(nbNodes);
5386     int iNode = 0;
5387     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5388     while ( itN->more() ) {
5389       const SMDS_MeshNode* node =
5390         static_cast<const SMDS_MeshNode*>( itN->next() );
5391       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5392       if ( nodeMapIt == nodeMap.end() )
5393         break; // not all nodes transformed
5394       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5395     }
5396     if ( iNode != nbNodes )
5397       continue; // not all nodes transformed
5398
5399     if ( theTargetMesh ) {
5400       if ( SMDS_MeshElement* copy =
5401            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5402         myLastCreatedElems.Append( copy );
5403         srcElems.Append( elem );
5404       }
5405     }
5406     else if ( theCopy ) {
5407       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5408         myLastCreatedElems.Append( copy );
5409         srcElems.Append( elem );
5410       }
5411     }
5412     else {
5413       // reverse element as it was reversed by transformation
5414       if ( nbNodes > 2 )
5415         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5416     }
5417   }
5418
5419   PGroupIDs newGroupIDs;
5420
5421   if ( theMakeGroups && theCopy ||
5422        theMakeGroups && theTargetMesh ) {
5423     string groupPostfix = "scaled";
5424     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5425   }
5426
5427   return newGroupIDs;
5428 }
5429
5430
5431 //=======================================================================
5432 /*!
5433  * \brief Create groups of elements made during transformation
5434  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5435  * \param elemGens - elements making corresponding myLastCreatedElems
5436  * \param postfix - to append to names of new groups
5437  */
5438 //=======================================================================
5439
5440 SMESH_MeshEditor::PGroupIDs
5441 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5442                                  const SMESH_SequenceOfElemPtr& elemGens,
5443                                  const std::string&             postfix,
5444                                  SMESH_Mesh*                    targetMesh)
5445 {
5446   PGroupIDs newGroupIDs( new list<int> );
5447   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5448
5449   // Sort existing groups by types and collect their names
5450
5451   // to store an old group and a generated new one
5452   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5453   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5454   // group names
5455   set< string > groupNames;
5456   //
5457   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5458   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5459   while ( groupIt->more() ) {
5460     SMESH_Group * group = groupIt->next();
5461     if ( !group ) continue;
5462     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5463     if ( !groupDS || groupDS->IsEmpty() ) continue;
5464     groupNames.insert( group->GetName() );
5465     groupDS->SetStoreName( group->GetName() );
5466     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5467   }
5468
5469   // Groups creation
5470
5471   // loop on nodes and elements
5472   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5473   {
5474     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5475     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5476     if ( gens.Length() != elems.Length() )
5477       throw SALOME_Exception(LOCALIZED("invalid args"));
5478
5479     // loop on created elements
5480     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5481     {
5482       const SMDS_MeshElement* sourceElem = gens( iElem );
5483       if ( !sourceElem ) {
5484         MESSAGE("generateGroups(): NULL source element");
5485         continue;
5486       }
5487       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5488       if ( groupsOldNew.empty() ) {
5489         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5490           ++iElem; // skip all elements made by sourceElem
5491         continue;
5492       }
5493       // collect all elements made by sourceElem
5494       list< const SMDS_MeshElement* > resultElems;
5495       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5496         if ( resElem != sourceElem )
5497           resultElems.push_back( resElem );
5498       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5499         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5500           if ( resElem != sourceElem )
5501             resultElems.push_back( resElem );
5502       // do not generate element groups from node ones
5503       if ( sourceElem->GetType() == SMDSAbs_Node &&
5504            elems( iElem )->GetType() != SMDSAbs_Node )
5505         continue;
5506
5507       // add resultElems to groups made by ones the sourceElem belongs to
5508       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5509       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5510       {
5511         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5512         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5513         {
5514           SMDS_MeshGroup* & newGroup = gOldNew->second;
5515           if ( !newGroup )// create a new group
5516           {
5517             // make a name
5518             string name = oldGroup->GetStoreName();
5519             if ( !targetMesh ) {
5520               name += "_";
5521               name += postfix;
5522               int nb = 0;
5523               while ( !groupNames.insert( name ).second ) // name exists
5524               {
5525                 if ( nb == 0 ) {
5526                   name += "_1";
5527                 }
5528                 else {
5529                   TCollection_AsciiString nbStr(nb+1);
5530                   name.resize( name.rfind('_')+1 );
5531                   name += nbStr.ToCString();
5532                 }
5533                 ++nb;
5534               }
5535             }
5536             // make a group
5537             int id;
5538             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5539                                                  name.c_str(), id );
5540             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5541             newGroup = & groupDS->SMDSGroup();
5542             newGroupIDs->push_back( id );
5543           }
5544
5545           // fill in a new group
5546           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5547           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5548             newGroup->Add( *resElemIt );
5549         }
5550       }
5551     } // loop on created elements
5552   }// loop on nodes and elements
5553
5554   return newGroupIDs;
5555 }
5556
5557 //================================================================================
5558 /*!
5559  * \brief Return list of group of nodes close to each other within theTolerance
5560  *        Search among theNodes or in the whole mesh if theNodes is empty using
5561  *        an Octree algorithm
5562  */
5563 //================================================================================
5564
5565 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5566                                             const double                theTolerance,
5567                                             TListOfListOfNodes &        theGroupsOfNodes)
5568 {
5569   myLastCreatedElems.Clear();
5570   myLastCreatedNodes.Clear();
5571
5572   set<const SMDS_MeshNode*> nodes;
5573   if ( theNodes.empty() )
5574   { // get all nodes in the mesh
5575     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5576     while ( nIt->more() )
5577       nodes.insert( nodes.end(),nIt->next());
5578   }
5579   else
5580     nodes=theNodes;
5581
5582   SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5583 }
5584
5585
5586 //=======================================================================
5587 /*!
5588  * \brief Implementation of search for the node closest to point
5589  */
5590 //=======================================================================
5591
5592 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5593 {
5594   //---------------------------------------------------------------------
5595   /*!
5596    * \brief Constructor
5597    */
5598   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5599   {
5600     myMesh = ( SMESHDS_Mesh* ) theMesh;
5601
5602     set<const SMDS_MeshNode*> nodes;
5603     if ( theMesh ) {
5604       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5605       while ( nIt->more() )
5606         nodes.insert( nodes.end(), nIt->next() );
5607     }
5608     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5609
5610     // get max size of a leaf box
5611     SMESH_OctreeNode* tree = myOctreeNode;
5612     while ( !tree->isLeaf() )
5613     {
5614       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5615       if ( cIt->more() )
5616         tree = cIt->next();
5617     }
5618     myHalfLeafSize = tree->maxSize() / 2.;
5619   }
5620
5621   //---------------------------------------------------------------------
5622   /*!
5623    * \brief Move node and update myOctreeNode accordingly
5624    */
5625   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5626   {
5627     myOctreeNode->UpdateByMoveNode( node, toPnt );
5628     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5629   }
5630
5631   //---------------------------------------------------------------------
5632   /*!
5633    * \brief Do it's job
5634    */
5635   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5636   {
5637     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5638     map<double, const SMDS_MeshNode*> dist2Nodes;
5639     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5640     if ( !dist2Nodes.empty() )
5641       return dist2Nodes.begin()->second;
5642     list<const SMDS_MeshNode*> nodes;
5643     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5644
5645     double minSqDist = DBL_MAX;
5646     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5647     {
5648       // sort leafs by their distance from thePnt
5649       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5650       TDistTreeMap treeMap;
5651       list< SMESH_OctreeNode* > treeList;
5652       list< SMESH_OctreeNode* >::iterator trIt;
5653       treeList.push_back( myOctreeNode );
5654
5655       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5656       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5657       {
5658         SMESH_OctreeNode* tree = *trIt;
5659         if ( !tree->isLeaf() ) // put children to the queue
5660         {
5661           if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5662           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5663           while ( cIt->more() )
5664             treeList.push_back( cIt->next() );
5665         }
5666         else if ( tree->NbNodes() ) // put a tree to the treeMap
5667         {
5668           const Bnd_B3d& box = tree->getBox();
5669           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5670           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5671           if ( !it_in.second ) // not unique distance to box center
5672             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5673         }
5674       }
5675       // find distance after which there is no sense to check tree's
5676       double sqLimit = DBL_MAX;
5677       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5678       if ( treeMap.size() > 5 ) {
5679         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5680         const Bnd_B3d& box = closestTree->getBox();
5681         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5682         sqLimit = limit * limit;
5683       }
5684       // get all nodes from trees
5685       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5686         if ( sqDist_tree->first > sqLimit )
5687           break;
5688         SMESH_OctreeNode* tree = sqDist_tree->second;
5689         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5690       }
5691     }
5692     // find closest among nodes
5693     minSqDist = DBL_MAX;
5694     const SMDS_MeshNode* closestNode = 0;
5695     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5696     for ( ; nIt != nodes.end(); ++nIt ) {
5697       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5698       if ( minSqDist > sqDist ) {
5699         closestNode = *nIt;
5700         minSqDist = sqDist;
5701       }
5702     }
5703     return closestNode;
5704   }
5705
5706   //---------------------------------------------------------------------
5707   /*!
5708    * \brief Destructor
5709    */
5710   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5711
5712   //---------------------------------------------------------------------
5713   /*!
5714    * \brief Return the node tree
5715    */
5716   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5717
5718 private:
5719   SMESH_OctreeNode* myOctreeNode;
5720   SMESHDS_Mesh*     myMesh;
5721   double            myHalfLeafSize; // max size of a leaf box
5722 };
5723
5724 //=======================================================================
5725 /*!
5726  * \brief Return SMESH_NodeSearcher
5727  */
5728 //=======================================================================
5729
5730 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
5731 {
5732   return new SMESH_NodeSearcherImpl( GetMeshDS() );
5733 }
5734
5735 // ========================================================================
5736 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5737 {
5738   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5739   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5740   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
5741
5742   //=======================================================================
5743   /*!
5744    * \brief Octal tree of bounding boxes of elements
5745    */
5746   //=======================================================================
5747
5748   class ElementBndBoxTree : public SMESH_Octree
5749   {
5750   public:
5751
5752     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5753     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5754     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5755     ~ElementBndBoxTree();
5756
5757   protected:
5758     ElementBndBoxTree() {}
5759     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5760     void buildChildrenData();
5761     Bnd_B3d* buildRootBox();
5762   private:
5763     //!< Bounding box of element
5764     struct ElementBox : public Bnd_B3d
5765     {
5766       const SMDS_MeshElement* _element;
5767       int                     _refCount; // an ElementBox can be included in several tree branches
5768       ElementBox(const SMDS_MeshElement* elem);
5769     };
5770     vector< ElementBox* > _elements;
5771   };
5772
5773   //================================================================================
5774   /*!
5775    * \brief ElementBndBoxTree creation
5776    */
5777   //================================================================================
5778
5779   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5780     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5781   {
5782     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5783     _elements.reserve( nbElems );
5784
5785     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5786     while ( elemIt->more() )
5787       _elements.push_back( new ElementBox( elemIt->next() ));
5788
5789     if ( _elements.size() > MaxNbElemsInLeaf )
5790       compute();
5791     else
5792       myIsLeaf = true;
5793   }
5794
5795   //================================================================================
5796   /*!
5797    * \brief Destructor
5798    */
5799   //================================================================================
5800
5801   ElementBndBoxTree::~ElementBndBoxTree()
5802   {
5803     for ( int i = 0; i < _elements.size(); ++i )
5804       if ( --_elements[i]->_refCount <= 0 )
5805         delete _elements[i];
5806   }
5807
5808   //================================================================================
5809   /*!
5810    * \brief Return the maximal box
5811    */
5812   //================================================================================
5813
5814   Bnd_B3d* ElementBndBoxTree::buildRootBox()
5815   {
5816     Bnd_B3d* box = new Bnd_B3d;
5817     for ( int i = 0; i < _elements.size(); ++i )
5818       box->Add( *_elements[i] );
5819     return box;
5820   }
5821
5822   //================================================================================
5823   /*!
5824    * \brief Redistrubute element boxes among children
5825    */
5826   //================================================================================
5827
5828   void ElementBndBoxTree::buildChildrenData()
5829   {
5830     for ( int i = 0; i < _elements.size(); ++i )
5831     {
5832       for (int j = 0; j < 8; j++)
5833       {
5834         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5835         {
5836           _elements[i]->_refCount++;
5837           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5838         }
5839       }
5840       _elements[i]->_refCount--;
5841     }
5842     _elements.clear();
5843
5844     for (int j = 0; j < 8; j++)
5845     {
5846       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5847       if ( child->_elements.size() <= MaxNbElemsInLeaf )
5848         child->myIsLeaf = true;
5849
5850       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5851         child->_elements.resize( child->_elements.size() ); // compact
5852     }
5853   }
5854
5855   //================================================================================
5856   /*!
5857    * \brief Return elements which can include the point
5858    */
5859   //================================================================================
5860
5861   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
5862                                                 TIDSortedElemSet& foundElems)
5863   {
5864     if ( level() && getBox().IsOut( point.XYZ() ))
5865       return;
5866
5867     if ( isLeaf() )
5868     {
5869       for ( int i = 0; i < _elements.size(); ++i )
5870         if ( !_elements[i]->IsOut( point.XYZ() ))
5871           foundElems.insert( _elements[i]->_element );
5872     }
5873     else
5874     {
5875       for (int i = 0; i < 8; i++)
5876         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5877     }
5878   }
5879
5880   //================================================================================
5881   /*!
5882    * \brief Return elements which can be intersected by the line
5883    */
5884   //================================================================================
5885
5886   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
5887                                                TIDSortedElemSet& foundElems)
5888   {
5889     if ( level() && getBox().IsOut( line ))
5890       return;
5891
5892     if ( isLeaf() )
5893     {
5894       for ( int i = 0; i < _elements.size(); ++i )
5895         if ( !_elements[i]->IsOut( line ))
5896           foundElems.insert( _elements[i]->_element );
5897     }
5898     else
5899     {
5900       for (int i = 0; i < 8; i++)
5901         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
5902     }
5903   }
5904
5905   //================================================================================
5906   /*!
5907    * \brief Construct the element box
5908    */
5909   //================================================================================
5910
5911   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5912   {
5913     _element  = elem;
5914     _refCount = 1;
5915     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5916     while ( nIt->more() )
5917       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
5918     Enlarge( NodeRadius );
5919   }
5920
5921 } // namespace
5922
5923 //=======================================================================
5924 /*!
5925  * \brief Implementation of search for the elements by point and
5926  *        of classification of point in 2D mesh
5927  */
5928 //=======================================================================
5929
5930 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5931 {
5932   SMESHDS_Mesh*                _mesh;
5933   ElementBndBoxTree*           _ebbTree;
5934   SMESH_NodeSearcherImpl*      _nodeSearcher;
5935   SMDSAbs_ElementType          _elementType;
5936   double                       _tolerance;
5937   set<const SMDS_MeshElement*> _internalFaces;
5938
5939   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
5940     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1) {}
5941   ~SMESH_ElementSearcherImpl()
5942   {
5943     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
5944     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5945   }
5946   virtual int FindElementsByPoint(const gp_Pnt&                      point,
5947                                   SMDSAbs_ElementType                type,
5948                                   vector< const SMDS_MeshElement* >& foundElements);
5949   virtual TopAbs_State GetPointState(const gp_Pnt& point);
5950
5951   struct TInters //!< data of intersection of the line and the mesh face
5952   {
5953     const SMDS_MeshElement* _face;
5954     gp_Vec                  _faceNorm;
5955     bool                    _coincides; //!< the line lays in face plane
5956     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
5957       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
5958   };
5959   double getTolerance();
5960   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
5961                             const double tolerance, double & param);
5962   void findOuterBoundary();
5963   bool isOuterBoundary(const SMDS_MeshElement* face) const { return !_internalFaces.count(face);}
5964 };
5965
5966 //=======================================================================
5967 /*!
5968  * \brief define tolerance for search
5969  */
5970 //=======================================================================
5971
5972 double SMESH_ElementSearcherImpl::getTolerance()
5973 {
5974   if ( _tolerance < 0 )
5975   {
5976     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5977
5978     _tolerance = 0;
5979     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
5980     {
5981       double boxSize = _nodeSearcher->getTree()->maxSize();
5982       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
5983     }
5984     else if ( _ebbTree && meshInfo.NbElements() > 0 )
5985     {
5986       double boxSize = _ebbTree->maxSize();
5987       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
5988     }
5989     if ( _tolerance == 0 )
5990     {
5991       // define tolerance by size of a most complex element
5992       int complexType = SMDSAbs_Volume;
5993       while ( complexType > SMDSAbs_All &&
5994               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
5995         --complexType;
5996       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
5997
5998       double elemSize;
5999       if ( complexType == int( SMDSAbs_Node ))
6000       {
6001         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6002         elemSize = 1;
6003         if ( meshInfo.NbNodes() > 2 )
6004           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6005       }
6006       else
6007       {
6008         const SMDS_MeshElement* elem =
6009           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6010         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6011         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6012         while ( nodeIt->more() )
6013         {
6014           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6015           elemSize = max( dist, elemSize );
6016         }
6017       }
6018       _tolerance = 1e-6 * elemSize;
6019     }
6020   }
6021   return _tolerance;
6022 }
6023
6024 //================================================================================
6025 /*!
6026  * \brief Find intersection of the line and an edge of face and return parameter on line
6027  */
6028 //================================================================================
6029
6030 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6031                                                      const SMDS_MeshElement* face,
6032                                                      const double            tol,
6033                                                      double &                param)
6034 {
6035   int nbInts = 0;
6036   param = 0;
6037
6038   GeomAPI_ExtremaCurveCurve anExtCC;
6039   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6040   
6041   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6042   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6043   {
6044     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6045                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6046     anExtCC.Init( lineCurve, edge);
6047     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6048     {
6049       Quantity_Parameter pl, pe;
6050       anExtCC.LowerDistanceParameters( pl, pe );
6051       param += pl;
6052       if ( ++nbInts == 2 )
6053         break;
6054     }
6055   }
6056   if ( nbInts > 0 ) param /= nbInts;
6057   return nbInts > 0;
6058 }
6059 //================================================================================
6060 /*!
6061  * \brief Find all faces belonging to the outer boundary of mesh
6062  */
6063 //================================================================================
6064
6065 void SMESH_ElementSearcherImpl::findOuterBoundary()
6066 {
6067   
6068 }
6069
6070 //=======================================================================
6071 /*!
6072  * \brief Find elements of given type where the given point is IN or ON.
6073  *        Returns nb of found elements and elements them-selves.
6074  *
6075  * 'ALL' type means elements of any type excluding nodes and 0D elements
6076  */
6077 //=======================================================================
6078
6079 int SMESH_ElementSearcherImpl::
6080 FindElementsByPoint(const gp_Pnt&                      point,
6081                     SMDSAbs_ElementType                type,
6082                     vector< const SMDS_MeshElement* >& foundElements)
6083 {
6084   foundElements.clear();
6085
6086   double tolerance = getTolerance();
6087
6088   // =================================================================================
6089   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6090   {
6091     if ( !_nodeSearcher )
6092       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6093
6094     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6095     if ( !closeNode ) return foundElements.size();
6096
6097     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6098       return foundElements.size(); // to far from any node
6099
6100     if ( type == SMDSAbs_Node )
6101     {
6102       foundElements.push_back( closeNode );
6103     }
6104     else
6105     {
6106       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6107       while ( elemIt->more() )
6108         foundElements.push_back( elemIt->next() );
6109     }
6110   }
6111   // =================================================================================
6112   else // elements more complex than 0D
6113   {
6114     if ( !_ebbTree || _elementType != type )
6115     {
6116       if ( _ebbTree ) delete _ebbTree;
6117       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6118     }
6119     TIDSortedElemSet suspectElems;
6120     _ebbTree->getElementsNearPoint( point, suspectElems );
6121     TIDSortedElemSet::iterator elem = suspectElems.begin();
6122     for ( ; elem != suspectElems.end(); ++elem )
6123       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6124         foundElements.push_back( *elem );
6125   }
6126   return foundElements.size();
6127 }
6128
6129 //================================================================================
6130 /*!
6131  * \brief Classify the given point in the closed 2D mesh
6132  */
6133 //================================================================================
6134
6135 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6136 {
6137   double tolerance = getTolerance();
6138   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6139   {
6140     if ( _ebbTree ) delete _ebbTree;
6141     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6142   }
6143   // algo: analyse transition of a line starting at the point through mesh boundary;
6144   // try several lines, if none of attemps gives a clear answer, we give up as the
6145   // task can be too complex including internal boundaries, concave surfaces etc.
6146
6147   const int nbAxes = 3;
6148   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6149   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6150   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6151   multimap< int, int > nbInt2Axis; // to find the simplest case
6152   for ( int axis = 0; axis < nbAxes; ++axis )
6153   {
6154     gp_Ax1 lineAxis( point, axisDir[axis]);
6155     gp_Lin line    ( lineAxis );
6156
6157     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6158     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6159
6160     // Intersect faces with the line
6161
6162     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6163     TIDSortedElemSet::iterator face = suspectFaces.begin();
6164     for ( ; face != suspectFaces.end(); ++face )
6165     {
6166       // get face plane
6167       gp_XYZ fNorm;
6168       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6169       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6170
6171       // intersection
6172       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6173       if ( !intersection.IsDone() )
6174         continue;
6175       if ( intersection.IsInQuadric() )
6176       {
6177         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6178       }
6179       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6180       {
6181         gp_Pnt intersectionPoint = intersection.Point(1);
6182         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6183           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6184       }
6185     }
6186     // Analyse intersections roughly
6187
6188     int nbInter = u2inters.size();
6189     if ( nbInter == 0 )
6190       return TopAbs_OUT; 
6191
6192     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6193     if ( nbInter == 1 )
6194       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6195
6196     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6197       return TopAbs_ON;
6198
6199     if ( (f<0) == (l<0) )
6200       return TopAbs_OUT;
6201
6202     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6203     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6204     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6205       return TopAbs_IN;
6206
6207     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6208
6209   } // three attempts - loop on CS axes
6210
6211   // Analyse intersections thoroughly
6212   // We make two loops, on the first one we correctly exclude touching intersections,
6213   // on the second, we additionally just throw away intersections with small angles
6214
6215   for ( int angleCheck = 0; angleCheck < 2; ++angleCheck )
6216   {
6217     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6218     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6219     {
6220       int axis = nb_axis->second;
6221       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6222
6223       gp_Ax1 lineAxis( point, axisDir[axis]);
6224       gp_Lin line    ( lineAxis );
6225
6226       // add tangent intersections to u2inters
6227       double param;
6228       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6229       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6230         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6231           u2inters.insert(make_pair( param, *tgtInt ));
6232       tangentInters[ axis ].clear();
6233
6234       // Count intersections before and after the point excluding touching ones.
6235
6236       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6237       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6238       map< double, TInters >::iterator u_int2 = u2inters.begin(), u_int1 = u_int2++;
6239       bool ok = ! u_int1->second._coincides;
6240       while ( ok && u_int1 != u2inters.end() )
6241       {
6242         // skip intersections at the same point (if line pass through edge or node)
6243         int nbSamePnt = 0;
6244         double u = u_int1->first;
6245         while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6246         {
6247           ++nbSamePnt;
6248           ++u_int2;
6249         }
6250
6251         // skip tangent intersections
6252         int nbTgt = 0;
6253         const SMDS_MeshElement* prevFace = u_int1->second._face;
6254         while ( ok && u_int2->second._coincides )
6255         {
6256           if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6257             ok = false;
6258           else
6259           {
6260             nbTgt++;
6261             u_int2++;
6262             ok = ( u_int2 != u2inters.end() );
6263           }
6264         }
6265         if ( !ok ) break;
6266
6267         // skip intersections at the same point after tangent intersections
6268         if ( nbTgt > 0 )
6269         {
6270           double u = u_int2->first;
6271           ++u_int2;
6272           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6273           {
6274             ++nbSamePnt;
6275             ++u_int2;
6276           }
6277         }
6278
6279         bool touchingInt = false;
6280         if ( nbSamePnt + nbTgt > 0 )
6281         {
6282           double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6283           map< double, TInters >::iterator u_int = u_int1;
6284           for ( ; u_int != u_int2; ++u_int )
6285           {
6286             if ( u_int->second._coincides ) continue;
6287             double dot = u_int->second._faceNorm * line.Direction();
6288             if ( dot > maxDot ) maxDot = dot;
6289             if ( dot < minDot ) minDot = dot;
6290           }
6291           touchingInt = ( minDot*maxDot < 0 );
6292         }
6293         // throw away intersection with lower angles
6294         if ( !touchingInt && angleCheck )
6295         {
6296           const double angTol = 2 * Standard_PI180, normAng = Standard_PI / 2;
6297           double angle = u_int1->second._faceNorm.Angle( line.Direction() );
6298           touchingInt = ( fabs( angle - normAng ) < angTol );
6299         }
6300         if ( !touchingInt )
6301         {
6302           if ( u < 0 )
6303             ++nbIntBeforePoint;
6304           else
6305             ++nbIntAfterPoint;
6306
6307           if ( u < f ) f = u;
6308           if ( u > l ) l = u;
6309         }
6310
6311         u_int1 = u_int2++; // to next intersection
6312
6313       } // loop on intersections with one line
6314
6315       if ( ok )
6316       {
6317         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6318           return TopAbs_OUT; 
6319
6320         if ( nbIntBeforePoint + nbIntAfterPoint == 1 )
6321           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6322
6323         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6324           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6325
6326         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6327           return TopAbs_ON;
6328
6329         if ( (f<0) == (l<0) )
6330           return TopAbs_OUT;
6331       }
6332     } // loop on intersections of the tree lines - thorough analysis
6333   } // two attempts - with and w/o angleCheck
6334
6335   return TopAbs_UNKNOWN;
6336 }
6337
6338 //=======================================================================
6339 /*!
6340  * \brief Return SMESH_ElementSearcher
6341  */
6342 //=======================================================================
6343
6344 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6345 {
6346   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6347 }
6348
6349 //=======================================================================
6350 /*!
6351  * \brief Return true if the point is IN or ON of the element
6352  */
6353 //=======================================================================
6354
6355 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6356 {
6357   if ( element->GetType() == SMDSAbs_Volume)
6358   {
6359     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6360   }
6361
6362   // get ordered nodes
6363
6364   vector< gp_XYZ > xyz;
6365
6366   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6367   if ( element->IsQuadratic() )
6368     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6369       nodeIt = f->interlacedNodesElemIterator();
6370     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6371       nodeIt = e->interlacedNodesElemIterator();
6372
6373   while ( nodeIt->more() )
6374     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6375
6376   int i, nbNodes = element->NbNodes();
6377
6378   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6379   {
6380     // compute face normal
6381     gp_Vec faceNorm(0,0,0);
6382     xyz.push_back( xyz.front() );
6383     for ( i = 0; i < nbNodes; ++i )
6384     {
6385       gp_Vec edge1( xyz[i+1], xyz[i]);
6386       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6387       faceNorm += edge1 ^ edge2;
6388     }
6389     double normSize = faceNorm.Magnitude();
6390     if ( normSize <= tol )
6391     {
6392       // degenerated face: point is out if it is out of all face edges
6393       for ( i = 0; i < nbNodes; ++i )
6394       {
6395         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6396         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6397         SMDS_MeshEdge edge( &n1, &n2 );
6398         if ( !isOut( &edge, point, tol ))
6399           return false;
6400       }
6401       return true;
6402     }
6403     faceNorm /= normSize;
6404
6405     // check if the point lays on face plane
6406     gp_Vec n2p( xyz[0], point );
6407     if ( fabs( n2p * faceNorm ) > tol )
6408       return true; // not on face plane
6409
6410     // check if point is out of face boundary:
6411     // define it by closest transition of a ray point->infinity through face boundary
6412     // on the face plane.
6413     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6414     // to find intersections of the ray with the boundary.
6415     gp_Vec ray = n2p;
6416     gp_Vec plnNorm = ray ^ faceNorm;
6417     normSize = plnNorm.Magnitude();
6418     if ( normSize <= tol ) return false; // point coincides with the first node
6419     plnNorm /= normSize;
6420     // for each node of the face, compute its signed distance to the plane
6421     vector<double> dist( nbNodes + 1);
6422     for ( i = 0; i < nbNodes; ++i )
6423     {
6424       gp_Vec n2p( xyz[i], point );
6425       dist[i] = n2p * plnNorm;
6426     }
6427     dist.back() = dist.front();
6428     // find the closest intersection
6429     int    iClosest = -1;
6430     double rClosest, distClosest = 1e100;;
6431     gp_Pnt pClosest;
6432     for ( i = 0; i < nbNodes; ++i )
6433     {
6434       double r;
6435       if ( fabs( dist[i]) < tol )
6436         r = 0.;
6437       else if ( fabs( dist[i+1]) < tol )
6438         r = 1.;
6439       else if ( dist[i] * dist[i+1] < 0 )
6440         r = dist[i] / ( dist[i] - dist[i+1] );
6441       else
6442         continue; // no intersection
6443       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6444       gp_Vec p2int ( point, pInt);
6445       if ( p2int * ray > -tol ) // right half-space
6446       {
6447         double intDist = p2int.SquareMagnitude();
6448         if ( intDist < distClosest )
6449         {
6450           iClosest = i;
6451           rClosest = r;
6452           pClosest = pInt;
6453           distClosest = intDist;
6454         }
6455       }
6456     }
6457     if ( iClosest < 0 )
6458       return true; // no intesections - out
6459
6460     // analyse transition
6461     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6462     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6463     gp_Vec p2int ( point, pClosest );
6464     bool out = (edgeNorm * p2int) < -tol;
6465     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6466       return out;
6467
6468     // ray pass through a face node; analyze transition through an adjacent edge
6469     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6470     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6471     gp_Vec edgeAdjacent( p1, p2 );
6472     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6473     bool out2 = (edgeNorm2 * p2int) < -tol;
6474
6475     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6476     return covexCorner ? (out || out2) : (out && out2);
6477   }
6478   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6479   {
6480     // point is out of edge if it is NOT ON any straight part of edge
6481     // (we consider quadratic edge as being composed of two straight parts)
6482     for ( i = 1; i < nbNodes; ++i )
6483     {
6484       gp_Vec edge( xyz[i-1], xyz[i]);
6485       gp_Vec n1p ( xyz[i-1], point);
6486       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6487       if ( dist > tol )
6488         continue;
6489       gp_Vec n2p( xyz[i], point );
6490       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6491         continue;
6492       return false; // point is ON this part
6493     }
6494     return true;
6495   }
6496   // Node or 0D element -------------------------------------------------------------------------
6497   {
6498     gp_Vec n2p ( xyz[0], point );
6499     return n2p.Magnitude() <= tol;
6500   }
6501   return true;
6502 }
6503
6504 //=======================================================================
6505 //function : SimplifyFace
6506 //purpose  :
6507 //=======================================================================
6508 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6509                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6510                                     vector<int>&                        quantities) const
6511 {
6512   int nbNodes = faceNodes.size();
6513
6514   if (nbNodes < 3)
6515     return 0;
6516
6517   set<const SMDS_MeshNode*> nodeSet;
6518
6519   // get simple seq of nodes
6520   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6521   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6522   int iSimple = 0, nbUnique = 0;
6523
6524   simpleNodes[iSimple++] = faceNodes[0];
6525   nbUnique++;
6526   for (int iCur = 1; iCur < nbNodes; iCur++) {
6527     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6528       simpleNodes[iSimple++] = faceNodes[iCur];
6529       if (nodeSet.insert( faceNodes[iCur] ).second)
6530         nbUnique++;
6531     }
6532   }
6533   int nbSimple = iSimple;
6534   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6535     nbSimple--;
6536     iSimple--;
6537   }
6538
6539   if (nbUnique < 3)
6540     return 0;
6541
6542   // separate loops
6543   int nbNew = 0;
6544   bool foundLoop = (nbSimple > nbUnique);
6545   while (foundLoop) {
6546     foundLoop = false;
6547     set<const SMDS_MeshNode*> loopSet;
6548     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6549       const SMDS_MeshNode* n = simpleNodes[iSimple];
6550       if (!loopSet.insert( n ).second) {
6551         foundLoop = true;
6552
6553         // separate loop
6554         int iC = 0, curLast = iSimple;
6555         for (; iC < curLast; iC++) {
6556           if (simpleNodes[iC] == n) break;
6557         }
6558         int loopLen = curLast - iC;
6559         if (loopLen > 2) {
6560           // create sub-element
6561           nbNew++;
6562           quantities.push_back(loopLen);
6563           for (; iC < curLast; iC++) {
6564             poly_nodes.push_back(simpleNodes[iC]);
6565           }
6566         }
6567         // shift the rest nodes (place from the first loop position)
6568         for (iC = curLast + 1; iC < nbSimple; iC++) {
6569           simpleNodes[iC - loopLen] = simpleNodes[iC];
6570         }
6571         nbSimple -= loopLen;
6572         iSimple -= loopLen;
6573       }
6574     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6575   } // while (foundLoop)
6576
6577   if (iSimple > 2) {
6578     nbNew++;
6579     quantities.push_back(iSimple);
6580     for (int i = 0; i < iSimple; i++)
6581       poly_nodes.push_back(simpleNodes[i]);
6582   }
6583
6584   return nbNew;
6585 }
6586
6587 //=======================================================================
6588 //function : MergeNodes
6589 //purpose  : In each group, the cdr of nodes are substituted by the first one
6590 //           in all elements.
6591 //=======================================================================
6592
6593 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6594 {
6595   myLastCreatedElems.Clear();
6596   myLastCreatedNodes.Clear();
6597
6598   SMESHDS_Mesh* aMesh = GetMeshDS();
6599
6600   TNodeNodeMap nodeNodeMap; // node to replace - new node
6601   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6602   list< int > rmElemIds, rmNodeIds;
6603
6604   // Fill nodeNodeMap and elems
6605
6606   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6607   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6608     list<const SMDS_MeshNode*>& nodes = *grIt;
6609     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6610     const SMDS_MeshNode* nToKeep = *nIt;
6611     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6612       const SMDS_MeshNode* nToRemove = *nIt;
6613       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6614       if ( nToRemove != nToKeep ) {
6615         rmNodeIds.push_back( nToRemove->GetID() );
6616         AddToSameGroups( nToKeep, nToRemove, aMesh );
6617       }
6618
6619       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6620       while ( invElemIt->more() ) {
6621         const SMDS_MeshElement* elem = invElemIt->next();
6622         elems.insert(elem);
6623       }
6624     }
6625   }
6626   // Change element nodes or remove an element
6627
6628   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6629   for ( ; eIt != elems.end(); eIt++ ) {
6630     const SMDS_MeshElement* elem = *eIt;
6631     int nbNodes = elem->NbNodes();
6632     int aShapeId = FindShape( elem );
6633
6634     set<const SMDS_MeshNode*> nodeSet;
6635     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6636     int iUnique = 0, iCur = 0, nbRepl = 0;
6637     vector<int> iRepl( nbNodes );
6638
6639     // get new seq of nodes
6640     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6641     while ( itN->more() ) {
6642       const SMDS_MeshNode* n =
6643         static_cast<const SMDS_MeshNode*>( itN->next() );
6644
6645       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6646       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6647         n = (*nnIt).second;
6648         // BUG 0020185: begin
6649         {
6650           bool stopRecur = false;
6651           set<const SMDS_MeshNode*> nodesRecur;
6652           nodesRecur.insert(n);
6653           while (!stopRecur) {
6654             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6655             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6656               n = (*nnIt_i).second;
6657               if (!nodesRecur.insert(n).second) {
6658                 // error: recursive dependancy
6659                 stopRecur = true;
6660               }
6661             }
6662             else
6663               stopRecur = true;
6664           }
6665         }
6666         // BUG 0020185: end
6667         iRepl[ nbRepl++ ] = iCur;
6668       }
6669       curNodes[ iCur ] = n;
6670       bool isUnique = nodeSet.insert( n ).second;
6671       if ( isUnique )
6672         uniqueNodes[ iUnique++ ] = n;
6673       iCur++;
6674     }
6675
6676     // Analyse element topology after replacement
6677
6678     bool isOk = true;
6679     int nbUniqueNodes = nodeSet.size();
6680     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6681       // Polygons and Polyhedral volumes
6682       if (elem->IsPoly()) {
6683
6684         if (elem->GetType() == SMDSAbs_Face) {
6685           // Polygon
6686           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6687           int inode = 0;
6688           for (; inode < nbNodes; inode++) {
6689             face_nodes[inode] = curNodes[inode];
6690           }
6691
6692           vector<const SMDS_MeshNode *> polygons_nodes;
6693           vector<int> quantities;
6694           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6695
6696           if (nbNew > 0) {
6697             inode = 0;
6698             for (int iface = 0; iface < nbNew - 1; iface++) {
6699               int nbNodes = quantities[iface];
6700               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6701               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6702                 poly_nodes[ii] = polygons_nodes[inode];
6703               }
6704               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6705               myLastCreatedElems.Append(newElem);
6706               if (aShapeId)
6707                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6708             }
6709             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6710           }
6711           else {
6712             rmElemIds.push_back(elem->GetID());
6713           }
6714
6715         }
6716         else if (elem->GetType() == SMDSAbs_Volume) {
6717           // Polyhedral volume
6718           if (nbUniqueNodes < 4) {
6719             rmElemIds.push_back(elem->GetID());
6720           }
6721           else {
6722             // each face has to be analized in order to check volume validity
6723             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6724               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6725             if (aPolyedre) {
6726               int nbFaces = aPolyedre->NbFaces();
6727
6728               vector<const SMDS_MeshNode *> poly_nodes;
6729               vector<int> quantities;
6730
6731               for (int iface = 1; iface <= nbFaces; iface++) {
6732                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6733                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6734
6735                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6736                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6737                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6738                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6739                     faceNode = (*nnIt).second;
6740                   }
6741                   faceNodes[inode - 1] = faceNode;
6742                 }
6743
6744                 SimplifyFace(faceNodes, poly_nodes, quantities);
6745               }
6746
6747               if (quantities.size() > 3) {
6748                 // to be done: remove coincident faces
6749               }
6750
6751               if (quantities.size() > 3)
6752                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6753               else
6754                 rmElemIds.push_back(elem->GetID());
6755
6756             }
6757             else {
6758               rmElemIds.push_back(elem->GetID());
6759             }
6760           }
6761         }
6762         else {
6763         }
6764
6765         continue;
6766       }
6767
6768       // Regular elements
6769       switch ( nbNodes ) {
6770       case 2: ///////////////////////////////////// EDGE
6771         isOk = false; break;
6772       case 3: ///////////////////////////////////// TRIANGLE
6773         isOk = false; break;
6774       case 4:
6775         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6776           isOk = false;
6777         else { //////////////////////////////////// QUADRANGLE
6778           if ( nbUniqueNodes < 3 )
6779             isOk = false;
6780           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6781             isOk = false; // opposite nodes stick
6782         }
6783         break;
6784       case 6: ///////////////////////////////////// PENTAHEDRON
6785         if ( nbUniqueNodes == 4 ) {
6786           // ---------------------------------> tetrahedron
6787           if (nbRepl == 3 &&
6788               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6789             // all top nodes stick: reverse a bottom
6790             uniqueNodes[ 0 ] = curNodes [ 1 ];
6791             uniqueNodes[ 1 ] = curNodes [ 0 ];
6792           }
6793           else if (nbRepl == 3 &&
6794                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6795             // all bottom nodes stick: set a top before
6796             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6797             uniqueNodes[ 0 ] = curNodes [ 3 ];
6798             uniqueNodes[ 1 ] = curNodes [ 4 ];
6799             uniqueNodes[ 2 ] = curNodes [ 5 ];
6800           }
6801           else if (nbRepl == 4 &&
6802                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6803             // a lateral face turns into a line: reverse a bottom
6804             uniqueNodes[ 0 ] = curNodes [ 1 ];
6805             uniqueNodes[ 1 ] = curNodes [ 0 ];
6806           }
6807           else
6808             isOk = false;
6809         }
6810         else if ( nbUniqueNodes == 5 ) {
6811           // PENTAHEDRON --------------------> 2 tetrahedrons
6812           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6813             // a bottom node sticks with a linked top one
6814             // 1.
6815             SMDS_MeshElement* newElem =
6816               aMesh->AddVolume(curNodes[ 3 ],
6817                                curNodes[ 4 ],
6818                                curNodes[ 5 ],
6819                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6820             myLastCreatedElems.Append(newElem);
6821             if ( aShapeId )
6822               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6823             // 2. : reverse a bottom
6824             uniqueNodes[ 0 ] = curNodes [ 1 ];
6825             uniqueNodes[ 1 ] = curNodes [ 0 ];
6826             nbUniqueNodes = 4;
6827           }
6828           else
6829             isOk = false;
6830         }
6831         else
6832           isOk = false;
6833         break;
6834       case 8: {
6835         if(elem->IsQuadratic()) { // Quadratic quadrangle
6836           //   1    5    2
6837           //    +---+---+
6838           //    |       |
6839           //    |       |
6840           //   4+       +6
6841           //    |       |
6842           //    |       |
6843           //    +---+---+
6844           //   0    7    3
6845           isOk = false;
6846           if(nbRepl==3) {
6847             nbUniqueNodes = 6;
6848             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6849               uniqueNodes[0] = curNodes[0];
6850               uniqueNodes[1] = curNodes[2];
6851               uniqueNodes[2] = curNodes[3];
6852               uniqueNodes[3] = curNodes[5];
6853               uniqueNodes[4] = curNodes[6];
6854               uniqueNodes[5] = curNodes[7];
6855               isOk = true;
6856             }
6857             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6858               uniqueNodes[0] = curNodes[0];
6859               uniqueNodes[1] = curNodes[1];
6860               uniqueNodes[2] = curNodes[2];
6861               uniqueNodes[3] = curNodes[4];
6862               uniqueNodes[4] = curNodes[5];
6863               uniqueNodes[5] = curNodes[6];
6864               isOk = true;
6865             }
6866             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6867               uniqueNodes[0] = curNodes[1];
6868               uniqueNodes[1] = curNodes[2];
6869               uniqueNodes[2] = curNodes[3];
6870               uniqueNodes[3] = curNodes[5];
6871               uniqueNodes[4] = curNodes[6];
6872               uniqueNodes[5] = curNodes[0];
6873               isOk = true;
6874             }
6875             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6876               uniqueNodes[0] = curNodes[0];
6877               uniqueNodes[1] = curNodes[1];
6878               uniqueNodes[2] = curNodes[3];
6879               uniqueNodes[3] = curNodes[4];
6880               uniqueNodes[4] = curNodes[6];
6881               uniqueNodes[5] = curNodes[7];
6882               isOk = true;
6883             }
6884             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6885               uniqueNodes[0] = curNodes[0];
6886               uniqueNodes[1] = curNodes[2];
6887               uniqueNodes[2] = curNodes[3];
6888               uniqueNodes[3] = curNodes[1];
6889               uniqueNodes[4] = curNodes[6];
6890               uniqueNodes[5] = curNodes[7];
6891               isOk = true;
6892             }
6893             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6894               uniqueNodes[0] = curNodes[0];
6895               uniqueNodes[1] = curNodes[1];
6896               uniqueNodes[2] = curNodes[2];
6897               uniqueNodes[3] = curNodes[4];
6898               uniqueNodes[4] = curNodes[5];
6899               uniqueNodes[5] = curNodes[7];
6900               isOk = true;
6901             }
6902             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6903               uniqueNodes[0] = curNodes[0];
6904               uniqueNodes[1] = curNodes[1];
6905               uniqueNodes[2] = curNodes[3];
6906               uniqueNodes[3] = curNodes[4];
6907               uniqueNodes[4] = curNodes[2];
6908               uniqueNodes[5] = curNodes[7];
6909               isOk = true;
6910             }
6911             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6912               uniqueNodes[0] = curNodes[0];
6913               uniqueNodes[1] = curNodes[1];
6914               uniqueNodes[2] = curNodes[2];
6915               uniqueNodes[3] = curNodes[4];
6916               uniqueNodes[4] = curNodes[5];
6917               uniqueNodes[5] = curNodes[3];
6918               isOk = true;
6919             }
6920           }
6921           break;
6922         }
6923         //////////////////////////////////// HEXAHEDRON
6924         isOk = false;
6925         SMDS_VolumeTool hexa (elem);
6926         hexa.SetExternalNormal();
6927         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
6928           //////////////////////// ---> tetrahedron
6929           for ( int iFace = 0; iFace < 6; iFace++ ) {
6930             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6931             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6932                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6933                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6934               // one face turns into a point ...
6935               int iOppFace = hexa.GetOppFaceIndex( iFace );
6936               ind = hexa.GetFaceNodesIndices( iOppFace );
6937               int nbStick = 0;
6938               iUnique = 2; // reverse a tetrahedron bottom
6939               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6940                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6941                   nbStick++;
6942                 else if ( iUnique >= 0 )
6943                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6944               }
6945               if ( nbStick == 1 ) {
6946                 // ... and the opposite one - into a triangle.
6947                 // set a top node
6948                 ind = hexa.GetFaceNodesIndices( iFace );
6949                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6950                 isOk = true;
6951               }
6952               break;
6953             }
6954           }
6955         }
6956         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6957           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6958           for ( int iFace = 0; iFace < 6; iFace++ ) {
6959             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6960             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6961                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6962                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6963               // one face turns into a point ...
6964               int iOppFace = hexa.GetOppFaceIndex( iFace );
6965               ind = hexa.GetFaceNodesIndices( iOppFace );
6966               int nbStick = 0;
6967               iUnique = 2;  // reverse a tetrahedron 1 bottom
6968               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6969                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6970                   nbStick++;
6971                 else if ( iUnique >= 0 )
6972                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6973               }
6974               if ( nbStick == 0 ) {
6975                 // ... and the opposite one is a quadrangle
6976                 // set a top node
6977                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6978                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6979                 nbUniqueNodes = 4;
6980                 // tetrahedron 2
6981                 SMDS_MeshElement* newElem =
6982                   aMesh->AddVolume(curNodes[ind[ 0 ]],
6983                                    curNodes[ind[ 3 ]],
6984                                    curNodes[ind[ 2 ]],
6985                                    curNodes[indTop[ 0 ]]);
6986                 myLastCreatedElems.Append(newElem);
6987                 if ( aShapeId )
6988                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
6989                 isOk = true;
6990               }
6991               break;
6992             }
6993           }
6994         }
6995         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6996           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6997           // find indices of quad and tri faces
6998           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6999           for ( iFace = 0; iFace < 6; iFace++ ) {
7000             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7001             nodeSet.clear();
7002             for ( iCur = 0; iCur < 4; iCur++ )
7003               nodeSet.insert( curNodes[ind[ iCur ]] );
7004             nbUniqueNodes = nodeSet.size();
7005             if ( nbUniqueNodes == 3 )
7006               iTriFace[ nbTri++ ] = iFace;
7007             else if ( nbUniqueNodes == 4 )
7008               iQuadFace[ nbQuad++ ] = iFace;
7009           }
7010           if (nbQuad == 2 && nbTri == 4 &&
7011               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7012             // 2 opposite quadrangles stuck with a diagonal;
7013             // sample groups of merged indices: (0-4)(2-6)
7014             // --------------------------------------------> 2 tetrahedrons
7015             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7016             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7017             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7018             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7019                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7020               // stuck with 0-2 diagonal
7021               i0  = ind1[ 3 ];
7022               i1d = ind1[ 0 ];
7023               i2  = ind1[ 1 ];
7024               i3d = ind1[ 2 ];
7025               i0t = ind2[ 1 ];
7026               i2t = ind2[ 3 ];
7027             }
7028             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7029                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7030               // stuck with 1-3 diagonal
7031               i0  = ind1[ 0 ];
7032               i1d = ind1[ 1 ];
7033               i2  = ind1[ 2 ];
7034               i3d = ind1[ 3 ];
7035               i0t = ind2[ 0 ];
7036               i2t = ind2[ 1 ];
7037             }
7038             else {
7039               ASSERT(0);
7040             }
7041             // tetrahedron 1
7042             uniqueNodes[ 0 ] = curNodes [ i0 ];
7043             uniqueNodes[ 1 ] = curNodes [ i1d ];
7044             uniqueNodes[ 2 ] = curNodes [ i3d ];
7045             uniqueNodes[ 3 ] = curNodes [ i0t ];
7046             nbUniqueNodes = 4;
7047             // tetrahedron 2
7048             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7049                                                          curNodes[ i2 ],
7050                                                          curNodes[ i3d ],
7051                                                          curNodes[ i2t ]);
7052             myLastCreatedElems.Append(newElem);
7053             if ( aShapeId )
7054               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7055             isOk = true;
7056           }
7057           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7058                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7059             // --------------------------------------------> prism
7060             // find 2 opposite triangles
7061             nbUniqueNodes = 6;
7062             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7063               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7064                 // find indices of kept and replaced nodes
7065                 // and fill unique nodes of 2 opposite triangles
7066                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7067                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7068                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7069                 // fill unique nodes
7070                 iUnique = 0;
7071                 isOk = true;
7072                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7073                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7074                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7075                   if ( n == nInit ) {
7076                     // iCur of a linked node of the opposite face (make normals co-directed):
7077                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7078                     // check that correspondent corners of triangles are linked
7079                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7080                       isOk = false;
7081                     else {
7082                       uniqueNodes[ iUnique ] = n;
7083                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7084                       iUnique++;
7085                     }
7086                   }
7087                 }
7088                 break;
7089               }
7090             }
7091           }
7092         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7093         break;
7094       } // HEXAHEDRON
7095
7096       default:
7097         isOk = false;
7098       } // switch ( nbNodes )
7099
7100     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7101
7102     if ( isOk ) {
7103       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7104         // Change nodes of polyedre
7105         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7106           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7107         if (aPolyedre) {
7108           int nbFaces = aPolyedre->NbFaces();
7109
7110           vector<const SMDS_MeshNode *> poly_nodes;
7111           vector<int> quantities (nbFaces);
7112
7113           for (int iface = 1; iface <= nbFaces; iface++) {
7114             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7115             quantities[iface - 1] = nbFaceNodes;
7116
7117             for (inode = 1; inode <= nbFaceNodes; inode++) {
7118               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7119
7120               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7121               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7122                 curNode = (*nnIt).second;
7123               }
7124               poly_nodes.push_back(curNode);
7125             }
7126           }
7127           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7128         }
7129       }
7130       else {
7131         // Change regular element or polygon
7132         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7133       }
7134     }
7135     else {
7136       // Remove invalid regular element or invalid polygon
7137       rmElemIds.push_back( elem->GetID() );
7138     }
7139
7140   } // loop on elements
7141
7142   // Remove equal nodes and bad elements
7143
7144   Remove( rmNodeIds, true );
7145   Remove( rmElemIds, false );
7146
7147 }
7148
7149
7150 // ========================================================
7151 // class   : SortableElement
7152 // purpose : allow sorting elements basing on their nodes
7153 // ========================================================
7154 class SortableElement : public set <const SMDS_MeshElement*>
7155 {
7156 public:
7157
7158   SortableElement( const SMDS_MeshElement* theElem )
7159   {
7160     myElem = theElem;
7161     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7162     while ( nodeIt->more() )
7163       this->insert( nodeIt->next() );
7164   }
7165
7166   const SMDS_MeshElement* Get() const
7167   { return myElem; }
7168
7169   void Set(const SMDS_MeshElement* e) const
7170   { myElem = e; }
7171
7172
7173 private:
7174   mutable const SMDS_MeshElement* myElem;
7175 };
7176
7177 //=======================================================================
7178 //function : FindEqualElements
7179 //purpose  : Return list of group of elements built on the same nodes.
7180 //           Search among theElements or in the whole mesh if theElements is empty
7181 //=======================================================================
7182 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7183                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7184 {
7185   myLastCreatedElems.Clear();
7186   myLastCreatedNodes.Clear();
7187
7188   typedef set<const SMDS_MeshElement*> TElemsSet;
7189   typedef map< SortableElement, int > TMapOfNodeSet;
7190   typedef list<int> TGroupOfElems;
7191
7192   TElemsSet elems;
7193   if ( theElements.empty() )
7194   { // get all elements in the mesh
7195     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7196     while ( eIt->more() )
7197       elems.insert( elems.end(), eIt->next());
7198   }
7199   else
7200     elems = theElements;
7201
7202   vector< TGroupOfElems > arrayOfGroups;
7203   TGroupOfElems groupOfElems;
7204   TMapOfNodeSet mapOfNodeSet;
7205
7206   TElemsSet::iterator elemIt = elems.begin();
7207   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7208     const SMDS_MeshElement* curElem = *elemIt;
7209     SortableElement SE(curElem);
7210     int ind = -1;
7211     // check uniqueness
7212     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7213     if( !(pp.second) ) {
7214       TMapOfNodeSet::iterator& itSE = pp.first;
7215       ind = (*itSE).second;
7216       arrayOfGroups[ind].push_back(curElem->GetID());
7217     }
7218     else {
7219       groupOfElems.clear();
7220       groupOfElems.push_back(curElem->GetID());
7221       arrayOfGroups.push_back(groupOfElems);
7222       i++;
7223     }
7224   }
7225
7226   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7227   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7228     groupOfElems = *groupIt;
7229     if ( groupOfElems.size() > 1 ) {
7230       groupOfElems.sort();
7231       theGroupsOfElementsID.push_back(groupOfElems);
7232     }
7233   }
7234 }
7235
7236 //=======================================================================
7237 //function : MergeElements
7238 //purpose  : In each given group, substitute all elements by the first one.
7239 //=======================================================================
7240
7241 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7242 {
7243   myLastCreatedElems.Clear();
7244   myLastCreatedNodes.Clear();
7245
7246   typedef list<int> TListOfIDs;
7247   TListOfIDs rmElemIds; // IDs of elems to remove
7248
7249   SMESHDS_Mesh* aMesh = GetMeshDS();
7250
7251   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7252   while ( groupsIt != theGroupsOfElementsID.end() ) {
7253     TListOfIDs& aGroupOfElemID = *groupsIt;
7254     aGroupOfElemID.sort();
7255     int elemIDToKeep = aGroupOfElemID.front();
7256     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7257     aGroupOfElemID.pop_front();
7258     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7259     while ( idIt != aGroupOfElemID.end() ) {
7260       int elemIDToRemove = *idIt;
7261       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7262       // add the kept element in groups of removed one (PAL15188)
7263       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7264       rmElemIds.push_back( elemIDToRemove );
7265       ++idIt;
7266     }
7267     ++groupsIt;
7268   }
7269
7270   Remove( rmElemIds, false );
7271 }
7272
7273 //=======================================================================
7274 //function : MergeEqualElements
7275 //purpose  : Remove all but one of elements built on the same nodes.
7276 //=======================================================================
7277
7278 void SMESH_MeshEditor::MergeEqualElements()
7279 {
7280   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7281                                                  to merge equal elements in the whole mesh */
7282   TListOfListOfElementsID aGroupsOfElementsID;
7283   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7284   MergeElements(aGroupsOfElementsID);
7285 }
7286
7287 //=======================================================================
7288 //function : FindFaceInSet
7289 //purpose  : Return a face having linked nodes n1 and n2 and which is
7290 //           - not in avoidSet,
7291 //           - in elemSet provided that !elemSet.empty()
7292 //           i1 and i2 optionally returns indices of n1 and n2
7293 //=======================================================================
7294
7295 const SMDS_MeshElement*
7296 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7297                                 const SMDS_MeshNode*    n2,
7298                                 const TIDSortedElemSet& elemSet,
7299                                 const TIDSortedElemSet& avoidSet,
7300                                 int*                    n1ind,
7301                                 int*                    n2ind)
7302
7303 {
7304   int i1, i2;
7305   const SMDS_MeshElement* face = 0;
7306
7307   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7308   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7309   {
7310     const SMDS_MeshElement* elem = invElemIt->next();
7311     if (avoidSet.count( elem ))
7312       continue;
7313     if ( !elemSet.empty() && !elemSet.count( elem ))
7314       continue;
7315     // index of n1
7316     i1 = elem->GetNodeIndex( n1 );
7317     // find a n2 linked to n1
7318     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7319     for ( int di = -1; di < 2 && !face; di += 2 )
7320     {
7321       i2 = (i1+di+nbN) % nbN;
7322       if ( elem->GetNode( i2 ) == n2 )
7323         face = elem;
7324     }
7325     if ( !face && elem->IsQuadratic())
7326     {
7327       // analysis for quadratic elements using all nodes
7328       const SMDS_QuadraticFaceOfNodes* F =
7329         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7330       // use special nodes iterator
7331       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7332       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7333       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7334       {
7335         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7336         if ( n1 == prevN && n2 == n )
7337         {
7338           face = elem;
7339         }
7340         else if ( n2 == prevN && n1 == n )
7341         {
7342           face = elem; swap( i1, i2 );
7343         }
7344         prevN = n;
7345       }
7346     }
7347   }
7348   if ( n1ind ) *n1ind = i1;
7349   if ( n2ind ) *n2ind = i2;
7350   return face;
7351 }
7352
7353 //=======================================================================
7354 //function : findAdjacentFace
7355 //purpose  :
7356 //=======================================================================
7357
7358 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7359                                                 const SMDS_MeshNode* n2,
7360                                                 const SMDS_MeshElement* elem)
7361 {
7362   TIDSortedElemSet elemSet, avoidSet;
7363   if ( elem )
7364     avoidSet.insert ( elem );
7365   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7366 }
7367
7368 //=======================================================================
7369 //function : FindFreeBorder
7370 //purpose  :
7371 //=======================================================================
7372
7373 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7374
7375 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7376                                        const SMDS_MeshNode*             theSecondNode,
7377                                        const SMDS_MeshNode*             theLastNode,
7378                                        list< const SMDS_MeshNode* > &   theNodes,
7379                                        list< const SMDS_MeshElement* >& theFaces)
7380 {
7381   if ( !theFirstNode || !theSecondNode )
7382     return false;
7383   // find border face between theFirstNode and theSecondNode
7384   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7385   if ( !curElem )
7386     return false;
7387
7388   theFaces.push_back( curElem );
7389   theNodes.push_back( theFirstNode );
7390   theNodes.push_back( theSecondNode );
7391
7392   //vector<const SMDS_MeshNode*> nodes;
7393   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7394   TIDSortedElemSet foundElems;
7395   bool needTheLast = ( theLastNode != 0 );
7396
7397   while ( nStart != theLastNode ) {
7398     if ( nStart == theFirstNode )
7399       return !needTheLast;
7400
7401     // find all free border faces sharing form nStart
7402
7403     list< const SMDS_MeshElement* > curElemList;
7404     list< const SMDS_MeshNode* > nStartList;
7405     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7406     while ( invElemIt->more() ) {
7407       const SMDS_MeshElement* e = invElemIt->next();
7408       if ( e == curElem || foundElems.insert( e ).second ) {
7409         // get nodes
7410         int iNode = 0, nbNodes = e->NbNodes();
7411         //const SMDS_MeshNode* nodes[nbNodes+1];
7412         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7413
7414         if(e->IsQuadratic()) {
7415           const SMDS_QuadraticFaceOfNodes* F =
7416             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7417           // use special nodes iterator
7418           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7419           while( anIter->more() ) {
7420             nodes[ iNode++ ] = anIter->next();
7421           }
7422         }
7423         else {
7424           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7425           while ( nIt->more() )
7426             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7427         }
7428         nodes[ iNode ] = nodes[ 0 ];
7429         // check 2 links
7430         for ( iNode = 0; iNode < nbNodes; iNode++ )
7431           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7432                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7433               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7434           {
7435             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7436             curElemList.push_back( e );
7437           }
7438       }
7439     }
7440     // analyse the found
7441
7442     int nbNewBorders = curElemList.size();
7443     if ( nbNewBorders == 0 ) {
7444       // no free border furthermore
7445       return !needTheLast;
7446     }
7447     else if ( nbNewBorders == 1 ) {
7448       // one more element found
7449       nIgnore = nStart;
7450       nStart = nStartList.front();
7451       curElem = curElemList.front();
7452       theFaces.push_back( curElem );
7453       theNodes.push_back( nStart );
7454     }
7455     else {
7456       // several continuations found
7457       list< const SMDS_MeshElement* >::iterator curElemIt;
7458       list< const SMDS_MeshNode* >::iterator nStartIt;
7459       // check if one of them reached the last node
7460       if ( needTheLast ) {
7461         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7462              curElemIt!= curElemList.end();
7463              curElemIt++, nStartIt++ )
7464           if ( *nStartIt == theLastNode ) {
7465             theFaces.push_back( *curElemIt );
7466             theNodes.push_back( *nStartIt );
7467             return true;
7468           }
7469       }
7470       // find the best free border by the continuations
7471       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7472       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7473       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7474            curElemIt!= curElemList.end();
7475            curElemIt++, nStartIt++ )
7476       {
7477         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7478         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7479         // find one more free border
7480         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7481           cNL->clear();
7482           cFL->clear();
7483         }
7484         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7485           // choice: clear a worse one
7486           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7487           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7488           contNodes[ iWorse ].clear();
7489           contFaces[ iWorse ].clear();
7490         }
7491       }
7492       if ( contNodes[0].empty() && contNodes[1].empty() )
7493         return false;
7494
7495       // append the best free border
7496       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7497       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7498       theNodes.pop_back(); // remove nIgnore
7499       theNodes.pop_back(); // remove nStart
7500       theFaces.pop_back(); // remove curElem
7501       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7502       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7503       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7504       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7505       return true;
7506
7507     } // several continuations found
7508   } // while ( nStart != theLastNode )
7509
7510   return true;
7511 }
7512
7513 //=======================================================================
7514 //function : CheckFreeBorderNodes
7515 //purpose  : Return true if the tree nodes are on a free border
7516 //=======================================================================
7517
7518 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7519                                             const SMDS_MeshNode* theNode2,
7520                                             const SMDS_MeshNode* theNode3)
7521 {
7522   list< const SMDS_MeshNode* > nodes;
7523   list< const SMDS_MeshElement* > faces;
7524   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7525 }
7526
7527 //=======================================================================
7528 //function : SewFreeBorder
7529 //purpose  :
7530 //=======================================================================
7531
7532 SMESH_MeshEditor::Sew_Error
7533 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7534                                  const SMDS_MeshNode* theBordSecondNode,
7535                                  const SMDS_MeshNode* theBordLastNode,
7536                                  const SMDS_MeshNode* theSideFirstNode,
7537                                  const SMDS_MeshNode* theSideSecondNode,
7538                                  const SMDS_MeshNode* theSideThirdNode,
7539                                  const bool           theSideIsFreeBorder,
7540                                  const bool           toCreatePolygons,
7541                                  const bool           toCreatePolyedrs)
7542 {
7543   myLastCreatedElems.Clear();
7544   myLastCreatedNodes.Clear();
7545
7546   MESSAGE("::SewFreeBorder()");
7547   Sew_Error aResult = SEW_OK;
7548
7549   // ====================================
7550   //    find side nodes and elements
7551   // ====================================
7552
7553   list< const SMDS_MeshNode* > nSide[ 2 ];
7554   list< const SMDS_MeshElement* > eSide[ 2 ];
7555   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7556   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7557
7558   // Free border 1
7559   // --------------
7560   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7561                       nSide[0], eSide[0])) {
7562     MESSAGE(" Free Border 1 not found " );
7563     aResult = SEW_BORDER1_NOT_FOUND;
7564   }
7565   if (theSideIsFreeBorder) {
7566     // Free border 2
7567     // --------------
7568     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7569                         nSide[1], eSide[1])) {
7570       MESSAGE(" Free Border 2 not found " );
7571       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7572     }
7573   }
7574   if ( aResult != SEW_OK )
7575     return aResult;
7576
7577   if (!theSideIsFreeBorder) {
7578     // Side 2
7579     // --------------
7580
7581     // -------------------------------------------------------------------------
7582     // Algo:
7583     // 1. If nodes to merge are not coincident, move nodes of the free border
7584     //    from the coord sys defined by the direction from the first to last
7585     //    nodes of the border to the correspondent sys of the side 2
7586     // 2. On the side 2, find the links most co-directed with the correspondent
7587     //    links of the free border
7588     // -------------------------------------------------------------------------
7589
7590     // 1. Since sewing may brake if there are volumes to split on the side 2,
7591     //    we wont move nodes but just compute new coordinates for them
7592     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7593     TNodeXYZMap nBordXYZ;
7594     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7595     list< const SMDS_MeshNode* >::iterator nBordIt;
7596
7597     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7598     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7599     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7600     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7601     double tol2 = 1.e-8;
7602     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7603     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7604       // Need node movement.
7605
7606       // find X and Z axes to create trsf
7607       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7608       gp_Vec X = Zs ^ Zb;
7609       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7610         // Zb || Zs
7611         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7612
7613       // coord systems
7614       gp_Ax3 toBordAx( Pb1, Zb, X );
7615       gp_Ax3 fromSideAx( Ps1, Zs, X );
7616       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7617       // set trsf
7618       gp_Trsf toBordSys, fromSide2Sys;
7619       toBordSys.SetTransformation( toBordAx );
7620       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7621       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7622
7623       // move
7624       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7625         const SMDS_MeshNode* n = *nBordIt;
7626         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7627         toBordSys.Transforms( xyz );
7628         fromSide2Sys.Transforms( xyz );
7629         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7630       }
7631     }
7632     else {
7633       // just insert nodes XYZ in the nBordXYZ map
7634       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7635         const SMDS_MeshNode* n = *nBordIt;
7636         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7637       }
7638     }
7639
7640     // 2. On the side 2, find the links most co-directed with the correspondent
7641     //    links of the free border
7642
7643     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7644     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7645     sideNodes.push_back( theSideFirstNode );
7646
7647     bool hasVolumes = false;
7648     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7649     set<long> foundSideLinkIDs, checkedLinkIDs;
7650     SMDS_VolumeTool volume;
7651     //const SMDS_MeshNode* faceNodes[ 4 ];
7652
7653     const SMDS_MeshNode*    sideNode;
7654     const SMDS_MeshElement* sideElem;
7655     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7656     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7657     nBordIt = bordNodes.begin();
7658     nBordIt++;
7659     // border node position and border link direction to compare with
7660     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7661     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7662     // choose next side node by link direction or by closeness to
7663     // the current border node:
7664     bool searchByDir = ( *nBordIt != theBordLastNode );
7665     do {
7666       // find the next node on the Side 2
7667       sideNode = 0;
7668       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7669       long linkID;
7670       checkedLinkIDs.clear();
7671       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7672
7673       // loop on inverse elements of current node (prevSideNode) on the Side 2
7674       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7675       while ( invElemIt->more() )
7676       {
7677         const SMDS_MeshElement* elem = invElemIt->next();
7678         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7679         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7680         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7681         bool isVolume = volume.Set( elem );
7682         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7683         if ( isVolume ) // --volume
7684           hasVolumes = true;
7685         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7686           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7687           if(elem->IsQuadratic()) {
7688             const SMDS_QuadraticFaceOfNodes* F =
7689               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7690             // use special nodes iterator
7691             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7692             while( anIter->more() ) {
7693               nodes[ iNode ] = anIter->next();
7694               if ( nodes[ iNode++ ] == prevSideNode )
7695                 iPrevNode = iNode - 1;
7696             }
7697           }
7698           else {
7699             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7700             while ( nIt->more() ) {
7701               nodes[ iNode ] = cast2Node( nIt->next() );
7702               if ( nodes[ iNode++ ] == prevSideNode )
7703                 iPrevNode = iNode - 1;
7704             }
7705           }
7706           // there are 2 links to check
7707           nbNodes = 2;
7708         }
7709         else // --edge
7710           continue;
7711         // loop on links, to be precise, on the second node of links
7712         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7713           const SMDS_MeshNode* n = nodes[ iNode ];
7714           if ( isVolume ) {
7715             if ( !volume.IsLinked( n, prevSideNode ))
7716               continue;
7717           }
7718           else {
7719             if ( iNode ) // a node before prevSideNode
7720               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7721             else         // a node after prevSideNode
7722               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7723           }
7724           // check if this link was already used
7725           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7726           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7727           if (!isJustChecked &&
7728               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7729           {
7730             // test a link geometrically
7731             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7732             bool linkIsBetter = false;
7733             double dot = 0.0, dist = 0.0;
7734             if ( searchByDir ) { // choose most co-directed link
7735               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7736               linkIsBetter = ( dot > maxDot );
7737             }
7738             else { // choose link with the node closest to bordPos
7739               dist = ( nextXYZ - bordPos ).SquareModulus();
7740               linkIsBetter = ( dist < minDist );
7741             }
7742             if ( linkIsBetter ) {
7743               maxDot = dot;
7744               minDist = dist;
7745               linkID = iLink;
7746               sideNode = n;
7747               sideElem = elem;
7748             }
7749           }
7750         }
7751       } // loop on inverse elements of prevSideNode
7752
7753       if ( !sideNode ) {
7754         MESSAGE(" Cant find path by links of the Side 2 ");
7755         return SEW_BAD_SIDE_NODES;
7756       }
7757       sideNodes.push_back( sideNode );
7758       sideElems.push_back( sideElem );
7759       foundSideLinkIDs.insert ( linkID );
7760       prevSideNode = sideNode;
7761
7762       if ( *nBordIt == theBordLastNode )
7763         searchByDir = false;
7764       else {
7765         // find the next border link to compare with
7766         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7767         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7768         // move to next border node if sideNode is before forward border node (bordPos)
7769         while ( *nBordIt != theBordLastNode && !searchByDir ) {
7770           prevBordNode = *nBordIt;
7771           nBordIt++;
7772           bordPos = nBordXYZ[ *nBordIt ];
7773           bordDir = bordPos - nBordXYZ[ prevBordNode ];
7774           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7775         }
7776       }
7777     }
7778     while ( sideNode != theSideSecondNode );
7779
7780     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7781       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7782       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7783     }
7784   } // end nodes search on the side 2
7785
7786   // ============================
7787   // sew the border to the side 2
7788   // ============================
7789
7790   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
7791   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7792
7793   TListOfListOfNodes nodeGroupsToMerge;
7794   if ( nbNodes[0] == nbNodes[1] ||
7795        ( theSideIsFreeBorder && !theSideThirdNode)) {
7796
7797     // all nodes are to be merged
7798
7799     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7800          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7801          nIt[0]++, nIt[1]++ )
7802     {
7803       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7804       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7805       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7806     }
7807   }
7808   else {
7809
7810     // insert new nodes into the border and the side to get equal nb of segments
7811
7812     // get normalized parameters of nodes on the borders
7813     //double param[ 2 ][ maxNbNodes ];
7814     double* param[ 2 ];
7815     param[0] = new double [ maxNbNodes ];
7816     param[1] = new double [ maxNbNodes ];
7817     int iNode, iBord;
7818     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7819       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7820       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7821       const SMDS_MeshNode* nPrev = *nIt;
7822       double bordLength = 0;
7823       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7824         const SMDS_MeshNode* nCur = *nIt;
7825         gp_XYZ segment (nCur->X() - nPrev->X(),
7826                         nCur->Y() - nPrev->Y(),
7827                         nCur->Z() - nPrev->Z());
7828         double segmentLen = segment.Modulus();
7829         bordLength += segmentLen;
7830         param[ iBord ][ iNode ] = bordLength;
7831         nPrev = nCur;
7832       }
7833       // normalize within [0,1]
7834       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7835         param[ iBord ][ iNode ] /= bordLength;
7836       }
7837     }
7838
7839     // loop on border segments
7840     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7841     int i[ 2 ] = { 0, 0 };
7842     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7843     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7844
7845     TElemOfNodeListMap insertMap;
7846     TElemOfNodeListMap::iterator insertMapIt;
7847     // insertMap is
7848     // key:   elem to insert nodes into
7849     // value: 2 nodes to insert between + nodes to be inserted
7850     do {
7851       bool next[ 2 ] = { false, false };
7852
7853       // find min adjacent segment length after sewing
7854       double nextParam = 10., prevParam = 0;
7855       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7856         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7857           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7858         if ( i[ iBord ] > 0 )
7859           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7860       }
7861       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7862       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7863       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7864
7865       // choose to insert or to merge nodes
7866       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7867       if ( Abs( du ) <= minSegLen * 0.2 ) {
7868         // merge
7869         // ------
7870         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7871         const SMDS_MeshNode* n0 = *nIt[0];
7872         const SMDS_MeshNode* n1 = *nIt[1];
7873         nodeGroupsToMerge.back().push_back( n1 );
7874         nodeGroupsToMerge.back().push_back( n0 );
7875         // position of node of the border changes due to merge
7876         param[ 0 ][ i[0] ] += du;
7877         // move n1 for the sake of elem shape evaluation during insertion.
7878         // n1 will be removed by MergeNodes() anyway
7879         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7880         next[0] = next[1] = true;
7881       }
7882       else {
7883         // insert
7884         // ------
7885         int intoBord = ( du < 0 ) ? 0 : 1;
7886         const SMDS_MeshElement* elem = *eIt[ intoBord ];
7887         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
7888         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
7889         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
7890         if ( intoBord == 1 ) {
7891           // move node of the border to be on a link of elem of the side
7892           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7893           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7894           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7895           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7896           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7897         }
7898         insertMapIt = insertMap.find( elem );
7899         bool notFound = ( insertMapIt == insertMap.end() );
7900         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7901         if ( otherLink ) {
7902           // insert into another link of the same element:
7903           // 1. perform insertion into the other link of the elem
7904           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7905           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7906           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7907           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7908           // 2. perform insertion into the link of adjacent faces
7909           while (true) {
7910             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7911             if ( adjElem )
7912               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7913             else
7914               break;
7915           }
7916           if (toCreatePolyedrs) {
7917             // perform insertion into the links of adjacent volumes
7918             UpdateVolumes(n12, n22, nodeList);
7919           }
7920           // 3. find an element appeared on n1 and n2 after the insertion
7921           insertMap.erase( elem );
7922           elem = findAdjacentFace( n1, n2, 0 );
7923         }
7924         if ( notFound || otherLink ) {
7925           // add element and nodes of the side into the insertMap
7926           insertMapIt = insertMap.insert
7927             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7928           (*insertMapIt).second.push_back( n1 );
7929           (*insertMapIt).second.push_back( n2 );
7930         }
7931         // add node to be inserted into elem
7932         (*insertMapIt).second.push_back( nIns );
7933         next[ 1 - intoBord ] = true;
7934       }
7935
7936       // go to the next segment
7937       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7938         if ( next[ iBord ] ) {
7939           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7940             eIt[ iBord ]++;
7941           nPrev[ iBord ] = *nIt[ iBord ];
7942           nIt[ iBord ]++; i[ iBord ]++;
7943         }
7944       }
7945     }
7946     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7947
7948     // perform insertion of nodes into elements
7949
7950     for (insertMapIt = insertMap.begin();
7951          insertMapIt != insertMap.end();
7952          insertMapIt++ )
7953     {
7954       const SMDS_MeshElement* elem = (*insertMapIt).first;
7955       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7956       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7957       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7958
7959       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7960
7961       if ( !theSideIsFreeBorder ) {
7962         // look for and insert nodes into the faces adjacent to elem
7963         while (true) {
7964           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7965           if ( adjElem )
7966             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7967           else
7968             break;
7969         }
7970       }
7971       if (toCreatePolyedrs) {
7972         // perform insertion into the links of adjacent volumes
7973         UpdateVolumes(n1, n2, nodeList);
7974       }
7975     }
7976
7977     delete param[0];
7978     delete param[1];
7979   } // end: insert new nodes
7980
7981   MergeNodes ( nodeGroupsToMerge );
7982
7983   return aResult;
7984 }
7985
7986 //=======================================================================
7987 //function : InsertNodesIntoLink
7988 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
7989 //           and theBetweenNode2 and split theElement
7990 //=======================================================================
7991
7992 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
7993                                            const SMDS_MeshNode*        theBetweenNode1,
7994                                            const SMDS_MeshNode*        theBetweenNode2,
7995                                            list<const SMDS_MeshNode*>& theNodesToInsert,
7996                                            const bool                  toCreatePoly)
7997 {
7998   if ( theFace->GetType() != SMDSAbs_Face ) return;
7999
8000   // find indices of 2 link nodes and of the rest nodes
8001   int iNode = 0, il1, il2, i3, i4;
8002   il1 = il2 = i3 = i4 = -1;
8003   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8004   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8005
8006   if(theFace->IsQuadratic()) {
8007     const SMDS_QuadraticFaceOfNodes* F =
8008       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8009     // use special nodes iterator
8010     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8011     while( anIter->more() ) {
8012       const SMDS_MeshNode* n = anIter->next();
8013       if ( n == theBetweenNode1 )
8014         il1 = iNode;
8015       else if ( n == theBetweenNode2 )
8016         il2 = iNode;
8017       else if ( i3 < 0 )
8018         i3 = iNode;
8019       else
8020         i4 = iNode;
8021       nodes[ iNode++ ] = n;
8022     }
8023   }
8024   else {
8025     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8026     while ( nodeIt->more() ) {
8027       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8028       if ( n == theBetweenNode1 )
8029         il1 = iNode;
8030       else if ( n == theBetweenNode2 )
8031         il2 = iNode;
8032       else if ( i3 < 0 )
8033         i3 = iNode;
8034       else
8035         i4 = iNode;
8036       nodes[ iNode++ ] = n;
8037     }
8038   }
8039   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8040     return ;
8041
8042   // arrange link nodes to go one after another regarding the face orientation
8043   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8044   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8045   if ( reverse ) {
8046     iNode = il1;
8047     il1 = il2;
8048     il2 = iNode;
8049     aNodesToInsert.reverse();
8050   }
8051   // check that not link nodes of a quadrangles are in good order
8052   int nbFaceNodes = theFace->NbNodes();
8053   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8054     iNode = i3;
8055     i3 = i4;
8056     i4 = iNode;
8057   }
8058
8059   if (toCreatePoly || theFace->IsPoly()) {
8060
8061     iNode = 0;
8062     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8063
8064     // add nodes of face up to first node of link
8065     bool isFLN = false;
8066
8067     if(theFace->IsQuadratic()) {
8068       const SMDS_QuadraticFaceOfNodes* F =
8069         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8070       // use special nodes iterator
8071       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8072       while( anIter->more()  && !isFLN ) {
8073         const SMDS_MeshNode* n = anIter->next();
8074         poly_nodes[iNode++] = n;
8075         if (n == nodes[il1]) {
8076           isFLN = true;
8077         }
8078       }
8079       // add nodes to insert
8080       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8081       for (; nIt != aNodesToInsert.end(); nIt++) {
8082         poly_nodes[iNode++] = *nIt;
8083       }
8084       // add nodes of face starting from last node of link
8085       while ( anIter->more() ) {
8086         poly_nodes[iNode++] = anIter->next();
8087       }
8088     }
8089     else {
8090       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8091       while ( nodeIt->more() && !isFLN ) {
8092         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8093         poly_nodes[iNode++] = n;
8094         if (n == nodes[il1]) {
8095           isFLN = true;
8096         }
8097       }
8098       // add nodes to insert
8099       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8100       for (; nIt != aNodesToInsert.end(); nIt++) {
8101         poly_nodes[iNode++] = *nIt;
8102       }
8103       // add nodes of face starting from last node of link
8104       while ( nodeIt->more() ) {
8105         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8106         poly_nodes[iNode++] = n;
8107       }
8108     }
8109
8110     // edit or replace the face
8111     SMESHDS_Mesh *aMesh = GetMeshDS();
8112
8113     if (theFace->IsPoly()) {
8114       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8115     }
8116     else {
8117       int aShapeId = FindShape( theFace );
8118
8119       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8120       myLastCreatedElems.Append(newElem);
8121       if ( aShapeId && newElem )
8122         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8123
8124       aMesh->RemoveElement(theFace);
8125     }
8126     return;
8127   }
8128
8129   if( !theFace->IsQuadratic() ) {
8130
8131     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8132     int nbLinkNodes = 2 + aNodesToInsert.size();
8133     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8134     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8135     linkNodes[ 0 ] = nodes[ il1 ];
8136     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8137     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8138     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8139       linkNodes[ iNode++ ] = *nIt;
8140     }
8141     // decide how to split a quadrangle: compare possible variants
8142     // and choose which of splits to be a quadrangle
8143     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8144     if ( nbFaceNodes == 3 ) {
8145       iBestQuad = nbSplits;
8146       i4 = i3;
8147     }
8148     else if ( nbFaceNodes == 4 ) {
8149       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8150       double aBestRate = DBL_MAX;
8151       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8152         i1 = 0; i2 = 1;
8153         double aBadRate = 0;
8154         // evaluate elements quality
8155         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8156           if ( iSplit == iQuad ) {
8157             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8158                                    linkNodes[ i2++ ],
8159                                    nodes[ i3 ],
8160                                    nodes[ i4 ]);
8161             aBadRate += getBadRate( &quad, aCrit );
8162           }
8163           else {
8164             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8165                                    linkNodes[ i2++ ],
8166                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8167             aBadRate += getBadRate( &tria, aCrit );
8168           }
8169         }
8170         // choice
8171         if ( aBadRate < aBestRate ) {
8172           iBestQuad = iQuad;
8173           aBestRate = aBadRate;
8174         }
8175       }
8176     }
8177
8178     // create new elements
8179     SMESHDS_Mesh *aMesh = GetMeshDS();
8180     int aShapeId = FindShape( theFace );
8181
8182     i1 = 0; i2 = 1;
8183     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8184       SMDS_MeshElement* newElem = 0;
8185       if ( iSplit == iBestQuad )
8186         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8187                                   linkNodes[ i2++ ],
8188                                   nodes[ i3 ],
8189                                   nodes[ i4 ]);
8190       else
8191         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8192                                   linkNodes[ i2++ ],
8193                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8194       myLastCreatedElems.Append(newElem);
8195       if ( aShapeId && newElem )
8196         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8197     }
8198
8199     // change nodes of theFace
8200     const SMDS_MeshNode* newNodes[ 4 ];
8201     newNodes[ 0 ] = linkNodes[ i1 ];
8202     newNodes[ 1 ] = linkNodes[ i2 ];
8203     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8204     newNodes[ 3 ] = nodes[ i4 ];
8205     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8206   } // end if(!theFace->IsQuadratic())
8207   else { // theFace is quadratic
8208     // we have to split theFace on simple triangles and one simple quadrangle
8209     int tmp = il1/2;
8210     int nbshift = tmp*2;
8211     // shift nodes in nodes[] by nbshift
8212     int i,j;
8213     for(i=0; i<nbshift; i++) {
8214       const SMDS_MeshNode* n = nodes[0];
8215       for(j=0; j<nbFaceNodes-1; j++) {
8216         nodes[j] = nodes[j+1];
8217       }
8218       nodes[nbFaceNodes-1] = n;
8219     }
8220     il1 = il1 - nbshift;
8221     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8222     //   n0      n1     n2    n0      n1     n2
8223     //     +-----+-----+        +-----+-----+
8224     //      \         /         |           |
8225     //       \       /          |           |
8226     //      n5+     +n3       n7+           +n3
8227     //         \   /            |           |
8228     //          \ /             |           |
8229     //           +              +-----+-----+
8230     //           n4           n6      n5     n4
8231
8232     // create new elements
8233     SMESHDS_Mesh *aMesh = GetMeshDS();
8234     int aShapeId = FindShape( theFace );
8235
8236     int n1,n2,n3;
8237     if(nbFaceNodes==6) { // quadratic triangle
8238       SMDS_MeshElement* newElem =
8239         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8240       myLastCreatedElems.Append(newElem);
8241       if ( aShapeId && newElem )
8242         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8243       if(theFace->IsMediumNode(nodes[il1])) {
8244         // create quadrangle
8245         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8246         myLastCreatedElems.Append(newElem);
8247         if ( aShapeId && newElem )
8248           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8249         n1 = 1;
8250         n2 = 2;
8251         n3 = 3;
8252       }
8253       else {
8254         // create quadrangle
8255         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8256         myLastCreatedElems.Append(newElem);
8257         if ( aShapeId && newElem )
8258           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8259         n1 = 0;
8260         n2 = 1;
8261         n3 = 5;
8262       }
8263     }
8264     else { // nbFaceNodes==8 - quadratic quadrangle
8265       SMDS_MeshElement* newElem =
8266         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8267       myLastCreatedElems.Append(newElem);
8268       if ( aShapeId && newElem )
8269         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8270       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8271       myLastCreatedElems.Append(newElem);
8272       if ( aShapeId && newElem )
8273         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8274       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8275       myLastCreatedElems.Append(newElem);
8276       if ( aShapeId && newElem )
8277         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8278       if(theFace->IsMediumNode(nodes[il1])) {
8279         // create quadrangle
8280         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8281         myLastCreatedElems.Append(newElem);
8282         if ( aShapeId && newElem )
8283           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8284         n1 = 1;
8285         n2 = 2;
8286         n3 = 3;
8287       }
8288       else {
8289         // create quadrangle
8290         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8291         myLastCreatedElems.Append(newElem);
8292         if ( aShapeId && newElem )
8293           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8294         n1 = 0;
8295         n2 = 1;
8296         n3 = 7;
8297       }
8298     }
8299     // create needed triangles using n1,n2,n3 and inserted nodes
8300     int nbn = 2 + aNodesToInsert.size();
8301     //const SMDS_MeshNode* aNodes[nbn];
8302     vector<const SMDS_MeshNode*> aNodes(nbn);
8303     aNodes[0] = nodes[n1];
8304     aNodes[nbn-1] = nodes[n2];
8305     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8306     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8307       aNodes[iNode++] = *nIt;
8308     }
8309     for(i=1; i<nbn; i++) {
8310       SMDS_MeshElement* newElem =
8311         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8312       myLastCreatedElems.Append(newElem);
8313       if ( aShapeId && newElem )
8314         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8315     }
8316     // remove old quadratic face
8317     aMesh->RemoveElement(theFace);
8318   }
8319 }
8320
8321 //=======================================================================
8322 //function : UpdateVolumes
8323 //purpose  :
8324 //=======================================================================
8325 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8326                                       const SMDS_MeshNode*        theBetweenNode2,
8327                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8328 {
8329   myLastCreatedElems.Clear();
8330   myLastCreatedNodes.Clear();
8331
8332   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8333   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8334     const SMDS_MeshElement* elem = invElemIt->next();
8335
8336     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8337     SMDS_VolumeTool aVolume (elem);
8338     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8339       continue;
8340
8341     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8342     int iface, nbFaces = aVolume.NbFaces();
8343     vector<const SMDS_MeshNode *> poly_nodes;
8344     vector<int> quantities (nbFaces);
8345
8346     for (iface = 0; iface < nbFaces; iface++) {
8347       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8348       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8349       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8350
8351       for (int inode = 0; inode < nbFaceNodes; inode++) {
8352         poly_nodes.push_back(faceNodes[inode]);
8353
8354         if (nbInserted == 0) {
8355           if (faceNodes[inode] == theBetweenNode1) {
8356             if (faceNodes[inode + 1] == theBetweenNode2) {
8357               nbInserted = theNodesToInsert.size();
8358
8359               // add nodes to insert
8360               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8361               for (; nIt != theNodesToInsert.end(); nIt++) {
8362                 poly_nodes.push_back(*nIt);
8363               }
8364             }
8365           }
8366           else if (faceNodes[inode] == theBetweenNode2) {
8367             if (faceNodes[inode + 1] == theBetweenNode1) {
8368               nbInserted = theNodesToInsert.size();
8369
8370               // add nodes to insert in reversed order
8371               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8372               nIt--;
8373               for (; nIt != theNodesToInsert.begin(); nIt--) {
8374                 poly_nodes.push_back(*nIt);
8375               }
8376               poly_nodes.push_back(*nIt);
8377             }
8378           }
8379           else {
8380           }
8381         }
8382       }
8383       quantities[iface] = nbFaceNodes + nbInserted;
8384     }
8385
8386     // Replace or update the volume
8387     SMESHDS_Mesh *aMesh = GetMeshDS();
8388
8389     if (elem->IsPoly()) {
8390       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8391
8392     }
8393     else {
8394       int aShapeId = FindShape( elem );
8395
8396       SMDS_MeshElement* newElem =
8397         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8398       myLastCreatedElems.Append(newElem);
8399       if (aShapeId && newElem)
8400         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8401
8402       aMesh->RemoveElement(elem);
8403     }
8404   }
8405 }
8406
8407 //=======================================================================
8408 /*!
8409  * \brief Convert elements contained in a submesh to quadratic
8410  * \retval int - nb of checked elements
8411  */
8412 //=======================================================================
8413
8414 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8415                                              SMESH_MesherHelper& theHelper,
8416                                              const bool          theForce3d)
8417 {
8418   int nbElem = 0;
8419   if( !theSm ) return nbElem;
8420
8421   const bool notFromGroups = false;
8422   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8423   while(ElemItr->more())
8424   {
8425     nbElem++;
8426     const SMDS_MeshElement* elem = ElemItr->next();
8427     if( !elem || elem->IsQuadratic() ) continue;
8428
8429     int id = elem->GetID();
8430     int nbNodes = elem->NbNodes();
8431     vector<const SMDS_MeshNode *> aNds (nbNodes);
8432
8433     for(int i = 0; i < nbNodes; i++)
8434     {
8435       aNds[i] = elem->GetNode(i);
8436     }
8437     SMDSAbs_ElementType aType = elem->GetType();
8438
8439     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8440
8441     const SMDS_MeshElement* NewElem = 0;
8442
8443     switch( aType )
8444     {
8445     case SMDSAbs_Edge :
8446       {
8447         NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8448         break;
8449       }
8450     case SMDSAbs_Face :
8451       {
8452         switch(nbNodes)
8453         {
8454         case 3:
8455           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8456           break;
8457         case 4:
8458           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8459           break;
8460         default:
8461           continue;
8462         }
8463         break;
8464       }
8465     case SMDSAbs_Volume :
8466       {
8467         switch(nbNodes)
8468         {
8469         case 4:
8470           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8471           break;
8472         case 5:
8473           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8474           break;
8475         case 6:
8476           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8477           break;
8478         case 8:
8479           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8480                                         aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8481           break;
8482         default:
8483           continue;
8484         }
8485         break;
8486       }
8487     default :
8488       continue;
8489     }
8490     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8491     if( NewElem )
8492       theSm->AddElement( NewElem );
8493   }
8494   return nbElem;
8495 }
8496
8497 //=======================================================================
8498 //function : ConvertToQuadratic
8499 //purpose  :
8500 //=======================================================================
8501 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8502 {
8503   SMESHDS_Mesh* meshDS = GetMeshDS();
8504
8505   SMESH_MesherHelper aHelper(*myMesh);
8506   aHelper.SetIsQuadratic( true );
8507   const bool notFromGroups = false;
8508
8509   int nbCheckedElems = 0;
8510   if ( myMesh->HasShapeToMesh() )
8511   {
8512     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8513     {
8514       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8515       while ( smIt->more() ) {
8516         SMESH_subMesh* sm = smIt->next();
8517         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8518           aHelper.SetSubShape( sm->GetSubShape() );
8519           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8520         }
8521       }
8522     }
8523   }
8524   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8525   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8526   {
8527     SMESHDS_SubMesh *smDS = 0;
8528     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8529     while(aEdgeItr->more())
8530     {
8531       const SMDS_MeshEdge* edge = aEdgeItr->next();
8532       if(edge && !edge->IsQuadratic())
8533       {
8534         int id = edge->GetID();
8535         const SMDS_MeshNode* n1 = edge->GetNode(0);
8536         const SMDS_MeshNode* n2 = edge->GetNode(1);
8537
8538         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8539
8540         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8541         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8542       }
8543     }
8544     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8545     while(aFaceItr->more())
8546     {
8547       const SMDS_MeshFace* face = aFaceItr->next();
8548       if(!face || face->IsQuadratic() ) continue;
8549
8550       int id = face->GetID();
8551       int nbNodes = face->NbNodes();
8552       vector<const SMDS_MeshNode *> aNds (nbNodes);
8553
8554       for(int i = 0; i < nbNodes; i++)
8555       {
8556         aNds[i] = face->GetNode(i);
8557       }
8558
8559       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
8560
8561       SMDS_MeshFace * NewFace = 0;
8562       switch(nbNodes)
8563       {
8564       case 3:
8565         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8566         break;
8567       case 4:
8568         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8569         break;
8570       default:
8571         continue;
8572       }
8573       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8574     }
8575     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8576     while(aVolumeItr->more())
8577     {
8578       const SMDS_MeshVolume* volume = aVolumeItr->next();
8579       if(!volume || volume->IsQuadratic() ) continue;
8580
8581       int id = volume->GetID();
8582       int nbNodes = volume->NbNodes();
8583       vector<const SMDS_MeshNode *> aNds (nbNodes);
8584
8585       for(int i = 0; i < nbNodes; i++)
8586       {
8587         aNds[i] = volume->GetNode(i);
8588       }
8589
8590       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
8591
8592       SMDS_MeshVolume * NewVolume = 0;
8593       switch(nbNodes)
8594       {
8595       case 4:
8596         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8597                                       aNds[3], id, theForce3d );
8598         break;
8599       case 5:
8600         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8601                                       aNds[3], aNds[4], id, theForce3d);
8602         break;
8603       case 6:
8604         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8605                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
8606         break;
8607       case 8:
8608         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8609                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8610         break;
8611       default:
8612         continue;
8613       }
8614       ReplaceElemInGroups(volume, NewVolume, meshDS);
8615     }
8616   }
8617   if ( !theForce3d ) {
8618     aHelper.SetSubShape(0); // apply to the whole mesh
8619     aHelper.FixQuadraticElements();
8620   }
8621 }
8622
8623 //=======================================================================
8624 /*!
8625  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8626  * \retval int - nb of checked elements
8627  */
8628 //=======================================================================
8629
8630 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8631                                      SMDS_ElemIteratorPtr theItr,
8632                                      const int            theShapeID)
8633 {
8634   int nbElem = 0;
8635   SMESHDS_Mesh* meshDS = GetMeshDS();
8636   const bool notFromGroups = false;
8637
8638   while( theItr->more() )
8639   {
8640     const SMDS_MeshElement* elem = theItr->next();
8641     nbElem++;
8642     if( elem && elem->IsQuadratic())
8643     {
8644       int id = elem->GetID();
8645       int nbNodes = elem->NbNodes();
8646       vector<const SMDS_MeshNode *> aNds, mediumNodes;
8647       aNds.reserve( nbNodes );
8648       mediumNodes.reserve( nbNodes );
8649
8650       for(int i = 0; i < nbNodes; i++)
8651       {
8652         const SMDS_MeshNode* n = elem->GetNode(i);
8653
8654         if( elem->IsMediumNode( n ) )
8655           mediumNodes.push_back( n );
8656         else
8657           aNds.push_back( n );
8658       }
8659       if( aNds.empty() ) continue;
8660       SMDSAbs_ElementType aType = elem->GetType();
8661
8662       //remove old quadratic element
8663       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8664
8665       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
8666       ReplaceElemInGroups(elem, NewElem, meshDS);
8667       if( theSm && NewElem )
8668         theSm->AddElement( NewElem );
8669
8670       // remove medium nodes
8671       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8672       for ( ; nIt != mediumNodes.end(); ++nIt ) {
8673         const SMDS_MeshNode* n = *nIt;
8674         if ( n->NbInverseElements() == 0 ) {
8675           if ( n->GetPosition()->GetShapeId() != theShapeID )
8676             meshDS->RemoveFreeNode( n, meshDS->MeshElements
8677                                     ( n->GetPosition()->GetShapeId() ));
8678           else
8679             meshDS->RemoveFreeNode( n, theSm );
8680         }
8681       }
8682     }
8683   }
8684   return nbElem;
8685 }
8686
8687 //=======================================================================
8688 //function : ConvertFromQuadratic
8689 //purpose  :
8690 //=======================================================================
8691 bool  SMESH_MeshEditor::ConvertFromQuadratic()
8692 {
8693   int nbCheckedElems = 0;
8694   if ( myMesh->HasShapeToMesh() )
8695   {
8696     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8697     {
8698       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8699       while ( smIt->more() ) {
8700         SMESH_subMesh* sm = smIt->next();
8701         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8702           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8703       }
8704     }
8705   }
8706
8707   int totalNbElems =
8708     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8709   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8710   {
8711     SMESHDS_SubMesh *aSM = 0;
8712     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8713   }
8714
8715   return true;
8716 }
8717
8718 //=======================================================================
8719 //function : SewSideElements
8720 //purpose  :
8721 //=======================================================================
8722
8723 SMESH_MeshEditor::Sew_Error
8724 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
8725                                    TIDSortedElemSet&    theSide2,
8726                                    const SMDS_MeshNode* theFirstNode1,
8727                                    const SMDS_MeshNode* theFirstNode2,
8728                                    const SMDS_MeshNode* theSecondNode1,
8729                                    const SMDS_MeshNode* theSecondNode2)
8730 {
8731   myLastCreatedElems.Clear();
8732   myLastCreatedNodes.Clear();
8733
8734   MESSAGE ("::::SewSideElements()");
8735   if ( theSide1.size() != theSide2.size() )
8736     return SEW_DIFF_NB_OF_ELEMENTS;
8737
8738   Sew_Error aResult = SEW_OK;
8739   // Algo:
8740   // 1. Build set of faces representing each side
8741   // 2. Find which nodes of the side 1 to merge with ones on the side 2
8742   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8743
8744   // =======================================================================
8745   // 1. Build set of faces representing each side:
8746   // =======================================================================
8747   // a. build set of nodes belonging to faces
8748   // b. complete set of faces: find missing fices whose nodes are in set of nodes
8749   // c. create temporary faces representing side of volumes if correspondent
8750   //    face does not exist
8751
8752   SMESHDS_Mesh* aMesh = GetMeshDS();
8753   SMDS_Mesh aTmpFacesMesh;
8754   set<const SMDS_MeshElement*> faceSet1, faceSet2;
8755   set<const SMDS_MeshElement*> volSet1,  volSet2;
8756   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
8757   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
8758   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
8759   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8760   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
8761   int iSide, iFace, iNode;
8762
8763   for ( iSide = 0; iSide < 2; iSide++ ) {
8764     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
8765     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
8766     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8767     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
8768     set<const SMDS_MeshElement*>::iterator vIt;
8769     TIDSortedElemSet::iterator eIt;
8770     set<const SMDS_MeshNode*>::iterator    nIt;
8771
8772     // check that given nodes belong to given elements
8773     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8774     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8775     int firstIndex = -1, secondIndex = -1;
8776     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8777       const SMDS_MeshElement* elem = *eIt;
8778       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
8779       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8780       if ( firstIndex > -1 && secondIndex > -1 ) break;
8781     }
8782     if ( firstIndex < 0 || secondIndex < 0 ) {
8783       // we can simply return until temporary faces created
8784       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8785     }
8786
8787     // -----------------------------------------------------------
8788     // 1a. Collect nodes of existing faces
8789     //     and build set of face nodes in order to detect missing
8790     //     faces corresponing to sides of volumes
8791     // -----------------------------------------------------------
8792
8793     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8794
8795     // loop on the given element of a side
8796     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8797       //const SMDS_MeshElement* elem = *eIt;
8798       const SMDS_MeshElement* elem = *eIt;
8799       if ( elem->GetType() == SMDSAbs_Face ) {
8800         faceSet->insert( elem );
8801         set <const SMDS_MeshNode*> faceNodeSet;
8802         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8803         while ( nodeIt->more() ) {
8804           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8805           nodeSet->insert( n );
8806           faceNodeSet.insert( n );
8807         }
8808         setOfFaceNodeSet.insert( faceNodeSet );
8809       }
8810       else if ( elem->GetType() == SMDSAbs_Volume )
8811         volSet->insert( elem );
8812     }
8813     // ------------------------------------------------------------------------------
8814     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8815     // ------------------------------------------------------------------------------
8816
8817     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8818       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8819       while ( fIt->more() ) { // loop on faces sharing a node
8820         const SMDS_MeshElement* f = fIt->next();
8821         if ( faceSet->find( f ) == faceSet->end() ) {
8822           // check if all nodes are in nodeSet and
8823           // complete setOfFaceNodeSet if they are
8824           set <const SMDS_MeshNode*> faceNodeSet;
8825           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8826           bool allInSet = true;
8827           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8828             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8829             if ( nodeSet->find( n ) == nodeSet->end() )
8830               allInSet = false;
8831             else
8832               faceNodeSet.insert( n );
8833           }
8834           if ( allInSet ) {
8835             faceSet->insert( f );
8836             setOfFaceNodeSet.insert( faceNodeSet );
8837           }
8838         }
8839       }
8840     }
8841
8842     // -------------------------------------------------------------------------
8843     // 1c. Create temporary faces representing sides of volumes if correspondent
8844     //     face does not exist
8845     // -------------------------------------------------------------------------
8846
8847     if ( !volSet->empty() ) {
8848       //int nodeSetSize = nodeSet->size();
8849
8850       // loop on given volumes
8851       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8852         SMDS_VolumeTool vol (*vIt);
8853         // loop on volume faces: find free faces
8854         // --------------------------------------
8855         list<const SMDS_MeshElement* > freeFaceList;
8856         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8857           if ( !vol.IsFreeFace( iFace ))
8858             continue;
8859           // check if there is already a face with same nodes in a face set
8860           const SMDS_MeshElement* aFreeFace = 0;
8861           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8862           int nbNodes = vol.NbFaceNodes( iFace );
8863           set <const SMDS_MeshNode*> faceNodeSet;
8864           vol.GetFaceNodes( iFace, faceNodeSet );
8865           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8866           if ( isNewFace ) {
8867             // no such a face is given but it still can exist, check it
8868             if ( nbNodes == 3 ) {
8869               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8870             }
8871             else if ( nbNodes == 4 ) {
8872               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8873             }
8874             else {
8875               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8876               aFreeFace = aMesh->FindFace(poly_nodes);
8877             }
8878           }
8879           if ( !aFreeFace ) {
8880             // create a temporary face
8881             if ( nbNodes == 3 ) {
8882               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8883             }
8884             else if ( nbNodes == 4 ) {
8885               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8886             }
8887             else {
8888               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8889               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8890             }
8891           }
8892           if ( aFreeFace )
8893             freeFaceList.push_back( aFreeFace );
8894
8895         } // loop on faces of a volume
8896
8897         // choose one of several free faces
8898         // --------------------------------------
8899         if ( freeFaceList.size() > 1 ) {
8900           // choose a face having max nb of nodes shared by other elems of a side
8901           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
8902           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8903           while ( fIt != freeFaceList.end() ) { // loop on free faces
8904             int nbSharedNodes = 0;
8905             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8906             while ( nodeIt->more() ) { // loop on free face nodes
8907               const SMDS_MeshNode* n =
8908                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8909               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8910               while ( invElemIt->more() ) {
8911                 const SMDS_MeshElement* e = invElemIt->next();
8912                 if ( faceSet->find( e ) != faceSet->end() )
8913                   nbSharedNodes++;
8914                 if ( elemSet->find( e ) != elemSet->end() )
8915                   nbSharedNodes++;
8916               }
8917             }
8918             if ( nbSharedNodes >= maxNbNodes ) {
8919               maxNbNodes = nbSharedNodes;
8920               fIt++;
8921             }
8922             else
8923               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
8924           }
8925           if ( freeFaceList.size() > 1 )
8926           {
8927             // could not choose one face, use another way
8928             // choose a face most close to the bary center of the opposite side
8929             gp_XYZ aBC( 0., 0., 0. );
8930             set <const SMDS_MeshNode*> addedNodes;
8931             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8932             eIt = elemSet2->begin();
8933             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
8934               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
8935               while ( nodeIt->more() ) { // loop on free face nodes
8936                 const SMDS_MeshNode* n =
8937                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8938                 if ( addedNodes.insert( n ).second )
8939                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
8940               }
8941             }
8942             aBC /= addedNodes.size();
8943             double minDist = DBL_MAX;
8944             fIt = freeFaceList.begin();
8945             while ( fIt != freeFaceList.end() ) { // loop on free faces
8946               double dist = 0;
8947               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8948               while ( nodeIt->more() ) { // loop on free face nodes
8949                 const SMDS_MeshNode* n =
8950                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8951                 gp_XYZ p( n->X(),n->Y(),n->Z() );
8952                 dist += ( aBC - p ).SquareModulus();
8953               }
8954               if ( dist < minDist ) {
8955                 minDist = dist;
8956                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
8957               }
8958               else
8959                 fIt = freeFaceList.erase( fIt++ );
8960             }
8961           }
8962         } // choose one of several free faces of a volume
8963
8964         if ( freeFaceList.size() == 1 ) {
8965           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
8966           faceSet->insert( aFreeFace );
8967           // complete a node set with nodes of a found free face
8968           //           for ( iNode = 0; iNode < ; iNode++ )
8969           //             nodeSet->insert( fNodes[ iNode ] );
8970         }
8971
8972       } // loop on volumes of a side
8973
8974       //       // complete a set of faces if new nodes in a nodeSet appeared
8975       //       // ----------------------------------------------------------
8976       //       if ( nodeSetSize != nodeSet->size() ) {
8977       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8978       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8979       //           while ( fIt->more() ) { // loop on faces sharing a node
8980       //             const SMDS_MeshElement* f = fIt->next();
8981       //             if ( faceSet->find( f ) == faceSet->end() ) {
8982       //               // check if all nodes are in nodeSet and
8983       //               // complete setOfFaceNodeSet if they are
8984       //               set <const SMDS_MeshNode*> faceNodeSet;
8985       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8986       //               bool allInSet = true;
8987       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8988       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8989       //                 if ( nodeSet->find( n ) == nodeSet->end() )
8990       //                   allInSet = false;
8991       //                 else
8992       //                   faceNodeSet.insert( n );
8993       //               }
8994       //               if ( allInSet ) {
8995       //                 faceSet->insert( f );
8996       //                 setOfFaceNodeSet.insert( faceNodeSet );
8997       //               }
8998       //             }
8999       //           }
9000       //         }
9001       //       }
9002     } // Create temporary faces, if there are volumes given
9003   } // loop on sides
9004
9005   if ( faceSet1.size() != faceSet2.size() ) {
9006     // delete temporary faces: they are in reverseElements of actual nodes
9007     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9008     while ( tmpFaceIt->more() )
9009       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9010     MESSAGE("Diff nb of faces");
9011     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9012   }
9013
9014   // ============================================================
9015   // 2. Find nodes to merge:
9016   //              bind a node to remove to a node to put instead
9017   // ============================================================
9018
9019   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9020   if ( theFirstNode1 != theFirstNode2 )
9021     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9022   if ( theSecondNode1 != theSecondNode2 )
9023     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9024
9025   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9026   set< long > linkIdSet; // links to process
9027   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9028
9029   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9030   list< NLink > linkList[2];
9031   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9032   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9033   // loop on links in linkList; find faces by links and append links
9034   // of the found faces to linkList
9035   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9036   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9037     NLink link[] = { *linkIt[0], *linkIt[1] };
9038     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9039     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9040       continue;
9041
9042     // by links, find faces in the face sets,
9043     // and find indices of link nodes in the found faces;
9044     // in a face set, there is only one or no face sharing a link
9045     // ---------------------------------------------------------------
9046
9047     const SMDS_MeshElement* face[] = { 0, 0 };
9048     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9049     vector<const SMDS_MeshNode*> fnodes1(9);
9050     vector<const SMDS_MeshNode*> fnodes2(9);
9051     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9052     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9053     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9054     int iLinkNode[2][2];
9055     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9056       const SMDS_MeshNode* n1 = link[iSide].first;
9057       const SMDS_MeshNode* n2 = link[iSide].second;
9058       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9059       set< const SMDS_MeshElement* > fMap;
9060       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9061         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9062         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9063         while ( fIt->more() ) { // loop on faces sharing a node
9064           const SMDS_MeshElement* f = fIt->next();
9065           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9066               ! fMap.insert( f ).second ) // f encounters twice
9067           {
9068             if ( face[ iSide ] ) {
9069               MESSAGE( "2 faces per link " );
9070               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9071               break;
9072             }
9073             face[ iSide ] = f;
9074             faceSet->erase( f );
9075             // get face nodes and find ones of a link
9076             iNode = 0;
9077             int nbl = -1;
9078             if(f->IsPoly()) {
9079               if(iSide==0) {
9080                 fnodes1.resize(f->NbNodes()+1);
9081                 notLinkNodes1.resize(f->NbNodes()-2);
9082               }
9083               else {
9084                 fnodes2.resize(f->NbNodes()+1);
9085                 notLinkNodes2.resize(f->NbNodes()-2);
9086               }
9087             }
9088             if(!f->IsQuadratic()) {
9089               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9090               while ( nIt->more() ) {
9091                 const SMDS_MeshNode* n =
9092                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9093                 if ( n == n1 ) {
9094                   iLinkNode[ iSide ][ 0 ] = iNode;
9095                 }
9096                 else if ( n == n2 ) {
9097                   iLinkNode[ iSide ][ 1 ] = iNode;
9098                 }
9099                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9100                 //  notLinkNodes[ iSide ][ 1 ] = n;
9101                 //else
9102                 //  notLinkNodes[ iSide ][ 0 ] = n;
9103                 else {
9104                   nbl++;
9105                   if(iSide==0)
9106                     notLinkNodes1[nbl] = n;
9107                   //notLinkNodes1.push_back(n);
9108                   else
9109                     notLinkNodes2[nbl] = n;
9110                   //notLinkNodes2.push_back(n);
9111                 }
9112                 //faceNodes[ iSide ][ iNode++ ] = n;
9113                 if(iSide==0) {
9114                   fnodes1[iNode++] = n;
9115                 }
9116                 else {
9117                   fnodes2[iNode++] = n;
9118                 }
9119               }
9120             }
9121             else { // f->IsQuadratic()
9122               const SMDS_QuadraticFaceOfNodes* F =
9123                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9124               // use special nodes iterator
9125               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9126               while ( anIter->more() ) {
9127                 const SMDS_MeshNode* n =
9128                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9129                 if ( n == n1 ) {
9130                   iLinkNode[ iSide ][ 0 ] = iNode;
9131                 }
9132                 else if ( n == n2 ) {
9133                   iLinkNode[ iSide ][ 1 ] = iNode;
9134                 }
9135                 else {
9136                   nbl++;
9137                   if(iSide==0) {
9138                     notLinkNodes1[nbl] = n;
9139                   }
9140                   else {
9141                     notLinkNodes2[nbl] = n;
9142                   }
9143                 }
9144                 if(iSide==0) {
9145                   fnodes1[iNode++] = n;
9146                 }
9147                 else {
9148                   fnodes2[iNode++] = n;
9149                 }
9150               }
9151             }
9152             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9153             if(iSide==0) {
9154               fnodes1[iNode] = fnodes1[0];
9155             }
9156             else {
9157               fnodes2[iNode] = fnodes1[0];
9158             }
9159           }
9160         }
9161       }
9162     }
9163
9164     // check similarity of elements of the sides
9165     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9166       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9167       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9168         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9169       }
9170       else {
9171         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9172       }
9173       break; // do not return because it s necessary to remove tmp faces
9174     }
9175
9176     // set nodes to merge
9177     // -------------------
9178
9179     if ( face[0] && face[1] )  {
9180       int nbNodes = face[0]->NbNodes();
9181       if ( nbNodes != face[1]->NbNodes() ) {
9182         MESSAGE("Diff nb of face nodes");
9183         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9184         break; // do not return because it s necessary to remove tmp faces
9185       }
9186       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9187       if ( nbNodes == 3 ) {
9188         //nReplaceMap.insert( TNodeNodeMap::value_type
9189         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9190         nReplaceMap.insert( TNodeNodeMap::value_type
9191                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9192       }
9193       else {
9194         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9195           // analyse link orientation in faces
9196           int i1 = iLinkNode[ iSide ][ 0 ];
9197           int i2 = iLinkNode[ iSide ][ 1 ];
9198           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9199           // if notLinkNodes are the first and the last ones, then
9200           // their order does not correspond to the link orientation
9201           if (( i1 == 1 && i2 == 2 ) ||
9202               ( i1 == 2 && i2 == 1 ))
9203             reverse[ iSide ] = !reverse[ iSide ];
9204         }
9205         if ( reverse[0] == reverse[1] ) {
9206           //nReplaceMap.insert( TNodeNodeMap::value_type
9207           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9208           //nReplaceMap.insert( TNodeNodeMap::value_type
9209           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9210           for(int nn=0; nn<nbNodes-2; nn++) {
9211             nReplaceMap.insert( TNodeNodeMap::value_type
9212                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9213           }
9214         }
9215         else {
9216           //nReplaceMap.insert( TNodeNodeMap::value_type
9217           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9218           //nReplaceMap.insert( TNodeNodeMap::value_type
9219           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9220           for(int nn=0; nn<nbNodes-2; nn++) {
9221             nReplaceMap.insert( TNodeNodeMap::value_type
9222                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9223           }
9224         }
9225       }
9226
9227       // add other links of the faces to linkList
9228       // -----------------------------------------
9229
9230       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9231       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9232         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9233         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9234         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9235         if ( !iter_isnew.second ) { // already in a set: no need to process
9236           linkIdSet.erase( iter_isnew.first );
9237         }
9238         else // new in set == encountered for the first time: add
9239         {
9240           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9241           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9242           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9243           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9244           linkList[0].push_back ( NLink( n1, n2 ));
9245           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9246         }
9247       }
9248     } // 2 faces found
9249   } // loop on link lists
9250
9251   if ( aResult == SEW_OK &&
9252        ( linkIt[0] != linkList[0].end() ||
9253          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9254     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9255              " " << (faceSetPtr[1]->empty()));
9256     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9257   }
9258
9259   // ====================================================================
9260   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9261   // ====================================================================
9262
9263   // delete temporary faces: they are in reverseElements of actual nodes
9264   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9265   while ( tmpFaceIt->more() )
9266     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9267
9268   if ( aResult != SEW_OK)
9269     return aResult;
9270
9271   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9272   // loop on nodes replacement map
9273   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9274   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9275     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9276       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9277       nodeIDsToRemove.push_back( nToRemove->GetID() );
9278       // loop on elements sharing nToRemove
9279       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9280       while ( invElemIt->more() ) {
9281         const SMDS_MeshElement* e = invElemIt->next();
9282         // get a new suite of nodes: make replacement
9283         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9284         vector< const SMDS_MeshNode*> nodes( nbNodes );
9285         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9286         while ( nIt->more() ) {
9287           const SMDS_MeshNode* n =
9288             static_cast<const SMDS_MeshNode*>( nIt->next() );
9289           nnIt = nReplaceMap.find( n );
9290           if ( nnIt != nReplaceMap.end() ) {
9291             nbReplaced++;
9292             n = (*nnIt).second;
9293           }
9294           nodes[ i++ ] = n;
9295         }
9296         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9297         //         elemIDsToRemove.push_back( e->GetID() );
9298         //       else
9299         if ( nbReplaced )
9300           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9301       }
9302     }
9303
9304   Remove( nodeIDsToRemove, true );
9305
9306   return aResult;
9307 }
9308
9309 //================================================================================
9310 /*!
9311  * \brief Find corresponding nodes in two sets of faces
9312  * \param theSide1 - first face set
9313  * \param theSide2 - second first face
9314  * \param theFirstNode1 - a boundary node of set 1
9315  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9316  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9317  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9318  * \param nReplaceMap - output map of corresponding nodes
9319  * \retval bool  - is a success or not
9320  */
9321 //================================================================================
9322
9323 #ifdef _DEBUG_
9324 //#define DEBUG_MATCHING_NODES
9325 #endif
9326
9327 SMESH_MeshEditor::Sew_Error
9328 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9329                                     set<const SMDS_MeshElement*>& theSide2,
9330                                     const SMDS_MeshNode*          theFirstNode1,
9331                                     const SMDS_MeshNode*          theFirstNode2,
9332                                     const SMDS_MeshNode*          theSecondNode1,
9333                                     const SMDS_MeshNode*          theSecondNode2,
9334                                     TNodeNodeMap &                nReplaceMap)
9335 {
9336   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9337
9338   nReplaceMap.clear();
9339   if ( theFirstNode1 != theFirstNode2 )
9340     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9341   if ( theSecondNode1 != theSecondNode2 )
9342     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9343
9344   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9345   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9346
9347   list< NLink > linkList[2];
9348   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9349   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9350
9351   // loop on links in linkList; find faces by links and append links
9352   // of the found faces to linkList
9353   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9354   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9355     NLink link[] = { *linkIt[0], *linkIt[1] };
9356     if ( linkSet.find( link[0] ) == linkSet.end() )
9357       continue;
9358
9359     // by links, find faces in the face sets,
9360     // and find indices of link nodes in the found faces;
9361     // in a face set, there is only one or no face sharing a link
9362     // ---------------------------------------------------------------
9363
9364     const SMDS_MeshElement* face[] = { 0, 0 };
9365     list<const SMDS_MeshNode*> notLinkNodes[2];
9366     //bool reverse[] = { false, false }; // order of notLinkNodes
9367     int nbNodes[2];
9368     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9369     {
9370       const SMDS_MeshNode* n1 = link[iSide].first;
9371       const SMDS_MeshNode* n2 = link[iSide].second;
9372       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9373       set< const SMDS_MeshElement* > facesOfNode1;
9374       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9375       {
9376         // during a loop of the first node, we find all faces around n1,
9377         // during a loop of the second node, we find one face sharing both n1 and n2
9378         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9379         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9380         while ( fIt->more() ) { // loop on faces sharing a node
9381           const SMDS_MeshElement* f = fIt->next();
9382           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9383               ! facesOfNode1.insert( f ).second ) // f encounters twice
9384           {
9385             if ( face[ iSide ] ) {
9386               MESSAGE( "2 faces per link " );
9387               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9388             }
9389             face[ iSide ] = f;
9390             faceSet->erase( f );
9391
9392             // get not link nodes
9393             int nbN = f->NbNodes();
9394             if ( f->IsQuadratic() )
9395               nbN /= 2;
9396             nbNodes[ iSide ] = nbN;
9397             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9398             int i1 = f->GetNodeIndex( n1 );
9399             int i2 = f->GetNodeIndex( n2 );
9400             int iEnd = nbN, iBeg = -1, iDelta = 1;
9401             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9402             if ( reverse ) {
9403               std::swap( iEnd, iBeg ); iDelta = -1;
9404             }
9405             int i = i2;
9406             while ( true ) {
9407               i += iDelta;
9408               if ( i == iEnd ) i = iBeg + iDelta;
9409               if ( i == i1 ) break;
9410               nodes.push_back ( f->GetNode( i ) );
9411             }
9412           }
9413         }
9414       }
9415     }
9416     // check similarity of elements of the sides
9417     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9418       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9419       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9420         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9421       }
9422       else {
9423         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9424       }
9425     }
9426
9427     // set nodes to merge
9428     // -------------------
9429
9430     if ( face[0] && face[1] )  {
9431       if ( nbNodes[0] != nbNodes[1] ) {
9432         MESSAGE("Diff nb of face nodes");
9433         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9434       }
9435 #ifdef DEBUG_MATCHING_NODES
9436       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9437                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9438                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9439 #endif
9440       int nbN = nbNodes[0];
9441       {
9442         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9443         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9444         for ( int i = 0 ; i < nbN - 2; ++i ) {
9445 #ifdef DEBUG_MATCHING_NODES
9446           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9447 #endif
9448           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9449         }
9450       }
9451
9452       // add other links of the face 1 to linkList
9453       // -----------------------------------------
9454
9455       const SMDS_MeshElement* f0 = face[0];
9456       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9457       for ( int i = 0; i < nbN; i++ )
9458       {
9459         const SMDS_MeshNode* n2 = f0->GetNode( i );
9460         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9461           linkSet.insert( SMESH_TLink( n1, n2 ));
9462         if ( !iter_isnew.second ) { // already in a set: no need to process
9463           linkSet.erase( iter_isnew.first );
9464         }
9465         else // new in set == encountered for the first time: add
9466         {
9467 #ifdef DEBUG_MATCHING_NODES
9468           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9469                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9470 #endif
9471           linkList[0].push_back ( NLink( n1, n2 ));
9472           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9473         }
9474         n1 = n2;
9475       }
9476     } // 2 faces found
9477   } // loop on link lists
9478
9479   return SEW_OK;
9480 }
9481
9482 //================================================================================
9483 /*!
9484   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9485   \param theElems - the list of elements (edges or faces) to be replicated
9486   The nodes for duplication could be found from these elements
9487   \param theNodesNot - list of nodes to NOT replicate
9488   \param theAffectedElems - the list of elements (cells and edges) to which the 
9489   replicated nodes should be associated to.
9490   \return TRUE if operation has been completed successfully, FALSE otherwise
9491 */
9492 //================================================================================
9493
9494 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9495                                     const TIDSortedElemSet& theNodesNot,
9496                                     const TIDSortedElemSet& theAffectedElems )
9497 {
9498   myLastCreatedElems.Clear();
9499   myLastCreatedNodes.Clear();
9500
9501   if ( theElems.size() == 0 )
9502     return false;
9503
9504   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9505   if ( !aMeshDS )
9506     return false;
9507
9508   bool res = false;
9509   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9510   // duplicate elements and nodes
9511   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9512   // replce nodes by duplications
9513   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9514   return res;
9515 }
9516
9517 //================================================================================
9518 /*!
9519   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9520   \param theMeshDS - mesh instance
9521   \param theElems - the elements replicated or modified (nodes should be changed)
9522   \param theNodesNot - nodes to NOT replicate
9523   \param theNodeNodeMap - relation of old node to new created node
9524   \param theIsDoubleElem - flag os to replicate element or modify
9525   \return TRUE if operation has been completed successfully, FALSE otherwise
9526 */
9527 //================================================================================
9528
9529 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9530                                     const TIDSortedElemSet& theElems,
9531                                     const TIDSortedElemSet& theNodesNot,
9532                                     std::map< const SMDS_MeshNode*,
9533                                     const SMDS_MeshNode* >& theNodeNodeMap,
9534                                     const bool theIsDoubleElem )
9535 {
9536   // iterate on through element and duplicate them (by nodes duplication)
9537   bool res = false;
9538   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9539   for ( ;  elemItr != theElems.end(); ++elemItr )
9540   {
9541     const SMDS_MeshElement* anElem = *elemItr;
9542     if (!anElem)
9543       continue;
9544
9545     bool isDuplicate = false;
9546     // duplicate nodes to duplicate element
9547     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9548     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9549     int ind = 0;
9550     while ( anIter->more() ) 
9551     { 
9552
9553       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9554       SMDS_MeshNode* aNewNode = aCurrNode;
9555       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9556         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9557       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9558       {
9559         // duplicate node
9560         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9561         theNodeNodeMap[ aCurrNode ] = aNewNode;
9562         myLastCreatedNodes.Append( aNewNode );
9563       }
9564       isDuplicate |= (aCurrNode != aNewNode);
9565       newNodes[ ind++ ] = aNewNode;
9566     }
9567     if ( !isDuplicate )
9568       continue;
9569
9570     if ( theIsDoubleElem )
9571       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
9572     else
9573       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9574
9575     res = true;
9576   }
9577   return res;
9578 }
9579
9580 //================================================================================
9581 /*!
9582   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9583   \param theNodes - identifiers of nodes to be doubled
9584   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
9585          nodes. If list of element identifiers is empty then nodes are doubled but 
9586          they not assigned to elements
9587   \return TRUE if operation has been completed successfully, FALSE otherwise
9588 */
9589 //================================================================================
9590
9591 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
9592                                     const std::list< int >& theListOfModifiedElems )
9593 {
9594   myLastCreatedElems.Clear();
9595   myLastCreatedNodes.Clear();
9596
9597   if ( theListOfNodes.size() == 0 )
9598     return false;
9599
9600   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9601   if ( !aMeshDS )
9602     return false;
9603
9604   // iterate through nodes and duplicate them
9605
9606   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9607
9608   std::list< int >::const_iterator aNodeIter;
9609   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9610   {
9611     int aCurr = *aNodeIter;
9612     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9613     if ( !aNode )
9614       continue;
9615
9616     // duplicate node
9617
9618     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9619     if ( aNewNode )
9620     {
9621       anOldNodeToNewNode[ aNode ] = aNewNode;
9622       myLastCreatedNodes.Append( aNewNode );
9623     }
9624   }
9625
9626   // Create map of new nodes for modified elements
9627
9628   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9629
9630   std::list< int >::const_iterator anElemIter;
9631   for ( anElemIter = theListOfModifiedElems.begin(); 
9632         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9633   {
9634     int aCurr = *anElemIter;
9635     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9636     if ( !anElem )
9637       continue;
9638
9639     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9640
9641     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9642     int ind = 0;
9643     while ( anIter->more() ) 
9644     { 
9645       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9646       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9647       {
9648         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9649         aNodeArr[ ind++ ] = aNewNode;
9650       }
9651       else
9652         aNodeArr[ ind++ ] = aCurrNode;
9653     }
9654     anElemToNodes[ anElem ] = aNodeArr;
9655   }
9656
9657   // Change nodes of elements  
9658
9659   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9660     anElemToNodesIter = anElemToNodes.begin();
9661   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9662   {
9663     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9664     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9665     if ( anElem )
9666       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9667   }
9668
9669   return true;
9670 }
9671
9672 namespace {
9673
9674   //================================================================================
9675   /*!
9676   \brief Check if element located inside shape
9677   \return TRUE if IN or ON shape, FALSE otherwise
9678   */
9679   //================================================================================
9680
9681   template<class Classifier>
9682   bool isInside(const SMDS_MeshElement* theElem,
9683                 Classifier&             theClassifier,
9684                 const double            theTol)
9685   {
9686     gp_XYZ centerXYZ (0, 0, 0);
9687     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9688     while (aNodeItr->more())
9689       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9690
9691     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9692     theClassifier.Perform(aPnt, theTol);
9693     TopAbs_State aState = theClassifier.State();
9694     return (aState == TopAbs_IN || aState == TopAbs_ON );
9695   }
9696
9697   //================================================================================
9698   /*!
9699    * \brief Classifier of the 3D point on the TopoDS_Face
9700    *        with interaface suitable for isInside()
9701    */
9702   //================================================================================
9703
9704   struct _FaceClassifier
9705   {
9706     Extrema_ExtPS       _extremum;
9707     BRepAdaptor_Surface _surface;
9708     TopAbs_State        _state;
9709
9710     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9711     {
9712       _extremum.Initialize( _surface,
9713                             _surface.FirstUParameter(), _surface.LastUParameter(),
9714                             _surface.FirstVParameter(), _surface.LastVParameter(),
9715                             _surface.Tolerance(), _surface.Tolerance() );
9716     }
9717     void Perform(const gp_Pnt& aPnt, double theTol)
9718     {
9719       _state = TopAbs_OUT;
9720       _extremum.Perform(aPnt);
9721       if ( _extremum.IsDone() )
9722         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9723           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9724     }
9725     TopAbs_State State() const
9726     {
9727       return _state;
9728     }
9729   };
9730 }
9731
9732 //================================================================================
9733 /*!
9734   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9735   \param theElems - group of of elements (edges or faces) to be replicated
9736   \param theNodesNot - group of nodes not to replicate
9737   \param theShape - shape to detect affected elements (element which geometric center
9738   located on or inside shape).
9739   The replicated nodes should be associated to affected elements.
9740   \return TRUE if operation has been completed successfully, FALSE otherwise
9741 */
9742 //================================================================================
9743
9744 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
9745                                             const TIDSortedElemSet& theNodesNot,
9746                                             const TopoDS_Shape&     theShape )
9747 {
9748   if ( theShape.IsNull() )
9749     return false;
9750
9751   const double aTol = Precision::Confusion();
9752   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9753   auto_ptr<_FaceClassifier>              aFaceClassifier;
9754   if ( theShape.ShapeType() == TopAbs_SOLID )
9755   {
9756     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9757     bsc3d->PerformInfinitePoint(aTol);
9758   }
9759   else if (theShape.ShapeType() == TopAbs_FACE )
9760   {
9761     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9762   }
9763
9764   // iterates on indicated elements and get elements by back references from their nodes
9765   TIDSortedElemSet anAffected;
9766   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9767   for ( ;  elemItr != theElems.end(); ++elemItr )
9768   {
9769     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9770     if (!anElem)
9771       continue;
9772
9773     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9774     while ( nodeItr->more() )
9775     {
9776       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9777       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9778         continue;
9779       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9780       while ( backElemItr->more() )
9781       {
9782         const SMDS_MeshElement* curElem = backElemItr->next();
9783         if ( curElem && theElems.find(curElem) == theElems.end() &&
9784              ( bsc3d.get() ?
9785                isInside( curElem, *bsc3d, aTol ) :
9786                isInside( curElem, *aFaceClassifier, aTol )))
9787           anAffected.insert( curElem );
9788       }
9789     }
9790   }
9791   return DoubleNodes( theElems, theNodesNot, anAffected );
9792 }
9793
9794 //================================================================================
9795 /*!
9796  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
9797  * The created 2D mesh elements based on nodes of free faces of boundary volumes
9798  * \return TRUE if operation has been completed successfully, FALSE otherwise
9799  */
9800 //================================================================================
9801
9802 bool SMESH_MeshEditor::Make2DMeshFrom3D()
9803 {
9804   // iterates on volume elements and detect all free faces on them
9805   SMESHDS_Mesh* aMesh = GetMeshDS();
9806   if (!aMesh)
9807     return false;
9808   bool res = false;
9809   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
9810   while(vIt->more())
9811   {
9812     const SMDS_MeshVolume* volume = vIt->next();
9813     SMDS_VolumeTool vTool( volume );
9814     vTool.SetExternalNormal();
9815     const bool isPoly = volume->IsPoly();
9816     const bool isQuad = volume->IsQuadratic();
9817     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9818     {
9819       if (!vTool.IsFreeFace(iface))
9820         continue;
9821       vector<const SMDS_MeshNode *> nodes;
9822       int nbFaceNodes = vTool.NbFaceNodes(iface);
9823       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
9824       int inode = 0;
9825       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
9826         nodes.push_back(faceNodes[inode]);
9827       if (isQuad)
9828         for ( inode = 1; inode < nbFaceNodes; inode += 2)
9829           nodes.push_back(faceNodes[inode]);
9830
9831       // add new face based on volume nodes
9832       if (aMesh->FindFace( nodes ) )
9833         continue; // face already exsist
9834       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
9835       res = true;
9836     }
9837   }
9838   return res;
9839 }