Salome HOME
merge V5_1_4
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_LinearEdge.hxx"
39
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
42
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
49
50 #include "utilities.h"
51
52 #include <BRepAdaptor_Surface.hxx>
53 #include <BRepClass3d_SolidClassifier.hxx>
54 #include <BRep_Tool.hxx>
55 #include <ElCLib.hxx>
56 #include <Extrema_GenExtPS.hxx>
57 #include <Extrema_POnCurv.hxx>
58 #include <Extrema_POnSurf.hxx>
59 #include <GC_MakeSegment.hxx>
60 #include <Geom2d_Curve.hxx>
61 #include <GeomAPI_ExtremaCurveCurve.hxx>
62 #include <GeomAdaptor_Surface.hxx>
63 #include <Geom_Curve.hxx>
64 #include <Geom_Line.hxx>
65 #include <Geom_Surface.hxx>
66 #include <IntAna_IntConicQuad.hxx>
67 #include <IntAna_Quadric.hxx>
68 #include <Precision.hxx>
69 #include <TColStd_ListOfInteger.hxx>
70 #include <TopAbs_State.hxx>
71 #include <TopExp.hxx>
72 #include <TopExp_Explorer.hxx>
73 #include <TopTools_ListIteratorOfListOfShape.hxx>
74 #include <TopTools_ListOfShape.hxx>
75 #include <TopTools_SequenceOfShape.hxx>
76 #include <TopoDS.hxx>
77 #include <TopoDS_Face.hxx>
78 #include <gp.hxx>
79 #include <gp_Ax1.hxx>
80 #include <gp_Dir.hxx>
81 #include <gp_Lin.hxx>
82 #include <gp_Pln.hxx>
83 #include <gp_Trsf.hxx>
84 #include <gp_Vec.hxx>
85 #include <gp_XY.hxx>
86 #include <gp_XYZ.hxx>
87
88 #include <math.h>
89
90 #include <map>
91 #include <set>
92 #include <numeric>
93 #include <limits>
94
95 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
96
97 using namespace std;
98 using namespace SMESH::Controls;
99
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
101 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
102
103 //=======================================================================
104 //function : SMESH_MeshEditor
105 //purpose  :
106 //=======================================================================
107
108 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
109   :myMesh( theMesh ) // theMesh may be NULL
110 {
111 }
112
113 //=======================================================================
114 /*!
115  * \brief Add element
116  */
117 //=======================================================================
118
119 SMDS_MeshElement*
120 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
121                              const SMDSAbs_ElementType            type,
122                              const bool                           isPoly,
123                              const int                            ID)
124 {
125   SMDS_MeshElement* e = 0;
126   int nbnode = node.size();
127   SMESHDS_Mesh* mesh = GetMeshDS();
128   switch ( type ) {
129   case SMDSAbs_0DElement:
130     if ( nbnode == 1 )
131       if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
132       else      e = mesh->Add0DElement      (node[0] );
133     break;
134   case SMDSAbs_Edge:
135     if ( nbnode == 2 )
136       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
137       else      e = mesh->AddEdge      (node[0], node[1] );
138     else if ( nbnode == 3 )
139       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
140       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
141     break;
142   case SMDSAbs_Face:
143     if ( !isPoly ) {
144       if      (nbnode == 3)
145         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
146         else      e = mesh->AddFace      (node[0], node[1], node[2] );
147       else if (nbnode == 4) 
148         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
149         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
150       else if (nbnode == 6)
151         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
152                                           node[4], node[5], ID);
153         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
154                                           node[4], node[5] );
155       else if (nbnode == 8)
156         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
157                                           node[4], node[5], node[6], node[7], ID);
158         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
159                                           node[4], node[5], node[6], node[7] );
160     } else {
161       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
162       else      e = mesh->AddPolygonalFace      (node    );
163     }
164     break;
165   case SMDSAbs_Volume:
166     if ( !isPoly ) {
167       if      (nbnode == 4)
168         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
170       else if (nbnode == 5)
171         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
172                                             node[4], ID);
173         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
174                                             node[4] );
175       else if (nbnode == 6)
176         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
177                                             node[4], node[5], ID);
178         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
179                                             node[4], node[5] );
180       else if (nbnode == 8)
181         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
182                                             node[4], node[5], node[6], node[7], ID);
183         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
184                                             node[4], node[5], node[6], node[7] );
185       else if (nbnode == 10)
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], ID);
189         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
190                                             node[4], node[5], node[6], node[7],
191                                             node[8], node[9] );
192       else if (nbnode == 13)
193         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
194                                             node[4], node[5], node[6], node[7],
195                                             node[8], node[9], node[10],node[11],
196                                             node[12],ID);
197         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
198                                             node[4], node[5], node[6], node[7],
199                                             node[8], node[9], node[10],node[11],
200                                             node[12] );
201       else if (nbnode == 15)
202         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
203                                             node[4], node[5], node[6], node[7],
204                                             node[8], node[9], node[10],node[11],
205                                             node[12],node[13],node[14],ID);
206         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
207                                             node[4], node[5], node[6], node[7],
208                                             node[8], node[9], node[10],node[11],
209                                             node[12],node[13],node[14] );
210       else if (nbnode == 20)
211         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
212                                             node[4], node[5], node[6], node[7],
213                                             node[8], node[9], node[10],node[11],
214                                             node[12],node[13],node[14],node[15],
215                                             node[16],node[17],node[18],node[19],ID);
216         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
217                                             node[4], node[5], node[6], node[7],
218                                             node[8], node[9], node[10],node[11],
219                                             node[12],node[13],node[14],node[15],
220                                             node[16],node[17],node[18],node[19] );
221     }
222   }
223   return e;
224 }
225
226 //=======================================================================
227 /*!
228  * \brief Add element
229  */
230 //=======================================================================
231
232 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
233                                                const SMDSAbs_ElementType type,
234                                                const bool                isPoly,
235                                                const int                 ID)
236 {
237   vector<const SMDS_MeshNode*> nodes;
238   nodes.reserve( nodeIDs.size() );
239   vector<int>::const_iterator id = nodeIDs.begin();
240   while ( id != nodeIDs.end() ) {
241     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
242       nodes.push_back( node );
243     else
244       return 0;
245   }
246   return AddElement( nodes, type, isPoly, ID );
247 }
248
249 //=======================================================================
250 //function : Remove
251 //purpose  : Remove a node or an element.
252 //           Modify a compute state of sub-meshes which become empty
253 //=======================================================================
254
255 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
256                                const bool         isNodes )
257 {
258   myLastCreatedElems.Clear();
259   myLastCreatedNodes.Clear();
260
261   SMESHDS_Mesh* aMesh = GetMeshDS();
262   set< SMESH_subMesh *> smmap;
263
264   list<int>::const_iterator it = theIDs.begin();
265   for ( ; it != theIDs.end(); it++ ) {
266     const SMDS_MeshElement * elem;
267     if ( isNodes )
268       elem = aMesh->FindNode( *it );
269     else
270       elem = aMesh->FindElement( *it );
271     if ( !elem )
272       continue;
273
274     // Notify VERTEX sub-meshes about modification
275     if ( isNodes ) {
276       const SMDS_MeshNode* node = cast2Node( elem );
277       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
278         if ( int aShapeID = node->GetPosition()->GetShapeId() )
279           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
280             smmap.insert( sm );
281     }
282     // Find sub-meshes to notify about modification
283     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
284     //     while ( nodeIt->more() ) {
285     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
286     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
287     //       if ( aPosition.get() ) {
288     //         if ( int aShapeID = aPosition->GetShapeId() ) {
289     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
290     //             smmap.insert( sm );
291     //         }
292     //       }
293     //     }
294
295     // Do remove
296     if ( isNodes )
297       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
298     else
299       aMesh->RemoveElement( elem );
300   }
301
302   // Notify sub-meshes about modification
303   if ( !smmap.empty() ) {
304     set< SMESH_subMesh *>::iterator smIt;
305     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
306       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
307   }
308
309   //   // Check if the whole mesh becomes empty
310   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
311   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
312
313   return true;
314 }
315
316 //=======================================================================
317 //function : FindShape
318 //purpose  : Return an index of the shape theElem is on
319 //           or zero if a shape not found
320 //=======================================================================
321
322 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
323 {
324   myLastCreatedElems.Clear();
325   myLastCreatedNodes.Clear();
326
327   SMESHDS_Mesh * aMesh = GetMeshDS();
328   if ( aMesh->ShapeToMesh().IsNull() )
329     return 0;
330
331   if ( theElem->GetType() == SMDSAbs_Node ) {
332     const SMDS_PositionPtr& aPosition =
333       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
334     if ( aPosition )
335       return aPosition->GetShapeId();
336     else
337       return 0;
338   }
339
340   TopoDS_Shape aShape; // the shape a node is on
341   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
342   while ( nodeIt->more() ) {
343     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
344     const SMDS_PositionPtr& aPosition = node->GetPosition();
345     if ( aPosition ) {
346       int aShapeID = aPosition->GetShapeId();
347       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
348       if ( sm ) {
349         if ( sm->Contains( theElem ))
350           return aShapeID;
351         if ( aShape.IsNull() )
352           aShape = aMesh->IndexToShape( aShapeID );
353       }
354       else {
355         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
356       }
357     }
358   }
359
360   // None of nodes is on a proper shape,
361   // find the shape among ancestors of aShape on which a node is
362   if ( aShape.IsNull() ) {
363     //MESSAGE ("::FindShape() - NONE node is on shape")
364     return 0;
365   }
366   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
367   for ( ; ancIt.More(); ancIt.Next() ) {
368     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
369     if ( sm && sm->Contains( theElem ))
370       return aMesh->ShapeToIndex( ancIt.Value() );
371   }
372
373   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
374   return 0;
375 }
376
377 //=======================================================================
378 //function : IsMedium
379 //purpose  :
380 //=======================================================================
381
382 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
383                                 const SMDSAbs_ElementType typeToCheck)
384 {
385   bool isMedium = false;
386   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
387   while (it->more() && !isMedium ) {
388     const SMDS_MeshElement* elem = it->next();
389     isMedium = elem->IsMediumNode(node);
390   }
391   return isMedium;
392 }
393
394 //=======================================================================
395 //function : ShiftNodesQuadTria
396 //purpose  : auxilary
397 //           Shift nodes in the array corresponded to quadratic triangle
398 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
399 //=======================================================================
400 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
401 {
402   const SMDS_MeshNode* nd1 = aNodes[0];
403   aNodes[0] = aNodes[1];
404   aNodes[1] = aNodes[2];
405   aNodes[2] = nd1;
406   const SMDS_MeshNode* nd2 = aNodes[3];
407   aNodes[3] = aNodes[4];
408   aNodes[4] = aNodes[5];
409   aNodes[5] = nd2;
410 }
411
412 //=======================================================================
413 //function : GetNodesFromTwoTria
414 //purpose  : auxilary
415 //           Shift nodes in the array corresponded to quadratic triangle
416 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
417 //=======================================================================
418 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
419                                 const SMDS_MeshElement * theTria2,
420                                 const SMDS_MeshNode* N1[],
421                                 const SMDS_MeshNode* N2[])
422 {
423   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
424   int i=0;
425   while(i<6) {
426     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
427     i++;
428   }
429   if(it->more()) return false;
430   it = theTria2->nodesIterator();
431   i=0;
432   while(i<6) {
433     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
434     i++;
435   }
436   if(it->more()) return false;
437
438   int sames[3] = {-1,-1,-1};
439   int nbsames = 0;
440   int j;
441   for(i=0; i<3; i++) {
442     for(j=0; j<3; j++) {
443       if(N1[i]==N2[j]) {
444         sames[i] = j;
445         nbsames++;
446         break;
447       }
448     }
449   }
450   if(nbsames!=2) return false;
451   if(sames[0]>-1) {
452     ShiftNodesQuadTria(N1);
453     if(sames[1]>-1) {
454       ShiftNodesQuadTria(N1);
455     }
456   }
457   i = sames[0] + sames[1] + sames[2];
458   for(; i<2; i++) {
459     ShiftNodesQuadTria(N2);
460   }
461   // now we receive following N1 and N2 (using numeration as above image)
462   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
463   // i.e. first nodes from both arrays determ new diagonal
464   return true;
465 }
466
467 //=======================================================================
468 //function : InverseDiag
469 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
470 //           but having other common link.
471 //           Return False if args are improper
472 //=======================================================================
473
474 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
475                                     const SMDS_MeshElement * theTria2 )
476 {
477   myLastCreatedElems.Clear();
478   myLastCreatedNodes.Clear();
479
480   if (!theTria1 || !theTria2)
481     return false;
482
483   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
484   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
485   if (F1 && F2) {
486
487     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
488     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
489     //    |/ |                                         | \|
490     //  B +--+ 2                                     B +--+ 2
491
492     // put nodes in array and find out indices of the same ones
493     const SMDS_MeshNode* aNodes [6];
494     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
495     int i = 0;
496     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
497     while ( it->more() ) {
498       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
499
500       if ( i > 2 ) // theTria2
501         // find same node of theTria1
502         for ( int j = 0; j < 3; j++ )
503           if ( aNodes[ i ] == aNodes[ j ]) {
504             sameInd[ j ] = i;
505             sameInd[ i ] = j;
506             break;
507           }
508       // next
509       i++;
510       if ( i == 3 ) {
511         if ( it->more() )
512           return false; // theTria1 is not a triangle
513         it = theTria2->nodesIterator();
514       }
515       if ( i == 6 && it->more() )
516         return false; // theTria2 is not a triangle
517     }
518
519     // find indices of 1,2 and of A,B in theTria1
520     int iA = 0, iB = 0, i1 = 0, i2 = 0;
521     for ( i = 0; i < 6; i++ ) {
522       if ( sameInd [ i ] == 0 )
523         if ( i < 3 ) i1 = i;
524         else         i2 = i;
525       else if (i < 3)
526         if ( iA ) iB = i;
527         else      iA = i;
528     }
529     // nodes 1 and 2 should not be the same
530     if ( aNodes[ i1 ] == aNodes[ i2 ] )
531       return false;
532
533     // theTria1: A->2
534     aNodes[ iA ] = aNodes[ i2 ];
535     // theTria2: B->1
536     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
537
538     //MESSAGE( theTria1 << theTria2 );
539
540     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
541     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
542
543     //MESSAGE( theTria1 << theTria2 );
544
545     return true;
546
547   } // end if(F1 && F2)
548
549   // check case of quadratic faces
550   const SMDS_QuadraticFaceOfNodes* QF1 =
551     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
552   if(!QF1) return false;
553   const SMDS_QuadraticFaceOfNodes* QF2 =
554     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
555   if(!QF2) return false;
556
557   //       5
558   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
559   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
560   //    |   / |
561   //  7 +  +  + 6
562   //    | /9  |
563   //    |/    |
564   //  4 +--+--+ 3
565   //       8
566
567   const SMDS_MeshNode* N1 [6];
568   const SMDS_MeshNode* N2 [6];
569   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
570     return false;
571   // now we receive following N1 and N2 (using numeration as above image)
572   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
573   // i.e. first nodes from both arrays determ new diagonal
574
575   const SMDS_MeshNode* N1new [6];
576   const SMDS_MeshNode* N2new [6];
577   N1new[0] = N1[0];
578   N1new[1] = N2[0];
579   N1new[2] = N2[1];
580   N1new[3] = N1[4];
581   N1new[4] = N2[3];
582   N1new[5] = N1[5];
583   N2new[0] = N1[0];
584   N2new[1] = N1[1];
585   N2new[2] = N2[0];
586   N2new[3] = N1[3];
587   N2new[4] = N2[5];
588   N2new[5] = N1[4];
589   // replaces nodes in faces
590   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
591   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
592
593   return true;
594 }
595
596 //=======================================================================
597 //function : findTriangles
598 //purpose  : find triangles sharing theNode1-theNode2 link
599 //=======================================================================
600
601 static bool findTriangles(const SMDS_MeshNode *    theNode1,
602                           const SMDS_MeshNode *    theNode2,
603                           const SMDS_MeshElement*& theTria1,
604                           const SMDS_MeshElement*& theTria2)
605 {
606   if ( !theNode1 || !theNode2 ) return false;
607
608   theTria1 = theTria2 = 0;
609
610   set< const SMDS_MeshElement* > emap;
611   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
612   while (it->more()) {
613     const SMDS_MeshElement* elem = it->next();
614     if ( elem->NbNodes() == 3 )
615       emap.insert( elem );
616   }
617   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
618   while (it->more()) {
619     const SMDS_MeshElement* elem = it->next();
620     if ( emap.find( elem ) != emap.end() )
621       if ( theTria1 ) {
622         // theTria1 must be element with minimum ID
623         if( theTria1->GetID() < elem->GetID() ) {
624           theTria2 = elem;
625         }
626         else {
627           theTria2 = theTria1;
628           theTria1 = elem;
629         }
630         break;
631       }
632       else {
633         theTria1 = elem;
634       }
635   }
636   return ( theTria1 && theTria2 );
637 }
638
639 //=======================================================================
640 //function : InverseDiag
641 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
642 //           with ones built on the same 4 nodes but having other common link.
643 //           Return false if proper faces not found
644 //=======================================================================
645
646 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
647                                     const SMDS_MeshNode * theNode2)
648 {
649   myLastCreatedElems.Clear();
650   myLastCreatedNodes.Clear();
651
652   MESSAGE( "::InverseDiag()" );
653
654   const SMDS_MeshElement *tr1, *tr2;
655   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
656     return false;
657
658   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
659   //if (!F1) return false;
660   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
661   //if (!F2) return false;
662   if (F1 && F2) {
663
664     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
665     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
666     //    |/ |                                    | \|
667     //  B +--+ 2                                B +--+ 2
668
669     // put nodes in array
670     // and find indices of 1,2 and of A in tr1 and of B in tr2
671     int i, iA1 = 0, i1 = 0;
672     const SMDS_MeshNode* aNodes1 [3];
673     SMDS_ElemIteratorPtr it;
674     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
675       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
676       if ( aNodes1[ i ] == theNode1 )
677         iA1 = i; // node A in tr1
678       else if ( aNodes1[ i ] != theNode2 )
679         i1 = i;  // node 1
680     }
681     int iB2 = 0, i2 = 0;
682     const SMDS_MeshNode* aNodes2 [3];
683     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
684       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
685       if ( aNodes2[ i ] == theNode2 )
686         iB2 = i; // node B in tr2
687       else if ( aNodes2[ i ] != theNode1 )
688         i2 = i;  // node 2
689     }
690
691     // nodes 1 and 2 should not be the same
692     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
693       return false;
694
695     // tr1: A->2
696     aNodes1[ iA1 ] = aNodes2[ i2 ];
697     // tr2: B->1
698     aNodes2[ iB2 ] = aNodes1[ i1 ];
699
700     //MESSAGE( tr1 << tr2 );
701
702     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
703     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
704
705     //MESSAGE( tr1 << tr2 );
706
707     return true;
708   }
709
710   // check case of quadratic faces
711   const SMDS_QuadraticFaceOfNodes* QF1 =
712     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
713   if(!QF1) return false;
714   const SMDS_QuadraticFaceOfNodes* QF2 =
715     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
716   if(!QF2) return false;
717   return InverseDiag(tr1,tr2);
718 }
719
720 //=======================================================================
721 //function : getQuadrangleNodes
722 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
723 //           fusion of triangles tr1 and tr2 having shared link on
724 //           theNode1 and theNode2
725 //=======================================================================
726
727 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
728                         const SMDS_MeshNode *    theNode1,
729                         const SMDS_MeshNode *    theNode2,
730                         const SMDS_MeshElement * tr1,
731                         const SMDS_MeshElement * tr2 )
732 {
733   if( tr1->NbNodes() != tr2->NbNodes() )
734     return false;
735   // find the 4-th node to insert into tr1
736   const SMDS_MeshNode* n4 = 0;
737   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
738   int i=0;
739   while ( !n4 && i<3 ) {
740     const SMDS_MeshNode * n = cast2Node( it->next() );
741     i++;
742     bool isDiag = ( n == theNode1 || n == theNode2 );
743     if ( !isDiag )
744       n4 = n;
745   }
746   // Make an array of nodes to be in a quadrangle
747   int iNode = 0, iFirstDiag = -1;
748   it = tr1->nodesIterator();
749   i=0;
750   while ( i<3 ) {
751     const SMDS_MeshNode * n = cast2Node( it->next() );
752     i++;
753     bool isDiag = ( n == theNode1 || n == theNode2 );
754     if ( isDiag ) {
755       if ( iFirstDiag < 0 )
756         iFirstDiag = iNode;
757       else if ( iNode - iFirstDiag == 1 )
758         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
759     }
760     else if ( n == n4 ) {
761       return false; // tr1 and tr2 should not have all the same nodes
762     }
763     theQuadNodes[ iNode++ ] = n;
764   }
765   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
766     theQuadNodes[ iNode ] = n4;
767
768   return true;
769 }
770
771 //=======================================================================
772 //function : DeleteDiag
773 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
774 //           with a quadrangle built on the same 4 nodes.
775 //           Return false if proper faces not found
776 //=======================================================================
777
778 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
779                                    const SMDS_MeshNode * theNode2)
780 {
781   myLastCreatedElems.Clear();
782   myLastCreatedNodes.Clear();
783
784   MESSAGE( "::DeleteDiag()" );
785
786   const SMDS_MeshElement *tr1, *tr2;
787   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
788     return false;
789
790   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
791   //if (!F1) return false;
792   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
793   //if (!F2) return false;
794   if (F1 && F2) {
795
796     const SMDS_MeshNode* aNodes [ 4 ];
797     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
798       return false;
799
800     //MESSAGE( endl << tr1 << tr2 );
801
802     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
803     myLastCreatedElems.Append(tr1);
804     GetMeshDS()->RemoveElement( tr2 );
805
806     //MESSAGE( endl << tr1 );
807
808     return true;
809   }
810
811   // check case of quadratic faces
812   const SMDS_QuadraticFaceOfNodes* QF1 =
813     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
814   if(!QF1) return false;
815   const SMDS_QuadraticFaceOfNodes* QF2 =
816     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
817   if(!QF2) return false;
818
819   //       5
820   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
821   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
822   //    |   / |
823   //  7 +  +  + 6
824   //    | /9  |
825   //    |/    |
826   //  4 +--+--+ 3
827   //       8
828
829   const SMDS_MeshNode* N1 [6];
830   const SMDS_MeshNode* N2 [6];
831   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
832     return false;
833   // now we receive following N1 and N2 (using numeration as above image)
834   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
835   // i.e. first nodes from both arrays determ new diagonal
836
837   const SMDS_MeshNode* aNodes[8];
838   aNodes[0] = N1[0];
839   aNodes[1] = N1[1];
840   aNodes[2] = N2[0];
841   aNodes[3] = N2[1];
842   aNodes[4] = N1[3];
843   aNodes[5] = N2[5];
844   aNodes[6] = N2[3];
845   aNodes[7] = N1[5];
846
847   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
848   myLastCreatedElems.Append(tr1);
849   GetMeshDS()->RemoveElement( tr2 );
850
851   // remove middle node (9)
852   GetMeshDS()->RemoveNode( N1[4] );
853
854   return true;
855 }
856
857 //=======================================================================
858 //function : Reorient
859 //purpose  : Reverse theElement orientation
860 //=======================================================================
861
862 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
863 {
864   myLastCreatedElems.Clear();
865   myLastCreatedNodes.Clear();
866
867   if (!theElem)
868     return false;
869   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
870   if ( !it || !it->more() )
871     return false;
872
873   switch ( theElem->GetType() ) {
874
875   case SMDSAbs_Edge:
876   case SMDSAbs_Face: {
877     if(!theElem->IsQuadratic()) {
878       int i = theElem->NbNodes();
879       vector<const SMDS_MeshNode*> aNodes( i );
880       while ( it->more() )
881         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
882       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
883     }
884     else {
885       // quadratic elements
886       if(theElem->GetType()==SMDSAbs_Edge) {
887         vector<const SMDS_MeshNode*> aNodes(3);
888         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
889         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
890         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
891         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
892       }
893       else {
894         int nbn = theElem->NbNodes();
895         vector<const SMDS_MeshNode*> aNodes(nbn);
896         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
897         int i=1;
898         for(; i<nbn/2; i++) {
899           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
900         }
901         for(i=0; i<nbn/2; i++) {
902           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
903         }
904         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
905       }
906     }
907   }
908   case SMDSAbs_Volume: {
909     if (theElem->IsPoly()) {
910       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
911         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
912       if (!aPolyedre) {
913         MESSAGE("Warning: bad volumic element");
914         return false;
915       }
916
917       int nbFaces = aPolyedre->NbFaces();
918       vector<const SMDS_MeshNode *> poly_nodes;
919       vector<int> quantities (nbFaces);
920
921       // reverse each face of the polyedre
922       for (int iface = 1; iface <= nbFaces; iface++) {
923         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
924         quantities[iface - 1] = nbFaceNodes;
925
926         for (inode = nbFaceNodes; inode >= 1; inode--) {
927           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
928           poly_nodes.push_back(curNode);
929         }
930       }
931
932       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
933
934     }
935     else {
936       SMDS_VolumeTool vTool;
937       if ( !vTool.Set( theElem ))
938         return false;
939       vTool.Inverse();
940       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
941     }
942   }
943   default:;
944   }
945
946   return false;
947 }
948
949 //=======================================================================
950 //function : getBadRate
951 //purpose  :
952 //=======================================================================
953
954 static double getBadRate (const SMDS_MeshElement*               theElem,
955                           SMESH::Controls::NumericalFunctorPtr& theCrit)
956 {
957   SMESH::Controls::TSequenceOfXYZ P;
958   if ( !theElem || !theCrit->GetPoints( theElem, P ))
959     return 1e100;
960   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
961   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
962 }
963
964 //=======================================================================
965 //function : QuadToTri
966 //purpose  : Cut quadrangles into triangles.
967 //           theCrit is used to select a diagonal to cut
968 //=======================================================================
969
970 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
971                                   SMESH::Controls::NumericalFunctorPtr theCrit)
972 {
973   myLastCreatedElems.Clear();
974   myLastCreatedNodes.Clear();
975
976   MESSAGE( "::QuadToTri()" );
977
978   if ( !theCrit.get() )
979     return false;
980
981   SMESHDS_Mesh * aMesh = GetMeshDS();
982
983   Handle(Geom_Surface) surface;
984   SMESH_MesherHelper   helper( *GetMesh() );
985
986   TIDSortedElemSet::iterator itElem;
987   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
988     const SMDS_MeshElement* elem = *itElem;
989     if ( !elem || elem->GetType() != SMDSAbs_Face )
990       continue;
991     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
992       continue;
993
994     // retrieve element nodes
995     const SMDS_MeshNode* aNodes [8];
996     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
997     int i = 0;
998     while ( itN->more() )
999       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1000
1001     // compare two sets of possible triangles
1002     double aBadRate1, aBadRate2; // to what extent a set is bad
1003     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1004     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1005     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1006
1007     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1008     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1009     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1010
1011     int aShapeId = FindShape( elem );
1012     const SMDS_MeshElement* newElem = 0;
1013
1014     if( !elem->IsQuadratic() ) {
1015
1016       // split liner quadrangle
1017
1018       if ( aBadRate1 <= aBadRate2 ) {
1019         // tr1 + tr2 is better
1020         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1021         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1022       }
1023       else {
1024         // tr3 + tr4 is better
1025         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1026         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1027       }
1028     }
1029     else {
1030
1031       // split quadratic quadrangle
1032
1033       // get surface elem is on
1034       if ( aShapeId != helper.GetSubShapeID() ) {
1035         surface.Nullify();
1036         TopoDS_Shape shape;
1037         if ( aShapeId > 0 )
1038           shape = aMesh->IndexToShape( aShapeId );
1039         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1040           TopoDS_Face face = TopoDS::Face( shape );
1041           surface = BRep_Tool::Surface( face );
1042           if ( !surface.IsNull() )
1043             helper.SetSubShape( shape );
1044         }
1045       }
1046       // get elem nodes
1047       const SMDS_MeshNode* aNodes [8];
1048       const SMDS_MeshNode* inFaceNode = 0;
1049       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1050       int i = 0;
1051       while ( itN->more() ) {
1052         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1053         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1054              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1055         {
1056           inFaceNode = aNodes[ i-1 ];
1057         }
1058       }
1059       // find middle point for (0,1,2,3)
1060       // and create a node in this point;
1061       gp_XYZ p( 0,0,0 );
1062       if ( surface.IsNull() ) {
1063         for(i=0; i<4; i++)
1064           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1065         p /= 4;
1066       }
1067       else {
1068         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1069         gp_XY uv( 0,0 );
1070         for(i=0; i<4; i++)
1071           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1072         uv /= 4.;
1073         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1074       }
1075       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1076       myLastCreatedNodes.Append(newN);
1077
1078       // create a new element
1079       const SMDS_MeshNode* N[6];
1080       if ( aBadRate1 <= aBadRate2 ) {
1081         N[0] = aNodes[0];
1082         N[1] = aNodes[1];
1083         N[2] = aNodes[2];
1084         N[3] = aNodes[4];
1085         N[4] = aNodes[5];
1086         N[5] = newN;
1087         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1088                                  aNodes[6], aNodes[7], newN );
1089       }
1090       else {
1091         N[0] = aNodes[1];
1092         N[1] = aNodes[2];
1093         N[2] = aNodes[3];
1094         N[3] = aNodes[5];
1095         N[4] = aNodes[6];
1096         N[5] = newN;
1097         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1098                                  aNodes[7], aNodes[4], newN );
1099       }
1100       aMesh->ChangeElementNodes( elem, N, 6 );
1101
1102     } // quadratic case
1103
1104     // care of a new element
1105
1106     myLastCreatedElems.Append(newElem);
1107     AddToSameGroups( newElem, elem, aMesh );
1108
1109     // put a new triangle on the same shape
1110     if ( aShapeId )
1111       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1112   }
1113   return true;
1114 }
1115
1116 //=======================================================================
1117 //function : BestSplit
1118 //purpose  : Find better diagonal for cutting.
1119 //=======================================================================
1120
1121 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1122                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1123 {
1124   myLastCreatedElems.Clear();
1125   myLastCreatedNodes.Clear();
1126
1127   if (!theCrit.get())
1128     return -1;
1129
1130   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1131     return -1;
1132
1133   if( theQuad->NbNodes()==4 ||
1134       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1135
1136     // retrieve element nodes
1137     const SMDS_MeshNode* aNodes [4];
1138     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1139     int i = 0;
1140     //while (itN->more())
1141     while (i<4) {
1142       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1143     }
1144     // compare two sets of possible triangles
1145     double aBadRate1, aBadRate2; // to what extent a set is bad
1146     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1147     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1148     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1149
1150     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1151     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1152     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1153
1154     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1155       return 1; // diagonal 1-3
1156
1157     return 2; // diagonal 2-4
1158   }
1159   return -1;
1160 }
1161
1162 namespace
1163 {
1164   // Methods of splitting volumes into tetra
1165
1166   const int theHexTo5_1[5*4+1] =
1167     {
1168       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1169     };
1170   const int theHexTo5_2[5*4+1] =
1171     {
1172       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1173     };
1174   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1175
1176   const int theHexTo6_1[6*4+1] =
1177     {
1178       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1179     };
1180   const int theHexTo6_2[6*4+1] =
1181     {
1182       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1183     };
1184   const int theHexTo6_3[6*4+1] =
1185     {
1186       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1187     };
1188   const int theHexTo6_4[6*4+1] =
1189     {
1190       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1191     };
1192   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1193
1194   const int thePyraTo2_1[2*4+1] =
1195     {
1196       0, 1, 2, 4,    0, 2, 3, 4,   -1
1197     };
1198   const int thePyraTo2_2[2*4+1] =
1199     {
1200       1, 2, 3, 4,    1, 3, 0, 4,   -1
1201     };
1202   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1203
1204   const int thePentaTo3_1[3*4+1] =
1205     {
1206       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1207     };
1208   const int thePentaTo3_2[3*4+1] =
1209     {
1210       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1211     };
1212   const int thePentaTo3_3[3*4+1] =
1213     {
1214       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1215     };
1216   const int thePentaTo3_4[3*4+1] =
1217     {
1218       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1219     };
1220   const int thePentaTo3_5[3*4+1] =
1221     {
1222       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1223     };
1224   const int thePentaTo3_6[3*4+1] =
1225     {
1226       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1227     };
1228   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1229                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1230
1231   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1232   {
1233     int _n1, _n2, _n3;
1234     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1235     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1236     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1237   };
1238   struct TSplitMethod
1239   {
1240     int        _nbTetra;
1241     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1242     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1243     bool       _ownConn;      //!< to delete _connectivity in destructor
1244
1245     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1246       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1247     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1248     bool hasFacet( const TTriangleFacet& facet ) const
1249     {
1250       const int* tetConn = _connectivity;
1251       for ( ; tetConn[0] >= 0; tetConn += 4 )
1252         if (( facet.contains( tetConn[0] ) +
1253               facet.contains( tetConn[1] ) +
1254               facet.contains( tetConn[2] ) +
1255               facet.contains( tetConn[3] )) == 3 )
1256           return true;
1257       return false;
1258     }
1259   };
1260
1261   //=======================================================================
1262   /*!
1263    * \brief return TSplitMethod for the given element
1264    */
1265   //=======================================================================
1266
1267   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1268   {
1269     int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1270
1271     // Find out how adjacent volumes are split
1272
1273     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1274     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1275     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1276     {
1277       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1278       maxTetConnSize += 4 * ( nbNodes - 2 );
1279       if ( nbNodes < 4 ) continue;
1280
1281       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1282       const int* nInd = vol.GetFaceNodesIndices( iF );
1283       if ( nbNodes == 4 )
1284       {
1285         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1286         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1287         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1288         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1289       }
1290       else
1291       {
1292         int iCom = 0; // common node of triangle faces to split into
1293         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1294         {
1295           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1296                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1297                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1298           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1299                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1300                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1301           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1302           {
1303             triaSplits.push_back( t012 );
1304             triaSplits.push_back( t023 );
1305             break;
1306           }
1307         }
1308       }
1309       if ( !triaSplits.empty() )
1310         hasAdjacentSplits = true;
1311     }
1312
1313     // Among variants of split method select one compliant with adjacent volumes
1314
1315     TSplitMethod method;
1316     if ( !vol.Element()->IsPoly() )
1317     {
1318       int nbVariants = 2, nbTet = 0;
1319       const int** connVariants = 0;
1320       switch ( vol.Element()->GetEntityType() )
1321       {
1322       case SMDSEntity_Hexa:
1323       case SMDSEntity_Quad_Hexa:
1324         if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1325           connVariants = theHexTo5, nbTet = 5;
1326         else
1327           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1328         break;
1329       case SMDSEntity_Pyramid:
1330       case SMDSEntity_Quad_Pyramid:
1331         connVariants = thePyraTo2;  nbTet = 2;
1332         break;
1333       case SMDSEntity_Penta:
1334       case SMDSEntity_Quad_Penta:
1335         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1336         break;
1337       default:
1338         nbVariants = 0;
1339       }
1340       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1341       {
1342         // check method compliancy with adjacent tetras,
1343         // all found splits must be among facets of tetras described by this method
1344         method = TSplitMethod( nbTet, connVariants[variant] );
1345         if ( hasAdjacentSplits && method._nbTetra > 0 )
1346         {
1347           bool facetCreated = true;
1348           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1349           {
1350             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1351             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1352               facetCreated = method.hasFacet( *facet );
1353           }
1354           if ( !facetCreated )
1355             method = TSplitMethod(0); // incompatible method
1356         }
1357       }
1358     }
1359     if ( method._nbTetra < 1 )
1360     {
1361       // No standard method is applicable, use a generic solution:
1362       // each facet of a volume is split into triangles and
1363       // each of triangles and a volume barycenter form a tetrahedron.
1364
1365       int* connectivity = new int[ maxTetConnSize + 1 ];
1366       method._connectivity = connectivity;
1367       method._ownConn = true;
1368       method._baryNode = true;
1369
1370       int connSize = 0;
1371       int baryCenInd = vol.NbNodes();
1372       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1373       {
1374         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1375         const int*   nInd = vol.GetFaceNodesIndices( iF );
1376         // find common node of triangle facets of tetra to create
1377         int iCommon = 0; // index in linear numeration
1378         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1379         if ( !triaSplits.empty() )
1380         {
1381           // by found facets
1382           const TTriangleFacet* facet = &triaSplits.front();
1383           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1384             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1385                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1386               break;
1387         }
1388         else if ( nbNodes > 3 )
1389         {
1390           // find the best method of splitting into triangles by aspect ratio
1391           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1392           map< double, int > badness2iCommon;
1393           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1394           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1395           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1396             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1397             {
1398               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1399                                       nodes[ iQ*((iLast-1)%nbNodes)],
1400                                       nodes[ iQ*((iLast  )%nbNodes)]);
1401               double badness = getBadRate( &tria, aspectRatio );
1402               badness2iCommon.insert( make_pair( badness, iCommon ));
1403             }
1404           // use iCommon with lowest badness
1405           iCommon = badness2iCommon.begin()->second;
1406         }
1407         if ( iCommon >= nbNodes )
1408           iCommon = 0; // something wrong
1409         // fill connectivity of tetra
1410         int nbTet = nbNodes - 2;
1411         for ( int i = 0; i < nbTet; ++i )
1412         {
1413           int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1414           if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1415           connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1416           connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1417           connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1418           connectivity[ connSize++ ] = baryCenInd;
1419           ++method._nbTetra;
1420         }
1421       }
1422       connectivity[ connSize++ ] = -1;
1423     }
1424     return method;
1425   }
1426   //================================================================================
1427   /*!
1428    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1429    */
1430   //================================================================================
1431
1432   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1433   {
1434     // find the tetrahedron including the three nodes of facet
1435     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1436     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1437     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1438     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1439     while ( volIt1->more() )
1440     {
1441       const SMDS_MeshElement* v = volIt1->next();
1442       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1443         continue;
1444       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1445       while ( volIt2->more() )
1446         if ( v != volIt2->next() )
1447           continue;
1448       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1449       while ( volIt3->more() )
1450         if ( v == volIt3->next() )
1451           return true;
1452     }
1453     return false;
1454   }
1455 } // namespace
1456
1457 //=======================================================================
1458 //function : SplitVolumesIntoTetra
1459 //purpose  : Split volumic elements into tetrahedra.
1460 //=======================================================================
1461
1462 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1463                                               const int                theMethodFlags)
1464 {
1465   // std-like iterator on coordinates of nodes of mesh element
1466   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1467   NXyzIterator xyzEnd;
1468
1469   SMDS_VolumeTool    volTool;
1470   SMESH_MesherHelper helper( *GetMesh());
1471
1472   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1473   SMESHDS_SubMesh* fSubMesh = subMesh;
1474   
1475   SMESH_SequenceOfElemPtr newNodes, newElems;
1476
1477   TIDSortedElemSet::const_iterator elem = theElems.begin();
1478   for ( ; elem != theElems.end(); ++elem )
1479   {
1480     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1481     if ( geomType <= SMDSEntity_Quad_Tetra )
1482       continue; // tetra or face or ...
1483
1484     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1485
1486     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1487     if ( splitMethod._nbTetra < 1 ) continue;
1488
1489     // find submesh to add new tetras in
1490     if ( !subMesh || !subMesh->Contains( *elem ))
1491     {
1492       int shapeID = FindShape( *elem );
1493       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1494       subMesh = GetMeshDS()->MeshElements( shapeID );
1495     }
1496     int iQ;
1497     if ( (*elem)->IsQuadratic() )
1498     {
1499       iQ = 2;
1500       // add quadratic links to the helper
1501       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1502       {
1503         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1504         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1505           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1506       }
1507       helper.SetIsQuadratic( true );
1508     }
1509     else
1510     {
1511       iQ = 1;
1512       helper.SetIsQuadratic( false );
1513     }
1514     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1515     if ( splitMethod._baryNode )
1516     {
1517       // make a node at barycenter
1518       gp_XYZ gc( 0,0,0 );
1519       gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1520       SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1521       nodes.push_back( gcNode );
1522       newNodes.Append( gcNode );
1523     }
1524
1525     // make tetras
1526     helper.SetElementsOnShape( true );
1527     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1528     const int* tetConn = splitMethod._connectivity;
1529     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1530       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1531                                                        nodes[ tetConn[1] ],
1532                                                        nodes[ tetConn[2] ],
1533                                                        nodes[ tetConn[3] ]));
1534
1535     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1536
1537     // Split faces on sides of the split volume
1538
1539     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1540     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1541     {
1542       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1543       if ( nbNodes < 4 ) continue;
1544
1545       // find an existing face
1546       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1547                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1548       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1549       {
1550         // among possible triangles create ones discribed by split method
1551         const int* nInd = volTool.GetFaceNodesIndices( iF );
1552         int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1553         int iCom = 0; // common node of triangle faces to split into
1554         list< TTriangleFacet > facets;
1555         for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1556         {
1557           TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1558                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1559                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1560           TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1561                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1562                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1563           if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1564           {
1565             facets.push_back( t012 );
1566             facets.push_back( t023 );
1567             for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1568               facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1569                                                 nInd[ iQ * ((iLast-1)%nbNodes )],
1570                                                 nInd[ iQ * ((iLast  )%nbNodes )]));
1571             break;
1572           }
1573         }
1574         // find submesh to add new faces in
1575         if ( !fSubMesh || !fSubMesh->Contains( face ))
1576         {
1577           int shapeID = FindShape( face );
1578           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1579         }
1580         // make triangles
1581         helper.SetElementsOnShape( false );
1582         vector< const SMDS_MeshElement* > triangles;
1583         list< TTriangleFacet >::iterator facet = facets.begin();
1584         for ( ; facet != facets.end(); ++facet )
1585         {
1586           if ( !volTool.IsFaceExternal( iF ))
1587             swap( facet->_n2, facet->_n3 );
1588           triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1589                                                volNodes[ facet->_n2 ],
1590                                                volNodes[ facet->_n3 ]));
1591           if ( triangles.back() && fSubMesh )
1592             fSubMesh->AddElement( triangles.back());
1593           newElems.Append( triangles.back() );
1594         }
1595         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1596         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1597       }
1598
1599     } // loop on volume faces to split them into triangles
1600
1601     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1602
1603   } // loop on volumes to split
1604
1605   myLastCreatedNodes = newNodes;
1606   myLastCreatedElems = newElems;
1607 }
1608
1609 //=======================================================================
1610 //function : AddToSameGroups
1611 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1612 //=======================================================================
1613
1614 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1615                                         const SMDS_MeshElement* elemInGroups,
1616                                         SMESHDS_Mesh *          aMesh)
1617 {
1618   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1619   if (!groups.empty()) {
1620     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1621     for ( ; grIt != groups.end(); grIt++ ) {
1622       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1623       if ( group && group->Contains( elemInGroups ))
1624         group->SMDSGroup().Add( elemToAdd );
1625     }
1626   }
1627 }
1628
1629
1630 //=======================================================================
1631 //function : RemoveElemFromGroups
1632 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1633 //=======================================================================
1634 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1635                                              SMESHDS_Mesh *          aMesh)
1636 {
1637   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1638   if (!groups.empty())
1639   {
1640     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1641     for (; GrIt != groups.end(); GrIt++)
1642     {
1643       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1644       if (!grp || grp->IsEmpty()) continue;
1645       grp->SMDSGroup().Remove(removeelem);
1646     }
1647   }
1648 }
1649
1650 //================================================================================
1651 /*!
1652  * \brief Replace elemToRm by elemToAdd in the all groups
1653  */
1654 //================================================================================
1655
1656 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1657                                             const SMDS_MeshElement* elemToAdd,
1658                                             SMESHDS_Mesh *          aMesh)
1659 {
1660   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1661   if (!groups.empty()) {
1662     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1663     for ( ; grIt != groups.end(); grIt++ ) {
1664       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1665       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1666         group->SMDSGroup().Add( elemToAdd );
1667     }
1668   }
1669 }
1670
1671 //================================================================================
1672 /*!
1673  * \brief Replace elemToRm by elemToAdd in the all groups
1674  */
1675 //================================================================================
1676
1677 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1678                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1679                                             SMESHDS_Mesh *                         aMesh)
1680 {
1681   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1682   if (!groups.empty())
1683   {
1684     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1685     for ( ; grIt != groups.end(); grIt++ ) {
1686       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1687       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1688         for ( int i = 0; i < elemToAdd.size(); ++i )
1689           group->SMDSGroup().Add( elemToAdd[ i ] );
1690     }
1691   }
1692 }
1693
1694 //=======================================================================
1695 //function : QuadToTri
1696 //purpose  : Cut quadrangles into triangles.
1697 //           theCrit is used to select a diagonal to cut
1698 //=======================================================================
1699
1700 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1701                                   const bool         the13Diag)
1702 {
1703   myLastCreatedElems.Clear();
1704   myLastCreatedNodes.Clear();
1705
1706   MESSAGE( "::QuadToTri()" );
1707
1708   SMESHDS_Mesh * aMesh = GetMeshDS();
1709
1710   Handle(Geom_Surface) surface;
1711   SMESH_MesherHelper   helper( *GetMesh() );
1712
1713   TIDSortedElemSet::iterator itElem;
1714   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1715     const SMDS_MeshElement* elem = *itElem;
1716     if ( !elem || elem->GetType() != SMDSAbs_Face )
1717       continue;
1718     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1719     if(!isquad) continue;
1720
1721     if(elem->NbNodes()==4) {
1722       // retrieve element nodes
1723       const SMDS_MeshNode* aNodes [4];
1724       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1725       int i = 0;
1726       while ( itN->more() )
1727         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1728
1729       int aShapeId = FindShape( elem );
1730       const SMDS_MeshElement* newElem = 0;
1731       if ( the13Diag ) {
1732         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1733         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1734       }
1735       else {
1736         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1737         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1738       }
1739       myLastCreatedElems.Append(newElem);
1740       // put a new triangle on the same shape and add to the same groups
1741       if ( aShapeId )
1742         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1743       AddToSameGroups( newElem, elem, aMesh );
1744     }
1745
1746     // Quadratic quadrangle
1747
1748     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1749
1750       // get surface elem is on
1751       int aShapeId = FindShape( elem );
1752       if ( aShapeId != helper.GetSubShapeID() ) {
1753         surface.Nullify();
1754         TopoDS_Shape shape;
1755         if ( aShapeId > 0 )
1756           shape = aMesh->IndexToShape( aShapeId );
1757         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1758           TopoDS_Face face = TopoDS::Face( shape );
1759           surface = BRep_Tool::Surface( face );
1760           if ( !surface.IsNull() )
1761             helper.SetSubShape( shape );
1762         }
1763       }
1764
1765       const SMDS_MeshNode* aNodes [8];
1766       const SMDS_MeshNode* inFaceNode = 0;
1767       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1768       int i = 0;
1769       while ( itN->more() ) {
1770         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1771         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1772              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1773         {
1774           inFaceNode = aNodes[ i-1 ];
1775         }
1776       }
1777
1778       // find middle point for (0,1,2,3)
1779       // and create a node in this point;
1780       gp_XYZ p( 0,0,0 );
1781       if ( surface.IsNull() ) {
1782         for(i=0; i<4; i++)
1783           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1784         p /= 4;
1785       }
1786       else {
1787         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1788         gp_XY uv( 0,0 );
1789         for(i=0; i<4; i++)
1790           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1791         uv /= 4.;
1792         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1793       }
1794       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1795       myLastCreatedNodes.Append(newN);
1796
1797       // create a new element
1798       const SMDS_MeshElement* newElem = 0;
1799       const SMDS_MeshNode* N[6];
1800       if ( the13Diag ) {
1801         N[0] = aNodes[0];
1802         N[1] = aNodes[1];
1803         N[2] = aNodes[2];
1804         N[3] = aNodes[4];
1805         N[4] = aNodes[5];
1806         N[5] = newN;
1807         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1808                                  aNodes[6], aNodes[7], newN );
1809       }
1810       else {
1811         N[0] = aNodes[1];
1812         N[1] = aNodes[2];
1813         N[2] = aNodes[3];
1814         N[3] = aNodes[5];
1815         N[4] = aNodes[6];
1816         N[5] = newN;
1817         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1818                                  aNodes[7], aNodes[4], newN );
1819       }
1820       myLastCreatedElems.Append(newElem);
1821       aMesh->ChangeElementNodes( elem, N, 6 );
1822       // put a new triangle on the same shape and add to the same groups
1823       if ( aShapeId )
1824         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1825       AddToSameGroups( newElem, elem, aMesh );
1826     }
1827   }
1828
1829   return true;
1830 }
1831
1832 //=======================================================================
1833 //function : getAngle
1834 //purpose  :
1835 //=======================================================================
1836
1837 double getAngle(const SMDS_MeshElement * tr1,
1838                 const SMDS_MeshElement * tr2,
1839                 const SMDS_MeshNode *    n1,
1840                 const SMDS_MeshNode *    n2)
1841 {
1842   double angle = 2*PI; // bad angle
1843
1844   // get normals
1845   SMESH::Controls::TSequenceOfXYZ P1, P2;
1846   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1847        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1848     return angle;
1849   gp_Vec N1,N2;
1850   if(!tr1->IsQuadratic())
1851     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1852   else
1853     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1854   if ( N1.SquareMagnitude() <= gp::Resolution() )
1855     return angle;
1856   if(!tr2->IsQuadratic())
1857     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1858   else
1859     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1860   if ( N2.SquareMagnitude() <= gp::Resolution() )
1861     return angle;
1862
1863   // find the first diagonal node n1 in the triangles:
1864   // take in account a diagonal link orientation
1865   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1866   for ( int t = 0; t < 2; t++ ) {
1867     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1868     int i = 0, iDiag = -1;
1869     while ( it->more()) {
1870       const SMDS_MeshElement *n = it->next();
1871       if ( n == n1 || n == n2 )
1872         if ( iDiag < 0)
1873           iDiag = i;
1874         else {
1875           if ( i - iDiag == 1 )
1876             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1877           else
1878             nFirst[ t ] = n;
1879           break;
1880         }
1881       i++;
1882     }
1883   }
1884   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1885     N2.Reverse();
1886
1887   angle = N1.Angle( N2 );
1888   //SCRUTE( angle );
1889   return angle;
1890 }
1891
1892 // =================================================
1893 // class generating a unique ID for a pair of nodes
1894 // and able to return nodes by that ID
1895 // =================================================
1896 class LinkID_Gen {
1897 public:
1898
1899   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1900     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1901   {}
1902
1903   long GetLinkID (const SMDS_MeshNode * n1,
1904                   const SMDS_MeshNode * n2) const
1905   {
1906     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1907   }
1908
1909   bool GetNodes (const long             theLinkID,
1910                  const SMDS_MeshNode* & theNode1,
1911                  const SMDS_MeshNode* & theNode2) const
1912   {
1913     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1914     if ( !theNode1 ) return false;
1915     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1916     if ( !theNode2 ) return false;
1917     return true;
1918   }
1919
1920 private:
1921   LinkID_Gen();
1922   const SMESHDS_Mesh* myMesh;
1923   long                myMaxID;
1924 };
1925
1926
1927 //=======================================================================
1928 //function : TriToQuad
1929 //purpose  : Fuse neighbour triangles into quadrangles.
1930 //           theCrit is used to select a neighbour to fuse with.
1931 //           theMaxAngle is a max angle between element normals at which
1932 //           fusion is still performed.
1933 //=======================================================================
1934
1935 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1936                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1937                                   const double                         theMaxAngle)
1938 {
1939   myLastCreatedElems.Clear();
1940   myLastCreatedNodes.Clear();
1941
1942   MESSAGE( "::TriToQuad()" );
1943
1944   if ( !theCrit.get() )
1945     return false;
1946
1947   SMESHDS_Mesh * aMesh = GetMeshDS();
1948
1949   // Prepare data for algo: build
1950   // 1. map of elements with their linkIDs
1951   // 2. map of linkIDs with their elements
1952
1953   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1954   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1955   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
1956   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1957
1958   TIDSortedElemSet::iterator itElem;
1959   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1960     const SMDS_MeshElement* elem = *itElem;
1961     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1962     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1963     if(!IsTria) continue;
1964
1965     // retrieve element nodes
1966     const SMDS_MeshNode* aNodes [4];
1967     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1968     int i = 0;
1969     while ( i<3 )
1970       aNodes[ i++ ] = cast2Node( itN->next() );
1971     aNodes[ 3 ] = aNodes[ 0 ];
1972
1973     // fill maps
1974     for ( i = 0; i < 3; i++ ) {
1975       SMESH_TLink link( aNodes[i], aNodes[i+1] );
1976       // check if elements sharing a link can be fused
1977       itLE = mapLi_listEl.find( link );
1978       if ( itLE != mapLi_listEl.end() ) {
1979         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1980           continue;
1981         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1982         //if ( FindShape( elem ) != FindShape( elem2 ))
1983         //  continue; // do not fuse triangles laying on different shapes
1984         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1985           continue; // avoid making badly shaped quads
1986         (*itLE).second.push_back( elem );
1987       }
1988       else {
1989         mapLi_listEl[ link ].push_back( elem );
1990       }
1991       mapEl_setLi [ elem ].insert( link );
1992     }
1993   }
1994   // Clean the maps from the links shared by a sole element, ie
1995   // links to which only one element is bound in mapLi_listEl
1996
1997   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1998     int nbElems = (*itLE).second.size();
1999     if ( nbElems < 2  ) {
2000       const SMDS_MeshElement* elem = (*itLE).second.front();
2001       SMESH_TLink link = (*itLE).first;
2002       mapEl_setLi[ elem ].erase( link );
2003       if ( mapEl_setLi[ elem ].empty() )
2004         mapEl_setLi.erase( elem );
2005     }
2006   }
2007
2008   // Algo: fuse triangles into quadrangles
2009
2010   while ( ! mapEl_setLi.empty() ) {
2011     // Look for the start element:
2012     // the element having the least nb of shared links
2013     const SMDS_MeshElement* startElem = 0;
2014     int minNbLinks = 4;
2015     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2016       int nbLinks = (*itEL).second.size();
2017       if ( nbLinks < minNbLinks ) {
2018         startElem = (*itEL).first;
2019         minNbLinks = nbLinks;
2020         if ( minNbLinks == 1 )
2021           break;
2022       }
2023     }
2024
2025     // search elements to fuse starting from startElem or links of elements
2026     // fused earlyer - startLinks
2027     list< SMESH_TLink > startLinks;
2028     while ( startElem || !startLinks.empty() ) {
2029       while ( !startElem && !startLinks.empty() ) {
2030         // Get an element to start, by a link
2031         SMESH_TLink linkId = startLinks.front();
2032         startLinks.pop_front();
2033         itLE = mapLi_listEl.find( linkId );
2034         if ( itLE != mapLi_listEl.end() ) {
2035           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2036           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2037           for ( ; itE != listElem.end() ; itE++ )
2038             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2039               startElem = (*itE);
2040           mapLi_listEl.erase( itLE );
2041         }
2042       }
2043
2044       if ( startElem ) {
2045         // Get candidates to be fused
2046         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2047         const SMESH_TLink *link12, *link13;
2048         startElem = 0;
2049         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2050         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2051         ASSERT( !setLi.empty() );
2052         set< SMESH_TLink >::iterator itLi;
2053         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2054         {
2055           const SMESH_TLink & link = (*itLi);
2056           itLE = mapLi_listEl.find( link );
2057           if ( itLE == mapLi_listEl.end() )
2058             continue;
2059
2060           const SMDS_MeshElement* elem = (*itLE).second.front();
2061           if ( elem == tr1 )
2062             elem = (*itLE).second.back();
2063           mapLi_listEl.erase( itLE );
2064           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2065             continue;
2066           if ( tr2 ) {
2067             tr3 = elem;
2068             link13 = &link;
2069           }
2070           else {
2071             tr2 = elem;
2072             link12 = &link;
2073           }
2074
2075           // add other links of elem to list of links to re-start from
2076           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2077           set< SMESH_TLink >::iterator it;
2078           for ( it = links.begin(); it != links.end(); it++ ) {
2079             const SMESH_TLink& link2 = (*it);
2080             if ( link2 != link )
2081               startLinks.push_back( link2 );
2082           }
2083         }
2084
2085         // Get nodes of possible quadrangles
2086         const SMDS_MeshNode *n12 [4], *n13 [4];
2087         bool Ok12 = false, Ok13 = false;
2088         const SMDS_MeshNode *linkNode1, *linkNode2;
2089         if(tr2) {
2090           linkNode1 = link12->first;
2091           linkNode2 = link12->second;
2092           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2093             Ok12 = true;
2094         }
2095         if(tr3) {
2096           linkNode1 = link13->first;
2097           linkNode2 = link13->second;
2098           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2099             Ok13 = true;
2100         }
2101
2102         // Choose a pair to fuse
2103         if ( Ok12 && Ok13 ) {
2104           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2105           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2106           double aBadRate12 = getBadRate( &quad12, theCrit );
2107           double aBadRate13 = getBadRate( &quad13, theCrit );
2108           if (  aBadRate13 < aBadRate12 )
2109             Ok12 = false;
2110           else
2111             Ok13 = false;
2112         }
2113
2114         // Make quadrangles
2115         // and remove fused elems and removed links from the maps
2116         mapEl_setLi.erase( tr1 );
2117         if ( Ok12 ) {
2118           mapEl_setLi.erase( tr2 );
2119           mapLi_listEl.erase( *link12 );
2120           if(tr1->NbNodes()==3) {
2121             if( tr1->GetID() < tr2->GetID() ) {
2122               aMesh->ChangeElementNodes( tr1, n12, 4 );
2123               myLastCreatedElems.Append(tr1);
2124               aMesh->RemoveElement( tr2 );
2125             }
2126             else {
2127               aMesh->ChangeElementNodes( tr2, n12, 4 );
2128               myLastCreatedElems.Append(tr2);
2129               aMesh->RemoveElement( tr1);
2130             }
2131           }
2132           else {
2133             const SMDS_MeshNode* N1 [6];
2134             const SMDS_MeshNode* N2 [6];
2135             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2136             // now we receive following N1 and N2 (using numeration as above image)
2137             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2138             // i.e. first nodes from both arrays determ new diagonal
2139             const SMDS_MeshNode* aNodes[8];
2140             aNodes[0] = N1[0];
2141             aNodes[1] = N1[1];
2142             aNodes[2] = N2[0];
2143             aNodes[3] = N2[1];
2144             aNodes[4] = N1[3];
2145             aNodes[5] = N2[5];
2146             aNodes[6] = N2[3];
2147             aNodes[7] = N1[5];
2148             if( tr1->GetID() < tr2->GetID() ) {
2149               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2150               myLastCreatedElems.Append(tr1);
2151               GetMeshDS()->RemoveElement( tr2 );
2152             }
2153             else {
2154               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2155               myLastCreatedElems.Append(tr2);
2156               GetMeshDS()->RemoveElement( tr1 );
2157             }
2158             // remove middle node (9)
2159             GetMeshDS()->RemoveNode( N1[4] );
2160           }
2161         }
2162         else if ( Ok13 ) {
2163           mapEl_setLi.erase( tr3 );
2164           mapLi_listEl.erase( *link13 );
2165           if(tr1->NbNodes()==3) {
2166             if( tr1->GetID() < tr2->GetID() ) {
2167               aMesh->ChangeElementNodes( tr1, n13, 4 );
2168               myLastCreatedElems.Append(tr1);
2169               aMesh->RemoveElement( tr3 );
2170             }
2171             else {
2172               aMesh->ChangeElementNodes( tr3, n13, 4 );
2173               myLastCreatedElems.Append(tr3);
2174               aMesh->RemoveElement( tr1 );
2175             }
2176           }
2177           else {
2178             const SMDS_MeshNode* N1 [6];
2179             const SMDS_MeshNode* N2 [6];
2180             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2181             // now we receive following N1 and N2 (using numeration as above image)
2182             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2183             // i.e. first nodes from both arrays determ new diagonal
2184             const SMDS_MeshNode* aNodes[8];
2185             aNodes[0] = N1[0];
2186             aNodes[1] = N1[1];
2187             aNodes[2] = N2[0];
2188             aNodes[3] = N2[1];
2189             aNodes[4] = N1[3];
2190             aNodes[5] = N2[5];
2191             aNodes[6] = N2[3];
2192             aNodes[7] = N1[5];
2193             if( tr1->GetID() < tr2->GetID() ) {
2194               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2195               myLastCreatedElems.Append(tr1);
2196               GetMeshDS()->RemoveElement( tr3 );
2197             }
2198             else {
2199               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2200               myLastCreatedElems.Append(tr3);
2201               GetMeshDS()->RemoveElement( tr1 );
2202             }
2203             // remove middle node (9)
2204             GetMeshDS()->RemoveNode( N1[4] );
2205           }
2206         }
2207
2208         // Next element to fuse: the rejected one
2209         if ( tr3 )
2210           startElem = Ok12 ? tr3 : tr2;
2211
2212       } // if ( startElem )
2213     } // while ( startElem || !startLinks.empty() )
2214   } // while ( ! mapEl_setLi.empty() )
2215
2216   return true;
2217 }
2218
2219
2220 /*#define DUMPSO(txt) \
2221 //  cout << txt << endl;
2222 //=============================================================================
2223 //
2224 //
2225 //
2226 //=============================================================================
2227 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2228 {
2229 if ( i1 == i2 )
2230 return;
2231 int tmp = idNodes[ i1 ];
2232 idNodes[ i1 ] = idNodes[ i2 ];
2233 idNodes[ i2 ] = tmp;
2234 gp_Pnt Ptmp = P[ i1 ];
2235 P[ i1 ] = P[ i2 ];
2236 P[ i2 ] = Ptmp;
2237 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2238 }
2239
2240 //=======================================================================
2241 //function : SortQuadNodes
2242 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2243 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2244 //           1 or 2 else 0.
2245 //=======================================================================
2246
2247 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2248 int               idNodes[] )
2249 {
2250   gp_Pnt P[4];
2251   int i;
2252   for ( i = 0; i < 4; i++ ) {
2253     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2254     if ( !n ) return 0;
2255     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2256   }
2257
2258   gp_Vec V1(P[0], P[1]);
2259   gp_Vec V2(P[0], P[2]);
2260   gp_Vec V3(P[0], P[3]);
2261
2262   gp_Vec Cross1 = V1 ^ V2;
2263   gp_Vec Cross2 = V2 ^ V3;
2264
2265   i = 0;
2266   if (Cross1.Dot(Cross2) < 0)
2267   {
2268     Cross1 = V2 ^ V1;
2269     Cross2 = V1 ^ V3;
2270
2271     if (Cross1.Dot(Cross2) < 0)
2272       i = 2;
2273     else
2274       i = 1;
2275     swap ( i, i + 1, idNodes, P );
2276
2277     //     for ( int ii = 0; ii < 4; ii++ ) {
2278     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2279     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2280     //     }
2281   }
2282   return i;
2283 }
2284
2285 //=======================================================================
2286 //function : SortHexaNodes
2287 //purpose  : Set 8 nodes of a hexahedron in a good order.
2288 //           Return success status
2289 //=======================================================================
2290
2291 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2292                                       int               idNodes[] )
2293 {
2294   gp_Pnt P[8];
2295   int i;
2296   DUMPSO( "INPUT: ========================================");
2297   for ( i = 0; i < 8; i++ ) {
2298     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2299     if ( !n ) return false;
2300     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2301     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2302   }
2303   DUMPSO( "========================================");
2304
2305
2306   set<int> faceNodes;  // ids of bottom face nodes, to be found
2307   set<int> checkedId1; // ids of tried 2-nd nodes
2308   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2309   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2310   int iMin, iLoop1 = 0;
2311
2312   // Loop to try the 2-nd nodes
2313
2314   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2315   {
2316     // Find not checked 2-nd node
2317     for ( i = 1; i < 8; i++ )
2318       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2319         int id1 = idNodes[i];
2320         swap ( 1, i, idNodes, P );
2321         checkedId1.insert ( id1 );
2322         break;
2323       }
2324
2325     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2326     // ie that all but meybe one (id3 which is on the same face) nodes
2327     // lay on the same side from the triangle plane.
2328
2329     bool manyInPlane = false; // more than 4 nodes lay in plane
2330     int iLoop2 = 0;
2331     while ( ++iLoop2 < 6 ) {
2332
2333       // get 1-2-3 plane coeffs
2334       Standard_Real A, B, C, D;
2335       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2336       if ( N.SquareMagnitude() > gp::Resolution() )
2337       {
2338         gp_Pln pln ( P[0], N );
2339         pln.Coefficients( A, B, C, D );
2340
2341         // find the node (iMin) closest to pln
2342         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2343         set<int> idInPln;
2344         for ( i = 3; i < 8; i++ ) {
2345           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2346           if ( fabs( dist[i] ) < minDist ) {
2347             minDist = fabs( dist[i] );
2348             iMin = i;
2349           }
2350           if ( fabs( dist[i] ) <= tol )
2351             idInPln.insert( idNodes[i] );
2352         }
2353
2354         // there should not be more than 4 nodes in bottom plane
2355         if ( idInPln.size() > 1 )
2356         {
2357           DUMPSO( "### idInPln.size() = " << idInPln.size());
2358           // idInPlane does not contain the first 3 nodes
2359           if ( manyInPlane || idInPln.size() == 5)
2360             return false; // all nodes in one plane
2361           manyInPlane = true;
2362
2363           // set the 1-st node to be not in plane
2364           for ( i = 3; i < 8; i++ ) {
2365             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2366               DUMPSO( "### Reset 0-th node");
2367               swap( 0, i, idNodes, P );
2368               break;
2369             }
2370           }
2371
2372           // reset to re-check second nodes
2373           leastDist = DBL_MAX;
2374           faceNodes.clear();
2375           checkedId1.clear();
2376           iLoop1 = 0;
2377           break; // from iLoop2;
2378         }
2379
2380         // check that the other 4 nodes are on the same side
2381         bool sameSide = true;
2382         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2383         for ( i = 3; sameSide && i < 8; i++ ) {
2384           if ( i != iMin )
2385             sameSide = ( isNeg == dist[i] <= 0.);
2386         }
2387
2388         // keep best solution
2389         if ( sameSide && minDist < leastDist ) {
2390           leastDist = minDist;
2391           faceNodes.clear();
2392           faceNodes.insert( idNodes[ 1 ] );
2393           faceNodes.insert( idNodes[ 2 ] );
2394           faceNodes.insert( idNodes[ iMin ] );
2395           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2396                   << " leastDist = " << leastDist);
2397           if ( leastDist <= DBL_MIN )
2398             break;
2399         }
2400       }
2401
2402       // set next 3-d node to check
2403       int iNext = 2 + iLoop2;
2404       if ( iNext < 8 ) {
2405         DUMPSO( "Try 2-nd");
2406         swap ( 2, iNext, idNodes, P );
2407       }
2408     } // while ( iLoop2 < 6 )
2409   } // iLoop1
2410
2411   if ( faceNodes.empty() ) return false;
2412
2413   // Put the faceNodes in proper places
2414   for ( i = 4; i < 8; i++ ) {
2415     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2416       // find a place to put
2417       int iTo = 1;
2418       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2419         iTo++;
2420       DUMPSO( "Set faceNodes");
2421       swap ( iTo, i, idNodes, P );
2422     }
2423   }
2424
2425
2426   // Set nodes of the found bottom face in good order
2427   DUMPSO( " Found bottom face: ");
2428   i = SortQuadNodes( theMesh, idNodes );
2429   if ( i ) {
2430     gp_Pnt Ptmp = P[ i ];
2431     P[ i ] = P[ i+1 ];
2432     P[ i+1 ] = Ptmp;
2433   }
2434   //   else
2435   //     for ( int ii = 0; ii < 4; ii++ ) {
2436   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2437   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2438   //    }
2439
2440   // Gravity center of the top and bottom faces
2441   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2442   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2443
2444   // Get direction from the bottom to the top face
2445   gp_Vec upDir ( aGCb, aGCt );
2446   Standard_Real upDirSize = upDir.Magnitude();
2447   if ( upDirSize <= gp::Resolution() ) return false;
2448   upDir / upDirSize;
2449
2450   // Assure that the bottom face normal points up
2451   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2452   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2453   if ( Nb.Dot( upDir ) < 0 ) {
2454     DUMPSO( "Reverse bottom face");
2455     swap( 1, 3, idNodes, P );
2456   }
2457
2458   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2459   Standard_Real minDist = DBL_MAX;
2460   for ( i = 4; i < 8; i++ ) {
2461     // projection of P[i] to the plane defined by P[0] and upDir
2462     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2463     Standard_Real sqDist = P[0].SquareDistance( Pp );
2464     if ( sqDist < minDist ) {
2465       minDist = sqDist;
2466       iMin = i;
2467     }
2468   }
2469   DUMPSO( "Set 4-th");
2470   swap ( 4, iMin, idNodes, P );
2471
2472   // Set nodes of the top face in good order
2473   DUMPSO( "Sort top face");
2474   i = SortQuadNodes( theMesh, &idNodes[4] );
2475   if ( i ) {
2476     i += 4;
2477     gp_Pnt Ptmp = P[ i ];
2478     P[ i ] = P[ i+1 ];
2479     P[ i+1 ] = Ptmp;
2480   }
2481
2482   // Assure that direction of the top face normal is from the bottom face
2483   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2484   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2485   if ( Nt.Dot( upDir ) < 0 ) {
2486     DUMPSO( "Reverse top face");
2487     swap( 5, 7, idNodes, P );
2488   }
2489
2490   //   DUMPSO( "OUTPUT: ========================================");
2491   //   for ( i = 0; i < 8; i++ ) {
2492   //     float *p = ugrid->GetPoint(idNodes[i]);
2493   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2494   //   }
2495
2496   return true;
2497 }*/
2498
2499 //================================================================================
2500 /*!
2501  * \brief Return nodes linked to the given one
2502  * \param theNode - the node
2503  * \param linkedNodes - the found nodes
2504  * \param type - the type of elements to check
2505  *
2506  * Medium nodes are ignored
2507  */
2508 //================================================================================
2509
2510 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2511                                        TIDSortedElemSet &   linkedNodes,
2512                                        SMDSAbs_ElementType  type )
2513 {
2514   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2515   while ( elemIt->more() )
2516   {
2517     const SMDS_MeshElement* elem = elemIt->next();
2518     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2519     if ( elem->GetType() == SMDSAbs_Volume )
2520     {
2521       SMDS_VolumeTool vol( elem );
2522       while ( nodeIt->more() ) {
2523         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2524         if ( theNode != n && vol.IsLinked( theNode, n ))
2525           linkedNodes.insert( n );
2526       }
2527     }
2528     else
2529     {
2530       for ( int i = 0; nodeIt->more(); ++i ) {
2531         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2532         if ( n == theNode ) {
2533           int iBefore = i - 1;
2534           int iAfter  = i + 1;
2535           if ( elem->IsQuadratic() ) {
2536             int nb = elem->NbNodes() / 2;
2537             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2538             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2539           }
2540           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2541           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2542         }
2543       }
2544     }
2545   }
2546 }
2547
2548 //=======================================================================
2549 //function : laplacianSmooth
2550 //purpose  : pulls theNode toward the center of surrounding nodes directly
2551 //           connected to that node along an element edge
2552 //=======================================================================
2553
2554 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2555                      const Handle(Geom_Surface)&          theSurface,
2556                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2557 {
2558   // find surrounding nodes
2559
2560   TIDSortedElemSet nodeSet;
2561   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2562
2563   // compute new coodrs
2564
2565   double coord[] = { 0., 0., 0. };
2566   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2567   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2568     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2569     if ( theSurface.IsNull() ) { // smooth in 3D
2570       coord[0] += node->X();
2571       coord[1] += node->Y();
2572       coord[2] += node->Z();
2573     }
2574     else { // smooth in 2D
2575       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2576       gp_XY* uv = theUVMap[ node ];
2577       coord[0] += uv->X();
2578       coord[1] += uv->Y();
2579     }
2580   }
2581   int nbNodes = nodeSet.size();
2582   if ( !nbNodes )
2583     return;
2584   coord[0] /= nbNodes;
2585   coord[1] /= nbNodes;
2586
2587   if ( !theSurface.IsNull() ) {
2588     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2589     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2590     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2591     coord[0] = p3d.X();
2592     coord[1] = p3d.Y();
2593     coord[2] = p3d.Z();
2594   }
2595   else
2596     coord[2] /= nbNodes;
2597
2598   // move node
2599
2600   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2601 }
2602
2603 //=======================================================================
2604 //function : centroidalSmooth
2605 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2606 //           surrounding elements
2607 //=======================================================================
2608
2609 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2610                       const Handle(Geom_Surface)&          theSurface,
2611                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2612 {
2613   gp_XYZ aNewXYZ(0.,0.,0.);
2614   SMESH::Controls::Area anAreaFunc;
2615   double totalArea = 0.;
2616   int nbElems = 0;
2617
2618   // compute new XYZ
2619
2620   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2621   while ( elemIt->more() )
2622   {
2623     const SMDS_MeshElement* elem = elemIt->next();
2624     nbElems++;
2625
2626     gp_XYZ elemCenter(0.,0.,0.);
2627     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2628     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2629     int nn = elem->NbNodes();
2630     if(elem->IsQuadratic()) nn = nn/2;
2631     int i=0;
2632     //while ( itN->more() ) {
2633     while ( i<nn ) {
2634       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2635       i++;
2636       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2637       aNodePoints.push_back( aP );
2638       if ( !theSurface.IsNull() ) { // smooth in 2D
2639         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2640         gp_XY* uv = theUVMap[ aNode ];
2641         aP.SetCoord( uv->X(), uv->Y(), 0. );
2642       }
2643       elemCenter += aP;
2644     }
2645     double elemArea = anAreaFunc.GetValue( aNodePoints );
2646     totalArea += elemArea;
2647     elemCenter /= nn;
2648     aNewXYZ += elemCenter * elemArea;
2649   }
2650   aNewXYZ /= totalArea;
2651   if ( !theSurface.IsNull() ) {
2652     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2653     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2654   }
2655
2656   // move node
2657
2658   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2659 }
2660
2661 //=======================================================================
2662 //function : getClosestUV
2663 //purpose  : return UV of closest projection
2664 //=======================================================================
2665
2666 static bool getClosestUV (Extrema_GenExtPS& projector,
2667                           const gp_Pnt&     point,
2668                           gp_XY &           result)
2669 {
2670   projector.Perform( point );
2671   if ( projector.IsDone() ) {
2672     double u, v, minVal = DBL_MAX;
2673     for ( int i = projector.NbExt(); i > 0; i-- )
2674       if ( projector.Value( i ) < minVal ) {
2675         minVal = projector.Value( i );
2676         projector.Point( i ).Parameter( u, v );
2677       }
2678     result.SetCoord( u, v );
2679     return true;
2680   }
2681   return false;
2682 }
2683
2684 //=======================================================================
2685 //function : Smooth
2686 //purpose  : Smooth theElements during theNbIterations or until a worst
2687 //           element has aspect ratio <= theTgtAspectRatio.
2688 //           Aspect Ratio varies in range [1.0, inf].
2689 //           If theElements is empty, the whole mesh is smoothed.
2690 //           theFixedNodes contains additionally fixed nodes. Nodes built
2691 //           on edges and boundary nodes are always fixed.
2692 //=======================================================================
2693
2694 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2695                                set<const SMDS_MeshNode*> & theFixedNodes,
2696                                const SmoothMethod          theSmoothMethod,
2697                                const int                   theNbIterations,
2698                                double                      theTgtAspectRatio,
2699                                const bool                  the2D)
2700 {
2701   myLastCreatedElems.Clear();
2702   myLastCreatedNodes.Clear();
2703
2704   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2705
2706   if ( theTgtAspectRatio < 1.0 )
2707     theTgtAspectRatio = 1.0;
2708
2709   const double disttol = 1.e-16;
2710
2711   SMESH::Controls::AspectRatio aQualityFunc;
2712
2713   SMESHDS_Mesh* aMesh = GetMeshDS();
2714
2715   if ( theElems.empty() ) {
2716     // add all faces to theElems
2717     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2718     while ( fIt->more() ) {
2719       const SMDS_MeshElement* face = fIt->next();
2720       theElems.insert( face );
2721     }
2722   }
2723   // get all face ids theElems are on
2724   set< int > faceIdSet;
2725   TIDSortedElemSet::iterator itElem;
2726   if ( the2D )
2727     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2728       int fId = FindShape( *itElem );
2729       // check that corresponding submesh exists and a shape is face
2730       if (fId &&
2731           faceIdSet.find( fId ) == faceIdSet.end() &&
2732           aMesh->MeshElements( fId )) {
2733         TopoDS_Shape F = aMesh->IndexToShape( fId );
2734         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2735           faceIdSet.insert( fId );
2736       }
2737     }
2738   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2739
2740   // ===============================================
2741   // smooth elements on each TopoDS_Face separately
2742   // ===============================================
2743
2744   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2745   for ( ; fId != faceIdSet.rend(); ++fId ) {
2746     // get face surface and submesh
2747     Handle(Geom_Surface) surface;
2748     SMESHDS_SubMesh* faceSubMesh = 0;
2749     TopoDS_Face face;
2750     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2751     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2752     bool isUPeriodic = false, isVPeriodic = false;
2753     if ( *fId ) {
2754       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2755       surface = BRep_Tool::Surface( face );
2756       faceSubMesh = aMesh->MeshElements( *fId );
2757       fToler2 = BRep_Tool::Tolerance( face );
2758       fToler2 *= fToler2 * 10.;
2759       isUPeriodic = surface->IsUPeriodic();
2760       if ( isUPeriodic )
2761         vPeriod = surface->UPeriod();
2762       isVPeriodic = surface->IsVPeriodic();
2763       if ( isVPeriodic )
2764         uPeriod = surface->VPeriod();
2765       surface->Bounds( u1, u2, v1, v2 );
2766     }
2767     // ---------------------------------------------------------
2768     // for elements on a face, find movable and fixed nodes and
2769     // compute UV for them
2770     // ---------------------------------------------------------
2771     bool checkBoundaryNodes = false;
2772     bool isQuadratic = false;
2773     set<const SMDS_MeshNode*> setMovableNodes;
2774     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2775     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2776     list< const SMDS_MeshElement* > elemsOnFace;
2777
2778     Extrema_GenExtPS projector;
2779     GeomAdaptor_Surface surfAdaptor;
2780     if ( !surface.IsNull() ) {
2781       surfAdaptor.Load( surface );
2782       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2783     }
2784     int nbElemOnFace = 0;
2785     itElem = theElems.begin();
2786     // loop on not yet smoothed elements: look for elems on a face
2787     while ( itElem != theElems.end() ) {
2788       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2789         break; // all elements found
2790
2791       const SMDS_MeshElement* elem = *itElem;
2792       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2793            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2794         ++itElem;
2795         continue;
2796       }
2797       elemsOnFace.push_back( elem );
2798       theElems.erase( itElem++ );
2799       nbElemOnFace++;
2800
2801       if ( !isQuadratic )
2802         isQuadratic = elem->IsQuadratic();
2803
2804       // get movable nodes of elem
2805       const SMDS_MeshNode* node;
2806       SMDS_TypeOfPosition posType;
2807       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2808       int nn = 0, nbn =  elem->NbNodes();
2809       if(elem->IsQuadratic())
2810         nbn = nbn/2;
2811       while ( nn++ < nbn ) {
2812         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2813         const SMDS_PositionPtr& pos = node->GetPosition();
2814         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2815         if (posType != SMDS_TOP_EDGE &&
2816             posType != SMDS_TOP_VERTEX &&
2817             theFixedNodes.find( node ) == theFixedNodes.end())
2818         {
2819           // check if all faces around the node are on faceSubMesh
2820           // because a node on edge may be bound to face
2821           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2822           bool all = true;
2823           if ( faceSubMesh ) {
2824             while ( eIt->more() && all ) {
2825               const SMDS_MeshElement* e = eIt->next();
2826               all = faceSubMesh->Contains( e );
2827             }
2828           }
2829           if ( all )
2830             setMovableNodes.insert( node );
2831           else
2832             checkBoundaryNodes = true;
2833         }
2834         if ( posType == SMDS_TOP_3DSPACE )
2835           checkBoundaryNodes = true;
2836       }
2837
2838       if ( surface.IsNull() )
2839         continue;
2840
2841       // get nodes to check UV
2842       list< const SMDS_MeshNode* > uvCheckNodes;
2843       itN = elem->nodesIterator();
2844       nn = 0; nbn =  elem->NbNodes();
2845       if(elem->IsQuadratic())
2846         nbn = nbn/2;
2847       while ( nn++ < nbn ) {
2848         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2849         if ( uvMap.find( node ) == uvMap.end() )
2850           uvCheckNodes.push_back( node );
2851         // add nodes of elems sharing node
2852         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2853         //         while ( eIt->more() ) {
2854         //           const SMDS_MeshElement* e = eIt->next();
2855         //           if ( e != elem ) {
2856         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2857         //             while ( nIt->more() ) {
2858         //               const SMDS_MeshNode* n =
2859         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2860         //               if ( uvMap.find( n ) == uvMap.end() )
2861         //                 uvCheckNodes.push_back( n );
2862         //             }
2863         //           }
2864         //         }
2865       }
2866       // check UV on face
2867       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2868       for ( ; n != uvCheckNodes.end(); ++n ) {
2869         node = *n;
2870         gp_XY uv( 0, 0 );
2871         const SMDS_PositionPtr& pos = node->GetPosition();
2872         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2873         // get existing UV
2874         switch ( posType ) {
2875         case SMDS_TOP_FACE: {
2876           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
2877           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2878           break;
2879         }
2880         case SMDS_TOP_EDGE: {
2881           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2882           Handle(Geom2d_Curve) pcurve;
2883           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2884             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2885           if ( !pcurve.IsNull() ) {
2886             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
2887             uv = pcurve->Value( u ).XY();
2888           }
2889           break;
2890         }
2891         case SMDS_TOP_VERTEX: {
2892           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2893           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2894             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2895           break;
2896         }
2897         default:;
2898         }
2899         // check existing UV
2900         bool project = true;
2901         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2902         double dist1 = DBL_MAX, dist2 = 0;
2903         if ( posType != SMDS_TOP_3DSPACE ) {
2904           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2905           project = dist1 > fToler2;
2906         }
2907         if ( project ) { // compute new UV
2908           gp_XY newUV;
2909           if ( !getClosestUV( projector, pNode, newUV )) {
2910             MESSAGE("Node Projection Failed " << node);
2911           }
2912           else {
2913             if ( isUPeriodic )
2914               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2915             if ( isVPeriodic )
2916               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2917             // check new UV
2918             if ( posType != SMDS_TOP_3DSPACE )
2919               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2920             if ( dist2 < dist1 )
2921               uv = newUV;
2922           }
2923         }
2924         // store UV in the map
2925         listUV.push_back( uv );
2926         uvMap.insert( make_pair( node, &listUV.back() ));
2927       }
2928     } // loop on not yet smoothed elements
2929
2930     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2931       checkBoundaryNodes = true;
2932
2933     // fix nodes on mesh boundary
2934
2935     if ( checkBoundaryNodes ) {
2936       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2937       map< NLink, int >::iterator link_nb;
2938       // put all elements links to linkNbMap
2939       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2940       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2941         const SMDS_MeshElement* elem = (*elemIt);
2942         int nbn =  elem->NbNodes();
2943         if(elem->IsQuadratic())
2944           nbn = nbn/2;
2945         // loop on elem links: insert them in linkNbMap
2946         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2947         for ( int iN = 0; iN < nbn; ++iN ) {
2948           curNode = elem->GetNode( iN );
2949           NLink link;
2950           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2951           else                      link = make_pair( prevNode , curNode );
2952           prevNode = curNode;
2953           link_nb = linkNbMap.find( link );
2954           if ( link_nb == linkNbMap.end() )
2955             linkNbMap.insert( make_pair ( link, 1 ));
2956           else
2957             link_nb->second++;
2958         }
2959       }
2960       // remove nodes that are in links encountered only once from setMovableNodes
2961       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2962         if ( link_nb->second == 1 ) {
2963           setMovableNodes.erase( link_nb->first.first );
2964           setMovableNodes.erase( link_nb->first.second );
2965         }
2966       }
2967     }
2968
2969     // -----------------------------------------------------
2970     // for nodes on seam edge, compute one more UV ( uvMap2 );
2971     // find movable nodes linked to nodes on seam and which
2972     // are to be smoothed using the second UV ( uvMap2 )
2973     // -----------------------------------------------------
2974
2975     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2976     if ( !surface.IsNull() ) {
2977       TopExp_Explorer eExp( face, TopAbs_EDGE );
2978       for ( ; eExp.More(); eExp.Next() ) {
2979         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2980         if ( !BRep_Tool::IsClosed( edge, face ))
2981           continue;
2982         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2983         if ( !sm ) continue;
2984         // find out which parameter varies for a node on seam
2985         double f,l;
2986         gp_Pnt2d uv1, uv2;
2987         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2988         if ( pcurve.IsNull() ) continue;
2989         uv1 = pcurve->Value( f );
2990         edge.Reverse();
2991         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2992         if ( pcurve.IsNull() ) continue;
2993         uv2 = pcurve->Value( f );
2994         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2995         // assure uv1 < uv2
2996         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2997           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2998         }
2999         // get nodes on seam and its vertices
3000         list< const SMDS_MeshNode* > seamNodes;
3001         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3002         while ( nSeamIt->more() ) {
3003           const SMDS_MeshNode* node = nSeamIt->next();
3004           if ( !isQuadratic || !IsMedium( node ))
3005             seamNodes.push_back( node );
3006         }
3007         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3008         for ( ; vExp.More(); vExp.Next() ) {
3009           sm = aMesh->MeshElements( vExp.Current() );
3010           if ( sm ) {
3011             nSeamIt = sm->GetNodes();
3012             while ( nSeamIt->more() )
3013               seamNodes.push_back( nSeamIt->next() );
3014           }
3015         }
3016         // loop on nodes on seam
3017         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3018         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3019           const SMDS_MeshNode* nSeam = *noSeIt;
3020           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3021           if ( n_uv == uvMap.end() )
3022             continue;
3023           // set the first UV
3024           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3025           // set the second UV
3026           listUV.push_back( *n_uv->second );
3027           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3028           if ( uvMap2.empty() )
3029             uvMap2 = uvMap; // copy the uvMap contents
3030           uvMap2[ nSeam ] = &listUV.back();
3031
3032           // collect movable nodes linked to ones on seam in nodesNearSeam
3033           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3034           while ( eIt->more() ) {
3035             const SMDS_MeshElement* e = eIt->next();
3036             int nbUseMap1 = 0, nbUseMap2 = 0;
3037             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3038             int nn = 0, nbn =  e->NbNodes();
3039             if(e->IsQuadratic()) nbn = nbn/2;
3040             while ( nn++ < nbn )
3041             {
3042               const SMDS_MeshNode* n =
3043                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3044               if (n == nSeam ||
3045                   setMovableNodes.find( n ) == setMovableNodes.end() )
3046                 continue;
3047               // add only nodes being closer to uv2 than to uv1
3048               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3049                            0.5 * ( n->Y() + nSeam->Y() ),
3050                            0.5 * ( n->Z() + nSeam->Z() ));
3051               gp_XY uv;
3052               getClosestUV( projector, pMid, uv );
3053               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3054                 nodesNearSeam.insert( n );
3055                 nbUseMap2++;
3056               }
3057               else
3058                 nbUseMap1++;
3059             }
3060             // for centroidalSmooth all element nodes must
3061             // be on one side of a seam
3062             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3063               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3064               nn = 0;
3065               while ( nn++ < nbn ) {
3066                 const SMDS_MeshNode* n =
3067                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3068                 setMovableNodes.erase( n );
3069               }
3070             }
3071           }
3072         } // loop on nodes on seam
3073       } // loop on edge of a face
3074     } // if ( !face.IsNull() )
3075
3076     if ( setMovableNodes.empty() ) {
3077       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3078       continue; // goto next face
3079     }
3080
3081     // -------------
3082     // SMOOTHING //
3083     // -------------
3084
3085     int it = -1;
3086     double maxRatio = -1., maxDisplacement = -1.;
3087     set<const SMDS_MeshNode*>::iterator nodeToMove;
3088     for ( it = 0; it < theNbIterations; it++ ) {
3089       maxDisplacement = 0.;
3090       nodeToMove = setMovableNodes.begin();
3091       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3092         const SMDS_MeshNode* node = (*nodeToMove);
3093         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3094
3095         // smooth
3096         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3097         if ( theSmoothMethod == LAPLACIAN )
3098           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3099         else
3100           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3101
3102         // node displacement
3103         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3104         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3105         if ( aDispl > maxDisplacement )
3106           maxDisplacement = aDispl;
3107       }
3108       // no node movement => exit
3109       //if ( maxDisplacement < 1.e-16 ) {
3110       if ( maxDisplacement < disttol ) {
3111         MESSAGE("-- no node movement --");
3112         break;
3113       }
3114
3115       // check elements quality
3116       maxRatio  = 0;
3117       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3118       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3119         const SMDS_MeshElement* elem = (*elemIt);
3120         if ( !elem || elem->GetType() != SMDSAbs_Face )
3121           continue;
3122         SMESH::Controls::TSequenceOfXYZ aPoints;
3123         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3124           double aValue = aQualityFunc.GetValue( aPoints );
3125           if ( aValue > maxRatio )
3126             maxRatio = aValue;
3127         }
3128       }
3129       if ( maxRatio <= theTgtAspectRatio ) {
3130         MESSAGE("-- quality achived --");
3131         break;
3132       }
3133       if (it+1 == theNbIterations) {
3134         MESSAGE("-- Iteration limit exceeded --");
3135       }
3136     } // smoothing iterations
3137
3138     MESSAGE(" Face id: " << *fId <<
3139             " Nb iterstions: " << it <<
3140             " Displacement: " << maxDisplacement <<
3141             " Aspect Ratio " << maxRatio);
3142
3143     // ---------------------------------------
3144     // new nodes positions are computed,
3145     // record movement in DS and set new UV
3146     // ---------------------------------------
3147     nodeToMove = setMovableNodes.begin();
3148     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3149       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3150       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3151       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3152       if ( node_uv != uvMap.end() ) {
3153         gp_XY* uv = node_uv->second;
3154         node->SetPosition
3155           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3156       }
3157     }
3158
3159     // move medium nodes of quadratic elements
3160     if ( isQuadratic )
3161     {
3162       SMESH_MesherHelper helper( *GetMesh() );
3163       if ( !face.IsNull() )
3164         helper.SetSubShape( face );
3165       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3166       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3167         const SMDS_QuadraticFaceOfNodes* QF =
3168           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3169         if(QF) {
3170           vector<const SMDS_MeshNode*> Ns;
3171           Ns.reserve(QF->NbNodes()+1);
3172           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3173           while ( anIter->more() )
3174             Ns.push_back( anIter->next() );
3175           Ns.push_back( Ns[0] );
3176           double x, y, z;
3177           for(int i=0; i<QF->NbNodes(); i=i+2) {
3178             if ( !surface.IsNull() ) {
3179               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3180               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3181               gp_XY uv = ( uv1 + uv2 ) / 2.;
3182               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3183               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3184             }
3185             else {
3186               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3187               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3188               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3189             }
3190             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3191                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3192                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3193               // we have to move i+1 node
3194               aMesh->MoveNode( Ns[i+1], x, y, z );
3195             }
3196           }
3197         }
3198       }
3199     }
3200
3201   } // loop on face ids
3202
3203 }
3204
3205 //=======================================================================
3206 //function : isReverse
3207 //purpose  : Return true if normal of prevNodes is not co-directied with
3208 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3209 //           iNotSame is where prevNodes and nextNodes are different
3210 //=======================================================================
3211
3212 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3213                       vector<const SMDS_MeshNode*> nextNodes,
3214                       const int            nbNodes,
3215                       const int            iNotSame)
3216 {
3217   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3218   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3219
3220   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3221   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3222   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3223   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3224
3225   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3226   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3227   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3228   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3229
3230   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3231
3232   return (vA ^ vB) * vN < 0.0;
3233 }
3234
3235 //=======================================================================
3236 /*!
3237  * \brief Create elements by sweeping an element
3238  * \param elem - element to sweep
3239  * \param newNodesItVec - nodes generated from each node of the element
3240  * \param newElems - generated elements
3241  * \param nbSteps - number of sweeping steps
3242  * \param srcElements - to append elem for each generated element
3243  */
3244 //=======================================================================
3245
3246 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3247                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3248                                     list<const SMDS_MeshElement*>&        newElems,
3249                                     const int                             nbSteps,
3250                                     SMESH_SequenceOfElemPtr&              srcElements)
3251 {
3252   SMESHDS_Mesh* aMesh = GetMeshDS();
3253
3254   // Loop on elem nodes:
3255   // find new nodes and detect same nodes indices
3256   int nbNodes = elem->NbNodes();
3257   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3258   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3259   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3260   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3261
3262   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3263   vector<int> sames(nbNodes);
3264   vector<bool> issimple(nbNodes);
3265
3266   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3267     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3268     const SMDS_MeshNode*                 node         = nnIt->first;
3269     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3270     if ( listNewNodes.empty() ) {
3271       return;
3272     }
3273
3274     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3275
3276     itNN[ iNode ] = listNewNodes.begin();
3277     prevNod[ iNode ] = node;
3278     nextNod[ iNode ] = listNewNodes.front();
3279     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3280       if ( prevNod[ iNode ] != nextNod [ iNode ])
3281         iNotSameNode = iNode;
3282       else {
3283         iSameNode = iNode;
3284         //nbSame++;
3285         sames[nbSame++] = iNode;
3286       }
3287     }
3288   }
3289
3290   //cout<<"  nbSame = "<<nbSame<<endl;
3291   if ( nbSame == nbNodes || nbSame > 2) {
3292     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3293     //INFOS( " Too many same nodes of element " << elem->GetID() );
3294     return;
3295   }
3296
3297   //  if( elem->IsQuadratic() && nbSame>0 ) {
3298   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3299   //    return;
3300   //  }
3301
3302   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3303   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3304   if ( nbSame > 0 ) {
3305     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3306     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3307     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3308   }
3309
3310   //if(nbNodes==8)
3311   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3312   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3313   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3314   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3315
3316   // check element orientation
3317   int i0 = 0, i2 = 2;
3318   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3319     //MESSAGE("Reversed elem " << elem );
3320     i0 = 2;
3321     i2 = 0;
3322     if ( nbSame > 0 )
3323       std::swap( iBeforeSame, iAfterSame );
3324   }
3325
3326   // make new elements
3327   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3328     // get next nodes
3329     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3330       if(issimple[iNode]) {
3331         nextNod[ iNode ] = *itNN[ iNode ];
3332         itNN[ iNode ]++;
3333       }
3334       else {
3335         if( elem->GetType()==SMDSAbs_Node ) {
3336           // we have to use two nodes
3337           midlNod[ iNode ] = *itNN[ iNode ];
3338           itNN[ iNode ]++;
3339           nextNod[ iNode ] = *itNN[ iNode ];
3340           itNN[ iNode ]++;
3341         }
3342         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3343           // we have to use each second node
3344           //itNN[ iNode ]++;
3345           nextNod[ iNode ] = *itNN[ iNode ];
3346           itNN[ iNode ]++;
3347         }
3348         else {
3349           // we have to use two nodes
3350           midlNod[ iNode ] = *itNN[ iNode ];
3351           itNN[ iNode ]++;
3352           nextNod[ iNode ] = *itNN[ iNode ];
3353           itNN[ iNode ]++;
3354         }
3355       }
3356     }
3357     SMDS_MeshElement* aNewElem = 0;
3358     if(!elem->IsPoly()) {
3359       switch ( nbNodes ) {
3360       case 0:
3361         return;
3362       case 1: { // NODE
3363         if ( nbSame == 0 ) {
3364           if(issimple[0])
3365             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3366           else
3367             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3368         }
3369         break;
3370       }
3371       case 2: { // EDGE
3372         if ( nbSame == 0 )
3373           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3374                                     nextNod[ 1 ], nextNod[ 0 ] );
3375         else
3376           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3377                                     nextNod[ iNotSameNode ] );
3378         break;
3379       }
3380
3381       case 3: { // TRIANGLE or quadratic edge
3382         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3383
3384           if ( nbSame == 0 )       // --- pentahedron
3385             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3386                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3387
3388           else if ( nbSame == 1 )  // --- pyramid
3389             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3390                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3391                                          nextNod[ iSameNode ]);
3392
3393           else // 2 same nodes:      --- tetrahedron
3394             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3395                                          nextNod[ iNotSameNode ]);
3396         }
3397         else { // quadratic edge
3398           if(nbSame==0) {     // quadratic quadrangle
3399             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3400                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3401           }
3402           else if(nbSame==1) { // quadratic triangle
3403             if(sames[0]==2) {
3404               return; // medium node on axis
3405             }
3406             else if(sames[0]==0) {
3407               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3408                                         nextNod[2], midlNod[1], prevNod[2]);
3409             }
3410             else { // sames[0]==1
3411               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3412                                         midlNod[0], nextNod[2], prevNod[2]);
3413             }
3414           }
3415           else {
3416             return;
3417           }
3418         }
3419         break;
3420       }
3421       case 4: { // QUADRANGLE
3422
3423         if ( nbSame == 0 )       // --- hexahedron
3424           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3425                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3426
3427         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3428           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3429                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3430                                        nextNod[ iSameNode ]);
3431           newElems.push_back( aNewElem );
3432           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3433                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3434                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3435         }
3436         else if ( nbSame == 2 ) { // pentahedron
3437           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3438             // iBeforeSame is same too
3439             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3440                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3441                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3442           else
3443             // iAfterSame is same too
3444             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3445                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3446                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3447         }
3448         break;
3449       }
3450       case 6: { // quadratic triangle
3451         // create pentahedron with 15 nodes
3452         if(nbSame==0) {
3453           if(i0>0) { // reversed case
3454             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3455                                          nextNod[0], nextNod[2], nextNod[1],
3456                                          prevNod[5], prevNod[4], prevNod[3],
3457                                          nextNod[5], nextNod[4], nextNod[3],
3458                                          midlNod[0], midlNod[2], midlNod[1]);
3459           }
3460           else { // not reversed case
3461             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3462                                          nextNod[0], nextNod[1], nextNod[2],
3463                                          prevNod[3], prevNod[4], prevNod[5],
3464                                          nextNod[3], nextNod[4], nextNod[5],
3465                                          midlNod[0], midlNod[1], midlNod[2]);
3466           }
3467         }
3468         else if(nbSame==1) {
3469           // 2d order pyramid of 13 nodes
3470           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3471           //                                 int n12,int n23,int n34,int n41,
3472           //                                 int n15,int n25,int n35,int n45, int ID);
3473           int n5 = iSameNode;
3474           int n1,n4,n41,n15,n45;
3475           if(i0>0) { // reversed case
3476             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3477             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3478             n41 = n1 + 3;
3479             n15 = n5 + 3;
3480             n45 = n4 + 3;
3481           }
3482           else {
3483             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3484             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3485             n41 = n4 + 3;
3486             n15 = n1 + 3;
3487             n45 = n5 + 3;
3488           }
3489           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3490                                       nextNod[n4], prevNod[n4], prevNod[n5],
3491                                       midlNod[n1], nextNod[n41],
3492                                       midlNod[n4], prevNod[n41],
3493                                       prevNod[n15], nextNod[n15],
3494                                       nextNod[n45], prevNod[n45]);
3495         }
3496         else if(nbSame==2) {
3497           // 2d order tetrahedron of 10 nodes
3498           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3499           //                                 int n12,int n23,int n31,
3500           //                                 int n14,int n24,int n34, int ID);
3501           int n1 = iNotSameNode;
3502           int n2,n3,n12,n23,n31;
3503           if(i0>0) { // reversed case
3504             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3505             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3506             n12 = n2 + 3;
3507             n23 = n3 + 3;
3508             n31 = n1 + 3;
3509           }
3510           else {
3511             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3512             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3513             n12 = n1 + 3;
3514             n23 = n2 + 3;
3515             n31 = n3 + 3;
3516           }
3517           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3518                                        prevNod[n12], prevNod[n23], prevNod[n31],
3519                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3520         }
3521         break;
3522       }
3523       case 8: { // quadratic quadrangle
3524         if(nbSame==0) {
3525           // create hexahedron with 20 nodes
3526           if(i0>0) { // reversed case
3527             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3528                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3529                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3530                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3531                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3532           }
3533           else { // not reversed case
3534             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3535                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3536                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3537                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3538                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3539           }
3540         }
3541         else if(nbSame==1) { 
3542           // --- pyramid + pentahedron - can not be created since it is needed 
3543           // additional middle node ot the center of face
3544           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3545           return;
3546         }
3547         else if(nbSame==2) {
3548           // 2d order Pentahedron with 15 nodes
3549           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3550           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3551           //                                 int n14,int n25,int n36, int ID);
3552           int n1,n2,n4,n5;
3553           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3554             // iBeforeSame is same too
3555             n1 = iBeforeSame;
3556             n2 = iOpposSame;
3557             n4 = iSameNode;
3558             n5 = iAfterSame;
3559           }
3560           else {
3561             // iAfterSame is same too
3562             n1 = iSameNode;
3563             n2 = iBeforeSame;
3564             n4 = iAfterSame;
3565             n5 = iOpposSame;
3566           }
3567           int n12,n45,n14,n25;
3568           if(i0>0) { //reversed case
3569             n12 = n1 + 4;
3570             n45 = n5 + 4;
3571             n14 = n4 + 4;
3572             n25 = n2 + 4;
3573           }
3574           else {
3575             n12 = n2 + 4;
3576             n45 = n4 + 4;
3577             n14 = n1 + 4;
3578             n25 = n5 + 4;
3579           }
3580           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3581                                        prevNod[n4], prevNod[n5], nextNod[n5],
3582                                        prevNod[n12], midlNod[n2], nextNod[n12],
3583                                        prevNod[n45], midlNod[n5], nextNod[n45],
3584                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3585         }
3586         break;
3587       }
3588       default: {
3589         // realized for extrusion only
3590         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3591         //vector<int> quantities (nbNodes + 2);
3592
3593         //quantities[0] = nbNodes; // bottom of prism
3594         //for (int inode = 0; inode < nbNodes; inode++) {
3595         //  polyedre_nodes[inode] = prevNod[inode];
3596         //}
3597
3598         //quantities[1] = nbNodes; // top of prism
3599         //for (int inode = 0; inode < nbNodes; inode++) {
3600         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3601         //}
3602
3603         //for (int iface = 0; iface < nbNodes; iface++) {
3604         //  quantities[iface + 2] = 4;
3605         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3606         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3607         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3608         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3609         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3610         //}
3611         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3612         break;
3613       }
3614       }
3615     }
3616
3617     if(!aNewElem) {
3618       // realized for extrusion only
3619       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3620       vector<int> quantities (nbNodes + 2);
3621
3622       quantities[0] = nbNodes; // bottom of prism
3623       for (int inode = 0; inode < nbNodes; inode++) {
3624         polyedre_nodes[inode] = prevNod[inode];
3625       }
3626
3627       quantities[1] = nbNodes; // top of prism
3628       for (int inode = 0; inode < nbNodes; inode++) {
3629         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3630       }
3631
3632       for (int iface = 0; iface < nbNodes; iface++) {
3633         quantities[iface + 2] = 4;
3634         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3635         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3636         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3637         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3638         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3639       }
3640       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3641     }
3642
3643     if ( aNewElem ) {
3644       newElems.push_back( aNewElem );
3645       myLastCreatedElems.Append(aNewElem);
3646       srcElements.Append( elem );
3647     }
3648
3649     // set new prev nodes
3650     for ( iNode = 0; iNode < nbNodes; iNode++ )
3651       prevNod[ iNode ] = nextNod[ iNode ];
3652
3653   } // for steps
3654 }
3655
3656 //=======================================================================
3657 /*!
3658  * \brief Create 1D and 2D elements around swept elements
3659  * \param mapNewNodes - source nodes and ones generated from them
3660  * \param newElemsMap - source elements and ones generated from them
3661  * \param elemNewNodesMap - nodes generated from each node of each element
3662  * \param elemSet - all swept elements
3663  * \param nbSteps - number of sweeping steps
3664  * \param srcElements - to append elem for each generated element
3665  */
3666 //=======================================================================
3667
3668 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3669                                   TElemOfElemListMap &     newElemsMap,
3670                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3671                                   TIDSortedElemSet&        elemSet,
3672                                   const int                nbSteps,
3673                                   SMESH_SequenceOfElemPtr& srcElements)
3674 {
3675   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3676   SMESHDS_Mesh* aMesh = GetMeshDS();
3677
3678   // Find nodes belonging to only one initial element - sweep them to get edges.
3679
3680   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3681   for ( ; nList != mapNewNodes.end(); nList++ ) {
3682     const SMDS_MeshNode* node =
3683       static_cast<const SMDS_MeshNode*>( nList->first );
3684     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3685     int nbInitElems = 0;
3686     const SMDS_MeshElement* el = 0;
3687     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3688     while ( eIt->more() && nbInitElems < 2 ) {
3689       el = eIt->next();
3690       SMDSAbs_ElementType type = el->GetType();
3691       if ( type == SMDSAbs_Volume || type < highType ) continue;
3692       if ( type > highType ) {
3693         nbInitElems = 0;
3694         highType = type;
3695       }
3696       if ( elemSet.find(el) != elemSet.end() )
3697         nbInitElems++;
3698     }
3699     if ( nbInitElems < 2 ) {
3700       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3701       if(!NotCreateEdge) {
3702         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3703         list<const SMDS_MeshElement*> newEdges;
3704         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3705       }
3706     }
3707   }
3708
3709   // Make a ceiling for each element ie an equal element of last new nodes.
3710   // Find free links of faces - make edges and sweep them into faces.
3711
3712   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3713   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3714   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3715     const SMDS_MeshElement* elem = itElem->first;
3716     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3717
3718     if ( elem->GetType() == SMDSAbs_Edge ) {
3719       // create a ceiling edge
3720       if (!elem->IsQuadratic()) {
3721         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3722                                vecNewNodes[ 1 ]->second.back())) {
3723           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3724                                                    vecNewNodes[ 1 ]->second.back()));
3725           srcElements.Append( myLastCreatedElems.Last() );
3726         }
3727       }
3728       else {
3729         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3730                                vecNewNodes[ 1 ]->second.back(),
3731                                vecNewNodes[ 2 ]->second.back())) {
3732           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3733                                                    vecNewNodes[ 1 ]->second.back(),
3734                                                    vecNewNodes[ 2 ]->second.back()));
3735           srcElements.Append( myLastCreatedElems.Last() );
3736         }
3737       }
3738     }
3739     if ( elem->GetType() != SMDSAbs_Face )
3740       continue;
3741
3742     if(itElem->second.size()==0) continue;
3743
3744     bool hasFreeLinks = false;
3745
3746     TIDSortedElemSet avoidSet;
3747     avoidSet.insert( elem );
3748
3749     set<const SMDS_MeshNode*> aFaceLastNodes;
3750     int iNode, nbNodes = vecNewNodes.size();
3751     if(!elem->IsQuadratic()) {
3752       // loop on the face nodes
3753       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3754         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3755         // look for free links of the face
3756         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3757         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3758         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3759         // check if a link is free
3760         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3761           hasFreeLinks = true;
3762           // make an edge and a ceiling for a new edge
3763           if ( !aMesh->FindEdge( n1, n2 )) {
3764             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3765             srcElements.Append( myLastCreatedElems.Last() );
3766           }
3767           n1 = vecNewNodes[ iNode ]->second.back();
3768           n2 = vecNewNodes[ iNext ]->second.back();
3769           if ( !aMesh->FindEdge( n1, n2 )) {
3770             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3771             srcElements.Append( myLastCreatedElems.Last() );
3772           }
3773         }
3774       }
3775     }
3776     else { // elem is quadratic face
3777       int nbn = nbNodes/2;
3778       for ( iNode = 0; iNode < nbn; iNode++ ) {
3779         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3780         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3781         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3782         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3783         // check if a link is free
3784         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3785           hasFreeLinks = true;
3786           // make an edge and a ceiling for a new edge
3787           // find medium node
3788           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3789           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3790             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3791             srcElements.Append( myLastCreatedElems.Last() );
3792           }
3793           n1 = vecNewNodes[ iNode ]->second.back();
3794           n2 = vecNewNodes[ iNext ]->second.back();
3795           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3796           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3797             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3798             srcElements.Append( myLastCreatedElems.Last() );
3799           }
3800         }
3801       }
3802       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3803         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3804       }
3805     }
3806
3807     // sweep free links into faces
3808
3809     if ( hasFreeLinks )  {
3810       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3811       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3812
3813       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3814       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3815         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3816         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3817       }
3818       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3819         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3820         iVol = 0;
3821         while ( iVol++ < volNb ) v++;
3822         // find indices of free faces of a volume and their source edges
3823         list< int > freeInd;
3824         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3825         SMDS_VolumeTool vTool( *v );
3826         int iF, nbF = vTool.NbFaces();
3827         for ( iF = 0; iF < nbF; iF ++ ) {
3828           if (vTool.IsFreeFace( iF ) &&
3829               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3830               initNodeSet != faceNodeSet) // except an initial face
3831           {
3832             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3833               continue;
3834             freeInd.push_back( iF );
3835             // find source edge of a free face iF
3836             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3837             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3838             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3839                                    initNodeSet.begin(), initNodeSet.end(),
3840                                    commonNodes.begin());
3841             if ( (*v)->IsQuadratic() )
3842               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3843             else
3844               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3845 #ifdef _DEBUG_
3846             if ( !srcEdges.back() )
3847             {
3848               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3849                    << iF << " of volume #" << vTool.ID() << endl;
3850             }
3851 #endif
3852           }
3853         }
3854         if ( freeInd.empty() )
3855           continue;
3856
3857         // create faces for all steps;
3858         // if such a face has been already created by sweep of edge,
3859         // assure that its orientation is OK
3860         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3861           vTool.Set( *v );
3862           vTool.SetExternalNormal();
3863           list< int >::iterator ind = freeInd.begin();
3864           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3865           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3866           {
3867             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3868             int nbn = vTool.NbFaceNodes( *ind );
3869             switch ( nbn ) {
3870             case 3: { ///// triangle
3871               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3872               if ( !f )
3873                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3874               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3875                 aMesh->ChangeElementNodes( f, nodes, nbn );
3876               break;
3877             }
3878             case 4: { ///// quadrangle
3879               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3880               if ( !f )
3881                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3882               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3883                 aMesh->ChangeElementNodes( f, nodes, nbn );
3884               break;
3885             }
3886             default:
3887               if( (*v)->IsQuadratic() ) {
3888                 if(nbn==6) { /////// quadratic triangle
3889                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3890                                                              nodes[1], nodes[3], nodes[5] );
3891                   if ( !f ) {
3892                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3893                                                              nodes[1], nodes[3], nodes[5]));
3894                   }
3895                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3896                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3897                     tmpnodes[0] = nodes[0];
3898                     tmpnodes[1] = nodes[2];
3899                     tmpnodes[2] = nodes[4];
3900                     tmpnodes[3] = nodes[1];
3901                     tmpnodes[4] = nodes[3];
3902                     tmpnodes[5] = nodes[5];
3903                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3904                   }
3905                 }
3906                 else {       /////// quadratic quadrangle
3907                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3908                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3909                   if ( !f ) {
3910                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3911                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3912                   }
3913                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3914                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3915                     tmpnodes[0] = nodes[0];
3916                     tmpnodes[1] = nodes[2];
3917                     tmpnodes[2] = nodes[4];
3918                     tmpnodes[3] = nodes[6];
3919                     tmpnodes[4] = nodes[1];
3920                     tmpnodes[5] = nodes[3];
3921                     tmpnodes[6] = nodes[5];
3922                     tmpnodes[7] = nodes[7];
3923                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3924                   }
3925                 }
3926               }
3927               else { //////// polygon
3928                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3929                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3930                 if ( !f )
3931                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3932                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3933                   aMesh->ChangeElementNodes( f, nodes, nbn );
3934               }
3935             }
3936             while ( srcElements.Length() < myLastCreatedElems.Length() )
3937               srcElements.Append( *srcEdge );
3938
3939           }  // loop on free faces
3940
3941           // go to the next volume
3942           iVol = 0;
3943           while ( iVol++ < nbVolumesByStep ) v++;
3944         }
3945       }
3946     } // sweep free links into faces
3947
3948     // Make a ceiling face with a normal external to a volume
3949
3950     SMDS_VolumeTool lastVol( itElem->second.back() );
3951
3952     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3953     if ( iF >= 0 ) {
3954       lastVol.SetExternalNormal();
3955       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3956       int nbn = lastVol.NbFaceNodes( iF );
3957       switch ( nbn ) {
3958       case 3:
3959         if (!hasFreeLinks ||
3960             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3961           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3962         break;
3963       case 4:
3964         if (!hasFreeLinks ||
3965             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3966           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3967         break;
3968       default:
3969         if(itElem->second.back()->IsQuadratic()) {
3970           if(nbn==6) {
3971             if (!hasFreeLinks ||
3972                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3973                                  nodes[1], nodes[3], nodes[5]) ) {
3974               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3975                                                        nodes[1], nodes[3], nodes[5]));
3976             }
3977           }
3978           else { // nbn==8
3979             if (!hasFreeLinks ||
3980                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3981                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3982               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3983                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3984           }
3985         }
3986         else {
3987           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3988           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3989             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3990         }
3991       } // switch
3992
3993       while ( srcElements.Length() < myLastCreatedElems.Length() )
3994         srcElements.Append( myLastCreatedElems.Last() );
3995     }
3996   } // loop on swept elements
3997 }
3998
3999 //=======================================================================
4000 //function : RotationSweep
4001 //purpose  :
4002 //=======================================================================
4003
4004 SMESH_MeshEditor::PGroupIDs
4005 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4006                                 const gp_Ax1&      theAxis,
4007                                 const double       theAngle,
4008                                 const int          theNbSteps,
4009                                 const double       theTol,
4010                                 const bool         theMakeGroups,
4011                                 const bool         theMakeWalls)
4012 {
4013   myLastCreatedElems.Clear();
4014   myLastCreatedNodes.Clear();
4015
4016   // source elements for each generated one
4017   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4018
4019   MESSAGE( "RotationSweep()");
4020   gp_Trsf aTrsf;
4021   aTrsf.SetRotation( theAxis, theAngle );
4022   gp_Trsf aTrsf2;
4023   aTrsf2.SetRotation( theAxis, theAngle/2. );
4024
4025   gp_Lin aLine( theAxis );
4026   double aSqTol = theTol * theTol;
4027
4028   SMESHDS_Mesh* aMesh = GetMeshDS();
4029
4030   TNodeOfNodeListMap mapNewNodes;
4031   TElemOfVecOfNnlmiMap mapElemNewNodes;
4032   TElemOfElemListMap newElemsMap;
4033
4034   // loop on theElems
4035   TIDSortedElemSet::iterator itElem;
4036   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4037     const SMDS_MeshElement* elem = *itElem;
4038     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4039       continue;
4040     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4041     newNodesItVec.reserve( elem->NbNodes() );
4042
4043     // loop on elem nodes
4044     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4045     while ( itN->more() ) {
4046       // check if a node has been already sweeped
4047       const SMDS_MeshNode* node = cast2Node( itN->next() );
4048
4049       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4050       double coord[3];
4051       aXYZ.Coord( coord[0], coord[1], coord[2] );
4052       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4053
4054       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4055       if ( nIt == mapNewNodes.end() ) {
4056         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4057         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4058
4059         // make new nodes
4060         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4061         //double coord[3];
4062         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4063         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4064         const SMDS_MeshNode * newNode = node;
4065         for ( int i = 0; i < theNbSteps; i++ ) {
4066           if ( !isOnAxis ) {
4067             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4068               // create two nodes
4069               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4070               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4071               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4072               myLastCreatedNodes.Append(newNode);
4073               srcNodes.Append( node );
4074               listNewNodes.push_back( newNode );
4075               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4076               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4077             }
4078             else {
4079               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4080             }
4081             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4082             myLastCreatedNodes.Append(newNode);
4083             srcNodes.Append( node );
4084             listNewNodes.push_back( newNode );
4085           }
4086           else {
4087             listNewNodes.push_back( newNode );
4088             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4089               listNewNodes.push_back( newNode );
4090             }
4091           }
4092         }
4093       }
4094       /*
4095         else {
4096         // if current elem is quadratic and current node is not medium
4097         // we have to check - may be it is needed to insert additional nodes
4098         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4099         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4100         if(listNewNodes.size()==theNbSteps) {
4101         listNewNodes.clear();
4102         // make new nodes
4103         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4104         //double coord[3];
4105         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4106         const SMDS_MeshNode * newNode = node;
4107         if ( !isOnAxis ) {
4108         for(int i = 0; i<theNbSteps; i++) {
4109         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4110         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4111         cout<<"    3 AddNode:  "<<newNode;
4112         myLastCreatedNodes.Append(newNode);
4113         listNewNodes.push_back( newNode );
4114         srcNodes.Append( node );
4115         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4116         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4117         cout<<"    4 AddNode:  "<<newNode;
4118         myLastCreatedNodes.Append(newNode);
4119         srcNodes.Append( node );
4120         listNewNodes.push_back( newNode );
4121         }
4122         }
4123         else {
4124         listNewNodes.push_back( newNode );
4125         }
4126         }
4127         }
4128         }
4129       */
4130       newNodesItVec.push_back( nIt );
4131     }
4132     // make new elements
4133     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4134   }
4135
4136   if ( theMakeWalls )
4137     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4138
4139   PGroupIDs newGroupIDs;
4140   if ( theMakeGroups )
4141     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4142
4143   return newGroupIDs;
4144 }
4145
4146
4147 //=======================================================================
4148 //function : CreateNode
4149 //purpose  :
4150 //=======================================================================
4151 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4152                                                   const double y,
4153                                                   const double z,
4154                                                   const double tolnode,
4155                                                   SMESH_SequenceOfNode& aNodes)
4156 {
4157   myLastCreatedElems.Clear();
4158   myLastCreatedNodes.Clear();
4159
4160   gp_Pnt P1(x,y,z);
4161   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4162
4163   // try to search in sequence of existing nodes
4164   // if aNodes.Length()>0 we 'nave to use given sequence
4165   // else - use all nodes of mesh
4166   if(aNodes.Length()>0) {
4167     int i;
4168     for(i=1; i<=aNodes.Length(); i++) {
4169       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4170       if(P1.Distance(P2)<tolnode)
4171         return aNodes.Value(i);
4172     }
4173   }
4174   else {
4175     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4176     while(itn->more()) {
4177       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4178       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4179       if(P1.Distance(P2)<tolnode)
4180         return aN;
4181     }
4182   }
4183
4184   // create new node and return it
4185   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4186   myLastCreatedNodes.Append(NewNode);
4187   return NewNode;
4188 }
4189
4190
4191 //=======================================================================
4192 //function : ExtrusionSweep
4193 //purpose  :
4194 //=======================================================================
4195
4196 SMESH_MeshEditor::PGroupIDs
4197 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4198                                   const gp_Vec&       theStep,
4199                                   const int           theNbSteps,
4200                                   TElemOfElemListMap& newElemsMap,
4201                                   const bool          theMakeGroups,
4202                                   const int           theFlags,
4203                                   const double        theTolerance)
4204 {
4205   ExtrusParam aParams;
4206   aParams.myDir = gp_Dir(theStep);
4207   aParams.myNodes.Clear();
4208   aParams.mySteps = new TColStd_HSequenceOfReal;
4209   int i;
4210   for(i=1; i<=theNbSteps; i++)
4211     aParams.mySteps->Append(theStep.Magnitude());
4212
4213   return
4214     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4215 }
4216
4217
4218 //=======================================================================
4219 //function : ExtrusionSweep
4220 //purpose  :
4221 //=======================================================================
4222
4223 SMESH_MeshEditor::PGroupIDs
4224 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4225                                   ExtrusParam&        theParams,
4226                                   TElemOfElemListMap& newElemsMap,
4227                                   const bool          theMakeGroups,
4228                                   const int           theFlags,
4229                                   const double        theTolerance)
4230 {
4231   myLastCreatedElems.Clear();
4232   myLastCreatedNodes.Clear();
4233
4234   // source elements for each generated one
4235   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4236
4237   SMESHDS_Mesh* aMesh = GetMeshDS();
4238
4239   int nbsteps = theParams.mySteps->Length();
4240
4241   TNodeOfNodeListMap mapNewNodes;
4242   //TNodeOfNodeVecMap mapNewNodes;
4243   TElemOfVecOfNnlmiMap mapElemNewNodes;
4244   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4245
4246   // loop on theElems
4247   TIDSortedElemSet::iterator itElem;
4248   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4249     // check element type
4250     const SMDS_MeshElement* elem = *itElem;
4251     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4252       continue;
4253
4254     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4255     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4256     newNodesItVec.reserve( elem->NbNodes() );
4257
4258     // loop on elem nodes
4259     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4260     while ( itN->more() )
4261     {
4262       // check if a node has been already sweeped
4263       const SMDS_MeshNode* node = cast2Node( itN->next() );
4264       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4265       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4266       if ( nIt == mapNewNodes.end() ) {
4267         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4268         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4269         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4270         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4271         //vecNewNodes.reserve(nbsteps);
4272
4273         // make new nodes
4274         double coord[] = { node->X(), node->Y(), node->Z() };
4275         //int nbsteps = theParams.mySteps->Length();
4276         for ( int i = 0; i < nbsteps; i++ ) {
4277           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4278             // create additional node
4279             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4280             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4281             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4282             if( theFlags & EXTRUSION_FLAG_SEW ) {
4283               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4284                                                          theTolerance, theParams.myNodes);
4285               listNewNodes.push_back( newNode );
4286             }
4287             else {
4288               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4289               myLastCreatedNodes.Append(newNode);
4290               srcNodes.Append( node );
4291               listNewNodes.push_back( newNode );
4292             }
4293           }
4294           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4295           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4296           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4297           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4298           if( theFlags & EXTRUSION_FLAG_SEW ) {
4299             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4300                                                        theTolerance, theParams.myNodes);
4301             listNewNodes.push_back( newNode );
4302             //vecNewNodes[i]=newNode;
4303           }
4304           else {
4305             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4306             myLastCreatedNodes.Append(newNode);
4307             srcNodes.Append( node );
4308             listNewNodes.push_back( newNode );
4309             //vecNewNodes[i]=newNode;
4310           }
4311         }
4312       }
4313       else {
4314         // if current elem is quadratic and current node is not medium
4315         // we have to check - may be it is needed to insert additional nodes
4316         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4317           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4318           if(listNewNodes.size()==nbsteps) {
4319             listNewNodes.clear();
4320             double coord[] = { node->X(), node->Y(), node->Z() };
4321             for ( int i = 0; i < nbsteps; i++ ) {
4322               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4323               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4324               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4325               if( theFlags & EXTRUSION_FLAG_SEW ) {
4326                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4327                                                            theTolerance, theParams.myNodes);
4328                 listNewNodes.push_back( newNode );
4329               }
4330               else {
4331                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4332                 myLastCreatedNodes.Append(newNode);
4333                 srcNodes.Append( node );
4334                 listNewNodes.push_back( newNode );
4335               }
4336               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4337               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4338               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4339               if( theFlags & EXTRUSION_FLAG_SEW ) {
4340                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4341                                                            theTolerance, theParams.myNodes);
4342                 listNewNodes.push_back( newNode );
4343               }
4344               else {
4345                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4346                 myLastCreatedNodes.Append(newNode);
4347                 srcNodes.Append( node );
4348                 listNewNodes.push_back( newNode );
4349               }
4350             }
4351           }
4352         }
4353       }
4354       newNodesItVec.push_back( nIt );
4355     }
4356     // make new elements
4357     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4358   }
4359
4360   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4361     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4362   }
4363   PGroupIDs newGroupIDs;
4364   if ( theMakeGroups )
4365     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4366
4367   return newGroupIDs;
4368 }
4369
4370 /*
4371 //=======================================================================
4372 //class    : SMESH_MeshEditor_PathPoint
4373 //purpose  : auxiliary class
4374 //=======================================================================
4375 class SMESH_MeshEditor_PathPoint {
4376 public:
4377 SMESH_MeshEditor_PathPoint() {
4378 myPnt.SetCoord(99., 99., 99.);
4379 myTgt.SetCoord(1.,0.,0.);
4380 myAngle=0.;
4381 myPrm=0.;
4382 }
4383 void SetPnt(const gp_Pnt& aP3D){
4384 myPnt=aP3D;
4385 }
4386 void SetTangent(const gp_Dir& aTgt){
4387 myTgt=aTgt;
4388 }
4389 void SetAngle(const double& aBeta){
4390 myAngle=aBeta;
4391 }
4392 void SetParameter(const double& aPrm){
4393 myPrm=aPrm;
4394 }
4395 const gp_Pnt& Pnt()const{
4396 return myPnt;
4397 }
4398 const gp_Dir& Tangent()const{
4399 return myTgt;
4400 }
4401 double Angle()const{
4402 return myAngle;
4403 }
4404 double Parameter()const{
4405 return myPrm;
4406 }
4407
4408 protected:
4409 gp_Pnt myPnt;
4410 gp_Dir myTgt;
4411 double myAngle;
4412 double myPrm;
4413 };
4414 */
4415
4416 //=======================================================================
4417 //function : ExtrusionAlongTrack
4418 //purpose  :
4419 //=======================================================================
4420 SMESH_MeshEditor::Extrusion_Error
4421 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4422                                        SMESH_subMesh*       theTrack,
4423                                        const SMDS_MeshNode* theN1,
4424                                        const bool           theHasAngles,
4425                                        list<double>&        theAngles,
4426                                        const bool           theLinearVariation,
4427                                        const bool           theHasRefPoint,
4428                                        const gp_Pnt&        theRefPoint,
4429                                        const bool           theMakeGroups)
4430 {
4431   myLastCreatedElems.Clear();
4432   myLastCreatedNodes.Clear();
4433
4434   int aNbE;
4435   std::list<double> aPrms;
4436   TIDSortedElemSet::iterator itElem;
4437
4438   gp_XYZ aGC;
4439   TopoDS_Edge aTrackEdge;
4440   TopoDS_Vertex aV1, aV2;
4441
4442   SMDS_ElemIteratorPtr aItE;
4443   SMDS_NodeIteratorPtr aItN;
4444   SMDSAbs_ElementType aTypeE;
4445
4446   TNodeOfNodeListMap mapNewNodes;
4447
4448   // 1. Check data
4449   aNbE = theElements.size();
4450   // nothing to do
4451   if ( !aNbE )
4452     return EXTR_NO_ELEMENTS;
4453
4454   // 1.1 Track Pattern
4455   ASSERT( theTrack );
4456
4457   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4458
4459   aItE = pSubMeshDS->GetElements();
4460   while ( aItE->more() ) {
4461     const SMDS_MeshElement* pE = aItE->next();
4462     aTypeE = pE->GetType();
4463     // Pattern must contain links only
4464     if ( aTypeE != SMDSAbs_Edge )
4465       return EXTR_PATH_NOT_EDGE;
4466   }
4467
4468   list<SMESH_MeshEditor_PathPoint> fullList;
4469
4470   const TopoDS_Shape& aS = theTrack->GetSubShape();
4471   // Sub shape for the Pattern must be an Edge or Wire
4472   if( aS.ShapeType() == TopAbs_EDGE ) {
4473     aTrackEdge = TopoDS::Edge( aS );
4474     // the Edge must not be degenerated
4475     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4476       return EXTR_BAD_PATH_SHAPE;
4477     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4478     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4479     const SMDS_MeshNode* aN1 = aItN->next();
4480     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4481     const SMDS_MeshNode* aN2 = aItN->next();
4482     // starting node must be aN1 or aN2
4483     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4484       return EXTR_BAD_STARTING_NODE;
4485     aItN = pSubMeshDS->GetNodes();
4486     while ( aItN->more() ) {
4487       const SMDS_MeshNode* pNode = aItN->next();
4488       const SMDS_EdgePosition* pEPos =
4489         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4490       double aT = pEPos->GetUParameter();
4491       aPrms.push_back( aT );
4492     }
4493     //Extrusion_Error err =
4494     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4495   }
4496   else if( aS.ShapeType() == TopAbs_WIRE ) {
4497     list< SMESH_subMesh* > LSM;
4498     TopTools_SequenceOfShape Edges;
4499     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4500     while(itSM->more()) {
4501       SMESH_subMesh* SM = itSM->next();
4502       LSM.push_back(SM);
4503       const TopoDS_Shape& aS = SM->GetSubShape();
4504       Edges.Append(aS);
4505     }
4506     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4507     int startNid = theN1->GetID();
4508     TColStd_MapOfInteger UsedNums;
4509     int NbEdges = Edges.Length();
4510     int i = 1;
4511     for(; i<=NbEdges; i++) {
4512       int k = 0;
4513       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4514       for(; itLSM!=LSM.end(); itLSM++) {
4515         k++;
4516         if(UsedNums.Contains(k)) continue;
4517         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4518         SMESH_subMesh* locTrack = *itLSM;
4519         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4520         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4521         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4522         const SMDS_MeshNode* aN1 = aItN->next();
4523         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4524         const SMDS_MeshNode* aN2 = aItN->next();
4525         // starting node must be aN1 or aN2
4526         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4527         // 2. Collect parameters on the track edge
4528         aPrms.clear();
4529         aItN = locMeshDS->GetNodes();
4530         while ( aItN->more() ) {
4531           const SMDS_MeshNode* pNode = aItN->next();
4532           const SMDS_EdgePosition* pEPos =
4533             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4534           double aT = pEPos->GetUParameter();
4535           aPrms.push_back( aT );
4536         }
4537         list<SMESH_MeshEditor_PathPoint> LPP;
4538         //Extrusion_Error err =
4539         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4540         LLPPs.push_back(LPP);
4541         UsedNums.Add(k);
4542         // update startN for search following egde
4543         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4544         else startNid = aN1->GetID();
4545         break;
4546       }
4547     }
4548     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4549     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4550     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4551     for(; itPP!=firstList.end(); itPP++) {
4552       fullList.push_back( *itPP );
4553     }
4554     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4555     fullList.pop_back();
4556     itLLPP++;
4557     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4558       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4559       itPP = currList.begin();
4560       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4561       gp_Dir D1 = PP1.Tangent();
4562       gp_Dir D2 = PP2.Tangent();
4563       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4564                            (D1.Z()+D2.Z())/2 ) );
4565       PP1.SetTangent(Dnew);
4566       fullList.push_back(PP1);
4567       itPP++;
4568       for(; itPP!=firstList.end(); itPP++) {
4569         fullList.push_back( *itPP );
4570       }
4571       PP1 = fullList.back();
4572       fullList.pop_back();
4573     }
4574     // if wire not closed
4575     fullList.push_back(PP1);
4576     // else ???
4577   }
4578   else {
4579     return EXTR_BAD_PATH_SHAPE;
4580   }
4581
4582   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4583                           theHasRefPoint, theRefPoint, theMakeGroups);
4584 }
4585
4586
4587 //=======================================================================
4588 //function : ExtrusionAlongTrack
4589 //purpose  :
4590 //=======================================================================
4591 SMESH_MeshEditor::Extrusion_Error
4592 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4593                                        SMESH_Mesh*          theTrack,
4594                                        const SMDS_MeshNode* theN1,
4595                                        const bool           theHasAngles,
4596                                        list<double>&        theAngles,
4597                                        const bool           theLinearVariation,
4598                                        const bool           theHasRefPoint,
4599                                        const gp_Pnt&        theRefPoint,
4600                                        const bool           theMakeGroups)
4601 {
4602   myLastCreatedElems.Clear();
4603   myLastCreatedNodes.Clear();
4604
4605   int aNbE;
4606   std::list<double> aPrms;
4607   TIDSortedElemSet::iterator itElem;
4608
4609   gp_XYZ aGC;
4610   TopoDS_Edge aTrackEdge;
4611   TopoDS_Vertex aV1, aV2;
4612
4613   SMDS_ElemIteratorPtr aItE;
4614   SMDS_NodeIteratorPtr aItN;
4615   SMDSAbs_ElementType aTypeE;
4616
4617   TNodeOfNodeListMap mapNewNodes;
4618
4619   // 1. Check data
4620   aNbE = theElements.size();
4621   // nothing to do
4622   if ( !aNbE )
4623     return EXTR_NO_ELEMENTS;
4624
4625   // 1.1 Track Pattern
4626   ASSERT( theTrack );
4627
4628   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4629
4630   aItE = pMeshDS->elementsIterator();
4631   while ( aItE->more() ) {
4632     const SMDS_MeshElement* pE = aItE->next();
4633     aTypeE = pE->GetType();
4634     // Pattern must contain links only
4635     if ( aTypeE != SMDSAbs_Edge )
4636       return EXTR_PATH_NOT_EDGE;
4637   }
4638
4639   list<SMESH_MeshEditor_PathPoint> fullList;
4640
4641   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4642   // Sub shape for the Pattern must be an Edge or Wire
4643   if( aS.ShapeType() == TopAbs_EDGE ) {
4644     aTrackEdge = TopoDS::Edge( aS );
4645     // the Edge must not be degenerated
4646     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4647       return EXTR_BAD_PATH_SHAPE;
4648     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4649     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4650     const SMDS_MeshNode* aN1 = aItN->next();
4651     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4652     const SMDS_MeshNode* aN2 = aItN->next();
4653     // starting node must be aN1 or aN2
4654     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4655       return EXTR_BAD_STARTING_NODE;
4656     aItN = pMeshDS->nodesIterator();
4657     while ( aItN->more() ) {
4658       const SMDS_MeshNode* pNode = aItN->next();
4659       if( pNode==aN1 || pNode==aN2 ) continue;
4660       const SMDS_EdgePosition* pEPos =
4661         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4662       double aT = pEPos->GetUParameter();
4663       aPrms.push_back( aT );
4664     }
4665     //Extrusion_Error err =
4666     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4667   }
4668   else if( aS.ShapeType() == TopAbs_WIRE ) {
4669     list< SMESH_subMesh* > LSM;
4670     TopTools_SequenceOfShape Edges;
4671     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4672     for(; eExp.More(); eExp.Next()) {
4673       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4674       if( BRep_Tool::Degenerated(E) ) continue;
4675       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4676       if(SM) {
4677         LSM.push_back(SM);
4678         Edges.Append(E);
4679       }
4680     }
4681     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4682     int startNid = theN1->GetID();
4683     TColStd_MapOfInteger UsedNums;
4684     int NbEdges = Edges.Length();
4685     int i = 1;
4686     for(; i<=NbEdges; i++) {
4687       int k = 0;
4688       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4689       for(; itLSM!=LSM.end(); itLSM++) {
4690         k++;
4691         if(UsedNums.Contains(k)) continue;
4692         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4693         SMESH_subMesh* locTrack = *itLSM;
4694         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4695         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4696         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4697         const SMDS_MeshNode* aN1 = aItN->next();
4698         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4699         const SMDS_MeshNode* aN2 = aItN->next();
4700         // starting node must be aN1 or aN2
4701         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4702         // 2. Collect parameters on the track edge
4703         aPrms.clear();
4704         aItN = locMeshDS->GetNodes();
4705         while ( aItN->more() ) {
4706           const SMDS_MeshNode* pNode = aItN->next();
4707           const SMDS_EdgePosition* pEPos =
4708             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4709           double aT = pEPos->GetUParameter();
4710           aPrms.push_back( aT );
4711         }
4712         list<SMESH_MeshEditor_PathPoint> LPP;
4713         //Extrusion_Error err =
4714         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4715         LLPPs.push_back(LPP);
4716         UsedNums.Add(k);
4717         // update startN for search following egde
4718         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4719         else startNid = aN1->GetID();
4720         break;
4721       }
4722     }
4723     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4724     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4725     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4726     for(; itPP!=firstList.end(); itPP++) {
4727       fullList.push_back( *itPP );
4728     }
4729     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4730     fullList.pop_back();
4731     itLLPP++;
4732     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4733       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4734       itPP = currList.begin();
4735       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4736       gp_Pnt P1 = PP1.Pnt();
4737       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4738       gp_Pnt P2 = PP2.Pnt();
4739       gp_Dir D1 = PP1.Tangent();
4740       gp_Dir D2 = PP2.Tangent();
4741       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4742                            (D1.Z()+D2.Z())/2 ) );
4743       PP1.SetTangent(Dnew);
4744       fullList.push_back(PP1);
4745       itPP++;
4746       for(; itPP!=currList.end(); itPP++) {
4747         fullList.push_back( *itPP );
4748       }
4749       PP1 = fullList.back();
4750       fullList.pop_back();
4751     }
4752     // if wire not closed
4753     fullList.push_back(PP1);
4754     // else ???
4755   }
4756   else {
4757     return EXTR_BAD_PATH_SHAPE;
4758   }
4759
4760   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4761                           theHasRefPoint, theRefPoint, theMakeGroups);
4762 }
4763
4764
4765 //=======================================================================
4766 //function : MakeEdgePathPoints
4767 //purpose  : auxilary for ExtrusionAlongTrack
4768 //=======================================================================
4769 SMESH_MeshEditor::Extrusion_Error
4770 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4771                                      const TopoDS_Edge& aTrackEdge,
4772                                      bool FirstIsStart,
4773                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4774 {
4775   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4776   aTolVec=1.e-7;
4777   aTolVec2=aTolVec*aTolVec;
4778   double aT1, aT2;
4779   TopoDS_Vertex aV1, aV2;
4780   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4781   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4782   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4783   // 2. Collect parameters on the track edge
4784   aPrms.push_front( aT1 );
4785   aPrms.push_back( aT2 );
4786   // sort parameters
4787   aPrms.sort();
4788   if( FirstIsStart ) {
4789     if ( aT1 > aT2 ) {
4790       aPrms.reverse();
4791     }
4792   }
4793   else {
4794     if ( aT2 > aT1 ) {
4795       aPrms.reverse();
4796     }
4797   }
4798   // 3. Path Points
4799   SMESH_MeshEditor_PathPoint aPP;
4800   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4801   std::list<double>::iterator aItD = aPrms.begin();
4802   for(; aItD != aPrms.end(); ++aItD) {
4803     double aT = *aItD;
4804     gp_Pnt aP3D;
4805     gp_Vec aVec;
4806     aC3D->D1( aT, aP3D, aVec );
4807     aL2 = aVec.SquareMagnitude();
4808     if ( aL2 < aTolVec2 )
4809       return EXTR_CANT_GET_TANGENT;
4810     gp_Dir aTgt( aVec );
4811     aPP.SetPnt( aP3D );
4812     aPP.SetTangent( aTgt );
4813     aPP.SetParameter( aT );
4814     LPP.push_back(aPP);
4815   }
4816   return EXTR_OK;
4817 }
4818
4819
4820 //=======================================================================
4821 //function : MakeExtrElements
4822 //purpose  : auxilary for ExtrusionAlongTrack
4823 //=======================================================================
4824 SMESH_MeshEditor::Extrusion_Error
4825 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4826                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4827                                    const bool theHasAngles,
4828                                    list<double>& theAngles,
4829                                    const bool theLinearVariation,
4830                                    const bool theHasRefPoint,
4831                                    const gp_Pnt& theRefPoint,
4832                                    const bool theMakeGroups)
4833 {
4834   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4835   int aNbTP = fullList.size();
4836   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4837   // Angles
4838   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4839     LinearAngleVariation(aNbTP-1, theAngles);
4840   }
4841   vector<double> aAngles( aNbTP );
4842   int j = 0;
4843   for(; j<aNbTP; ++j) {
4844     aAngles[j] = 0.;
4845   }
4846   if ( theHasAngles ) {
4847     double anAngle;;
4848     std::list<double>::iterator aItD = theAngles.begin();
4849     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4850       anAngle = *aItD;
4851       aAngles[j] = anAngle;
4852     }
4853   }
4854   // fill vector of path points with angles
4855   //aPPs.resize(fullList.size());
4856   j = -1;
4857   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4858   for(; itPP!=fullList.end(); itPP++) {
4859     j++;
4860     SMESH_MeshEditor_PathPoint PP = *itPP;
4861     PP.SetAngle(aAngles[j]);
4862     aPPs[j] = PP;
4863   }
4864
4865   TNodeOfNodeListMap mapNewNodes;
4866   TElemOfVecOfNnlmiMap mapElemNewNodes;
4867   TElemOfElemListMap newElemsMap;
4868   TIDSortedElemSet::iterator itElem;
4869   double aX, aY, aZ;
4870   int aNb;
4871   SMDSAbs_ElementType aTypeE;
4872   // source elements for each generated one
4873   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4874
4875   // 3. Center of rotation aV0
4876   gp_Pnt aV0 = theRefPoint;
4877   gp_XYZ aGC;
4878   if ( !theHasRefPoint ) {
4879     aNb = 0;
4880     aGC.SetCoord( 0.,0.,0. );
4881
4882     itElem = theElements.begin();
4883     for ( ; itElem != theElements.end(); itElem++ ) {
4884       const SMDS_MeshElement* elem = *itElem;
4885
4886       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4887       while ( itN->more() ) {
4888         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4889         aX = node->X();
4890         aY = node->Y();
4891         aZ = node->Z();
4892
4893         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4894           list<const SMDS_MeshNode*> aLNx;
4895           mapNewNodes[node] = aLNx;
4896           //
4897           gp_XYZ aXYZ( aX, aY, aZ );
4898           aGC += aXYZ;
4899           ++aNb;
4900         }
4901       }
4902     }
4903     aGC /= aNb;
4904     aV0.SetXYZ( aGC );
4905   } // if (!theHasRefPoint) {
4906   mapNewNodes.clear();
4907
4908   // 4. Processing the elements
4909   SMESHDS_Mesh* aMesh = GetMeshDS();
4910
4911   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4912     // check element type
4913     const SMDS_MeshElement* elem = *itElem;
4914     aTypeE = elem->GetType();
4915     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4916       continue;
4917
4918     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4919     newNodesItVec.reserve( elem->NbNodes() );
4920
4921     // loop on elem nodes
4922     int nodeIndex = -1;
4923     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4924     while ( itN->more() )
4925     {
4926       ++nodeIndex;
4927       // check if a node has been already processed
4928       const SMDS_MeshNode* node =
4929         static_cast<const SMDS_MeshNode*>( itN->next() );
4930       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4931       if ( nIt == mapNewNodes.end() ) {
4932         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4933         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4934
4935         // make new nodes
4936         aX = node->X();  aY = node->Y(); aZ = node->Z();
4937
4938         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4939         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4940         gp_Ax1 anAx1, anAxT1T0;
4941         gp_Dir aDT1x, aDT0x, aDT1T0;
4942
4943         aTolAng=1.e-4;
4944
4945         aV0x = aV0;
4946         aPN0.SetCoord(aX, aY, aZ);
4947
4948         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4949         aP0x = aPP0.Pnt();
4950         aDT0x= aPP0.Tangent();
4951         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4952
4953         for ( j = 1; j < aNbTP; ++j ) {
4954           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4955           aP1x = aPP1.Pnt();
4956           aDT1x = aPP1.Tangent();
4957           aAngle1x = aPP1.Angle();
4958
4959           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4960           // Translation
4961           gp_Vec aV01x( aP0x, aP1x );
4962           aTrsf.SetTranslation( aV01x );
4963
4964           // traslated point
4965           aV1x = aV0x.Transformed( aTrsf );
4966           aPN1 = aPN0.Transformed( aTrsf );
4967
4968           // rotation 1 [ T1,T0 ]
4969           aAngleT1T0=-aDT1x.Angle( aDT0x );
4970           if (fabs(aAngleT1T0) > aTolAng) {
4971             aDT1T0=aDT1x^aDT0x;
4972             anAxT1T0.SetLocation( aV1x );
4973             anAxT1T0.SetDirection( aDT1T0 );
4974             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4975
4976             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4977           }
4978
4979           // rotation 2
4980           if ( theHasAngles ) {
4981             anAx1.SetLocation( aV1x );
4982             anAx1.SetDirection( aDT1x );
4983             aTrsfRot.SetRotation( anAx1, aAngle1x );
4984
4985             aPN1 = aPN1.Transformed( aTrsfRot );
4986           }
4987
4988           // make new node
4989           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4990             // create additional node
4991             double x = ( aPN1.X() + aPN0.X() )/2.;
4992             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4993             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4994             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4995             myLastCreatedNodes.Append(newNode);
4996             srcNodes.Append( node );
4997             listNewNodes.push_back( newNode );
4998           }
4999           aX = aPN1.X();
5000           aY = aPN1.Y();
5001           aZ = aPN1.Z();
5002           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5003           myLastCreatedNodes.Append(newNode);
5004           srcNodes.Append( node );
5005           listNewNodes.push_back( newNode );
5006
5007           aPN0 = aPN1;
5008           aP0x = aP1x;
5009           aV0x = aV1x;
5010           aDT0x = aDT1x;
5011         }
5012       }
5013
5014       else {
5015         // if current elem is quadratic and current node is not medium
5016         // we have to check - may be it is needed to insert additional nodes
5017         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5018           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5019           if(listNewNodes.size()==aNbTP-1) {
5020             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5021             gp_XYZ P(node->X(), node->Y(), node->Z());
5022             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5023             int i;
5024             for(i=0; i<aNbTP-1; i++) {
5025               const SMDS_MeshNode* N = *it;
5026               double x = ( N->X() + P.X() )/2.;
5027               double y = ( N->Y() + P.Y() )/2.;
5028               double z = ( N->Z() + P.Z() )/2.;
5029               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5030               srcNodes.Append( node );
5031               myLastCreatedNodes.Append(newN);
5032               aNodes[2*i] = newN;
5033               aNodes[2*i+1] = N;
5034               P = gp_XYZ(N->X(),N->Y(),N->Z());
5035             }
5036             listNewNodes.clear();
5037             for(i=0; i<2*(aNbTP-1); i++) {
5038               listNewNodes.push_back(aNodes[i]);
5039             }
5040           }
5041         }
5042       }
5043
5044       newNodesItVec.push_back( nIt );
5045     }
5046     // make new elements
5047     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5048     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5049     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5050   }
5051
5052   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5053
5054   if ( theMakeGroups )
5055     generateGroups( srcNodes, srcElems, "extruded");
5056
5057   return EXTR_OK;
5058 }
5059
5060
5061 //=======================================================================
5062 //function : LinearAngleVariation
5063 //purpose  : auxilary for ExtrusionAlongTrack
5064 //=======================================================================
5065 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5066                                             list<double>& Angles)
5067 {
5068   int nbAngles = Angles.size();
5069   if( nbSteps > nbAngles ) {
5070     vector<double> theAngles(nbAngles);
5071     list<double>::iterator it = Angles.begin();
5072     int i = -1;
5073     for(; it!=Angles.end(); it++) {
5074       i++;
5075       theAngles[i] = (*it);
5076     }
5077     list<double> res;
5078     double rAn2St = double( nbAngles ) / double( nbSteps );
5079     double angPrev = 0, angle;
5080     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5081       double angCur = rAn2St * ( iSt+1 );
5082       double angCurFloor  = floor( angCur );
5083       double angPrevFloor = floor( angPrev );
5084       if ( angPrevFloor == angCurFloor )
5085         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5086       else {
5087         int iP = int( angPrevFloor );
5088         double angPrevCeil = ceil(angPrev);
5089         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5090
5091         int iC = int( angCurFloor );
5092         if ( iC < nbAngles )
5093           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5094
5095         iP = int( angPrevCeil );
5096         while ( iC-- > iP )
5097           angle += theAngles[ iC ];
5098       }
5099       res.push_back(angle);
5100       angPrev = angCur;
5101     }
5102     Angles.clear();
5103     it = res.begin();
5104     for(; it!=res.end(); it++)
5105       Angles.push_back( *it );
5106   }
5107 }
5108
5109
5110 //=======================================================================
5111 //function : Transform
5112 //purpose  :
5113 //=======================================================================
5114
5115 SMESH_MeshEditor::PGroupIDs
5116 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5117                              const gp_Trsf&     theTrsf,
5118                              const bool         theCopy,
5119                              const bool         theMakeGroups,
5120                              SMESH_Mesh*        theTargetMesh)
5121 {
5122   myLastCreatedElems.Clear();
5123   myLastCreatedNodes.Clear();
5124
5125   bool needReverse = false;
5126   string groupPostfix;
5127   switch ( theTrsf.Form() ) {
5128   case gp_PntMirror:
5129   case gp_Ax1Mirror:
5130   case gp_Ax2Mirror:
5131     needReverse = true;
5132     groupPostfix = "mirrored";
5133     break;
5134   case gp_Rotation:
5135     groupPostfix = "rotated";
5136     break;
5137   case gp_Translation:
5138     groupPostfix = "translated";
5139     break;
5140   case gp_Scale:
5141     groupPostfix = "scaled";
5142     break;
5143   default:
5144     needReverse = false;
5145     groupPostfix = "transformed";
5146   }
5147
5148   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5149   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5150   SMESHDS_Mesh* aMesh    = GetMeshDS();
5151
5152
5153   // map old node to new one
5154   TNodeNodeMap nodeMap;
5155
5156   // elements sharing moved nodes; those of them which have all
5157   // nodes mirrored but are not in theElems are to be reversed
5158   TIDSortedElemSet inverseElemSet;
5159
5160   // source elements for each generated one
5161   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5162
5163   // loop on theElems
5164   TIDSortedElemSet::iterator itElem;
5165   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5166     const SMDS_MeshElement* elem = *itElem;
5167     if ( !elem )
5168       continue;
5169
5170     // loop on elem nodes
5171     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5172     while ( itN->more() ) {
5173
5174       // check if a node has been already transformed
5175       const SMDS_MeshNode* node = cast2Node( itN->next() );
5176       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5177         nodeMap.insert( make_pair ( node, node ));
5178       if ( !n2n_isnew.second )
5179         continue;
5180
5181       double coord[3];
5182       coord[0] = node->X();
5183       coord[1] = node->Y();
5184       coord[2] = node->Z();
5185       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5186       if ( theTargetMesh ) {
5187         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5188         n2n_isnew.first->second = newNode;
5189         myLastCreatedNodes.Append(newNode);
5190         srcNodes.Append( node );
5191       }
5192       else if ( theCopy ) {
5193         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
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         // node position on shape becomes invalid
5201         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5202           ( SMDS_SpacePosition::originSpacePosition() );
5203       }
5204
5205       // keep inverse elements
5206       if ( !theCopy && !theTargetMesh && needReverse ) {
5207         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5208         while ( invElemIt->more() ) {
5209           const SMDS_MeshElement* iel = invElemIt->next();
5210           inverseElemSet.insert( iel );
5211         }
5212       }
5213     }
5214   }
5215
5216   // either create new elements or reverse mirrored ones
5217   if ( !theCopy && !needReverse && !theTargetMesh )
5218     return PGroupIDs();
5219
5220   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5221   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5222     theElems.insert( *invElemIt );
5223
5224   // replicate or reverse elements
5225
5226   enum {
5227     REV_TETRA   = 0,  //  = nbNodes - 4
5228     REV_PYRAMID = 1,  //  = nbNodes - 4
5229     REV_PENTA   = 2,  //  = nbNodes - 4
5230     REV_FACE    = 3,
5231     REV_HEXA    = 4,  //  = nbNodes - 4
5232     FORWARD     = 5
5233   };
5234   int index[][8] = {
5235     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5236     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5237     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5238     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5239     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5240     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5241   };
5242
5243   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5244   {
5245     const SMDS_MeshElement* elem = *itElem;
5246     if ( !elem || elem->GetType() == SMDSAbs_Node )
5247       continue;
5248
5249     int nbNodes = elem->NbNodes();
5250     int elemType = elem->GetType();
5251
5252     if (elem->IsPoly()) {
5253       // Polygon or Polyhedral Volume
5254       switch ( elemType ) {
5255       case SMDSAbs_Face:
5256         {
5257           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5258           int iNode = 0;
5259           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5260           while (itN->more()) {
5261             const SMDS_MeshNode* node =
5262               static_cast<const SMDS_MeshNode*>(itN->next());
5263             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5264             if (nodeMapIt == nodeMap.end())
5265               break; // not all nodes transformed
5266             if (needReverse) {
5267               // reverse mirrored faces and volumes
5268               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5269             } else {
5270               poly_nodes[iNode] = (*nodeMapIt).second;
5271             }
5272             iNode++;
5273           }
5274           if ( iNode != nbNodes )
5275             continue; // not all nodes transformed
5276
5277           if ( theTargetMesh ) {
5278             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5279             srcElems.Append( elem );
5280           }
5281           else if ( theCopy ) {
5282             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5283             srcElems.Append( elem );
5284           }
5285           else {
5286             aMesh->ChangePolygonNodes(elem, poly_nodes);
5287           }
5288         }
5289         break;
5290       case SMDSAbs_Volume:
5291         {
5292           // ATTENTION: Reversing is not yet done!!!
5293           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5294             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5295           if (!aPolyedre) {
5296             MESSAGE("Warning: bad volumic element");
5297             continue;
5298           }
5299
5300           vector<const SMDS_MeshNode*> poly_nodes;
5301           vector<int> quantities;
5302
5303           bool allTransformed = true;
5304           int nbFaces = aPolyedre->NbFaces();
5305           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5306             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5307             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5308               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5309               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5310               if (nodeMapIt == nodeMap.end()) {
5311                 allTransformed = false; // not all nodes transformed
5312               } else {
5313                 poly_nodes.push_back((*nodeMapIt).second);
5314               }
5315             }
5316             quantities.push_back(nbFaceNodes);
5317           }
5318           if ( !allTransformed )
5319             continue; // not all nodes transformed
5320
5321           if ( theTargetMesh ) {
5322             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5323             srcElems.Append( elem );
5324           }
5325           else if ( theCopy ) {
5326             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5327             srcElems.Append( elem );
5328           }
5329           else {
5330             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5331           }
5332         }
5333         break;
5334       default:;
5335       }
5336       continue;
5337     }
5338
5339     // Regular elements
5340     int* i = index[ FORWARD ];
5341     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5342       if ( elemType == SMDSAbs_Face )
5343         i = index[ REV_FACE ];
5344       else
5345         i = index[ nbNodes - 4 ];
5346
5347     if(elem->IsQuadratic()) {
5348       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5349       i = anIds;
5350       if(needReverse) {
5351         if(nbNodes==3) { // quadratic edge
5352           static int anIds[] = {1,0,2};
5353           i = anIds;
5354         }
5355         else if(nbNodes==6) { // quadratic triangle
5356           static int anIds[] = {0,2,1,5,4,3};
5357           i = anIds;
5358         }
5359         else if(nbNodes==8) { // quadratic quadrangle
5360           static int anIds[] = {0,3,2,1,7,6,5,4};
5361           i = anIds;
5362         }
5363         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5364           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5365           i = anIds;
5366         }
5367         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5368           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5369           i = anIds;
5370         }
5371         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5372           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5373           i = anIds;
5374         }
5375         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5376           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5377           i = anIds;
5378         }
5379       }
5380     }
5381
5382     // find transformed nodes
5383     vector<const SMDS_MeshNode*> nodes(nbNodes);
5384     int iNode = 0;
5385     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5386     while ( itN->more() ) {
5387       const SMDS_MeshNode* node =
5388         static_cast<const SMDS_MeshNode*>( itN->next() );
5389       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5390       if ( nodeMapIt == nodeMap.end() )
5391         break; // not all nodes transformed
5392       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5393     }
5394     if ( iNode != nbNodes )
5395       continue; // not all nodes transformed
5396
5397     if ( theTargetMesh ) {
5398       if ( SMDS_MeshElement* copy =
5399            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5400         myLastCreatedElems.Append( copy );
5401         srcElems.Append( elem );
5402       }
5403     }
5404     else if ( theCopy ) {
5405       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5406         myLastCreatedElems.Append( copy );
5407         srcElems.Append( elem );
5408       }
5409     }
5410     else {
5411       // reverse element as it was reversed by transformation
5412       if ( nbNodes > 2 )
5413         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5414     }
5415   }
5416
5417   PGroupIDs newGroupIDs;
5418
5419   if ( theMakeGroups && theCopy ||
5420        theMakeGroups && theTargetMesh )
5421     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5422
5423   return newGroupIDs;
5424 }
5425
5426
5427 //=======================================================================
5428 //function : Scale
5429 //purpose  :
5430 //=======================================================================
5431
5432 SMESH_MeshEditor::PGroupIDs
5433 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5434                          const gp_Pnt&            thePoint,
5435                          const std::list<double>& theScaleFact,
5436                          const bool         theCopy,
5437                          const bool         theMakeGroups,
5438                          SMESH_Mesh*        theTargetMesh)
5439 {
5440   myLastCreatedElems.Clear();
5441   myLastCreatedNodes.Clear();
5442
5443   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5444   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5445   SMESHDS_Mesh* aMesh    = GetMeshDS();
5446
5447   double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5448   std::list<double>::const_iterator itS = theScaleFact.begin();
5449   scaleX = (*itS);
5450   if(theScaleFact.size()==1) {
5451     scaleY = (*itS);
5452     scaleZ= (*itS);
5453   }
5454   if(theScaleFact.size()==2) {
5455     itS++;
5456     scaleY = (*itS);
5457     scaleZ= (*itS);
5458   }
5459   if(theScaleFact.size()>2) {
5460     itS++;
5461     scaleY = (*itS);
5462     itS++;
5463     scaleZ= (*itS);
5464   }
5465   
5466   // map old node to new one
5467   TNodeNodeMap nodeMap;
5468
5469   // elements sharing moved nodes; those of them which have all
5470   // nodes mirrored but are not in theElems are to be reversed
5471   TIDSortedElemSet inverseElemSet;
5472
5473   // source elements for each generated one
5474   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5475
5476   // loop on theElems
5477   TIDSortedElemSet::iterator itElem;
5478   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5479     const SMDS_MeshElement* elem = *itElem;
5480     if ( !elem )
5481       continue;
5482
5483     // loop on elem nodes
5484     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5485     while ( itN->more() ) {
5486
5487       // check if a node has been already transformed
5488       const SMDS_MeshNode* node = cast2Node( itN->next() );
5489       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5490         nodeMap.insert( make_pair ( node, node ));
5491       if ( !n2n_isnew.second )
5492         continue;
5493
5494       //double coord[3];
5495       //coord[0] = node->X();
5496       //coord[1] = node->Y();
5497       //coord[2] = node->Z();
5498       //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5499       double dx = (node->X() - thePoint.X()) * scaleX;
5500       double dy = (node->Y() - thePoint.Y()) * scaleY;
5501       double dz = (node->Z() - thePoint.Z()) * scaleZ;
5502       if ( theTargetMesh ) {
5503         //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5504         const SMDS_MeshNode * newNode =
5505           aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5506         n2n_isnew.first->second = newNode;
5507         myLastCreatedNodes.Append(newNode);
5508         srcNodes.Append( node );
5509       }
5510       else if ( theCopy ) {
5511         //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5512         const SMDS_MeshNode * newNode =
5513           aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5514         n2n_isnew.first->second = newNode;
5515         myLastCreatedNodes.Append(newNode);
5516         srcNodes.Append( node );
5517       }
5518       else {
5519         //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5520         aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5521         // node position on shape becomes invalid
5522         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5523           ( SMDS_SpacePosition::originSpacePosition() );
5524       }
5525
5526       // keep inverse elements
5527       //if ( !theCopy && !theTargetMesh && needReverse ) {
5528       //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5529       //  while ( invElemIt->more() ) {
5530       //    const SMDS_MeshElement* iel = invElemIt->next();
5531       //    inverseElemSet.insert( iel );
5532       //  }
5533       //}
5534     }
5535   }
5536
5537   // either create new elements or reverse mirrored ones
5538   //if ( !theCopy && !needReverse && !theTargetMesh )
5539   if ( !theCopy && !theTargetMesh )
5540     return PGroupIDs();
5541
5542   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5543   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5544     theElems.insert( *invElemIt );
5545
5546   // replicate or reverse elements
5547
5548   enum {
5549     REV_TETRA   = 0,  //  = nbNodes - 4
5550     REV_PYRAMID = 1,  //  = nbNodes - 4
5551     REV_PENTA   = 2,  //  = nbNodes - 4
5552     REV_FACE    = 3,
5553     REV_HEXA    = 4,  //  = nbNodes - 4
5554     FORWARD     = 5
5555   };
5556   int index[][8] = {
5557     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5558     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5559     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5560     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5561     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5562     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5563   };
5564
5565   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5566   {
5567     const SMDS_MeshElement* elem = *itElem;
5568     if ( !elem || elem->GetType() == SMDSAbs_Node )
5569       continue;
5570
5571     int nbNodes = elem->NbNodes();
5572     int elemType = elem->GetType();
5573
5574     if (elem->IsPoly()) {
5575       // Polygon or Polyhedral Volume
5576       switch ( elemType ) {
5577       case SMDSAbs_Face:
5578         {
5579           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5580           int iNode = 0;
5581           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5582           while (itN->more()) {
5583             const SMDS_MeshNode* node =
5584               static_cast<const SMDS_MeshNode*>(itN->next());
5585             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5586             if (nodeMapIt == nodeMap.end())
5587               break; // not all nodes transformed
5588             //if (needReverse) {
5589             //  // reverse mirrored faces and volumes
5590             //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5591             //} else {
5592             poly_nodes[iNode] = (*nodeMapIt).second;
5593             //}
5594             iNode++;
5595           }
5596           if ( iNode != nbNodes )
5597             continue; // not all nodes transformed
5598
5599           if ( theTargetMesh ) {
5600             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5601             srcElems.Append( elem );
5602           }
5603           else if ( theCopy ) {
5604             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5605             srcElems.Append( elem );
5606           }
5607           else {
5608             aMesh->ChangePolygonNodes(elem, poly_nodes);
5609           }
5610         }
5611         break;
5612       case SMDSAbs_Volume:
5613         {
5614           // ATTENTION: Reversing is not yet done!!!
5615           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5616             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5617           if (!aPolyedre) {
5618             MESSAGE("Warning: bad volumic element");
5619             continue;
5620           }
5621
5622           vector<const SMDS_MeshNode*> poly_nodes;
5623           vector<int> quantities;
5624
5625           bool allTransformed = true;
5626           int nbFaces = aPolyedre->NbFaces();
5627           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5628             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5629             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5630               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5631               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5632               if (nodeMapIt == nodeMap.end()) {
5633                 allTransformed = false; // not all nodes transformed
5634               } else {
5635                 poly_nodes.push_back((*nodeMapIt).second);
5636               }
5637             }
5638             quantities.push_back(nbFaceNodes);
5639           }
5640           if ( !allTransformed )
5641             continue; // not all nodes transformed
5642
5643           if ( theTargetMesh ) {
5644             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5645             srcElems.Append( elem );
5646           }
5647           else if ( theCopy ) {
5648             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5649             srcElems.Append( elem );
5650           }
5651           else {
5652             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5653           }
5654         }
5655         break;
5656       default:;
5657       }
5658       continue;
5659     }
5660
5661     // Regular elements
5662     int* i = index[ FORWARD ];
5663     //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5664     //  if ( elemType == SMDSAbs_Face )
5665     //    i = index[ REV_FACE ];
5666     //  else
5667     //    i = index[ nbNodes - 4 ];
5668
5669     if(elem->IsQuadratic()) {
5670       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5671       i = anIds;
5672       //if(needReverse) {
5673       //  if(nbNodes==3) { // quadratic edge
5674       //    static int anIds[] = {1,0,2};
5675       //    i = anIds;
5676       //  }
5677       //  else if(nbNodes==6) { // quadratic triangle
5678       //    static int anIds[] = {0,2,1,5,4,3};
5679       //    i = anIds;
5680       //  }
5681       //  else if(nbNodes==8) { // quadratic quadrangle
5682       //    static int anIds[] = {0,3,2,1,7,6,5,4};
5683       //    i = anIds;
5684       //  }
5685       //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5686       //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5687       //    i = anIds;
5688       //  }
5689       //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5690       //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5691       //    i = anIds;
5692       //  }
5693       //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5694       //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5695       //    i = anIds;
5696       //  }
5697       //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5698       //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5699       //    i = anIds;
5700       //  }
5701       //}
5702     }
5703
5704     // find transformed nodes
5705     vector<const SMDS_MeshNode*> nodes(nbNodes);
5706     int iNode = 0;
5707     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5708     while ( itN->more() ) {
5709       const SMDS_MeshNode* node =
5710         static_cast<const SMDS_MeshNode*>( itN->next() );
5711       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5712       if ( nodeMapIt == nodeMap.end() )
5713         break; // not all nodes transformed
5714       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5715     }
5716     if ( iNode != nbNodes )
5717       continue; // not all nodes transformed
5718
5719     if ( theTargetMesh ) {
5720       if ( SMDS_MeshElement* copy =
5721            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5722         myLastCreatedElems.Append( copy );
5723         srcElems.Append( elem );
5724       }
5725     }
5726     else if ( theCopy ) {
5727       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5728         myLastCreatedElems.Append( copy );
5729         srcElems.Append( elem );
5730       }
5731     }
5732     else {
5733       // reverse element as it was reversed by transformation
5734       if ( nbNodes > 2 )
5735         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5736     }
5737   }
5738
5739   PGroupIDs newGroupIDs;
5740
5741   if ( theMakeGroups && theCopy ||
5742        theMakeGroups && theTargetMesh ) {
5743     string groupPostfix = "scaled";
5744     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5745   }
5746
5747   return newGroupIDs;
5748 }
5749
5750
5751 //=======================================================================
5752 /*!
5753  * \brief Create groups of elements made during transformation
5754  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5755  * \param elemGens - elements making corresponding myLastCreatedElems
5756  * \param postfix - to append to names of new groups
5757  */
5758 //=======================================================================
5759
5760 SMESH_MeshEditor::PGroupIDs
5761 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5762                                  const SMESH_SequenceOfElemPtr& elemGens,
5763                                  const std::string&             postfix,
5764                                  SMESH_Mesh*                    targetMesh)
5765 {
5766   PGroupIDs newGroupIDs( new list<int> );
5767   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5768
5769   // Sort existing groups by types and collect their names
5770
5771   // to store an old group and a generated new one
5772   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5773   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5774   // group names
5775   set< string > groupNames;
5776   //
5777   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5778   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5779   while ( groupIt->more() ) {
5780     SMESH_Group * group = groupIt->next();
5781     if ( !group ) continue;
5782     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5783     if ( !groupDS || groupDS->IsEmpty() ) continue;
5784     groupNames.insert( group->GetName() );
5785     groupDS->SetStoreName( group->GetName() );
5786     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5787   }
5788
5789   // Groups creation
5790
5791   // loop on nodes and elements
5792   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5793   {
5794     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5795     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5796     if ( gens.Length() != elems.Length() )
5797       throw SALOME_Exception(LOCALIZED("invalid args"));
5798
5799     // loop on created elements
5800     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5801     {
5802       const SMDS_MeshElement* sourceElem = gens( iElem );
5803       if ( !sourceElem ) {
5804         MESSAGE("generateGroups(): NULL source element");
5805         continue;
5806       }
5807       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5808       if ( groupsOldNew.empty() ) {
5809         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5810           ++iElem; // skip all elements made by sourceElem
5811         continue;
5812       }
5813       // collect all elements made by sourceElem
5814       list< const SMDS_MeshElement* > resultElems;
5815       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5816         if ( resElem != sourceElem )
5817           resultElems.push_back( resElem );
5818       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5819         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5820           if ( resElem != sourceElem )
5821             resultElems.push_back( resElem );
5822       // do not generate element groups from node ones
5823       if ( sourceElem->GetType() == SMDSAbs_Node &&
5824            elems( iElem )->GetType() != SMDSAbs_Node )
5825         continue;
5826
5827       // add resultElems to groups made by ones the sourceElem belongs to
5828       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5829       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5830       {
5831         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5832         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5833         {
5834           SMDS_MeshGroup* & newGroup = gOldNew->second;
5835           if ( !newGroup )// create a new group
5836           {
5837             // make a name
5838             string name = oldGroup->GetStoreName();
5839             if ( !targetMesh ) {
5840               name += "_";
5841               name += postfix;
5842               int nb = 0;
5843               while ( !groupNames.insert( name ).second ) // name exists
5844               {
5845                 if ( nb == 0 ) {
5846                   name += "_1";
5847                 }
5848                 else {
5849                   TCollection_AsciiString nbStr(nb+1);
5850                   name.resize( name.rfind('_')+1 );
5851                   name += nbStr.ToCString();
5852                 }
5853                 ++nb;
5854               }
5855             }
5856             // make a group
5857             int id;
5858             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5859                                                  name.c_str(), id );
5860             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5861             newGroup = & groupDS->SMDSGroup();
5862             newGroupIDs->push_back( id );
5863           }
5864
5865           // fill in a new group
5866           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5867           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5868             newGroup->Add( *resElemIt );
5869         }
5870       }
5871     } // loop on created elements
5872   }// loop on nodes and elements
5873
5874   return newGroupIDs;
5875 }
5876
5877 //================================================================================
5878 /*!
5879  * \brief Return list of group of nodes close to each other within theTolerance
5880  *        Search among theNodes or in the whole mesh if theNodes is empty using
5881  *        an Octree algorithm
5882  */
5883 //================================================================================
5884
5885 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5886                                             const double                theTolerance,
5887                                             TListOfListOfNodes &        theGroupsOfNodes)
5888 {
5889   myLastCreatedElems.Clear();
5890   myLastCreatedNodes.Clear();
5891
5892   set<const SMDS_MeshNode*> nodes;
5893   if ( theNodes.empty() )
5894   { // get all nodes in the mesh
5895     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5896     while ( nIt->more() )
5897       nodes.insert( nodes.end(),nIt->next());
5898   }
5899   else
5900     nodes=theNodes;
5901
5902   SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5903 }
5904
5905
5906 //=======================================================================
5907 /*!
5908  * \brief Implementation of search for the node closest to point
5909  */
5910 //=======================================================================
5911
5912 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5913 {
5914   //---------------------------------------------------------------------
5915   /*!
5916    * \brief Constructor
5917    */
5918   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5919   {
5920     myMesh = ( SMESHDS_Mesh* ) theMesh;
5921
5922     set<const SMDS_MeshNode*> nodes;
5923     if ( theMesh ) {
5924       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5925       while ( nIt->more() )
5926         nodes.insert( nodes.end(), nIt->next() );
5927     }
5928     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5929
5930     // get max size of a leaf box
5931     SMESH_OctreeNode* tree = myOctreeNode;
5932     while ( !tree->isLeaf() )
5933     {
5934       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5935       if ( cIt->more() )
5936         tree = cIt->next();
5937     }
5938     myHalfLeafSize = tree->maxSize() / 2.;
5939   }
5940
5941   //---------------------------------------------------------------------
5942   /*!
5943    * \brief Move node and update myOctreeNode accordingly
5944    */
5945   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5946   {
5947     myOctreeNode->UpdateByMoveNode( node, toPnt );
5948     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5949   }
5950
5951   //---------------------------------------------------------------------
5952   /*!
5953    * \brief Do it's job
5954    */
5955   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5956   {
5957     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5958     map<double, const SMDS_MeshNode*> dist2Nodes;
5959     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5960     if ( !dist2Nodes.empty() )
5961       return dist2Nodes.begin()->second;
5962     list<const SMDS_MeshNode*> nodes;
5963     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5964
5965     double minSqDist = DBL_MAX;
5966     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5967     {
5968       // sort leafs by their distance from thePnt
5969       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5970       TDistTreeMap treeMap;
5971       list< SMESH_OctreeNode* > treeList;
5972       list< SMESH_OctreeNode* >::iterator trIt;
5973       treeList.push_back( myOctreeNode );
5974
5975       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5976       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5977       {
5978         SMESH_OctreeNode* tree = *trIt;
5979         if ( !tree->isLeaf() ) // put children to the queue
5980         {
5981           if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5982           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5983           while ( cIt->more() )
5984             treeList.push_back( cIt->next() );
5985         }
5986         else if ( tree->NbNodes() ) // put a tree to the treeMap
5987         {
5988           const Bnd_B3d& box = tree->getBox();
5989           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5990           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5991           if ( !it_in.second ) // not unique distance to box center
5992             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5993         }
5994       }
5995       // find distance after which there is no sense to check tree's
5996       double sqLimit = DBL_MAX;
5997       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5998       if ( treeMap.size() > 5 ) {
5999         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6000         const Bnd_B3d& box = closestTree->getBox();
6001         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6002         sqLimit = limit * limit;
6003       }
6004       // get all nodes from trees
6005       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6006         if ( sqDist_tree->first > sqLimit )
6007           break;
6008         SMESH_OctreeNode* tree = sqDist_tree->second;
6009         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6010       }
6011     }
6012     // find closest among nodes
6013     minSqDist = DBL_MAX;
6014     const SMDS_MeshNode* closestNode = 0;
6015     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6016     for ( ; nIt != nodes.end(); ++nIt ) {
6017       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6018       if ( minSqDist > sqDist ) {
6019         closestNode = *nIt;
6020         minSqDist = sqDist;
6021       }
6022     }
6023     return closestNode;
6024   }
6025
6026   //---------------------------------------------------------------------
6027   /*!
6028    * \brief Destructor
6029    */
6030   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6031
6032   //---------------------------------------------------------------------
6033   /*!
6034    * \brief Return the node tree
6035    */
6036   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6037
6038 private:
6039   SMESH_OctreeNode* myOctreeNode;
6040   SMESHDS_Mesh*     myMesh;
6041   double            myHalfLeafSize; // max size of a leaf box
6042 };
6043
6044 //=======================================================================
6045 /*!
6046  * \brief Return SMESH_NodeSearcher
6047  */
6048 //=======================================================================
6049
6050 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6051 {
6052   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6053 }
6054
6055 // ========================================================================
6056 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6057 {
6058   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6059   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6060   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6061
6062   //=======================================================================
6063   /*!
6064    * \brief Octal tree of bounding boxes of elements
6065    */
6066   //=======================================================================
6067
6068   class ElementBndBoxTree : public SMESH_Octree
6069   {
6070   public:
6071
6072     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
6073     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6074     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6075     ~ElementBndBoxTree();
6076
6077   protected:
6078     ElementBndBoxTree() {}
6079     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6080     void buildChildrenData();
6081     Bnd_B3d* buildRootBox();
6082   private:
6083     //!< Bounding box of element
6084     struct ElementBox : public Bnd_B3d
6085     {
6086       const SMDS_MeshElement* _element;
6087       int                     _refCount; // an ElementBox can be included in several tree branches
6088       ElementBox(const SMDS_MeshElement* elem);
6089     };
6090     vector< ElementBox* > _elements;
6091   };
6092
6093   //================================================================================
6094   /*!
6095    * \brief ElementBndBoxTree creation
6096    */
6097   //================================================================================
6098
6099   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
6100     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6101   {
6102     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6103     _elements.reserve( nbElems );
6104
6105     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6106     while ( elemIt->more() )
6107       _elements.push_back( new ElementBox( elemIt->next() ));
6108
6109     if ( _elements.size() > MaxNbElemsInLeaf )
6110       compute();
6111     else
6112       myIsLeaf = true;
6113   }
6114
6115   //================================================================================
6116   /*!
6117    * \brief Destructor
6118    */
6119   //================================================================================
6120
6121   ElementBndBoxTree::~ElementBndBoxTree()
6122   {
6123     for ( int i = 0; i < _elements.size(); ++i )
6124       if ( --_elements[i]->_refCount <= 0 )
6125         delete _elements[i];
6126   }
6127
6128   //================================================================================
6129   /*!
6130    * \brief Return the maximal box
6131    */
6132   //================================================================================
6133
6134   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6135   {
6136     Bnd_B3d* box = new Bnd_B3d;
6137     for ( int i = 0; i < _elements.size(); ++i )
6138       box->Add( *_elements[i] );
6139     return box;
6140   }
6141
6142   //================================================================================
6143   /*!
6144    * \brief Redistrubute element boxes among children
6145    */
6146   //================================================================================
6147
6148   void ElementBndBoxTree::buildChildrenData()
6149   {
6150     for ( int i = 0; i < _elements.size(); ++i )
6151     {
6152       for (int j = 0; j < 8; j++)
6153       {
6154         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6155         {
6156           _elements[i]->_refCount++;
6157           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6158         }
6159       }
6160       _elements[i]->_refCount--;
6161     }
6162     _elements.clear();
6163
6164     for (int j = 0; j < 8; j++)
6165     {
6166       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6167       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6168         child->myIsLeaf = true;
6169
6170       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6171         child->_elements.resize( child->_elements.size() ); // compact
6172     }
6173   }
6174
6175   //================================================================================
6176   /*!
6177    * \brief Return elements which can include the point
6178    */
6179   //================================================================================
6180
6181   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6182                                                 TIDSortedElemSet& foundElems)
6183   {
6184     if ( level() && getBox().IsOut( point.XYZ() ))
6185       return;
6186
6187     if ( isLeaf() )
6188     {
6189       for ( int i = 0; i < _elements.size(); ++i )
6190         if ( !_elements[i]->IsOut( point.XYZ() ))
6191           foundElems.insert( _elements[i]->_element );
6192     }
6193     else
6194     {
6195       for (int i = 0; i < 8; i++)
6196         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6197     }
6198   }
6199
6200   //================================================================================
6201   /*!
6202    * \brief Return elements which can be intersected by the line
6203    */
6204   //================================================================================
6205
6206   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6207                                                TIDSortedElemSet& foundElems)
6208   {
6209     if ( level() && getBox().IsOut( line ))
6210       return;
6211
6212     if ( isLeaf() )
6213     {
6214       for ( int i = 0; i < _elements.size(); ++i )
6215         if ( !_elements[i]->IsOut( line ))
6216           foundElems.insert( _elements[i]->_element );
6217     }
6218     else
6219     {
6220       for (int i = 0; i < 8; i++)
6221         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6222     }
6223   }
6224
6225   //================================================================================
6226   /*!
6227    * \brief Construct the element box
6228    */
6229   //================================================================================
6230
6231   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
6232   {
6233     _element  = elem;
6234     _refCount = 1;
6235     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6236     while ( nIt->more() )
6237       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6238     Enlarge( NodeRadius );
6239   }
6240
6241 } // namespace
6242
6243 //=======================================================================
6244 /*!
6245  * \brief Implementation of search for the elements by point and
6246  *        of classification of point in 2D mesh
6247  */
6248 //=======================================================================
6249
6250 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6251 {
6252   SMESHDS_Mesh*                _mesh;
6253   ElementBndBoxTree*           _ebbTree;
6254   SMESH_NodeSearcherImpl*      _nodeSearcher;
6255   SMDSAbs_ElementType          _elementType;
6256   double                       _tolerance;
6257   bool                         _outerFacesFound;
6258   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6259
6260   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6261     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6262   ~SMESH_ElementSearcherImpl()
6263   {
6264     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6265     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6266   }
6267   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6268                                   SMDSAbs_ElementType                type,
6269                                   vector< const SMDS_MeshElement* >& foundElements);
6270   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6271
6272   double getTolerance();
6273   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6274                             const double tolerance, double & param);
6275   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6276   bool isOuterBoundary(const SMDS_MeshElement* face) const
6277   {
6278     return _outerFaces.empty() || _outerFaces.count(face);
6279   }
6280   struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
6281   {
6282     const SMDS_MeshElement* _face;
6283     gp_Vec                  _faceNorm;
6284     bool                    _coincides; //!< the line lays in face plane
6285     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6286       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6287   };
6288   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6289   {
6290     SMESH_TLink      _link;
6291     TIDSortedElemSet _faces;
6292     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6293       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6294   };
6295 };
6296
6297 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6298 {
6299   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6300              << ", _coincides="<<i._coincides << ")";
6301 }
6302
6303 //=======================================================================
6304 /*!
6305  * \brief define tolerance for search
6306  */
6307 //=======================================================================
6308
6309 double SMESH_ElementSearcherImpl::getTolerance()
6310 {
6311   if ( _tolerance < 0 )
6312   {
6313     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6314
6315     _tolerance = 0;
6316     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6317     {
6318       double boxSize = _nodeSearcher->getTree()->maxSize();
6319       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6320     }
6321     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6322     {
6323       double boxSize = _ebbTree->maxSize();
6324       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6325     }
6326     if ( _tolerance == 0 )
6327     {
6328       // define tolerance by size of a most complex element
6329       int complexType = SMDSAbs_Volume;
6330       while ( complexType > SMDSAbs_All &&
6331               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6332         --complexType;
6333       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6334
6335       double elemSize;
6336       if ( complexType == int( SMDSAbs_Node ))
6337       {
6338         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6339         elemSize = 1;
6340         if ( meshInfo.NbNodes() > 2 )
6341           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6342       }
6343       else
6344       {
6345         const SMDS_MeshElement* elem =
6346           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6347         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6348         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6349         while ( nodeIt->more() )
6350         {
6351           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6352           elemSize = max( dist, elemSize );
6353         }
6354       }
6355       _tolerance = 1e-6 * elemSize;
6356     }
6357   }
6358   return _tolerance;
6359 }
6360
6361 //================================================================================
6362 /*!
6363  * \brief Find intersection of the line and an edge of face and return parameter on line
6364  */
6365 //================================================================================
6366
6367 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6368                                                      const SMDS_MeshElement* face,
6369                                                      const double            tol,
6370                                                      double &                param)
6371 {
6372   int nbInts = 0;
6373   param = 0;
6374
6375   GeomAPI_ExtremaCurveCurve anExtCC;
6376   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6377   
6378   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6379   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6380   {
6381     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6382                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6383     anExtCC.Init( lineCurve, edge);
6384     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6385     {
6386       Quantity_Parameter pl, pe;
6387       anExtCC.LowerDistanceParameters( pl, pe );
6388       param += pl;
6389       if ( ++nbInts == 2 )
6390         break;
6391     }
6392   }
6393   if ( nbInts > 0 ) param /= nbInts;
6394   return nbInts > 0;
6395 }
6396 //================================================================================
6397 /*!
6398  * \brief Find all faces belonging to the outer boundary of mesh
6399  */
6400 //================================================================================
6401
6402 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6403 {
6404   if ( _outerFacesFound ) return;
6405
6406   // Collect all outer faces by passing from one outer face to another via their links
6407   // and BTW find out if there are internal faces at all.
6408
6409   // checked links and links where outer boundary meets internal one
6410   set< SMESH_TLink > visitedLinks, seamLinks;
6411
6412   // links to treat with already visited faces sharing them
6413   list < TFaceLink > startLinks;
6414
6415   // load startLinks with the first outerFace
6416   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6417   _outerFaces.insert( outerFace );
6418
6419   TIDSortedElemSet emptySet;
6420   while ( !startLinks.empty() )
6421   {
6422     const SMESH_TLink& link  = startLinks.front()._link;
6423     TIDSortedElemSet&  faces = startLinks.front()._faces;
6424
6425     outerFace = *faces.begin();
6426     // find other faces sharing the link
6427     const SMDS_MeshElement* f;
6428     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6429       faces.insert( f );
6430
6431     // select another outer face among the found 
6432     const SMDS_MeshElement* outerFace2 = 0;
6433     if ( faces.size() == 2 )
6434     {
6435       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6436     }
6437     else if ( faces.size() > 2 )
6438     {
6439       seamLinks.insert( link );
6440
6441       // link direction within the outerFace
6442       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6443                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6444       int i1 = outerFace->GetNodeIndex( link.node1() );
6445       int i2 = outerFace->GetNodeIndex( link.node2() );
6446       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6447       if ( rev ) n1n2.Reverse();
6448       // outerFace normal
6449       gp_XYZ ofNorm, fNorm;
6450       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6451       {
6452         // direction from the link inside outerFace
6453         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6454         // sort all other faces by angle with the dirInOF
6455         map< double, const SMDS_MeshElement* > angle2Face;
6456         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6457         for ( ; face != faces.end(); ++face )
6458         {
6459           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6460             continue;
6461           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6462           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6463           if ( angle < 0 ) angle += 2*PI;
6464           angle2Face.insert( make_pair( angle, *face ));
6465         }
6466         if ( !angle2Face.empty() )
6467           outerFace2 = angle2Face.begin()->second;
6468       }
6469     }
6470     // store the found outer face and add its links to continue seaching from
6471     if ( outerFace2 )
6472     {
6473       _outerFaces.insert( outerFace );
6474       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6475       for ( int i = 0; i < nbNodes; ++i )
6476       {
6477         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6478         if ( visitedLinks.insert( link2 ).second )
6479           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6480       }
6481     }
6482     startLinks.pop_front();
6483   }
6484   _outerFacesFound = true;
6485
6486   if ( !seamLinks.empty() )
6487   {
6488     // There are internal boundaries touching the outher one,
6489     // find all faces of internal boundaries in order to find
6490     // faces of boundaries of holes, if any.
6491     
6492   }
6493   else
6494   {
6495     _outerFaces.clear();
6496   }
6497 }
6498
6499 //=======================================================================
6500 /*!
6501  * \brief Find elements of given type where the given point is IN or ON.
6502  *        Returns nb of found elements and elements them-selves.
6503  *
6504  * 'ALL' type means elements of any type excluding nodes and 0D elements
6505  */
6506 //=======================================================================
6507
6508 int SMESH_ElementSearcherImpl::
6509 FindElementsByPoint(const gp_Pnt&                      point,
6510                     SMDSAbs_ElementType                type,
6511                     vector< const SMDS_MeshElement* >& foundElements)
6512 {
6513   foundElements.clear();
6514
6515   double tolerance = getTolerance();
6516
6517   // =================================================================================
6518   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6519   {
6520     if ( !_nodeSearcher )
6521       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6522
6523     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6524     if ( !closeNode ) return foundElements.size();
6525
6526     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6527       return foundElements.size(); // to far from any node
6528
6529     if ( type == SMDSAbs_Node )
6530     {
6531       foundElements.push_back( closeNode );
6532     }
6533     else
6534     {
6535       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6536       while ( elemIt->more() )
6537         foundElements.push_back( elemIt->next() );
6538     }
6539   }
6540   // =================================================================================
6541   else // elements more complex than 0D
6542   {
6543     if ( !_ebbTree || _elementType != type )
6544     {
6545       if ( _ebbTree ) delete _ebbTree;
6546       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6547     }
6548     TIDSortedElemSet suspectElems;
6549     _ebbTree->getElementsNearPoint( point, suspectElems );
6550     TIDSortedElemSet::iterator elem = suspectElems.begin();
6551     for ( ; elem != suspectElems.end(); ++elem )
6552       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6553         foundElements.push_back( *elem );
6554   }
6555   return foundElements.size();
6556 }
6557
6558 //================================================================================
6559 /*!
6560  * \brief Classify the given point in the closed 2D mesh
6561  */
6562 //================================================================================
6563
6564 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6565 {
6566   double tolerance = getTolerance();
6567   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6568   {
6569     if ( _ebbTree ) delete _ebbTree;
6570     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6571   }
6572   // Algo: analyse transition of a line starting at the point through mesh boundary;
6573   // try three lines parallel to axis of the coordinate system and perform rough
6574   // analysis. If solution is not clear perform thorough analysis.
6575
6576   const int nbAxes = 3;
6577   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6578   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6579   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6580   multimap< int, int > nbInt2Axis; // to find the simplest case
6581   for ( int axis = 0; axis < nbAxes; ++axis )
6582   {
6583     gp_Ax1 lineAxis( point, axisDir[axis]);
6584     gp_Lin line    ( lineAxis );
6585
6586     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6587     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6588
6589     // Intersect faces with the line
6590
6591     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6592     TIDSortedElemSet::iterator face = suspectFaces.begin();
6593     for ( ; face != suspectFaces.end(); ++face )
6594     {
6595       // get face plane
6596       gp_XYZ fNorm;
6597       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6598       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6599
6600       // perform intersection
6601       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6602       if ( !intersection.IsDone() )
6603         continue;
6604       if ( intersection.IsInQuadric() )
6605       {
6606         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6607       }
6608       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6609       {
6610         gp_Pnt intersectionPoint = intersection.Point(1);
6611         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6612           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6613       }
6614     }
6615     // Analyse intersections roughly
6616
6617     int nbInter = u2inters.size();
6618     if ( nbInter == 0 )
6619       return TopAbs_OUT; 
6620
6621     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6622     if ( nbInter == 1 ) // not closed mesh
6623       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6624
6625     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6626       return TopAbs_ON;
6627
6628     if ( (f<0) == (l<0) )
6629       return TopAbs_OUT;
6630
6631     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6632     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6633     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6634       return TopAbs_IN;
6635
6636     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6637
6638     if ( _outerFacesFound ) break; // pass to thorough analysis
6639
6640   } // three attempts - loop on CS axes
6641
6642   // Analyse intersections thoroughly.
6643   // We make two loops maximum, on the first one we only exclude touching intersections,
6644   // on the second, if situation is still unclear, we gather and use information on
6645   // position of faces (internal or outer). If faces position is already gathered,
6646   // we make the second loop right away.
6647
6648   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6649   {
6650     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6651     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6652     {
6653       int axis = nb_axis->second;
6654       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6655
6656       gp_Ax1 lineAxis( point, axisDir[axis]);
6657       gp_Lin line    ( lineAxis );
6658
6659       // add tangent intersections to u2inters
6660       double param;
6661       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6662       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6663         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6664           u2inters.insert(make_pair( param, *tgtInt ));
6665       tangentInters[ axis ].clear();
6666
6667       // Count intersections before and after the point excluding touching ones.
6668       // If hasPositionInfo we count intersections of outer boundary only
6669
6670       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6671       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6672       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6673       bool ok = ! u_int1->second._coincides;
6674       while ( ok && u_int1 != u2inters.end() )
6675       {
6676         double u = u_int1->first;
6677         bool touchingInt = false;
6678         if ( ++u_int2 != u2inters.end() )
6679         {
6680           // skip intersections at the same point (if the line passes through edge or node)
6681           int nbSamePnt = 0;
6682           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6683           {
6684             ++nbSamePnt;
6685             ++u_int2;
6686           }
6687
6688           // skip tangent intersections
6689           int nbTgt = 0;
6690           const SMDS_MeshElement* prevFace = u_int1->second._face;
6691           while ( ok && u_int2->second._coincides )
6692           {
6693             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6694               ok = false;
6695             else
6696             {
6697               nbTgt++;
6698               u_int2++;
6699               ok = ( u_int2 != u2inters.end() );
6700             }
6701           }
6702           if ( !ok ) break;
6703
6704           // skip intersections at the same point after tangent intersections
6705           if ( nbTgt > 0 )
6706           {
6707             double u2 = u_int2->first;
6708             ++u_int2;
6709             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6710             {
6711               ++nbSamePnt;
6712               ++u_int2;
6713             }
6714           }
6715           // decide if we skipped a touching intersection
6716           if ( nbSamePnt + nbTgt > 0 )
6717           {
6718             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6719             map< double, TInters >::iterator u_int = u_int1;
6720             for ( ; u_int != u_int2; ++u_int )
6721             {
6722               if ( u_int->second._coincides ) continue;
6723               double dot = u_int->second._faceNorm * line.Direction();
6724               if ( dot > maxDot ) maxDot = dot;
6725               if ( dot < minDot ) minDot = dot;
6726             }
6727             touchingInt = ( minDot*maxDot < 0 );
6728           }
6729         }
6730         if ( !touchingInt )
6731         {
6732           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6733           {
6734             if ( u < 0 )
6735               ++nbIntBeforePoint;
6736             else
6737               ++nbIntAfterPoint;
6738           }
6739           if ( u < f ) f = u;
6740           if ( u > l ) l = u;
6741         }
6742
6743         u_int1 = u_int2; // to next intersection
6744
6745       } // loop on intersections with one line
6746
6747       if ( ok )
6748       {
6749         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6750           return TopAbs_ON;
6751
6752         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6753           return TopAbs_OUT; 
6754
6755         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6756           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6757
6758         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6759           return TopAbs_IN;
6760
6761         if ( (f<0) == (l<0) )
6762           return TopAbs_OUT;
6763
6764         if ( hasPositionInfo )
6765           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6766       }
6767     } // loop on intersections of the tree lines - thorough analysis
6768
6769     if ( !hasPositionInfo )
6770     {
6771       // gather info on faces position - is face in the outer boundary or not
6772       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6773       findOuterBoundary( u2inters.begin()->second._face );
6774     }
6775
6776   } // two attempts - with and w/o faces position info in the mesh
6777
6778   return TopAbs_UNKNOWN;
6779 }
6780
6781 //=======================================================================
6782 /*!
6783  * \brief Return SMESH_ElementSearcher
6784  */
6785 //=======================================================================
6786
6787 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6788 {
6789   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6790 }
6791
6792 //=======================================================================
6793 /*!
6794  * \brief Return true if the point is IN or ON of the element
6795  */
6796 //=======================================================================
6797
6798 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6799 {
6800   if ( element->GetType() == SMDSAbs_Volume)
6801   {
6802     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6803   }
6804
6805   // get ordered nodes
6806
6807   vector< gp_XYZ > xyz;
6808
6809   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6810   if ( element->IsQuadratic() )
6811     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6812       nodeIt = f->interlacedNodesElemIterator();
6813     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6814       nodeIt = e->interlacedNodesElemIterator();
6815
6816   while ( nodeIt->more() )
6817     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6818
6819   int i, nbNodes = element->NbNodes();
6820
6821   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6822   {
6823     // compute face normal
6824     gp_Vec faceNorm(0,0,0);
6825     xyz.push_back( xyz.front() );
6826     for ( i = 0; i < nbNodes; ++i )
6827     {
6828       gp_Vec edge1( xyz[i+1], xyz[i]);
6829       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6830       faceNorm += edge1 ^ edge2;
6831     }
6832     double normSize = faceNorm.Magnitude();
6833     if ( normSize <= tol )
6834     {
6835       // degenerated face: point is out if it is out of all face edges
6836       for ( i = 0; i < nbNodes; ++i )
6837       {
6838         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6839         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6840         SMDS_LinearEdge edge( &n1, &n2 );
6841         if ( !isOut( &edge, point, tol ))
6842           return false;
6843       }
6844       return true;
6845     }
6846     faceNorm /= normSize;
6847
6848     // check if the point lays on face plane
6849     gp_Vec n2p( xyz[0], point );
6850     if ( fabs( n2p * faceNorm ) > tol )
6851       return true; // not on face plane
6852
6853     // check if point is out of face boundary:
6854     // define it by closest transition of a ray point->infinity through face boundary
6855     // on the face plane.
6856     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6857     // to find intersections of the ray with the boundary.
6858     gp_Vec ray = n2p;
6859     gp_Vec plnNorm = ray ^ faceNorm;
6860     normSize = plnNorm.Magnitude();
6861     if ( normSize <= tol ) return false; // point coincides with the first node
6862     plnNorm /= normSize;
6863     // for each node of the face, compute its signed distance to the plane
6864     vector<double> dist( nbNodes + 1);
6865     for ( i = 0; i < nbNodes; ++i )
6866     {
6867       gp_Vec n2p( xyz[i], point );
6868       dist[i] = n2p * plnNorm;
6869     }
6870     dist.back() = dist.front();
6871     // find the closest intersection
6872     int    iClosest = -1;
6873     double rClosest, distClosest = 1e100;;
6874     gp_Pnt pClosest;
6875     for ( i = 0; i < nbNodes; ++i )
6876     {
6877       double r;
6878       if ( fabs( dist[i]) < tol )
6879         r = 0.;
6880       else if ( fabs( dist[i+1]) < tol )
6881         r = 1.;
6882       else if ( dist[i] * dist[i+1] < 0 )
6883         r = dist[i] / ( dist[i] - dist[i+1] );
6884       else
6885         continue; // no intersection
6886       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6887       gp_Vec p2int ( point, pInt);
6888       if ( p2int * ray > -tol ) // right half-space
6889       {
6890         double intDist = p2int.SquareMagnitude();
6891         if ( intDist < distClosest )
6892         {
6893           iClosest = i;
6894           rClosest = r;
6895           pClosest = pInt;
6896           distClosest = intDist;
6897         }
6898       }
6899     }
6900     if ( iClosest < 0 )
6901       return true; // no intesections - out
6902
6903     // analyse transition
6904     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6905     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6906     gp_Vec p2int ( point, pClosest );
6907     bool out = (edgeNorm * p2int) < -tol;
6908     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6909       return out;
6910
6911     // ray pass through a face node; analyze transition through an adjacent edge
6912     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6913     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6914     gp_Vec edgeAdjacent( p1, p2 );
6915     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6916     bool out2 = (edgeNorm2 * p2int) < -tol;
6917
6918     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6919     return covexCorner ? (out || out2) : (out && out2);
6920   }
6921   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6922   {
6923     // point is out of edge if it is NOT ON any straight part of edge
6924     // (we consider quadratic edge as being composed of two straight parts)
6925     for ( i = 1; i < nbNodes; ++i )
6926     {
6927       gp_Vec edge( xyz[i-1], xyz[i]);
6928       gp_Vec n1p ( xyz[i-1], point);
6929       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6930       if ( dist > tol )
6931         continue;
6932       gp_Vec n2p( xyz[i], point );
6933       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6934         continue;
6935       return false; // point is ON this part
6936     }
6937     return true;
6938   }
6939   // Node or 0D element -------------------------------------------------------------------------
6940   {
6941     gp_Vec n2p ( xyz[0], point );
6942     return n2p.Magnitude() <= tol;
6943   }
6944   return true;
6945 }
6946
6947 //=======================================================================
6948 //function : SimplifyFace
6949 //purpose  :
6950 //=======================================================================
6951 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6952                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6953                                     vector<int>&                        quantities) const
6954 {
6955   int nbNodes = faceNodes.size();
6956
6957   if (nbNodes < 3)
6958     return 0;
6959
6960   set<const SMDS_MeshNode*> nodeSet;
6961
6962   // get simple seq of nodes
6963   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6964   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6965   int iSimple = 0, nbUnique = 0;
6966
6967   simpleNodes[iSimple++] = faceNodes[0];
6968   nbUnique++;
6969   for (int iCur = 1; iCur < nbNodes; iCur++) {
6970     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6971       simpleNodes[iSimple++] = faceNodes[iCur];
6972       if (nodeSet.insert( faceNodes[iCur] ).second)
6973         nbUnique++;
6974     }
6975   }
6976   int nbSimple = iSimple;
6977   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6978     nbSimple--;
6979     iSimple--;
6980   }
6981
6982   if (nbUnique < 3)
6983     return 0;
6984
6985   // separate loops
6986   int nbNew = 0;
6987   bool foundLoop = (nbSimple > nbUnique);
6988   while (foundLoop) {
6989     foundLoop = false;
6990     set<const SMDS_MeshNode*> loopSet;
6991     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6992       const SMDS_MeshNode* n = simpleNodes[iSimple];
6993       if (!loopSet.insert( n ).second) {
6994         foundLoop = true;
6995
6996         // separate loop
6997         int iC = 0, curLast = iSimple;
6998         for (; iC < curLast; iC++) {
6999           if (simpleNodes[iC] == n) break;
7000         }
7001         int loopLen = curLast - iC;
7002         if (loopLen > 2) {
7003           // create sub-element
7004           nbNew++;
7005           quantities.push_back(loopLen);
7006           for (; iC < curLast; iC++) {
7007             poly_nodes.push_back(simpleNodes[iC]);
7008           }
7009         }
7010         // shift the rest nodes (place from the first loop position)
7011         for (iC = curLast + 1; iC < nbSimple; iC++) {
7012           simpleNodes[iC - loopLen] = simpleNodes[iC];
7013         }
7014         nbSimple -= loopLen;
7015         iSimple -= loopLen;
7016       }
7017     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7018   } // while (foundLoop)
7019
7020   if (iSimple > 2) {
7021     nbNew++;
7022     quantities.push_back(iSimple);
7023     for (int i = 0; i < iSimple; i++)
7024       poly_nodes.push_back(simpleNodes[i]);
7025   }
7026
7027   return nbNew;
7028 }
7029
7030 //=======================================================================
7031 //function : MergeNodes
7032 //purpose  : In each group, the cdr of nodes are substituted by the first one
7033 //           in all elements.
7034 //=======================================================================
7035
7036 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7037 {
7038   myLastCreatedElems.Clear();
7039   myLastCreatedNodes.Clear();
7040
7041   SMESHDS_Mesh* aMesh = GetMeshDS();
7042
7043   TNodeNodeMap nodeNodeMap; // node to replace - new node
7044   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7045   list< int > rmElemIds, rmNodeIds;
7046
7047   // Fill nodeNodeMap and elems
7048
7049   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7050   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7051     list<const SMDS_MeshNode*>& nodes = *grIt;
7052     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7053     const SMDS_MeshNode* nToKeep = *nIt;
7054     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7055       const SMDS_MeshNode* nToRemove = *nIt;
7056       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7057       if ( nToRemove != nToKeep ) {
7058         rmNodeIds.push_back( nToRemove->GetID() );
7059         AddToSameGroups( nToKeep, nToRemove, aMesh );
7060       }
7061
7062       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7063       while ( invElemIt->more() ) {
7064         const SMDS_MeshElement* elem = invElemIt->next();
7065         elems.insert(elem);
7066       }
7067     }
7068   }
7069   // Change element nodes or remove an element
7070
7071   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7072   for ( ; eIt != elems.end(); eIt++ ) {
7073     const SMDS_MeshElement* elem = *eIt;
7074     int nbNodes = elem->NbNodes();
7075     int aShapeId = FindShape( elem );
7076
7077     set<const SMDS_MeshNode*> nodeSet;
7078     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7079     int iUnique = 0, iCur = 0, nbRepl = 0;
7080     vector<int> iRepl( nbNodes );
7081
7082     // get new seq of nodes
7083     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7084     while ( itN->more() ) {
7085       const SMDS_MeshNode* n =
7086         static_cast<const SMDS_MeshNode*>( itN->next() );
7087
7088       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7089       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7090         n = (*nnIt).second;
7091         // BUG 0020185: begin
7092         {
7093           bool stopRecur = false;
7094           set<const SMDS_MeshNode*> nodesRecur;
7095           nodesRecur.insert(n);
7096           while (!stopRecur) {
7097             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7098             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7099               n = (*nnIt_i).second;
7100               if (!nodesRecur.insert(n).second) {
7101                 // error: recursive dependancy
7102                 stopRecur = true;
7103               }
7104             }
7105             else
7106               stopRecur = true;
7107           }
7108         }
7109         // BUG 0020185: end
7110         iRepl[ nbRepl++ ] = iCur;
7111       }
7112       curNodes[ iCur ] = n;
7113       bool isUnique = nodeSet.insert( n ).second;
7114       if ( isUnique )
7115         uniqueNodes[ iUnique++ ] = n;
7116       iCur++;
7117     }
7118
7119     // Analyse element topology after replacement
7120
7121     bool isOk = true;
7122     int nbUniqueNodes = nodeSet.size();
7123     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7124       // Polygons and Polyhedral volumes
7125       if (elem->IsPoly()) {
7126
7127         if (elem->GetType() == SMDSAbs_Face) {
7128           // Polygon
7129           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7130           int inode = 0;
7131           for (; inode < nbNodes; inode++) {
7132             face_nodes[inode] = curNodes[inode];
7133           }
7134
7135           vector<const SMDS_MeshNode *> polygons_nodes;
7136           vector<int> quantities;
7137           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7138
7139           if (nbNew > 0) {
7140             inode = 0;
7141             for (int iface = 0; iface < nbNew - 1; iface++) {
7142               int nbNodes = quantities[iface];
7143               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7144               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7145                 poly_nodes[ii] = polygons_nodes[inode];
7146               }
7147               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7148               myLastCreatedElems.Append(newElem);
7149               if (aShapeId)
7150                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7151             }
7152             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7153           }
7154           else {
7155             rmElemIds.push_back(elem->GetID());
7156           }
7157
7158         }
7159         else if (elem->GetType() == SMDSAbs_Volume) {
7160           // Polyhedral volume
7161           if (nbUniqueNodes < 4) {
7162             rmElemIds.push_back(elem->GetID());
7163           }
7164           else {
7165             // each face has to be analized in order to check volume validity
7166             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7167               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7168             if (aPolyedre) {
7169               int nbFaces = aPolyedre->NbFaces();
7170
7171               vector<const SMDS_MeshNode *> poly_nodes;
7172               vector<int> quantities;
7173
7174               for (int iface = 1; iface <= nbFaces; iface++) {
7175                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7176                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7177
7178                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7179                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7180                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7181                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7182                     faceNode = (*nnIt).second;
7183                   }
7184                   faceNodes[inode - 1] = faceNode;
7185                 }
7186
7187                 SimplifyFace(faceNodes, poly_nodes, quantities);
7188               }
7189
7190               if (quantities.size() > 3) {
7191                 // to be done: remove coincident faces
7192               }
7193
7194               if (quantities.size() > 3)
7195                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7196               else
7197                 rmElemIds.push_back(elem->GetID());
7198
7199             }
7200             else {
7201               rmElemIds.push_back(elem->GetID());
7202             }
7203           }
7204         }
7205         else {
7206         }
7207
7208         continue;
7209       }
7210
7211       // Regular elements
7212       switch ( nbNodes ) {
7213       case 2: ///////////////////////////////////// EDGE
7214         isOk = false; break;
7215       case 3: ///////////////////////////////////// TRIANGLE
7216         isOk = false; break;
7217       case 4:
7218         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7219           isOk = false;
7220         else { //////////////////////////////////// QUADRANGLE
7221           if ( nbUniqueNodes < 3 )
7222             isOk = false;
7223           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7224             isOk = false; // opposite nodes stick
7225         }
7226         break;
7227       case 6: ///////////////////////////////////// PENTAHEDRON
7228         if ( nbUniqueNodes == 4 ) {
7229           // ---------------------------------> tetrahedron
7230           if (nbRepl == 3 &&
7231               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7232             // all top nodes stick: reverse a bottom
7233             uniqueNodes[ 0 ] = curNodes [ 1 ];
7234             uniqueNodes[ 1 ] = curNodes [ 0 ];
7235           }
7236           else if (nbRepl == 3 &&
7237                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7238             // all bottom nodes stick: set a top before
7239             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7240             uniqueNodes[ 0 ] = curNodes [ 3 ];
7241             uniqueNodes[ 1 ] = curNodes [ 4 ];
7242             uniqueNodes[ 2 ] = curNodes [ 5 ];
7243           }
7244           else if (nbRepl == 4 &&
7245                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7246             // a lateral face turns into a line: reverse a bottom
7247             uniqueNodes[ 0 ] = curNodes [ 1 ];
7248             uniqueNodes[ 1 ] = curNodes [ 0 ];
7249           }
7250           else
7251             isOk = false;
7252         }
7253         else if ( nbUniqueNodes == 5 ) {
7254           // PENTAHEDRON --------------------> 2 tetrahedrons
7255           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7256             // a bottom node sticks with a linked top one
7257             // 1.
7258             SMDS_MeshElement* newElem =
7259               aMesh->AddVolume(curNodes[ 3 ],
7260                                curNodes[ 4 ],
7261                                curNodes[ 5 ],
7262                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7263             myLastCreatedElems.Append(newElem);
7264             if ( aShapeId )
7265               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7266             // 2. : reverse a bottom
7267             uniqueNodes[ 0 ] = curNodes [ 1 ];
7268             uniqueNodes[ 1 ] = curNodes [ 0 ];
7269             nbUniqueNodes = 4;
7270           }
7271           else
7272             isOk = false;
7273         }
7274         else
7275           isOk = false;
7276         break;
7277       case 8: {
7278         if(elem->IsQuadratic()) { // Quadratic quadrangle
7279           //   1    5    2
7280           //    +---+---+
7281           //    |       |
7282           //    |       |
7283           //   4+       +6
7284           //    |       |
7285           //    |       |
7286           //    +---+---+
7287           //   0    7    3
7288           isOk = false;
7289           if(nbRepl==3) {
7290             nbUniqueNodes = 6;
7291             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7292               uniqueNodes[0] = curNodes[0];
7293               uniqueNodes[1] = curNodes[2];
7294               uniqueNodes[2] = curNodes[3];
7295               uniqueNodes[3] = curNodes[5];
7296               uniqueNodes[4] = curNodes[6];
7297               uniqueNodes[5] = curNodes[7];
7298               isOk = true;
7299             }
7300             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7301               uniqueNodes[0] = curNodes[0];
7302               uniqueNodes[1] = curNodes[1];
7303               uniqueNodes[2] = curNodes[2];
7304               uniqueNodes[3] = curNodes[4];
7305               uniqueNodes[4] = curNodes[5];
7306               uniqueNodes[5] = curNodes[6];
7307               isOk = true;
7308             }
7309             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7310               uniqueNodes[0] = curNodes[1];
7311               uniqueNodes[1] = curNodes[2];
7312               uniqueNodes[2] = curNodes[3];
7313               uniqueNodes[3] = curNodes[5];
7314               uniqueNodes[4] = curNodes[6];
7315               uniqueNodes[5] = curNodes[0];
7316               isOk = true;
7317             }
7318             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7319               uniqueNodes[0] = curNodes[0];
7320               uniqueNodes[1] = curNodes[1];
7321               uniqueNodes[2] = curNodes[3];
7322               uniqueNodes[3] = curNodes[4];
7323               uniqueNodes[4] = curNodes[6];
7324               uniqueNodes[5] = curNodes[7];
7325               isOk = true;
7326             }
7327             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7328               uniqueNodes[0] = curNodes[0];
7329               uniqueNodes[1] = curNodes[2];
7330               uniqueNodes[2] = curNodes[3];
7331               uniqueNodes[3] = curNodes[1];
7332               uniqueNodes[4] = curNodes[6];
7333               uniqueNodes[5] = curNodes[7];
7334               isOk = true;
7335             }
7336             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7337               uniqueNodes[0] = curNodes[0];
7338               uniqueNodes[1] = curNodes[1];
7339               uniqueNodes[2] = curNodes[2];
7340               uniqueNodes[3] = curNodes[4];
7341               uniqueNodes[4] = curNodes[5];
7342               uniqueNodes[5] = curNodes[7];
7343               isOk = true;
7344             }
7345             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7346               uniqueNodes[0] = curNodes[0];
7347               uniqueNodes[1] = curNodes[1];
7348               uniqueNodes[2] = curNodes[3];
7349               uniqueNodes[3] = curNodes[4];
7350               uniqueNodes[4] = curNodes[2];
7351               uniqueNodes[5] = curNodes[7];
7352               isOk = true;
7353             }
7354             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7355               uniqueNodes[0] = curNodes[0];
7356               uniqueNodes[1] = curNodes[1];
7357               uniqueNodes[2] = curNodes[2];
7358               uniqueNodes[3] = curNodes[4];
7359               uniqueNodes[4] = curNodes[5];
7360               uniqueNodes[5] = curNodes[3];
7361               isOk = true;
7362             }
7363           }
7364           break;
7365         }
7366         //////////////////////////////////// HEXAHEDRON
7367         isOk = false;
7368         SMDS_VolumeTool hexa (elem);
7369         hexa.SetExternalNormal();
7370         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7371           //////////////////////// ---> tetrahedron
7372           for ( int iFace = 0; iFace < 6; iFace++ ) {
7373             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7374             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7375                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7376                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7377               // one face turns into a point ...
7378               int iOppFace = hexa.GetOppFaceIndex( iFace );
7379               ind = hexa.GetFaceNodesIndices( iOppFace );
7380               int nbStick = 0;
7381               iUnique = 2; // reverse a tetrahedron bottom
7382               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7383                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7384                   nbStick++;
7385                 else if ( iUnique >= 0 )
7386                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7387               }
7388               if ( nbStick == 1 ) {
7389                 // ... and the opposite one - into a triangle.
7390                 // set a top node
7391                 ind = hexa.GetFaceNodesIndices( iFace );
7392                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7393                 isOk = true;
7394               }
7395               break;
7396             }
7397           }
7398         }
7399         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7400           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7401           for ( int iFace = 0; iFace < 6; iFace++ ) {
7402             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7403             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7404                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7405                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7406               // one face turns into a point ...
7407               int iOppFace = hexa.GetOppFaceIndex( iFace );
7408               ind = hexa.GetFaceNodesIndices( iOppFace );
7409               int nbStick = 0;
7410               iUnique = 2;  // reverse a tetrahedron 1 bottom
7411               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7412                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7413                   nbStick++;
7414                 else if ( iUnique >= 0 )
7415                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7416               }
7417               if ( nbStick == 0 ) {
7418                 // ... and the opposite one is a quadrangle
7419                 // set a top node
7420                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7421                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7422                 nbUniqueNodes = 4;
7423                 // tetrahedron 2
7424                 SMDS_MeshElement* newElem =
7425                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7426                                    curNodes[ind[ 3 ]],
7427                                    curNodes[ind[ 2 ]],
7428                                    curNodes[indTop[ 0 ]]);
7429                 myLastCreatedElems.Append(newElem);
7430                 if ( aShapeId )
7431                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7432                 isOk = true;
7433               }
7434               break;
7435             }
7436           }
7437         }
7438         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7439           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7440           // find indices of quad and tri faces
7441           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7442           for ( iFace = 0; iFace < 6; iFace++ ) {
7443             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7444             nodeSet.clear();
7445             for ( iCur = 0; iCur < 4; iCur++ )
7446               nodeSet.insert( curNodes[ind[ iCur ]] );
7447             nbUniqueNodes = nodeSet.size();
7448             if ( nbUniqueNodes == 3 )
7449               iTriFace[ nbTri++ ] = iFace;
7450             else if ( nbUniqueNodes == 4 )
7451               iQuadFace[ nbQuad++ ] = iFace;
7452           }
7453           if (nbQuad == 2 && nbTri == 4 &&
7454               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7455             // 2 opposite quadrangles stuck with a diagonal;
7456             // sample groups of merged indices: (0-4)(2-6)
7457             // --------------------------------------------> 2 tetrahedrons
7458             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7459             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7460             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7461             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7462                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7463               // stuck with 0-2 diagonal
7464               i0  = ind1[ 3 ];
7465               i1d = ind1[ 0 ];
7466               i2  = ind1[ 1 ];
7467               i3d = ind1[ 2 ];
7468               i0t = ind2[ 1 ];
7469               i2t = ind2[ 3 ];
7470             }
7471             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7472                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7473               // stuck with 1-3 diagonal
7474               i0  = ind1[ 0 ];
7475               i1d = ind1[ 1 ];
7476               i2  = ind1[ 2 ];
7477               i3d = ind1[ 3 ];
7478               i0t = ind2[ 0 ];
7479               i2t = ind2[ 1 ];
7480             }
7481             else {
7482               ASSERT(0);
7483             }
7484             // tetrahedron 1
7485             uniqueNodes[ 0 ] = curNodes [ i0 ];
7486             uniqueNodes[ 1 ] = curNodes [ i1d ];
7487             uniqueNodes[ 2 ] = curNodes [ i3d ];
7488             uniqueNodes[ 3 ] = curNodes [ i0t ];
7489             nbUniqueNodes = 4;
7490             // tetrahedron 2
7491             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7492                                                          curNodes[ i2 ],
7493                                                          curNodes[ i3d ],
7494                                                          curNodes[ i2t ]);
7495             myLastCreatedElems.Append(newElem);
7496             if ( aShapeId )
7497               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7498             isOk = true;
7499           }
7500           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7501                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7502             // --------------------------------------------> prism
7503             // find 2 opposite triangles
7504             nbUniqueNodes = 6;
7505             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7506               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7507                 // find indices of kept and replaced nodes
7508                 // and fill unique nodes of 2 opposite triangles
7509                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7510                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7511                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7512                 // fill unique nodes
7513                 iUnique = 0;
7514                 isOk = true;
7515                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7516                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7517                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7518                   if ( n == nInit ) {
7519                     // iCur of a linked node of the opposite face (make normals co-directed):
7520                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7521                     // check that correspondent corners of triangles are linked
7522                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7523                       isOk = false;
7524                     else {
7525                       uniqueNodes[ iUnique ] = n;
7526                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7527                       iUnique++;
7528                     }
7529                   }
7530                 }
7531                 break;
7532               }
7533             }
7534           }
7535         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7536         break;
7537       } // HEXAHEDRON
7538
7539       default:
7540         isOk = false;
7541       } // switch ( nbNodes )
7542
7543     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7544
7545     if ( isOk ) {
7546       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7547         // Change nodes of polyedre
7548         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7549           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7550         if (aPolyedre) {
7551           int nbFaces = aPolyedre->NbFaces();
7552
7553           vector<const SMDS_MeshNode *> poly_nodes;
7554           vector<int> quantities (nbFaces);
7555
7556           for (int iface = 1; iface <= nbFaces; iface++) {
7557             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7558             quantities[iface - 1] = nbFaceNodes;
7559
7560             for (inode = 1; inode <= nbFaceNodes; inode++) {
7561               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7562
7563               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7564               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7565                 curNode = (*nnIt).second;
7566               }
7567               poly_nodes.push_back(curNode);
7568             }
7569           }
7570           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7571         }
7572       }
7573       else {
7574         // Change regular element or polygon
7575         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7576       }
7577     }
7578     else {
7579       // Remove invalid regular element or invalid polygon
7580       rmElemIds.push_back( elem->GetID() );
7581     }
7582
7583   } // loop on elements
7584
7585   // Remove equal nodes and bad elements
7586
7587   Remove( rmNodeIds, true );
7588   Remove( rmElemIds, false );
7589
7590 }
7591
7592
7593 // ========================================================
7594 // class   : SortableElement
7595 // purpose : allow sorting elements basing on their nodes
7596 // ========================================================
7597 class SortableElement : public set <const SMDS_MeshElement*>
7598 {
7599 public:
7600
7601   SortableElement( const SMDS_MeshElement* theElem )
7602   {
7603     myElem = theElem;
7604     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7605     while ( nodeIt->more() )
7606       this->insert( nodeIt->next() );
7607   }
7608
7609   const SMDS_MeshElement* Get() const
7610   { return myElem; }
7611
7612   void Set(const SMDS_MeshElement* e) const
7613   { myElem = e; }
7614
7615
7616 private:
7617   mutable const SMDS_MeshElement* myElem;
7618 };
7619
7620 //=======================================================================
7621 //function : FindEqualElements
7622 //purpose  : Return list of group of elements built on the same nodes.
7623 //           Search among theElements or in the whole mesh if theElements is empty
7624 //=======================================================================
7625 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7626                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7627 {
7628   myLastCreatedElems.Clear();
7629   myLastCreatedNodes.Clear();
7630
7631   typedef set<const SMDS_MeshElement*> TElemsSet;
7632   typedef map< SortableElement, int > TMapOfNodeSet;
7633   typedef list<int> TGroupOfElems;
7634
7635   TElemsSet elems;
7636   if ( theElements.empty() )
7637   { // get all elements in the mesh
7638     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7639     while ( eIt->more() )
7640       elems.insert( elems.end(), eIt->next());
7641   }
7642   else
7643     elems = theElements;
7644
7645   vector< TGroupOfElems > arrayOfGroups;
7646   TGroupOfElems groupOfElems;
7647   TMapOfNodeSet mapOfNodeSet;
7648
7649   TElemsSet::iterator elemIt = elems.begin();
7650   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7651     const SMDS_MeshElement* curElem = *elemIt;
7652     SortableElement SE(curElem);
7653     int ind = -1;
7654     // check uniqueness
7655     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7656     if( !(pp.second) ) {
7657       TMapOfNodeSet::iterator& itSE = pp.first;
7658       ind = (*itSE).second;
7659       arrayOfGroups[ind].push_back(curElem->GetID());
7660     }
7661     else {
7662       groupOfElems.clear();
7663       groupOfElems.push_back(curElem->GetID());
7664       arrayOfGroups.push_back(groupOfElems);
7665       i++;
7666     }
7667   }
7668
7669   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7670   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7671     groupOfElems = *groupIt;
7672     if ( groupOfElems.size() > 1 ) {
7673       groupOfElems.sort();
7674       theGroupsOfElementsID.push_back(groupOfElems);
7675     }
7676   }
7677 }
7678
7679 //=======================================================================
7680 //function : MergeElements
7681 //purpose  : In each given group, substitute all elements by the first one.
7682 //=======================================================================
7683
7684 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7685 {
7686   myLastCreatedElems.Clear();
7687   myLastCreatedNodes.Clear();
7688
7689   typedef list<int> TListOfIDs;
7690   TListOfIDs rmElemIds; // IDs of elems to remove
7691
7692   SMESHDS_Mesh* aMesh = GetMeshDS();
7693
7694   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7695   while ( groupsIt != theGroupsOfElementsID.end() ) {
7696     TListOfIDs& aGroupOfElemID = *groupsIt;
7697     aGroupOfElemID.sort();
7698     int elemIDToKeep = aGroupOfElemID.front();
7699     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7700     aGroupOfElemID.pop_front();
7701     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7702     while ( idIt != aGroupOfElemID.end() ) {
7703       int elemIDToRemove = *idIt;
7704       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7705       // add the kept element in groups of removed one (PAL15188)
7706       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7707       rmElemIds.push_back( elemIDToRemove );
7708       ++idIt;
7709     }
7710     ++groupsIt;
7711   }
7712
7713   Remove( rmElemIds, false );
7714 }
7715
7716 //=======================================================================
7717 //function : MergeEqualElements
7718 //purpose  : Remove all but one of elements built on the same nodes.
7719 //=======================================================================
7720
7721 void SMESH_MeshEditor::MergeEqualElements()
7722 {
7723   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7724                                                  to merge equal elements in the whole mesh */
7725   TListOfListOfElementsID aGroupsOfElementsID;
7726   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7727   MergeElements(aGroupsOfElementsID);
7728 }
7729
7730 //=======================================================================
7731 //function : FindFaceInSet
7732 //purpose  : Return a face having linked nodes n1 and n2 and which is
7733 //           - not in avoidSet,
7734 //           - in elemSet provided that !elemSet.empty()
7735 //           i1 and i2 optionally returns indices of n1 and n2
7736 //=======================================================================
7737
7738 const SMDS_MeshElement*
7739 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7740                                 const SMDS_MeshNode*    n2,
7741                                 const TIDSortedElemSet& elemSet,
7742                                 const TIDSortedElemSet& avoidSet,
7743                                 int*                    n1ind,
7744                                 int*                    n2ind)
7745
7746 {
7747   int i1, i2;
7748   const SMDS_MeshElement* face = 0;
7749
7750   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7751   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7752   {
7753     const SMDS_MeshElement* elem = invElemIt->next();
7754     if (avoidSet.count( elem ))
7755       continue;
7756     if ( !elemSet.empty() && !elemSet.count( elem ))
7757       continue;
7758     // index of n1
7759     i1 = elem->GetNodeIndex( n1 );
7760     // find a n2 linked to n1
7761     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7762     for ( int di = -1; di < 2 && !face; di += 2 )
7763     {
7764       i2 = (i1+di+nbN) % nbN;
7765       if ( elem->GetNode( i2 ) == n2 )
7766         face = elem;
7767     }
7768     if ( !face && elem->IsQuadratic())
7769     {
7770       // analysis for quadratic elements using all nodes
7771       const SMDS_QuadraticFaceOfNodes* F =
7772         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7773       // use special nodes iterator
7774       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7775       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7776       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7777       {
7778         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7779         if ( n1 == prevN && n2 == n )
7780         {
7781           face = elem;
7782         }
7783         else if ( n2 == prevN && n1 == n )
7784         {
7785           face = elem; swap( i1, i2 );
7786         }
7787         prevN = n;
7788       }
7789     }
7790   }
7791   if ( n1ind ) *n1ind = i1;
7792   if ( n2ind ) *n2ind = i2;
7793   return face;
7794 }
7795
7796 //=======================================================================
7797 //function : findAdjacentFace
7798 //purpose  :
7799 //=======================================================================
7800
7801 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7802                                                 const SMDS_MeshNode* n2,
7803                                                 const SMDS_MeshElement* elem)
7804 {
7805   TIDSortedElemSet elemSet, avoidSet;
7806   if ( elem )
7807     avoidSet.insert ( elem );
7808   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7809 }
7810
7811 //=======================================================================
7812 //function : FindFreeBorder
7813 //purpose  :
7814 //=======================================================================
7815
7816 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7817
7818 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7819                                        const SMDS_MeshNode*             theSecondNode,
7820                                        const SMDS_MeshNode*             theLastNode,
7821                                        list< const SMDS_MeshNode* > &   theNodes,
7822                                        list< const SMDS_MeshElement* >& theFaces)
7823 {
7824   if ( !theFirstNode || !theSecondNode )
7825     return false;
7826   // find border face between theFirstNode and theSecondNode
7827   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7828   if ( !curElem )
7829     return false;
7830
7831   theFaces.push_back( curElem );
7832   theNodes.push_back( theFirstNode );
7833   theNodes.push_back( theSecondNode );
7834
7835   //vector<const SMDS_MeshNode*> nodes;
7836   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7837   TIDSortedElemSet foundElems;
7838   bool needTheLast = ( theLastNode != 0 );
7839
7840   while ( nStart != theLastNode ) {
7841     if ( nStart == theFirstNode )
7842       return !needTheLast;
7843
7844     // find all free border faces sharing form nStart
7845
7846     list< const SMDS_MeshElement* > curElemList;
7847     list< const SMDS_MeshNode* > nStartList;
7848     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7849     while ( invElemIt->more() ) {
7850       const SMDS_MeshElement* e = invElemIt->next();
7851       if ( e == curElem || foundElems.insert( e ).second ) {
7852         // get nodes
7853         int iNode = 0, nbNodes = e->NbNodes();
7854         //const SMDS_MeshNode* nodes[nbNodes+1];
7855         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7856
7857         if(e->IsQuadratic()) {
7858           const SMDS_QuadraticFaceOfNodes* F =
7859             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7860           // use special nodes iterator
7861           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7862           while( anIter->more() ) {
7863             nodes[ iNode++ ] = anIter->next();
7864           }
7865         }
7866         else {
7867           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7868           while ( nIt->more() )
7869             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7870         }
7871         nodes[ iNode ] = nodes[ 0 ];
7872         // check 2 links
7873         for ( iNode = 0; iNode < nbNodes; iNode++ )
7874           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7875                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7876               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7877           {
7878             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7879             curElemList.push_back( e );
7880           }
7881       }
7882     }
7883     // analyse the found
7884
7885     int nbNewBorders = curElemList.size();
7886     if ( nbNewBorders == 0 ) {
7887       // no free border furthermore
7888       return !needTheLast;
7889     }
7890     else if ( nbNewBorders == 1 ) {
7891       // one more element found
7892       nIgnore = nStart;
7893       nStart = nStartList.front();
7894       curElem = curElemList.front();
7895       theFaces.push_back( curElem );
7896       theNodes.push_back( nStart );
7897     }
7898     else {
7899       // several continuations found
7900       list< const SMDS_MeshElement* >::iterator curElemIt;
7901       list< const SMDS_MeshNode* >::iterator nStartIt;
7902       // check if one of them reached the last node
7903       if ( needTheLast ) {
7904         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7905              curElemIt!= curElemList.end();
7906              curElemIt++, nStartIt++ )
7907           if ( *nStartIt == theLastNode ) {
7908             theFaces.push_back( *curElemIt );
7909             theNodes.push_back( *nStartIt );
7910             return true;
7911           }
7912       }
7913       // find the best free border by the continuations
7914       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7915       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7916       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7917            curElemIt!= curElemList.end();
7918            curElemIt++, nStartIt++ )
7919       {
7920         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7921         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7922         // find one more free border
7923         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7924           cNL->clear();
7925           cFL->clear();
7926         }
7927         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7928           // choice: clear a worse one
7929           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7930           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7931           contNodes[ iWorse ].clear();
7932           contFaces[ iWorse ].clear();
7933         }
7934       }
7935       if ( contNodes[0].empty() && contNodes[1].empty() )
7936         return false;
7937
7938       // append the best free border
7939       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7940       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7941       theNodes.pop_back(); // remove nIgnore
7942       theNodes.pop_back(); // remove nStart
7943       theFaces.pop_back(); // remove curElem
7944       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7945       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7946       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7947       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7948       return true;
7949
7950     } // several continuations found
7951   } // while ( nStart != theLastNode )
7952
7953   return true;
7954 }
7955
7956 //=======================================================================
7957 //function : CheckFreeBorderNodes
7958 //purpose  : Return true if the tree nodes are on a free border
7959 //=======================================================================
7960
7961 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7962                                             const SMDS_MeshNode* theNode2,
7963                                             const SMDS_MeshNode* theNode3)
7964 {
7965   list< const SMDS_MeshNode* > nodes;
7966   list< const SMDS_MeshElement* > faces;
7967   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7968 }
7969
7970 //=======================================================================
7971 //function : SewFreeBorder
7972 //purpose  :
7973 //=======================================================================
7974
7975 SMESH_MeshEditor::Sew_Error
7976 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7977                                  const SMDS_MeshNode* theBordSecondNode,
7978                                  const SMDS_MeshNode* theBordLastNode,
7979                                  const SMDS_MeshNode* theSideFirstNode,
7980                                  const SMDS_MeshNode* theSideSecondNode,
7981                                  const SMDS_MeshNode* theSideThirdNode,
7982                                  const bool           theSideIsFreeBorder,
7983                                  const bool           toCreatePolygons,
7984                                  const bool           toCreatePolyedrs)
7985 {
7986   myLastCreatedElems.Clear();
7987   myLastCreatedNodes.Clear();
7988
7989   MESSAGE("::SewFreeBorder()");
7990   Sew_Error aResult = SEW_OK;
7991
7992   // ====================================
7993   //    find side nodes and elements
7994   // ====================================
7995
7996   list< const SMDS_MeshNode* > nSide[ 2 ];
7997   list< const SMDS_MeshElement* > eSide[ 2 ];
7998   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7999   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8000
8001   // Free border 1
8002   // --------------
8003   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8004                       nSide[0], eSide[0])) {
8005     MESSAGE(" Free Border 1 not found " );
8006     aResult = SEW_BORDER1_NOT_FOUND;
8007   }
8008   if (theSideIsFreeBorder) {
8009     // Free border 2
8010     // --------------
8011     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8012                         nSide[1], eSide[1])) {
8013       MESSAGE(" Free Border 2 not found " );
8014       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8015     }
8016   }
8017   if ( aResult != SEW_OK )
8018     return aResult;
8019
8020   if (!theSideIsFreeBorder) {
8021     // Side 2
8022     // --------------
8023
8024     // -------------------------------------------------------------------------
8025     // Algo:
8026     // 1. If nodes to merge are not coincident, move nodes of the free border
8027     //    from the coord sys defined by the direction from the first to last
8028     //    nodes of the border to the correspondent sys of the side 2
8029     // 2. On the side 2, find the links most co-directed with the correspondent
8030     //    links of the free border
8031     // -------------------------------------------------------------------------
8032
8033     // 1. Since sewing may brake if there are volumes to split on the side 2,
8034     //    we wont move nodes but just compute new coordinates for them
8035     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8036     TNodeXYZMap nBordXYZ;
8037     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8038     list< const SMDS_MeshNode* >::iterator nBordIt;
8039
8040     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8041     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8042     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8043     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8044     double tol2 = 1.e-8;
8045     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8046     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8047       // Need node movement.
8048
8049       // find X and Z axes to create trsf
8050       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8051       gp_Vec X = Zs ^ Zb;
8052       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8053         // Zb || Zs
8054         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8055
8056       // coord systems
8057       gp_Ax3 toBordAx( Pb1, Zb, X );
8058       gp_Ax3 fromSideAx( Ps1, Zs, X );
8059       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8060       // set trsf
8061       gp_Trsf toBordSys, fromSide2Sys;
8062       toBordSys.SetTransformation( toBordAx );
8063       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8064       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8065
8066       // move
8067       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8068         const SMDS_MeshNode* n = *nBordIt;
8069         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8070         toBordSys.Transforms( xyz );
8071         fromSide2Sys.Transforms( xyz );
8072         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8073       }
8074     }
8075     else {
8076       // just insert nodes XYZ in the nBordXYZ map
8077       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8078         const SMDS_MeshNode* n = *nBordIt;
8079         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8080       }
8081     }
8082
8083     // 2. On the side 2, find the links most co-directed with the correspondent
8084     //    links of the free border
8085
8086     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8087     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8088     sideNodes.push_back( theSideFirstNode );
8089
8090     bool hasVolumes = false;
8091     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8092     set<long> foundSideLinkIDs, checkedLinkIDs;
8093     SMDS_VolumeTool volume;
8094     //const SMDS_MeshNode* faceNodes[ 4 ];
8095
8096     const SMDS_MeshNode*    sideNode;
8097     const SMDS_MeshElement* sideElem;
8098     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8099     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8100     nBordIt = bordNodes.begin();
8101     nBordIt++;
8102     // border node position and border link direction to compare with
8103     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8104     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8105     // choose next side node by link direction or by closeness to
8106     // the current border node:
8107     bool searchByDir = ( *nBordIt != theBordLastNode );
8108     do {
8109       // find the next node on the Side 2
8110       sideNode = 0;
8111       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8112       long linkID;
8113       checkedLinkIDs.clear();
8114       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8115
8116       // loop on inverse elements of current node (prevSideNode) on the Side 2
8117       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8118       while ( invElemIt->more() )
8119       {
8120         const SMDS_MeshElement* elem = invElemIt->next();
8121         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8122         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8123         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8124         bool isVolume = volume.Set( elem );
8125         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8126         if ( isVolume ) // --volume
8127           hasVolumes = true;
8128         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8129           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8130           if(elem->IsQuadratic()) {
8131             const SMDS_QuadraticFaceOfNodes* F =
8132               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8133             // use special nodes iterator
8134             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8135             while( anIter->more() ) {
8136               nodes[ iNode ] = anIter->next();
8137               if ( nodes[ iNode++ ] == prevSideNode )
8138                 iPrevNode = iNode - 1;
8139             }
8140           }
8141           else {
8142             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8143             while ( nIt->more() ) {
8144               nodes[ iNode ] = cast2Node( nIt->next() );
8145               if ( nodes[ iNode++ ] == prevSideNode )
8146                 iPrevNode = iNode - 1;
8147             }
8148           }
8149           // there are 2 links to check
8150           nbNodes = 2;
8151         }
8152         else // --edge
8153           continue;
8154         // loop on links, to be precise, on the second node of links
8155         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8156           const SMDS_MeshNode* n = nodes[ iNode ];
8157           if ( isVolume ) {
8158             if ( !volume.IsLinked( n, prevSideNode ))
8159               continue;
8160           }
8161           else {
8162             if ( iNode ) // a node before prevSideNode
8163               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8164             else         // a node after prevSideNode
8165               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8166           }
8167           // check if this link was already used
8168           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8169           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8170           if (!isJustChecked &&
8171               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8172           {
8173             // test a link geometrically
8174             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8175             bool linkIsBetter = false;
8176             double dot = 0.0, dist = 0.0;
8177             if ( searchByDir ) { // choose most co-directed link
8178               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8179               linkIsBetter = ( dot > maxDot );
8180             }
8181             else { // choose link with the node closest to bordPos
8182               dist = ( nextXYZ - bordPos ).SquareModulus();
8183               linkIsBetter = ( dist < minDist );
8184             }
8185             if ( linkIsBetter ) {
8186               maxDot = dot;
8187               minDist = dist;
8188               linkID = iLink;
8189               sideNode = n;
8190               sideElem = elem;
8191             }
8192           }
8193         }
8194       } // loop on inverse elements of prevSideNode
8195
8196       if ( !sideNode ) {
8197         MESSAGE(" Cant find path by links of the Side 2 ");
8198         return SEW_BAD_SIDE_NODES;
8199       }
8200       sideNodes.push_back( sideNode );
8201       sideElems.push_back( sideElem );
8202       foundSideLinkIDs.insert ( linkID );
8203       prevSideNode = sideNode;
8204
8205       if ( *nBordIt == theBordLastNode )
8206         searchByDir = false;
8207       else {
8208         // find the next border link to compare with
8209         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8210         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8211         // move to next border node if sideNode is before forward border node (bordPos)
8212         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8213           prevBordNode = *nBordIt;
8214           nBordIt++;
8215           bordPos = nBordXYZ[ *nBordIt ];
8216           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8217           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8218         }
8219       }
8220     }
8221     while ( sideNode != theSideSecondNode );
8222
8223     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8224       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8225       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8226     }
8227   } // end nodes search on the side 2
8228
8229   // ============================
8230   // sew the border to the side 2
8231   // ============================
8232
8233   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8234   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8235
8236   TListOfListOfNodes nodeGroupsToMerge;
8237   if ( nbNodes[0] == nbNodes[1] ||
8238        ( theSideIsFreeBorder && !theSideThirdNode)) {
8239
8240     // all nodes are to be merged
8241
8242     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8243          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8244          nIt[0]++, nIt[1]++ )
8245     {
8246       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8247       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8248       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8249     }
8250   }
8251   else {
8252
8253     // insert new nodes into the border and the side to get equal nb of segments
8254
8255     // get normalized parameters of nodes on the borders
8256     //double param[ 2 ][ maxNbNodes ];
8257     double* param[ 2 ];
8258     param[0] = new double [ maxNbNodes ];
8259     param[1] = new double [ maxNbNodes ];
8260     int iNode, iBord;
8261     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8262       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8263       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8264       const SMDS_MeshNode* nPrev = *nIt;
8265       double bordLength = 0;
8266       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8267         const SMDS_MeshNode* nCur = *nIt;
8268         gp_XYZ segment (nCur->X() - nPrev->X(),
8269                         nCur->Y() - nPrev->Y(),
8270                         nCur->Z() - nPrev->Z());
8271         double segmentLen = segment.Modulus();
8272         bordLength += segmentLen;
8273         param[ iBord ][ iNode ] = bordLength;
8274         nPrev = nCur;
8275       }
8276       // normalize within [0,1]
8277       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8278         param[ iBord ][ iNode ] /= bordLength;
8279       }
8280     }
8281
8282     // loop on border segments
8283     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8284     int i[ 2 ] = { 0, 0 };
8285     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8286     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8287
8288     TElemOfNodeListMap insertMap;
8289     TElemOfNodeListMap::iterator insertMapIt;
8290     // insertMap is
8291     // key:   elem to insert nodes into
8292     // value: 2 nodes to insert between + nodes to be inserted
8293     do {
8294       bool next[ 2 ] = { false, false };
8295
8296       // find min adjacent segment length after sewing
8297       double nextParam = 10., prevParam = 0;
8298       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8299         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8300           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8301         if ( i[ iBord ] > 0 )
8302           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8303       }
8304       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8305       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8306       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8307
8308       // choose to insert or to merge nodes
8309       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8310       if ( Abs( du ) <= minSegLen * 0.2 ) {
8311         // merge
8312         // ------
8313         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8314         const SMDS_MeshNode* n0 = *nIt[0];
8315         const SMDS_MeshNode* n1 = *nIt[1];
8316         nodeGroupsToMerge.back().push_back( n1 );
8317         nodeGroupsToMerge.back().push_back( n0 );
8318         // position of node of the border changes due to merge
8319         param[ 0 ][ i[0] ] += du;
8320         // move n1 for the sake of elem shape evaluation during insertion.
8321         // n1 will be removed by MergeNodes() anyway
8322         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8323         next[0] = next[1] = true;
8324       }
8325       else {
8326         // insert
8327         // ------
8328         int intoBord = ( du < 0 ) ? 0 : 1;
8329         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8330         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8331         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8332         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8333         if ( intoBord == 1 ) {
8334           // move node of the border to be on a link of elem of the side
8335           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8336           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8337           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8338           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8339           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8340         }
8341         insertMapIt = insertMap.find( elem );
8342         bool notFound = ( insertMapIt == insertMap.end() );
8343         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8344         if ( otherLink ) {
8345           // insert into another link of the same element:
8346           // 1. perform insertion into the other link of the elem
8347           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8348           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8349           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8350           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8351           // 2. perform insertion into the link of adjacent faces
8352           while (true) {
8353             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8354             if ( adjElem )
8355               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8356             else
8357               break;
8358           }
8359           if (toCreatePolyedrs) {
8360             // perform insertion into the links of adjacent volumes
8361             UpdateVolumes(n12, n22, nodeList);
8362           }
8363           // 3. find an element appeared on n1 and n2 after the insertion
8364           insertMap.erase( elem );
8365           elem = findAdjacentFace( n1, n2, 0 );
8366         }
8367         if ( notFound || otherLink ) {
8368           // add element and nodes of the side into the insertMap
8369           insertMapIt = insertMap.insert
8370             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8371           (*insertMapIt).second.push_back( n1 );
8372           (*insertMapIt).second.push_back( n2 );
8373         }
8374         // add node to be inserted into elem
8375         (*insertMapIt).second.push_back( nIns );
8376         next[ 1 - intoBord ] = true;
8377       }
8378
8379       // go to the next segment
8380       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8381         if ( next[ iBord ] ) {
8382           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8383             eIt[ iBord ]++;
8384           nPrev[ iBord ] = *nIt[ iBord ];
8385           nIt[ iBord ]++; i[ iBord ]++;
8386         }
8387       }
8388     }
8389     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8390
8391     // perform insertion of nodes into elements
8392
8393     for (insertMapIt = insertMap.begin();
8394          insertMapIt != insertMap.end();
8395          insertMapIt++ )
8396     {
8397       const SMDS_MeshElement* elem = (*insertMapIt).first;
8398       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8399       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8400       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8401
8402       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8403
8404       if ( !theSideIsFreeBorder ) {
8405         // look for and insert nodes into the faces adjacent to elem
8406         while (true) {
8407           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8408           if ( adjElem )
8409             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8410           else
8411             break;
8412         }
8413       }
8414       if (toCreatePolyedrs) {
8415         // perform insertion into the links of adjacent volumes
8416         UpdateVolumes(n1, n2, nodeList);
8417       }
8418     }
8419
8420     delete param[0];
8421     delete param[1];
8422   } // end: insert new nodes
8423
8424   MergeNodes ( nodeGroupsToMerge );
8425
8426   return aResult;
8427 }
8428
8429 //=======================================================================
8430 //function : InsertNodesIntoLink
8431 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8432 //           and theBetweenNode2 and split theElement
8433 //=======================================================================
8434
8435 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8436                                            const SMDS_MeshNode*        theBetweenNode1,
8437                                            const SMDS_MeshNode*        theBetweenNode2,
8438                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8439                                            const bool                  toCreatePoly)
8440 {
8441   if ( theFace->GetType() != SMDSAbs_Face ) return;
8442
8443   // find indices of 2 link nodes and of the rest nodes
8444   int iNode = 0, il1, il2, i3, i4;
8445   il1 = il2 = i3 = i4 = -1;
8446   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8447   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8448
8449   if(theFace->IsQuadratic()) {
8450     const SMDS_QuadraticFaceOfNodes* F =
8451       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8452     // use special nodes iterator
8453     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8454     while( anIter->more() ) {
8455       const SMDS_MeshNode* n = anIter->next();
8456       if ( n == theBetweenNode1 )
8457         il1 = iNode;
8458       else if ( n == theBetweenNode2 )
8459         il2 = iNode;
8460       else if ( i3 < 0 )
8461         i3 = iNode;
8462       else
8463         i4 = iNode;
8464       nodes[ iNode++ ] = n;
8465     }
8466   }
8467   else {
8468     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8469     while ( nodeIt->more() ) {
8470       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8471       if ( n == theBetweenNode1 )
8472         il1 = iNode;
8473       else if ( n == theBetweenNode2 )
8474         il2 = iNode;
8475       else if ( i3 < 0 )
8476         i3 = iNode;
8477       else
8478         i4 = iNode;
8479       nodes[ iNode++ ] = n;
8480     }
8481   }
8482   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8483     return ;
8484
8485   // arrange link nodes to go one after another regarding the face orientation
8486   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8487   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8488   if ( reverse ) {
8489     iNode = il1;
8490     il1 = il2;
8491     il2 = iNode;
8492     aNodesToInsert.reverse();
8493   }
8494   // check that not link nodes of a quadrangles are in good order
8495   int nbFaceNodes = theFace->NbNodes();
8496   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8497     iNode = i3;
8498     i3 = i4;
8499     i4 = iNode;
8500   }
8501
8502   if (toCreatePoly || theFace->IsPoly()) {
8503
8504     iNode = 0;
8505     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8506
8507     // add nodes of face up to first node of link
8508     bool isFLN = false;
8509
8510     if(theFace->IsQuadratic()) {
8511       const SMDS_QuadraticFaceOfNodes* F =
8512         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8513       // use special nodes iterator
8514       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8515       while( anIter->more()  && !isFLN ) {
8516         const SMDS_MeshNode* n = anIter->next();
8517         poly_nodes[iNode++] = n;
8518         if (n == nodes[il1]) {
8519           isFLN = true;
8520         }
8521       }
8522       // add nodes to insert
8523       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8524       for (; nIt != aNodesToInsert.end(); nIt++) {
8525         poly_nodes[iNode++] = *nIt;
8526       }
8527       // add nodes of face starting from last node of link
8528       while ( anIter->more() ) {
8529         poly_nodes[iNode++] = anIter->next();
8530       }
8531     }
8532     else {
8533       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8534       while ( nodeIt->more() && !isFLN ) {
8535         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8536         poly_nodes[iNode++] = n;
8537         if (n == nodes[il1]) {
8538           isFLN = true;
8539         }
8540       }
8541       // add nodes to insert
8542       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8543       for (; nIt != aNodesToInsert.end(); nIt++) {
8544         poly_nodes[iNode++] = *nIt;
8545       }
8546       // add nodes of face starting from last node of link
8547       while ( nodeIt->more() ) {
8548         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8549         poly_nodes[iNode++] = n;
8550       }
8551     }
8552
8553     // edit or replace the face
8554     SMESHDS_Mesh *aMesh = GetMeshDS();
8555
8556     if (theFace->IsPoly()) {
8557       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8558     }
8559     else {
8560       int aShapeId = FindShape( theFace );
8561
8562       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8563       myLastCreatedElems.Append(newElem);
8564       if ( aShapeId && newElem )
8565         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8566
8567       aMesh->RemoveElement(theFace);
8568     }
8569     return;
8570   }
8571
8572   if( !theFace->IsQuadratic() ) {
8573
8574     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8575     int nbLinkNodes = 2 + aNodesToInsert.size();
8576     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8577     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8578     linkNodes[ 0 ] = nodes[ il1 ];
8579     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8580     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8581     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8582       linkNodes[ iNode++ ] = *nIt;
8583     }
8584     // decide how to split a quadrangle: compare possible variants
8585     // and choose which of splits to be a quadrangle
8586     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8587     if ( nbFaceNodes == 3 ) {
8588       iBestQuad = nbSplits;
8589       i4 = i3;
8590     }
8591     else if ( nbFaceNodes == 4 ) {
8592       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8593       double aBestRate = DBL_MAX;
8594       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8595         i1 = 0; i2 = 1;
8596         double aBadRate = 0;
8597         // evaluate elements quality
8598         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8599           if ( iSplit == iQuad ) {
8600             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8601                                    linkNodes[ i2++ ],
8602                                    nodes[ i3 ],
8603                                    nodes[ i4 ]);
8604             aBadRate += getBadRate( &quad, aCrit );
8605           }
8606           else {
8607             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8608                                    linkNodes[ i2++ ],
8609                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8610             aBadRate += getBadRate( &tria, aCrit );
8611           }
8612         }
8613         // choice
8614         if ( aBadRate < aBestRate ) {
8615           iBestQuad = iQuad;
8616           aBestRate = aBadRate;
8617         }
8618       }
8619     }
8620
8621     // create new elements
8622     SMESHDS_Mesh *aMesh = GetMeshDS();
8623     int aShapeId = FindShape( theFace );
8624
8625     i1 = 0; i2 = 1;
8626     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8627       SMDS_MeshElement* newElem = 0;
8628       if ( iSplit == iBestQuad )
8629         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8630                                   linkNodes[ i2++ ],
8631                                   nodes[ i3 ],
8632                                   nodes[ i4 ]);
8633       else
8634         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8635                                   linkNodes[ i2++ ],
8636                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8637       myLastCreatedElems.Append(newElem);
8638       if ( aShapeId && newElem )
8639         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8640     }
8641
8642     // change nodes of theFace
8643     const SMDS_MeshNode* newNodes[ 4 ];
8644     newNodes[ 0 ] = linkNodes[ i1 ];
8645     newNodes[ 1 ] = linkNodes[ i2 ];
8646     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8647     newNodes[ 3 ] = nodes[ i4 ];
8648     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8649   } // end if(!theFace->IsQuadratic())
8650   else { // theFace is quadratic
8651     // we have to split theFace on simple triangles and one simple quadrangle
8652     int tmp = il1/2;
8653     int nbshift = tmp*2;
8654     // shift nodes in nodes[] by nbshift
8655     int i,j;
8656     for(i=0; i<nbshift; i++) {
8657       const SMDS_MeshNode* n = nodes[0];
8658       for(j=0; j<nbFaceNodes-1; j++) {
8659         nodes[j] = nodes[j+1];
8660       }
8661       nodes[nbFaceNodes-1] = n;
8662     }
8663     il1 = il1 - nbshift;
8664     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8665     //   n0      n1     n2    n0      n1     n2
8666     //     +-----+-----+        +-----+-----+
8667     //      \         /         |           |
8668     //       \       /          |           |
8669     //      n5+     +n3       n7+           +n3
8670     //         \   /            |           |
8671     //          \ /             |           |
8672     //           +              +-----+-----+
8673     //           n4           n6      n5     n4
8674
8675     // create new elements
8676     SMESHDS_Mesh *aMesh = GetMeshDS();
8677     int aShapeId = FindShape( theFace );
8678
8679     int n1,n2,n3;
8680     if(nbFaceNodes==6) { // quadratic triangle
8681       SMDS_MeshElement* newElem =
8682         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8683       myLastCreatedElems.Append(newElem);
8684       if ( aShapeId && newElem )
8685         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8686       if(theFace->IsMediumNode(nodes[il1])) {
8687         // create quadrangle
8688         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8689         myLastCreatedElems.Append(newElem);
8690         if ( aShapeId && newElem )
8691           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8692         n1 = 1;
8693         n2 = 2;
8694         n3 = 3;
8695       }
8696       else {
8697         // create quadrangle
8698         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8699         myLastCreatedElems.Append(newElem);
8700         if ( aShapeId && newElem )
8701           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8702         n1 = 0;
8703         n2 = 1;
8704         n3 = 5;
8705       }
8706     }
8707     else { // nbFaceNodes==8 - quadratic quadrangle
8708       SMDS_MeshElement* newElem =
8709         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8710       myLastCreatedElems.Append(newElem);
8711       if ( aShapeId && newElem )
8712         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8713       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8714       myLastCreatedElems.Append(newElem);
8715       if ( aShapeId && newElem )
8716         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8717       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8718       myLastCreatedElems.Append(newElem);
8719       if ( aShapeId && newElem )
8720         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8721       if(theFace->IsMediumNode(nodes[il1])) {
8722         // create quadrangle
8723         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8724         myLastCreatedElems.Append(newElem);
8725         if ( aShapeId && newElem )
8726           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8727         n1 = 1;
8728         n2 = 2;
8729         n3 = 3;
8730       }
8731       else {
8732         // create quadrangle
8733         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8734         myLastCreatedElems.Append(newElem);
8735         if ( aShapeId && newElem )
8736           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8737         n1 = 0;
8738         n2 = 1;
8739         n3 = 7;
8740       }
8741     }
8742     // create needed triangles using n1,n2,n3 and inserted nodes
8743     int nbn = 2 + aNodesToInsert.size();
8744     //const SMDS_MeshNode* aNodes[nbn];
8745     vector<const SMDS_MeshNode*> aNodes(nbn);
8746     aNodes[0] = nodes[n1];
8747     aNodes[nbn-1] = nodes[n2];
8748     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8749     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8750       aNodes[iNode++] = *nIt;
8751     }
8752     for(i=1; i<nbn; i++) {
8753       SMDS_MeshElement* newElem =
8754         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8755       myLastCreatedElems.Append(newElem);
8756       if ( aShapeId && newElem )
8757         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8758     }
8759     // remove old quadratic face
8760     aMesh->RemoveElement(theFace);
8761   }
8762 }
8763
8764 //=======================================================================
8765 //function : UpdateVolumes
8766 //purpose  :
8767 //=======================================================================
8768 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8769                                       const SMDS_MeshNode*        theBetweenNode2,
8770                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8771 {
8772   myLastCreatedElems.Clear();
8773   myLastCreatedNodes.Clear();
8774
8775   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8776   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8777     const SMDS_MeshElement* elem = invElemIt->next();
8778
8779     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8780     SMDS_VolumeTool aVolume (elem);
8781     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8782       continue;
8783
8784     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8785     int iface, nbFaces = aVolume.NbFaces();
8786     vector<const SMDS_MeshNode *> poly_nodes;
8787     vector<int> quantities (nbFaces);
8788
8789     for (iface = 0; iface < nbFaces; iface++) {
8790       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8791       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8792       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8793
8794       for (int inode = 0; inode < nbFaceNodes; inode++) {
8795         poly_nodes.push_back(faceNodes[inode]);
8796
8797         if (nbInserted == 0) {
8798           if (faceNodes[inode] == theBetweenNode1) {
8799             if (faceNodes[inode + 1] == theBetweenNode2) {
8800               nbInserted = theNodesToInsert.size();
8801
8802               // add nodes to insert
8803               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8804               for (; nIt != theNodesToInsert.end(); nIt++) {
8805                 poly_nodes.push_back(*nIt);
8806               }
8807             }
8808           }
8809           else if (faceNodes[inode] == theBetweenNode2) {
8810             if (faceNodes[inode + 1] == theBetweenNode1) {
8811               nbInserted = theNodesToInsert.size();
8812
8813               // add nodes to insert in reversed order
8814               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8815               nIt--;
8816               for (; nIt != theNodesToInsert.begin(); nIt--) {
8817                 poly_nodes.push_back(*nIt);
8818               }
8819               poly_nodes.push_back(*nIt);
8820             }
8821           }
8822           else {
8823           }
8824         }
8825       }
8826       quantities[iface] = nbFaceNodes + nbInserted;
8827     }
8828
8829     // Replace or update the volume
8830     SMESHDS_Mesh *aMesh = GetMeshDS();
8831
8832     if (elem->IsPoly()) {
8833       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8834
8835     }
8836     else {
8837       int aShapeId = FindShape( elem );
8838
8839       SMDS_MeshElement* newElem =
8840         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8841       myLastCreatedElems.Append(newElem);
8842       if (aShapeId && newElem)
8843         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8844
8845       aMesh->RemoveElement(elem);
8846     }
8847   }
8848 }
8849
8850 //=======================================================================
8851 /*!
8852  * \brief Convert elements contained in a submesh to quadratic
8853  * \retval int - nb of checked elements
8854  */
8855 //=======================================================================
8856
8857 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8858                                              SMESH_MesherHelper& theHelper,
8859                                              const bool          theForce3d)
8860 {
8861   int nbElem = 0;
8862   if( !theSm ) return nbElem;
8863
8864   const bool notFromGroups = false;
8865   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8866   while(ElemItr->more())
8867   {
8868     nbElem++;
8869     const SMDS_MeshElement* elem = ElemItr->next();
8870     if( !elem || elem->IsQuadratic() ) continue;
8871
8872     int id = elem->GetID();
8873     int nbNodes = elem->NbNodes();
8874     vector<const SMDS_MeshNode *> aNds (nbNodes);
8875
8876     for(int i = 0; i < nbNodes; i++)
8877     {
8878       aNds[i] = elem->GetNode(i);
8879     }
8880     SMDSAbs_ElementType aType = elem->GetType();
8881
8882     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8883
8884     const SMDS_MeshElement* NewElem = 0;
8885
8886     switch( aType )
8887     {
8888     case SMDSAbs_Edge :
8889       {
8890         NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8891         break;
8892       }
8893     case SMDSAbs_Face :
8894       {
8895         switch(nbNodes)
8896         {
8897         case 3:
8898           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8899           break;
8900         case 4:
8901           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8902           break;
8903         default:
8904           continue;
8905         }
8906         break;
8907       }
8908     case SMDSAbs_Volume :
8909       {
8910         switch(nbNodes)
8911         {
8912         case 4:
8913           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8914           break;
8915         case 5:
8916           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8917           break;
8918         case 6:
8919           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8920           break;
8921         case 8:
8922           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8923                                         aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8924           break;
8925         default:
8926           continue;
8927         }
8928         break;
8929       }
8930     default :
8931       continue;
8932     }
8933     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8934     if( NewElem )
8935       theSm->AddElement( NewElem );
8936   }
8937   return nbElem;
8938 }
8939
8940 //=======================================================================
8941 //function : ConvertToQuadratic
8942 //purpose  :
8943 //=======================================================================
8944 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8945 {
8946   SMESHDS_Mesh* meshDS = GetMeshDS();
8947
8948   SMESH_MesherHelper aHelper(*myMesh);
8949   aHelper.SetIsQuadratic( true );
8950   const bool notFromGroups = false;
8951
8952   int nbCheckedElems = 0;
8953   if ( myMesh->HasShapeToMesh() )
8954   {
8955     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8956     {
8957       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8958       while ( smIt->more() ) {
8959         SMESH_subMesh* sm = smIt->next();
8960         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8961           aHelper.SetSubShape( sm->GetSubShape() );
8962           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8963         }
8964       }
8965     }
8966   }
8967   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8968   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8969   {
8970     SMESHDS_SubMesh *smDS = 0;
8971     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8972     while(aEdgeItr->more())
8973     {
8974       const SMDS_MeshEdge* edge = aEdgeItr->next();
8975       if(edge && !edge->IsQuadratic())
8976       {
8977         int id = edge->GetID();
8978         const SMDS_MeshNode* n1 = edge->GetNode(0);
8979         const SMDS_MeshNode* n2 = edge->GetNode(1);
8980
8981         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8982
8983         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8984         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8985       }
8986     }
8987     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8988     while(aFaceItr->more())
8989     {
8990       const SMDS_MeshFace* face = aFaceItr->next();
8991       if(!face || face->IsQuadratic() ) continue;
8992
8993       int id = face->GetID();
8994       int nbNodes = face->NbNodes();
8995       vector<const SMDS_MeshNode *> aNds (nbNodes);
8996
8997       for(int i = 0; i < nbNodes; i++)
8998       {
8999         aNds[i] = face->GetNode(i);
9000       }
9001
9002       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9003
9004       SMDS_MeshFace * NewFace = 0;
9005       switch(nbNodes)
9006       {
9007       case 3:
9008         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9009         break;
9010       case 4:
9011         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9012         break;
9013       default:
9014         continue;
9015       }
9016       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9017     }
9018     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9019     while(aVolumeItr->more())
9020     {
9021       const SMDS_MeshVolume* volume = aVolumeItr->next();
9022       if(!volume || volume->IsQuadratic() ) continue;
9023
9024       int id = volume->GetID();
9025       int nbNodes = volume->NbNodes();
9026       vector<const SMDS_MeshNode *> aNds (nbNodes);
9027
9028       for(int i = 0; i < nbNodes; i++)
9029       {
9030         aNds[i] = volume->GetNode(i);
9031       }
9032
9033       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9034
9035       SMDS_MeshVolume * NewVolume = 0;
9036       switch(nbNodes)
9037       {
9038       case 4:
9039         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9040                                       aNds[3], id, theForce3d );
9041         break;
9042       case 5:
9043         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9044                                       aNds[3], aNds[4], id, theForce3d);
9045         break;
9046       case 6:
9047         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9048                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
9049         break;
9050       case 8:
9051         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9052                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9053         break;
9054       default:
9055         continue;
9056       }
9057       ReplaceElemInGroups(volume, NewVolume, meshDS);
9058     }
9059   }
9060   if ( !theForce3d  && !getenv("NO_FixQuadraticElements")) {
9061     aHelper.SetSubShape(0); // apply to the whole mesh
9062     aHelper.FixQuadraticElements();
9063   }
9064 }
9065
9066 //=======================================================================
9067 /*!
9068  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9069  * \retval int - nb of checked elements
9070  */
9071 //=======================================================================
9072
9073 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9074                                      SMDS_ElemIteratorPtr theItr,
9075                                      const int            theShapeID)
9076 {
9077   int nbElem = 0;
9078   SMESHDS_Mesh* meshDS = GetMeshDS();
9079   const bool notFromGroups = false;
9080
9081   while( theItr->more() )
9082   {
9083     const SMDS_MeshElement* elem = theItr->next();
9084     nbElem++;
9085     if( elem && elem->IsQuadratic())
9086     {
9087       int id = elem->GetID();
9088       int nbNodes = elem->NbNodes();
9089       vector<const SMDS_MeshNode *> aNds, mediumNodes;
9090       aNds.reserve( nbNodes );
9091       mediumNodes.reserve( nbNodes );
9092
9093       for(int i = 0; i < nbNodes; i++)
9094       {
9095         const SMDS_MeshNode* n = elem->GetNode(i);
9096
9097         if( elem->IsMediumNode( n ) )
9098           mediumNodes.push_back( n );
9099         else
9100           aNds.push_back( n );
9101       }
9102       if( aNds.empty() ) continue;
9103       SMDSAbs_ElementType aType = elem->GetType();
9104
9105       //remove old quadratic element
9106       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9107
9108       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9109       ReplaceElemInGroups(elem, NewElem, meshDS);
9110       if( theSm && NewElem )
9111         theSm->AddElement( NewElem );
9112
9113       // remove medium nodes
9114       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9115       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9116         const SMDS_MeshNode* n = *nIt;
9117         if ( n->NbInverseElements() == 0 ) {
9118           if ( n->GetPosition()->GetShapeId() != theShapeID )
9119             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9120                                     ( n->GetPosition()->GetShapeId() ));
9121           else
9122             meshDS->RemoveFreeNode( n, theSm );
9123         }
9124       }
9125     }
9126   }
9127   return nbElem;
9128 }
9129
9130 //=======================================================================
9131 //function : ConvertFromQuadratic
9132 //purpose  :
9133 //=======================================================================
9134 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9135 {
9136   int nbCheckedElems = 0;
9137   if ( myMesh->HasShapeToMesh() )
9138   {
9139     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9140     {
9141       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9142       while ( smIt->more() ) {
9143         SMESH_subMesh* sm = smIt->next();
9144         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9145           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9146       }
9147     }
9148   }
9149
9150   int totalNbElems =
9151     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9152   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9153   {
9154     SMESHDS_SubMesh *aSM = 0;
9155     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9156   }
9157
9158   return true;
9159 }
9160
9161 //=======================================================================
9162 //function : SewSideElements
9163 //purpose  :
9164 //=======================================================================
9165
9166 SMESH_MeshEditor::Sew_Error
9167 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9168                                    TIDSortedElemSet&    theSide2,
9169                                    const SMDS_MeshNode* theFirstNode1,
9170                                    const SMDS_MeshNode* theFirstNode2,
9171                                    const SMDS_MeshNode* theSecondNode1,
9172                                    const SMDS_MeshNode* theSecondNode2)
9173 {
9174   myLastCreatedElems.Clear();
9175   myLastCreatedNodes.Clear();
9176
9177   MESSAGE ("::::SewSideElements()");
9178   if ( theSide1.size() != theSide2.size() )
9179     return SEW_DIFF_NB_OF_ELEMENTS;
9180
9181   Sew_Error aResult = SEW_OK;
9182   // Algo:
9183   // 1. Build set of faces representing each side
9184   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9185   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9186
9187   // =======================================================================
9188   // 1. Build set of faces representing each side:
9189   // =======================================================================
9190   // a. build set of nodes belonging to faces
9191   // b. complete set of faces: find missing fices whose nodes are in set of nodes
9192   // c. create temporary faces representing side of volumes if correspondent
9193   //    face does not exist
9194
9195   SMESHDS_Mesh* aMesh = GetMeshDS();
9196   SMDS_Mesh aTmpFacesMesh;
9197   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9198   set<const SMDS_MeshElement*> volSet1,  volSet2;
9199   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9200   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9201   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9202   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9203   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9204   int iSide, iFace, iNode;
9205
9206   for ( iSide = 0; iSide < 2; iSide++ ) {
9207     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9208     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9209     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9210     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9211     set<const SMDS_MeshElement*>::iterator vIt;
9212     TIDSortedElemSet::iterator eIt;
9213     set<const SMDS_MeshNode*>::iterator    nIt;
9214
9215     // check that given nodes belong to given elements
9216     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9217     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9218     int firstIndex = -1, secondIndex = -1;
9219     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9220       const SMDS_MeshElement* elem = *eIt;
9221       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9222       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9223       if ( firstIndex > -1 && secondIndex > -1 ) break;
9224     }
9225     if ( firstIndex < 0 || secondIndex < 0 ) {
9226       // we can simply return until temporary faces created
9227       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9228     }
9229
9230     // -----------------------------------------------------------
9231     // 1a. Collect nodes of existing faces
9232     //     and build set of face nodes in order to detect missing
9233     //     faces corresponing to sides of volumes
9234     // -----------------------------------------------------------
9235
9236     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9237
9238     // loop on the given element of a side
9239     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9240       //const SMDS_MeshElement* elem = *eIt;
9241       const SMDS_MeshElement* elem = *eIt;
9242       if ( elem->GetType() == SMDSAbs_Face ) {
9243         faceSet->insert( elem );
9244         set <const SMDS_MeshNode*> faceNodeSet;
9245         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9246         while ( nodeIt->more() ) {
9247           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9248           nodeSet->insert( n );
9249           faceNodeSet.insert( n );
9250         }
9251         setOfFaceNodeSet.insert( faceNodeSet );
9252       }
9253       else if ( elem->GetType() == SMDSAbs_Volume )
9254         volSet->insert( elem );
9255     }
9256     // ------------------------------------------------------------------------------
9257     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9258     // ------------------------------------------------------------------------------
9259
9260     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9261       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9262       while ( fIt->more() ) { // loop on faces sharing a node
9263         const SMDS_MeshElement* f = fIt->next();
9264         if ( faceSet->find( f ) == faceSet->end() ) {
9265           // check if all nodes are in nodeSet and
9266           // complete setOfFaceNodeSet if they are
9267           set <const SMDS_MeshNode*> faceNodeSet;
9268           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9269           bool allInSet = true;
9270           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9271             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9272             if ( nodeSet->find( n ) == nodeSet->end() )
9273               allInSet = false;
9274             else
9275               faceNodeSet.insert( n );
9276           }
9277           if ( allInSet ) {
9278             faceSet->insert( f );
9279             setOfFaceNodeSet.insert( faceNodeSet );
9280           }
9281         }
9282       }
9283     }
9284
9285     // -------------------------------------------------------------------------
9286     // 1c. Create temporary faces representing sides of volumes if correspondent
9287     //     face does not exist
9288     // -------------------------------------------------------------------------
9289
9290     if ( !volSet->empty() ) {
9291       //int nodeSetSize = nodeSet->size();
9292
9293       // loop on given volumes
9294       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9295         SMDS_VolumeTool vol (*vIt);
9296         // loop on volume faces: find free faces
9297         // --------------------------------------
9298         list<const SMDS_MeshElement* > freeFaceList;
9299         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9300           if ( !vol.IsFreeFace( iFace ))
9301             continue;
9302           // check if there is already a face with same nodes in a face set
9303           const SMDS_MeshElement* aFreeFace = 0;
9304           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9305           int nbNodes = vol.NbFaceNodes( iFace );
9306           set <const SMDS_MeshNode*> faceNodeSet;
9307           vol.GetFaceNodes( iFace, faceNodeSet );
9308           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9309           if ( isNewFace ) {
9310             // no such a face is given but it still can exist, check it
9311             if ( nbNodes == 3 ) {
9312               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9313             }
9314             else if ( nbNodes == 4 ) {
9315               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9316             }
9317             else {
9318               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9319               aFreeFace = aMesh->FindFace(poly_nodes);
9320             }
9321           }
9322           if ( !aFreeFace ) {
9323             // create a temporary face
9324             if ( nbNodes == 3 ) {
9325               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9326             }
9327             else if ( nbNodes == 4 ) {
9328               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9329             }
9330             else {
9331               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9332               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9333             }
9334           }
9335           if ( aFreeFace )
9336             freeFaceList.push_back( aFreeFace );
9337
9338         } // loop on faces of a volume
9339
9340         // choose one of several free faces
9341         // --------------------------------------
9342         if ( freeFaceList.size() > 1 ) {
9343           // choose a face having max nb of nodes shared by other elems of a side
9344           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9345           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9346           while ( fIt != freeFaceList.end() ) { // loop on free faces
9347             int nbSharedNodes = 0;
9348             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9349             while ( nodeIt->more() ) { // loop on free face nodes
9350               const SMDS_MeshNode* n =
9351                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9352               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9353               while ( invElemIt->more() ) {
9354                 const SMDS_MeshElement* e = invElemIt->next();
9355                 if ( faceSet->find( e ) != faceSet->end() )
9356                   nbSharedNodes++;
9357                 if ( elemSet->find( e ) != elemSet->end() )
9358                   nbSharedNodes++;
9359               }
9360             }
9361             if ( nbSharedNodes >= maxNbNodes ) {
9362               maxNbNodes = nbSharedNodes;
9363               fIt++;
9364             }
9365             else
9366               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9367           }
9368           if ( freeFaceList.size() > 1 )
9369           {
9370             // could not choose one face, use another way
9371             // choose a face most close to the bary center of the opposite side
9372             gp_XYZ aBC( 0., 0., 0. );
9373             set <const SMDS_MeshNode*> addedNodes;
9374             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9375             eIt = elemSet2->begin();
9376             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9377               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9378               while ( nodeIt->more() ) { // loop on free face nodes
9379                 const SMDS_MeshNode* n =
9380                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9381                 if ( addedNodes.insert( n ).second )
9382                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9383               }
9384             }
9385             aBC /= addedNodes.size();
9386             double minDist = DBL_MAX;
9387             fIt = freeFaceList.begin();
9388             while ( fIt != freeFaceList.end() ) { // loop on free faces
9389               double dist = 0;
9390               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9391               while ( nodeIt->more() ) { // loop on free face nodes
9392                 const SMDS_MeshNode* n =
9393                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9394                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9395                 dist += ( aBC - p ).SquareModulus();
9396               }
9397               if ( dist < minDist ) {
9398                 minDist = dist;
9399                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9400               }
9401               else
9402                 fIt = freeFaceList.erase( fIt++ );
9403             }
9404           }
9405         } // choose one of several free faces of a volume
9406
9407         if ( freeFaceList.size() == 1 ) {
9408           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9409           faceSet->insert( aFreeFace );
9410           // complete a node set with nodes of a found free face
9411           //           for ( iNode = 0; iNode < ; iNode++ )
9412           //             nodeSet->insert( fNodes[ iNode ] );
9413         }
9414
9415       } // loop on volumes of a side
9416
9417       //       // complete a set of faces if new nodes in a nodeSet appeared
9418       //       // ----------------------------------------------------------
9419       //       if ( nodeSetSize != nodeSet->size() ) {
9420       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9421       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9422       //           while ( fIt->more() ) { // loop on faces sharing a node
9423       //             const SMDS_MeshElement* f = fIt->next();
9424       //             if ( faceSet->find( f ) == faceSet->end() ) {
9425       //               // check if all nodes are in nodeSet and
9426       //               // complete setOfFaceNodeSet if they are
9427       //               set <const SMDS_MeshNode*> faceNodeSet;
9428       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9429       //               bool allInSet = true;
9430       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9431       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9432       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9433       //                   allInSet = false;
9434       //                 else
9435       //                   faceNodeSet.insert( n );
9436       //               }
9437       //               if ( allInSet ) {
9438       //                 faceSet->insert( f );
9439       //                 setOfFaceNodeSet.insert( faceNodeSet );
9440       //               }
9441       //             }
9442       //           }
9443       //         }
9444       //       }
9445     } // Create temporary faces, if there are volumes given
9446   } // loop on sides
9447
9448   if ( faceSet1.size() != faceSet2.size() ) {
9449     // delete temporary faces: they are in reverseElements of actual nodes
9450     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9451     while ( tmpFaceIt->more() )
9452       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9453     MESSAGE("Diff nb of faces");
9454     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9455   }
9456
9457   // ============================================================
9458   // 2. Find nodes to merge:
9459   //              bind a node to remove to a node to put instead
9460   // ============================================================
9461
9462   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9463   if ( theFirstNode1 != theFirstNode2 )
9464     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9465   if ( theSecondNode1 != theSecondNode2 )
9466     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9467
9468   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9469   set< long > linkIdSet; // links to process
9470   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9471
9472   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9473   list< NLink > linkList[2];
9474   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9475   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9476   // loop on links in linkList; find faces by links and append links
9477   // of the found faces to linkList
9478   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9479   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9480     NLink link[] = { *linkIt[0], *linkIt[1] };
9481     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9482     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9483       continue;
9484
9485     // by links, find faces in the face sets,
9486     // and find indices of link nodes in the found faces;
9487     // in a face set, there is only one or no face sharing a link
9488     // ---------------------------------------------------------------
9489
9490     const SMDS_MeshElement* face[] = { 0, 0 };
9491     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9492     vector<const SMDS_MeshNode*> fnodes1(9);
9493     vector<const SMDS_MeshNode*> fnodes2(9);
9494     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9495     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9496     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9497     int iLinkNode[2][2];
9498     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9499       const SMDS_MeshNode* n1 = link[iSide].first;
9500       const SMDS_MeshNode* n2 = link[iSide].second;
9501       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9502       set< const SMDS_MeshElement* > fMap;
9503       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9504         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9505         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9506         while ( fIt->more() ) { // loop on faces sharing a node
9507           const SMDS_MeshElement* f = fIt->next();
9508           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9509               ! fMap.insert( f ).second ) // f encounters twice
9510           {
9511             if ( face[ iSide ] ) {
9512               MESSAGE( "2 faces per link " );
9513               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9514               break;
9515             }
9516             face[ iSide ] = f;
9517             faceSet->erase( f );
9518             // get face nodes and find ones of a link
9519             iNode = 0;
9520             int nbl = -1;
9521             if(f->IsPoly()) {
9522               if(iSide==0) {
9523                 fnodes1.resize(f->NbNodes()+1);
9524                 notLinkNodes1.resize(f->NbNodes()-2);
9525               }
9526               else {
9527                 fnodes2.resize(f->NbNodes()+1);
9528                 notLinkNodes2.resize(f->NbNodes()-2);
9529               }
9530             }
9531             if(!f->IsQuadratic()) {
9532               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9533               while ( nIt->more() ) {
9534                 const SMDS_MeshNode* n =
9535                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9536                 if ( n == n1 ) {
9537                   iLinkNode[ iSide ][ 0 ] = iNode;
9538                 }
9539                 else if ( n == n2 ) {
9540                   iLinkNode[ iSide ][ 1 ] = iNode;
9541                 }
9542                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9543                 //  notLinkNodes[ iSide ][ 1 ] = n;
9544                 //else
9545                 //  notLinkNodes[ iSide ][ 0 ] = n;
9546                 else {
9547                   nbl++;
9548                   if(iSide==0)
9549                     notLinkNodes1[nbl] = n;
9550                   //notLinkNodes1.push_back(n);
9551                   else
9552                     notLinkNodes2[nbl] = n;
9553                   //notLinkNodes2.push_back(n);
9554                 }
9555                 //faceNodes[ iSide ][ iNode++ ] = n;
9556                 if(iSide==0) {
9557                   fnodes1[iNode++] = n;
9558                 }
9559                 else {
9560                   fnodes2[iNode++] = n;
9561                 }
9562               }
9563             }
9564             else { // f->IsQuadratic()
9565               const SMDS_QuadraticFaceOfNodes* F =
9566                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9567               // use special nodes iterator
9568               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9569               while ( anIter->more() ) {
9570                 const SMDS_MeshNode* n =
9571                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9572                 if ( n == n1 ) {
9573                   iLinkNode[ iSide ][ 0 ] = iNode;
9574                 }
9575                 else if ( n == n2 ) {
9576                   iLinkNode[ iSide ][ 1 ] = iNode;
9577                 }
9578                 else {
9579                   nbl++;
9580                   if(iSide==0) {
9581                     notLinkNodes1[nbl] = n;
9582                   }
9583                   else {
9584                     notLinkNodes2[nbl] = n;
9585                   }
9586                 }
9587                 if(iSide==0) {
9588                   fnodes1[iNode++] = n;
9589                 }
9590                 else {
9591                   fnodes2[iNode++] = n;
9592                 }
9593               }
9594             }
9595             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9596             if(iSide==0) {
9597               fnodes1[iNode] = fnodes1[0];
9598             }
9599             else {
9600               fnodes2[iNode] = fnodes1[0];
9601             }
9602           }
9603         }
9604       }
9605     }
9606
9607     // check similarity of elements of the sides
9608     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9609       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9610       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9611         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9612       }
9613       else {
9614         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9615       }
9616       break; // do not return because it s necessary to remove tmp faces
9617     }
9618
9619     // set nodes to merge
9620     // -------------------
9621
9622     if ( face[0] && face[1] )  {
9623       int nbNodes = face[0]->NbNodes();
9624       if ( nbNodes != face[1]->NbNodes() ) {
9625         MESSAGE("Diff nb of face nodes");
9626         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9627         break; // do not return because it s necessary to remove tmp faces
9628       }
9629       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9630       if ( nbNodes == 3 ) {
9631         //nReplaceMap.insert( TNodeNodeMap::value_type
9632         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9633         nReplaceMap.insert( TNodeNodeMap::value_type
9634                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9635       }
9636       else {
9637         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9638           // analyse link orientation in faces
9639           int i1 = iLinkNode[ iSide ][ 0 ];
9640           int i2 = iLinkNode[ iSide ][ 1 ];
9641           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9642           // if notLinkNodes are the first and the last ones, then
9643           // their order does not correspond to the link orientation
9644           if (( i1 == 1 && i2 == 2 ) ||
9645               ( i1 == 2 && i2 == 1 ))
9646             reverse[ iSide ] = !reverse[ iSide ];
9647         }
9648         if ( reverse[0] == reverse[1] ) {
9649           //nReplaceMap.insert( TNodeNodeMap::value_type
9650           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9651           //nReplaceMap.insert( TNodeNodeMap::value_type
9652           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9653           for(int nn=0; nn<nbNodes-2; nn++) {
9654             nReplaceMap.insert( TNodeNodeMap::value_type
9655                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9656           }
9657         }
9658         else {
9659           //nReplaceMap.insert( TNodeNodeMap::value_type
9660           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9661           //nReplaceMap.insert( TNodeNodeMap::value_type
9662           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9663           for(int nn=0; nn<nbNodes-2; nn++) {
9664             nReplaceMap.insert( TNodeNodeMap::value_type
9665                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9666           }
9667         }
9668       }
9669
9670       // add other links of the faces to linkList
9671       // -----------------------------------------
9672
9673       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9674       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9675         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9676         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9677         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9678         if ( !iter_isnew.second ) { // already in a set: no need to process
9679           linkIdSet.erase( iter_isnew.first );
9680         }
9681         else // new in set == encountered for the first time: add
9682         {
9683           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9684           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9685           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9686           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9687           linkList[0].push_back ( NLink( n1, n2 ));
9688           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9689         }
9690       }
9691     } // 2 faces found
9692   } // loop on link lists
9693
9694   if ( aResult == SEW_OK &&
9695        ( linkIt[0] != linkList[0].end() ||
9696          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9697     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9698              " " << (faceSetPtr[1]->empty()));
9699     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9700   }
9701
9702   // ====================================================================
9703   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9704   // ====================================================================
9705
9706   // delete temporary faces: they are in reverseElements of actual nodes
9707   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9708   while ( tmpFaceIt->more() )
9709     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9710
9711   if ( aResult != SEW_OK)
9712     return aResult;
9713
9714   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9715   // loop on nodes replacement map
9716   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9717   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9718     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9719       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9720       nodeIDsToRemove.push_back( nToRemove->GetID() );
9721       // loop on elements sharing nToRemove
9722       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9723       while ( invElemIt->more() ) {
9724         const SMDS_MeshElement* e = invElemIt->next();
9725         // get a new suite of nodes: make replacement
9726         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9727         vector< const SMDS_MeshNode*> nodes( nbNodes );
9728         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9729         while ( nIt->more() ) {
9730           const SMDS_MeshNode* n =
9731             static_cast<const SMDS_MeshNode*>( nIt->next() );
9732           nnIt = nReplaceMap.find( n );
9733           if ( nnIt != nReplaceMap.end() ) {
9734             nbReplaced++;
9735             n = (*nnIt).second;
9736           }
9737           nodes[ i++ ] = n;
9738         }
9739         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9740         //         elemIDsToRemove.push_back( e->GetID() );
9741         //       else
9742         if ( nbReplaced )
9743           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9744       }
9745     }
9746
9747   Remove( nodeIDsToRemove, true );
9748
9749   return aResult;
9750 }
9751
9752 //================================================================================
9753 /*!
9754  * \brief Find corresponding nodes in two sets of faces
9755  * \param theSide1 - first face set
9756  * \param theSide2 - second first face
9757  * \param theFirstNode1 - a boundary node of set 1
9758  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9759  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9760  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9761  * \param nReplaceMap - output map of corresponding nodes
9762  * \retval bool  - is a success or not
9763  */
9764 //================================================================================
9765
9766 #ifdef _DEBUG_
9767 //#define DEBUG_MATCHING_NODES
9768 #endif
9769
9770 SMESH_MeshEditor::Sew_Error
9771 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9772                                     set<const SMDS_MeshElement*>& theSide2,
9773                                     const SMDS_MeshNode*          theFirstNode1,
9774                                     const SMDS_MeshNode*          theFirstNode2,
9775                                     const SMDS_MeshNode*          theSecondNode1,
9776                                     const SMDS_MeshNode*          theSecondNode2,
9777                                     TNodeNodeMap &                nReplaceMap)
9778 {
9779   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9780
9781   nReplaceMap.clear();
9782   if ( theFirstNode1 != theFirstNode2 )
9783     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9784   if ( theSecondNode1 != theSecondNode2 )
9785     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9786
9787   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9788   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9789
9790   list< NLink > linkList[2];
9791   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9792   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9793
9794   // loop on links in linkList; find faces by links and append links
9795   // of the found faces to linkList
9796   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9797   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9798     NLink link[] = { *linkIt[0], *linkIt[1] };
9799     if ( linkSet.find( link[0] ) == linkSet.end() )
9800       continue;
9801
9802     // by links, find faces in the face sets,
9803     // and find indices of link nodes in the found faces;
9804     // in a face set, there is only one or no face sharing a link
9805     // ---------------------------------------------------------------
9806
9807     const SMDS_MeshElement* face[] = { 0, 0 };
9808     list<const SMDS_MeshNode*> notLinkNodes[2];
9809     //bool reverse[] = { false, false }; // order of notLinkNodes
9810     int nbNodes[2];
9811     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9812     {
9813       const SMDS_MeshNode* n1 = link[iSide].first;
9814       const SMDS_MeshNode* n2 = link[iSide].second;
9815       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9816       set< const SMDS_MeshElement* > facesOfNode1;
9817       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9818       {
9819         // during a loop of the first node, we find all faces around n1,
9820         // during a loop of the second node, we find one face sharing both n1 and n2
9821         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9822         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9823         while ( fIt->more() ) { // loop on faces sharing a node
9824           const SMDS_MeshElement* f = fIt->next();
9825           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9826               ! facesOfNode1.insert( f ).second ) // f encounters twice
9827           {
9828             if ( face[ iSide ] ) {
9829               MESSAGE( "2 faces per link " );
9830               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9831             }
9832             face[ iSide ] = f;
9833             faceSet->erase( f );
9834
9835             // get not link nodes
9836             int nbN = f->NbNodes();
9837             if ( f->IsQuadratic() )
9838               nbN /= 2;
9839             nbNodes[ iSide ] = nbN;
9840             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9841             int i1 = f->GetNodeIndex( n1 );
9842             int i2 = f->GetNodeIndex( n2 );
9843             int iEnd = nbN, iBeg = -1, iDelta = 1;
9844             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9845             if ( reverse ) {
9846               std::swap( iEnd, iBeg ); iDelta = -1;
9847             }
9848             int i = i2;
9849             while ( true ) {
9850               i += iDelta;
9851               if ( i == iEnd ) i = iBeg + iDelta;
9852               if ( i == i1 ) break;
9853               nodes.push_back ( f->GetNode( i ) );
9854             }
9855           }
9856         }
9857       }
9858     }
9859     // check similarity of elements of the sides
9860     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9861       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9862       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9863         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9864       }
9865       else {
9866         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9867       }
9868     }
9869
9870     // set nodes to merge
9871     // -------------------
9872
9873     if ( face[0] && face[1] )  {
9874       if ( nbNodes[0] != nbNodes[1] ) {
9875         MESSAGE("Diff nb of face nodes");
9876         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9877       }
9878 #ifdef DEBUG_MATCHING_NODES
9879       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9880                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9881                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9882 #endif
9883       int nbN = nbNodes[0];
9884       {
9885         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9886         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9887         for ( int i = 0 ; i < nbN - 2; ++i ) {
9888 #ifdef DEBUG_MATCHING_NODES
9889           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9890 #endif
9891           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9892         }
9893       }
9894
9895       // add other links of the face 1 to linkList
9896       // -----------------------------------------
9897
9898       const SMDS_MeshElement* f0 = face[0];
9899       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9900       for ( int i = 0; i < nbN; i++ )
9901       {
9902         const SMDS_MeshNode* n2 = f0->GetNode( i );
9903         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9904           linkSet.insert( SMESH_TLink( n1, n2 ));
9905         if ( !iter_isnew.second ) { // already in a set: no need to process
9906           linkSet.erase( iter_isnew.first );
9907         }
9908         else // new in set == encountered for the first time: add
9909         {
9910 #ifdef DEBUG_MATCHING_NODES
9911           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9912                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9913 #endif
9914           linkList[0].push_back ( NLink( n1, n2 ));
9915           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9916         }
9917         n1 = n2;
9918       }
9919     } // 2 faces found
9920   } // loop on link lists
9921
9922   return SEW_OK;
9923 }
9924
9925 //================================================================================
9926 /*!
9927   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9928   \param theElems - the list of elements (edges or faces) to be replicated
9929   The nodes for duplication could be found from these elements
9930   \param theNodesNot - list of nodes to NOT replicate
9931   \param theAffectedElems - the list of elements (cells and edges) to which the 
9932   replicated nodes should be associated to.
9933   \return TRUE if operation has been completed successfully, FALSE otherwise
9934 */
9935 //================================================================================
9936
9937 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9938                                     const TIDSortedElemSet& theNodesNot,
9939                                     const TIDSortedElemSet& theAffectedElems )
9940 {
9941   myLastCreatedElems.Clear();
9942   myLastCreatedNodes.Clear();
9943
9944   if ( theElems.size() == 0 )
9945     return false;
9946
9947   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9948   if ( !aMeshDS )
9949     return false;
9950
9951   bool res = false;
9952   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9953   // duplicate elements and nodes
9954   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9955   // replce nodes by duplications
9956   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9957   return res;
9958 }
9959
9960 //================================================================================
9961 /*!
9962   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9963   \param theMeshDS - mesh instance
9964   \param theElems - the elements replicated or modified (nodes should be changed)
9965   \param theNodesNot - nodes to NOT replicate
9966   \param theNodeNodeMap - relation of old node to new created node
9967   \param theIsDoubleElem - flag os to replicate element or modify
9968   \return TRUE if operation has been completed successfully, FALSE otherwise
9969 */
9970 //================================================================================
9971
9972 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9973                                     const TIDSortedElemSet& theElems,
9974                                     const TIDSortedElemSet& theNodesNot,
9975                                     std::map< const SMDS_MeshNode*,
9976                                     const SMDS_MeshNode* >& theNodeNodeMap,
9977                                     const bool theIsDoubleElem )
9978 {
9979   // iterate on through element and duplicate them (by nodes duplication)
9980   bool res = false;
9981   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9982   for ( ;  elemItr != theElems.end(); ++elemItr )
9983   {
9984     const SMDS_MeshElement* anElem = *elemItr;
9985     if (!anElem)
9986       continue;
9987
9988     bool isDuplicate = false;
9989     // duplicate nodes to duplicate element
9990     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9991     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9992     int ind = 0;
9993     while ( anIter->more() ) 
9994     { 
9995
9996       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9997       SMDS_MeshNode* aNewNode = aCurrNode;
9998       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9999         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10000       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10001       {
10002         // duplicate node
10003         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10004         theNodeNodeMap[ aCurrNode ] = aNewNode;
10005         myLastCreatedNodes.Append( aNewNode );
10006       }
10007       isDuplicate |= (aCurrNode != aNewNode);
10008       newNodes[ ind++ ] = aNewNode;
10009     }
10010     if ( !isDuplicate )
10011       continue;
10012
10013     if ( theIsDoubleElem )
10014       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10015     else
10016       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10017
10018     res = true;
10019   }
10020   return res;
10021 }
10022
10023 //================================================================================
10024 /*!
10025   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10026   \param theNodes - identifiers of nodes to be doubled
10027   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10028          nodes. If list of element identifiers is empty then nodes are doubled but 
10029          they not assigned to elements
10030   \return TRUE if operation has been completed successfully, FALSE otherwise
10031 */
10032 //================================================================================
10033
10034 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10035                                     const std::list< int >& theListOfModifiedElems )
10036 {
10037   myLastCreatedElems.Clear();
10038   myLastCreatedNodes.Clear();
10039
10040   if ( theListOfNodes.size() == 0 )
10041     return false;
10042
10043   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10044   if ( !aMeshDS )
10045     return false;
10046
10047   // iterate through nodes and duplicate them
10048
10049   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10050
10051   std::list< int >::const_iterator aNodeIter;
10052   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10053   {
10054     int aCurr = *aNodeIter;
10055     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10056     if ( !aNode )
10057       continue;
10058
10059     // duplicate node
10060
10061     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10062     if ( aNewNode )
10063     {
10064       anOldNodeToNewNode[ aNode ] = aNewNode;
10065       myLastCreatedNodes.Append( aNewNode );
10066     }
10067   }
10068
10069   // Create map of new nodes for modified elements
10070
10071   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10072
10073   std::list< int >::const_iterator anElemIter;
10074   for ( anElemIter = theListOfModifiedElems.begin(); 
10075         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10076   {
10077     int aCurr = *anElemIter;
10078     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10079     if ( !anElem )
10080       continue;
10081
10082     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10083
10084     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10085     int ind = 0;
10086     while ( anIter->more() ) 
10087     { 
10088       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10089       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10090       {
10091         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10092         aNodeArr[ ind++ ] = aNewNode;
10093       }
10094       else
10095         aNodeArr[ ind++ ] = aCurrNode;
10096     }
10097     anElemToNodes[ anElem ] = aNodeArr;
10098   }
10099
10100   // Change nodes of elements  
10101
10102   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10103     anElemToNodesIter = anElemToNodes.begin();
10104   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10105   {
10106     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10107     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10108     if ( anElem )
10109       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10110   }
10111
10112   return true;
10113 }
10114
10115 namespace {
10116
10117   //================================================================================
10118   /*!
10119   \brief Check if element located inside shape
10120   \return TRUE if IN or ON shape, FALSE otherwise
10121   */
10122   //================================================================================
10123
10124   template<class Classifier>
10125   bool isInside(const SMDS_MeshElement* theElem,
10126                 Classifier&             theClassifier,
10127                 const double            theTol)
10128   {
10129     gp_XYZ centerXYZ (0, 0, 0);
10130     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10131     while (aNodeItr->more())
10132       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10133
10134     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10135     theClassifier.Perform(aPnt, theTol);
10136     TopAbs_State aState = theClassifier.State();
10137     return (aState == TopAbs_IN || aState == TopAbs_ON );
10138   }
10139
10140   //================================================================================
10141   /*!
10142    * \brief Classifier of the 3D point on the TopoDS_Face
10143    *        with interaface suitable for isInside()
10144    */
10145   //================================================================================
10146
10147   struct _FaceClassifier
10148   {
10149     Extrema_ExtPS       _extremum;
10150     BRepAdaptor_Surface _surface;
10151     TopAbs_State        _state;
10152
10153     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10154     {
10155       _extremum.Initialize( _surface,
10156                             _surface.FirstUParameter(), _surface.LastUParameter(),
10157                             _surface.FirstVParameter(), _surface.LastVParameter(),
10158                             _surface.Tolerance(), _surface.Tolerance() );
10159     }
10160     void Perform(const gp_Pnt& aPnt, double theTol)
10161     {
10162       _state = TopAbs_OUT;
10163       _extremum.Perform(aPnt);
10164       if ( _extremum.IsDone() )
10165         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10166           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10167     }
10168     TopAbs_State State() const
10169     {
10170       return _state;
10171     }
10172   };
10173 }
10174
10175 //================================================================================
10176 /*!
10177   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10178   \param theElems - group of of elements (edges or faces) to be replicated
10179   \param theNodesNot - group of nodes not to replicate
10180   \param theShape - shape to detect affected elements (element which geometric center
10181   located on or inside shape).
10182   The replicated nodes should be associated to affected elements.
10183   \return TRUE if operation has been completed successfully, FALSE otherwise
10184 */
10185 //================================================================================
10186
10187 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10188                                             const TIDSortedElemSet& theNodesNot,
10189                                             const TopoDS_Shape&     theShape )
10190 {
10191   if ( theShape.IsNull() )
10192     return false;
10193
10194   const double aTol = Precision::Confusion();
10195   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10196   auto_ptr<_FaceClassifier>              aFaceClassifier;
10197   if ( theShape.ShapeType() == TopAbs_SOLID )
10198   {
10199     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10200     bsc3d->PerformInfinitePoint(aTol);
10201   }
10202   else if (theShape.ShapeType() == TopAbs_FACE )
10203   {
10204     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10205   }
10206
10207   // iterates on indicated elements and get elements by back references from their nodes
10208   TIDSortedElemSet anAffected;
10209   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10210   for ( ;  elemItr != theElems.end(); ++elemItr )
10211   {
10212     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10213     if (!anElem)
10214       continue;
10215
10216     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10217     while ( nodeItr->more() )
10218     {
10219       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10220       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10221         continue;
10222       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10223       while ( backElemItr->more() )
10224       {
10225         const SMDS_MeshElement* curElem = backElemItr->next();
10226         if ( curElem && theElems.find(curElem) == theElems.end() &&
10227              ( bsc3d.get() ?
10228                isInside( curElem, *bsc3d, aTol ) :
10229                isInside( curElem, *aFaceClassifier, aTol )))
10230           anAffected.insert( curElem );
10231       }
10232     }
10233   }
10234   return DoubleNodes( theElems, theNodesNot, anAffected );
10235 }
10236
10237 //================================================================================
10238 /*!
10239  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10240  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10241  * \return TRUE if operation has been completed successfully, FALSE otherwise
10242  */
10243 //================================================================================
10244
10245 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10246 {
10247   // iterates on volume elements and detect all free faces on them
10248   SMESHDS_Mesh* aMesh = GetMeshDS();
10249   if (!aMesh)
10250     return false;
10251   //bool res = false;
10252   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10253   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10254   while(vIt->more())
10255   {
10256     const SMDS_MeshVolume* volume = vIt->next();
10257     SMDS_VolumeTool vTool( volume );
10258     vTool.SetExternalNormal();
10259     const bool isPoly = volume->IsPoly();
10260     const bool isQuad = volume->IsQuadratic();
10261     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10262     {
10263       if (!vTool.IsFreeFace(iface))
10264         continue;
10265       nbFree++;
10266       vector<const SMDS_MeshNode *> nodes;
10267       int nbFaceNodes = vTool.NbFaceNodes(iface);
10268       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10269       int inode = 0;
10270       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10271         nodes.push_back(faceNodes[inode]);
10272       if (isQuad)
10273         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10274           nodes.push_back(faceNodes[inode]);
10275
10276       // add new face based on volume nodes
10277       if (aMesh->FindFace( nodes ) ) {
10278         nbExisted++;
10279         continue; // face already exsist
10280       }
10281       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10282       nbCreated++;
10283     }
10284   }
10285   return ( nbFree==(nbExisted+nbCreated) );
10286 }