Salome HOME
Fix bug of NodeSearcher: search fails if point is outside the mesh on the distance...
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
48
49 #include "utilities.h"
50
51 #include <BRepAdaptor_Surface.hxx>
52 #include <BRepClass3d_SolidClassifier.hxx>
53 #include <BRep_Tool.hxx>
54 #include <ElCLib.hxx>
55 #include <Extrema_GenExtPS.hxx>
56 #include <Extrema_POnCurv.hxx>
57 #include <Extrema_POnSurf.hxx>
58 #include <GC_MakeSegment.hxx>
59 #include <Geom2d_Curve.hxx>
60 #include <GeomAPI_ExtremaCurveCurve.hxx>
61 #include <GeomAdaptor_Surface.hxx>
62 #include <Geom_Curve.hxx>
63 #include <Geom_Line.hxx>
64 #include <Geom_Surface.hxx>
65 #include <IntAna_IntConicQuad.hxx>
66 #include <IntAna_Quadric.hxx>
67 #include <Precision.hxx>
68 #include <TColStd_ListOfInteger.hxx>
69 #include <TopAbs_State.hxx>
70 #include <TopExp.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopTools_ListIteratorOfListOfShape.hxx>
73 #include <TopTools_ListOfShape.hxx>
74 #include <TopTools_SequenceOfShape.hxx>
75 #include <TopoDS.hxx>
76 #include <TopoDS_Face.hxx>
77 #include <gp.hxx>
78 #include <gp_Ax1.hxx>
79 #include <gp_Dir.hxx>
80 #include <gp_Lin.hxx>
81 #include <gp_Pln.hxx>
82 #include <gp_Trsf.hxx>
83 #include <gp_Vec.hxx>
84 #include <gp_XY.hxx>
85 #include <gp_XYZ.hxx>
86
87 #include <math.h>
88
89 #include <map>
90 #include <set>
91 #include <numeric>
92 #include <limits>
93
94 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
95
96 using namespace std;
97 using namespace SMESH::Controls;
98
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
101
102 //=======================================================================
103 //function : SMESH_MeshEditor
104 //purpose  :
105 //=======================================================================
106
107 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
108   :myMesh( theMesh ) // theMesh may be NULL
109 {
110 }
111
112 //=======================================================================
113 /*!
114  * \brief Add element
115  */
116 //=======================================================================
117
118 SMDS_MeshElement*
119 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
120                              const SMDSAbs_ElementType            type,
121                              const bool                           isPoly,
122                              const int                            ID)
123 {
124   SMDS_MeshElement* e = 0;
125   int nbnode = node.size();
126   SMESHDS_Mesh* mesh = GetMeshDS();
127   switch ( type ) {
128   case SMDSAbs_0DElement:
129     if ( nbnode == 1 )
130       if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
131       else      e = mesh->Add0DElement      (node[0] );
132     break;
133   case SMDSAbs_Edge:
134     if ( nbnode == 2 )
135       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
136       else      e = mesh->AddEdge      (node[0], node[1] );
137     else if ( nbnode == 3 )
138       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
139       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
140     break;
141   case SMDSAbs_Face:
142     if ( !isPoly ) {
143       if      (nbnode == 3)
144         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
145         else      e = mesh->AddFace      (node[0], node[1], node[2] );
146       else if (nbnode == 4) 
147         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
148         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
149       else if (nbnode == 6)
150         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
151                                           node[4], node[5], ID);
152         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
153                                           node[4], node[5] );
154       else if (nbnode == 8)
155         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
156                                           node[4], node[5], node[6], node[7], ID);
157         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
158                                           node[4], node[5], node[6], node[7] );
159     } else {
160       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
161       else      e = mesh->AddPolygonalFace      (node    );
162     }
163     break;
164   case SMDSAbs_Volume:
165     if ( !isPoly ) {
166       if      (nbnode == 4)
167         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
168         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
169       else if (nbnode == 5)
170         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171                                             node[4], ID);
172         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
173                                             node[4] );
174       else if (nbnode == 6)
175         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
176                                             node[4], node[5], ID);
177         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
178                                             node[4], node[5] );
179       else if (nbnode == 8)
180         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
181                                             node[4], node[5], node[6], node[7], ID);
182         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
183                                             node[4], node[5], node[6], node[7] );
184       else if (nbnode == 10)
185         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
186                                             node[4], node[5], node[6], node[7],
187                                             node[8], node[9], ID);
188         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
189                                             node[4], node[5], node[6], node[7],
190                                             node[8], node[9] );
191       else if (nbnode == 13)
192         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193                                             node[4], node[5], node[6], node[7],
194                                             node[8], node[9], node[10],node[11],
195                                             node[12],ID);
196         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
197                                             node[4], node[5], node[6], node[7],
198                                             node[8], node[9], node[10],node[11],
199                                             node[12] );
200       else if (nbnode == 15)
201         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
202                                             node[4], node[5], node[6], node[7],
203                                             node[8], node[9], node[10],node[11],
204                                             node[12],node[13],node[14],ID);
205         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
206                                             node[4], node[5], node[6], node[7],
207                                             node[8], node[9], node[10],node[11],
208                                             node[12],node[13],node[14] );
209       else if (nbnode == 20)
210         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
211                                             node[4], node[5], node[6], node[7],
212                                             node[8], node[9], node[10],node[11],
213                                             node[12],node[13],node[14],node[15],
214                                             node[16],node[17],node[18],node[19],ID);
215         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
216                                             node[4], node[5], node[6], node[7],
217                                             node[8], node[9], node[10],node[11],
218                                             node[12],node[13],node[14],node[15],
219                                             node[16],node[17],node[18],node[19] );
220     }
221   }
222   return e;
223 }
224
225 //=======================================================================
226 /*!
227  * \brief Add element
228  */
229 //=======================================================================
230
231 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
232                                                const SMDSAbs_ElementType type,
233                                                const bool                isPoly,
234                                                const int                 ID)
235 {
236   vector<const SMDS_MeshNode*> nodes;
237   nodes.reserve( nodeIDs.size() );
238   vector<int>::const_iterator id = nodeIDs.begin();
239   while ( id != nodeIDs.end() ) {
240     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
241       nodes.push_back( node );
242     else
243       return 0;
244   }
245   return AddElement( nodes, type, isPoly, ID );
246 }
247
248 //=======================================================================
249 //function : Remove
250 //purpose  : Remove a node or an element.
251 //           Modify a compute state of sub-meshes which become empty
252 //=======================================================================
253
254 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
255                                const bool         isNodes )
256 {
257   myLastCreatedElems.Clear();
258   myLastCreatedNodes.Clear();
259
260   SMESHDS_Mesh* aMesh = GetMeshDS();
261   set< SMESH_subMesh *> smmap;
262
263   list<int>::const_iterator it = theIDs.begin();
264   for ( ; it != theIDs.end(); it++ ) {
265     const SMDS_MeshElement * elem;
266     if ( isNodes )
267       elem = aMesh->FindNode( *it );
268     else
269       elem = aMesh->FindElement( *it );
270     if ( !elem )
271       continue;
272
273     // Notify VERTEX sub-meshes about modification
274     if ( isNodes ) {
275       const SMDS_MeshNode* node = cast2Node( elem );
276       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
277         if ( int aShapeID = node->GetPosition()->GetShapeId() )
278           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
279             smmap.insert( sm );
280     }
281     // Find sub-meshes to notify about modification
282     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
283     //     while ( nodeIt->more() ) {
284     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
285     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
286     //       if ( aPosition.get() ) {
287     //         if ( int aShapeID = aPosition->GetShapeId() ) {
288     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
289     //             smmap.insert( sm );
290     //         }
291     //       }
292     //     }
293
294     // Do remove
295     if ( isNodes )
296       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
297     else
298       aMesh->RemoveElement( elem );
299   }
300
301   // Notify sub-meshes about modification
302   if ( !smmap.empty() ) {
303     set< SMESH_subMesh *>::iterator smIt;
304     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
305       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
306   }
307
308   //   // Check if the whole mesh becomes empty
309   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
310   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
311
312   return true;
313 }
314
315 //=======================================================================
316 //function : FindShape
317 //purpose  : Return an index of the shape theElem is on
318 //           or zero if a shape not found
319 //=======================================================================
320
321 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
322 {
323   myLastCreatedElems.Clear();
324   myLastCreatedNodes.Clear();
325
326   SMESHDS_Mesh * aMesh = GetMeshDS();
327   if ( aMesh->ShapeToMesh().IsNull() )
328     return 0;
329
330   if ( theElem->GetType() == SMDSAbs_Node ) {
331     const SMDS_PositionPtr& aPosition =
332       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
333     if ( aPosition.get() )
334       return aPosition->GetShapeId();
335     else
336       return 0;
337   }
338
339   TopoDS_Shape aShape; // the shape a node is on
340   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
341   while ( nodeIt->more() ) {
342     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
343     const SMDS_PositionPtr& aPosition = node->GetPosition();
344     if ( aPosition.get() ) {
345       int aShapeID = aPosition->GetShapeId();
346       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
347       if ( sm ) {
348         if ( sm->Contains( theElem ))
349           return aShapeID;
350         if ( aShape.IsNull() )
351           aShape = aMesh->IndexToShape( aShapeID );
352       }
353       else {
354         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
355       }
356     }
357   }
358
359   // None of nodes is on a proper shape,
360   // find the shape among ancestors of aShape on which a node is
361   if ( aShape.IsNull() ) {
362     //MESSAGE ("::FindShape() - NONE node is on shape")
363     return 0;
364   }
365   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
366   for ( ; ancIt.More(); ancIt.Next() ) {
367     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
368     if ( sm && sm->Contains( theElem ))
369       return aMesh->ShapeToIndex( ancIt.Value() );
370   }
371
372   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
373   return 0;
374 }
375
376 //=======================================================================
377 //function : IsMedium
378 //purpose  :
379 //=======================================================================
380
381 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
382                                 const SMDSAbs_ElementType typeToCheck)
383 {
384   bool isMedium = false;
385   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
386   while (it->more() && !isMedium ) {
387     const SMDS_MeshElement* elem = it->next();
388     isMedium = elem->IsMediumNode(node);
389   }
390   return isMedium;
391 }
392
393 //=======================================================================
394 //function : ShiftNodesQuadTria
395 //purpose  : auxilary
396 //           Shift nodes in the array corresponded to quadratic triangle
397 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
398 //=======================================================================
399 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
400 {
401   const SMDS_MeshNode* nd1 = aNodes[0];
402   aNodes[0] = aNodes[1];
403   aNodes[1] = aNodes[2];
404   aNodes[2] = nd1;
405   const SMDS_MeshNode* nd2 = aNodes[3];
406   aNodes[3] = aNodes[4];
407   aNodes[4] = aNodes[5];
408   aNodes[5] = nd2;
409 }
410
411 //=======================================================================
412 //function : GetNodesFromTwoTria
413 //purpose  : auxilary
414 //           Shift nodes in the array corresponded to quadratic triangle
415 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
416 //=======================================================================
417 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
418                                 const SMDS_MeshElement * theTria2,
419                                 const SMDS_MeshNode* N1[],
420                                 const SMDS_MeshNode* N2[])
421 {
422   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
423   int i=0;
424   while(i<6) {
425     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
426     i++;
427   }
428   if(it->more()) return false;
429   it = theTria2->nodesIterator();
430   i=0;
431   while(i<6) {
432     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
433     i++;
434   }
435   if(it->more()) return false;
436
437   int sames[3] = {-1,-1,-1};
438   int nbsames = 0;
439   int j;
440   for(i=0; i<3; i++) {
441     for(j=0; j<3; j++) {
442       if(N1[i]==N2[j]) {
443         sames[i] = j;
444         nbsames++;
445         break;
446       }
447     }
448   }
449   if(nbsames!=2) return false;
450   if(sames[0]>-1) {
451     ShiftNodesQuadTria(N1);
452     if(sames[1]>-1) {
453       ShiftNodesQuadTria(N1);
454     }
455   }
456   i = sames[0] + sames[1] + sames[2];
457   for(; i<2; i++) {
458     ShiftNodesQuadTria(N2);
459   }
460   // now we receive following N1 and N2 (using numeration as above image)
461   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
462   // i.e. first nodes from both arrays determ new diagonal
463   return true;
464 }
465
466 //=======================================================================
467 //function : InverseDiag
468 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
469 //           but having other common link.
470 //           Return False if args are improper
471 //=======================================================================
472
473 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
474                                     const SMDS_MeshElement * theTria2 )
475 {
476   myLastCreatedElems.Clear();
477   myLastCreatedNodes.Clear();
478
479   if (!theTria1 || !theTria2)
480     return false;
481
482   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
483   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
484   if (F1 && F2) {
485
486     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
487     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
488     //    |/ |                                         | \|
489     //  B +--+ 2                                     B +--+ 2
490
491     // put nodes in array and find out indices of the same ones
492     const SMDS_MeshNode* aNodes [6];
493     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
494     int i = 0;
495     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
496     while ( it->more() ) {
497       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
498
499       if ( i > 2 ) // theTria2
500         // find same node of theTria1
501         for ( int j = 0; j < 3; j++ )
502           if ( aNodes[ i ] == aNodes[ j ]) {
503             sameInd[ j ] = i;
504             sameInd[ i ] = j;
505             break;
506           }
507       // next
508       i++;
509       if ( i == 3 ) {
510         if ( it->more() )
511           return false; // theTria1 is not a triangle
512         it = theTria2->nodesIterator();
513       }
514       if ( i == 6 && it->more() )
515         return false; // theTria2 is not a triangle
516     }
517
518     // find indices of 1,2 and of A,B in theTria1
519     int iA = 0, iB = 0, i1 = 0, i2 = 0;
520     for ( i = 0; i < 6; i++ ) {
521       if ( sameInd [ i ] == 0 )
522         if ( i < 3 ) i1 = i;
523         else         i2 = i;
524       else if (i < 3)
525         if ( iA ) iB = i;
526         else      iA = i;
527     }
528     // nodes 1 and 2 should not be the same
529     if ( aNodes[ i1 ] == aNodes[ i2 ] )
530       return false;
531
532     // theTria1: A->2
533     aNodes[ iA ] = aNodes[ i2 ];
534     // theTria2: B->1
535     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
536
537     //MESSAGE( theTria1 << theTria2 );
538
539     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
540     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
541
542     //MESSAGE( theTria1 << theTria2 );
543
544     return true;
545
546   } // end if(F1 && F2)
547
548   // check case of quadratic faces
549   const SMDS_QuadraticFaceOfNodes* QF1 =
550     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
551   if(!QF1) return false;
552   const SMDS_QuadraticFaceOfNodes* QF2 =
553     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
554   if(!QF2) return false;
555
556   //       5
557   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
558   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
559   //    |   / |
560   //  7 +  +  + 6
561   //    | /9  |
562   //    |/    |
563   //  4 +--+--+ 3
564   //       8
565
566   const SMDS_MeshNode* N1 [6];
567   const SMDS_MeshNode* N2 [6];
568   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
569     return false;
570   // now we receive following N1 and N2 (using numeration as above image)
571   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
572   // i.e. first nodes from both arrays determ new diagonal
573
574   const SMDS_MeshNode* N1new [6];
575   const SMDS_MeshNode* N2new [6];
576   N1new[0] = N1[0];
577   N1new[1] = N2[0];
578   N1new[2] = N2[1];
579   N1new[3] = N1[4];
580   N1new[4] = N2[3];
581   N1new[5] = N1[5];
582   N2new[0] = N1[0];
583   N2new[1] = N1[1];
584   N2new[2] = N2[0];
585   N2new[3] = N1[3];
586   N2new[4] = N2[5];
587   N2new[5] = N1[4];
588   // replaces nodes in faces
589   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
590   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
591
592   return true;
593 }
594
595 //=======================================================================
596 //function : findTriangles
597 //purpose  : find triangles sharing theNode1-theNode2 link
598 //=======================================================================
599
600 static bool findTriangles(const SMDS_MeshNode *    theNode1,
601                           const SMDS_MeshNode *    theNode2,
602                           const SMDS_MeshElement*& theTria1,
603                           const SMDS_MeshElement*& theTria2)
604 {
605   if ( !theNode1 || !theNode2 ) return false;
606
607   theTria1 = theTria2 = 0;
608
609   set< const SMDS_MeshElement* > emap;
610   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
611   while (it->more()) {
612     const SMDS_MeshElement* elem = it->next();
613     if ( elem->NbNodes() == 3 )
614       emap.insert( elem );
615   }
616   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
617   while (it->more()) {
618     const SMDS_MeshElement* elem = it->next();
619     if ( emap.find( elem ) != emap.end() )
620       if ( theTria1 ) {
621         // theTria1 must be element with minimum ID
622         if( theTria1->GetID() < elem->GetID() ) {
623           theTria2 = elem;
624         }
625         else {
626           theTria2 = theTria1;
627           theTria1 = elem;
628         }
629         break;
630       }
631       else {
632         theTria1 = elem;
633       }
634   }
635   return ( theTria1 && theTria2 );
636 }
637
638 //=======================================================================
639 //function : InverseDiag
640 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
641 //           with ones built on the same 4 nodes but having other common link.
642 //           Return false if proper faces not found
643 //=======================================================================
644
645 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
646                                     const SMDS_MeshNode * theNode2)
647 {
648   myLastCreatedElems.Clear();
649   myLastCreatedNodes.Clear();
650
651   MESSAGE( "::InverseDiag()" );
652
653   const SMDS_MeshElement *tr1, *tr2;
654   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
655     return false;
656
657   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
658   //if (!F1) return false;
659   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
660   //if (!F2) return false;
661   if (F1 && F2) {
662
663     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
664     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
665     //    |/ |                                    | \|
666     //  B +--+ 2                                B +--+ 2
667
668     // put nodes in array
669     // and find indices of 1,2 and of A in tr1 and of B in tr2
670     int i, iA1 = 0, i1 = 0;
671     const SMDS_MeshNode* aNodes1 [3];
672     SMDS_ElemIteratorPtr it;
673     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
674       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
675       if ( aNodes1[ i ] == theNode1 )
676         iA1 = i; // node A in tr1
677       else if ( aNodes1[ i ] != theNode2 )
678         i1 = i;  // node 1
679     }
680     int iB2 = 0, i2 = 0;
681     const SMDS_MeshNode* aNodes2 [3];
682     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
683       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
684       if ( aNodes2[ i ] == theNode2 )
685         iB2 = i; // node B in tr2
686       else if ( aNodes2[ i ] != theNode1 )
687         i2 = i;  // node 2
688     }
689
690     // nodes 1 and 2 should not be the same
691     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
692       return false;
693
694     // tr1: A->2
695     aNodes1[ iA1 ] = aNodes2[ i2 ];
696     // tr2: B->1
697     aNodes2[ iB2 ] = aNodes1[ i1 ];
698
699     //MESSAGE( tr1 << tr2 );
700
701     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
702     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
703
704     //MESSAGE( tr1 << tr2 );
705
706     return true;
707   }
708
709   // check case of quadratic faces
710   const SMDS_QuadraticFaceOfNodes* QF1 =
711     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
712   if(!QF1) return false;
713   const SMDS_QuadraticFaceOfNodes* QF2 =
714     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
715   if(!QF2) return false;
716   return InverseDiag(tr1,tr2);
717 }
718
719 //=======================================================================
720 //function : getQuadrangleNodes
721 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
722 //           fusion of triangles tr1 and tr2 having shared link on
723 //           theNode1 and theNode2
724 //=======================================================================
725
726 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
727                         const SMDS_MeshNode *    theNode1,
728                         const SMDS_MeshNode *    theNode2,
729                         const SMDS_MeshElement * tr1,
730                         const SMDS_MeshElement * tr2 )
731 {
732   if( tr1->NbNodes() != tr2->NbNodes() )
733     return false;
734   // find the 4-th node to insert into tr1
735   const SMDS_MeshNode* n4 = 0;
736   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
737   int i=0;
738   while ( !n4 && i<3 ) {
739     const SMDS_MeshNode * n = cast2Node( it->next() );
740     i++;
741     bool isDiag = ( n == theNode1 || n == theNode2 );
742     if ( !isDiag )
743       n4 = n;
744   }
745   // Make an array of nodes to be in a quadrangle
746   int iNode = 0, iFirstDiag = -1;
747   it = tr1->nodesIterator();
748   i=0;
749   while ( i<3 ) {
750     const SMDS_MeshNode * n = cast2Node( it->next() );
751     i++;
752     bool isDiag = ( n == theNode1 || n == theNode2 );
753     if ( isDiag ) {
754       if ( iFirstDiag < 0 )
755         iFirstDiag = iNode;
756       else if ( iNode - iFirstDiag == 1 )
757         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
758     }
759     else if ( n == n4 ) {
760       return false; // tr1 and tr2 should not have all the same nodes
761     }
762     theQuadNodes[ iNode++ ] = n;
763   }
764   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
765     theQuadNodes[ iNode ] = n4;
766
767   return true;
768 }
769
770 //=======================================================================
771 //function : DeleteDiag
772 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
773 //           with a quadrangle built on the same 4 nodes.
774 //           Return false if proper faces not found
775 //=======================================================================
776
777 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
778                                    const SMDS_MeshNode * theNode2)
779 {
780   myLastCreatedElems.Clear();
781   myLastCreatedNodes.Clear();
782
783   MESSAGE( "::DeleteDiag()" );
784
785   const SMDS_MeshElement *tr1, *tr2;
786   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
787     return false;
788
789   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
790   //if (!F1) return false;
791   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
792   //if (!F2) return false;
793   if (F1 && F2) {
794
795     const SMDS_MeshNode* aNodes [ 4 ];
796     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
797       return false;
798
799     //MESSAGE( endl << tr1 << tr2 );
800
801     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
802     myLastCreatedElems.Append(tr1);
803     GetMeshDS()->RemoveElement( tr2 );
804
805     //MESSAGE( endl << tr1 );
806
807     return true;
808   }
809
810   // check case of quadratic faces
811   const SMDS_QuadraticFaceOfNodes* QF1 =
812     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
813   if(!QF1) return false;
814   const SMDS_QuadraticFaceOfNodes* QF2 =
815     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
816   if(!QF2) return false;
817
818   //       5
819   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
820   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
821   //    |   / |
822   //  7 +  +  + 6
823   //    | /9  |
824   //    |/    |
825   //  4 +--+--+ 3
826   //       8
827
828   const SMDS_MeshNode* N1 [6];
829   const SMDS_MeshNode* N2 [6];
830   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
831     return false;
832   // now we receive following N1 and N2 (using numeration as above image)
833   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
834   // i.e. first nodes from both arrays determ new diagonal
835
836   const SMDS_MeshNode* aNodes[8];
837   aNodes[0] = N1[0];
838   aNodes[1] = N1[1];
839   aNodes[2] = N2[0];
840   aNodes[3] = N2[1];
841   aNodes[4] = N1[3];
842   aNodes[5] = N2[5];
843   aNodes[6] = N2[3];
844   aNodes[7] = N1[5];
845
846   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
847   myLastCreatedElems.Append(tr1);
848   GetMeshDS()->RemoveElement( tr2 );
849
850   // remove middle node (9)
851   GetMeshDS()->RemoveNode( N1[4] );
852
853   return true;
854 }
855
856 //=======================================================================
857 //function : Reorient
858 //purpose  : Reverse theElement orientation
859 //=======================================================================
860
861 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
862 {
863   myLastCreatedElems.Clear();
864   myLastCreatedNodes.Clear();
865
866   if (!theElem)
867     return false;
868   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
869   if ( !it || !it->more() )
870     return false;
871
872   switch ( theElem->GetType() ) {
873
874   case SMDSAbs_Edge:
875   case SMDSAbs_Face: {
876     if(!theElem->IsQuadratic()) {
877       int i = theElem->NbNodes();
878       vector<const SMDS_MeshNode*> aNodes( i );
879       while ( it->more() )
880         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
881       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
882     }
883     else {
884       // quadratic elements
885       if(theElem->GetType()==SMDSAbs_Edge) {
886         vector<const SMDS_MeshNode*> aNodes(3);
887         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
888         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
889         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
890         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
891       }
892       else {
893         int nbn = theElem->NbNodes();
894         vector<const SMDS_MeshNode*> aNodes(nbn);
895         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
896         int i=1;
897         for(; i<nbn/2; i++) {
898           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
899         }
900         for(i=0; i<nbn/2; i++) {
901           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
902         }
903         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
904       }
905     }
906   }
907   case SMDSAbs_Volume: {
908     if (theElem->IsPoly()) {
909       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
910         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
911       if (!aPolyedre) {
912         MESSAGE("Warning: bad volumic element");
913         return false;
914       }
915
916       int nbFaces = aPolyedre->NbFaces();
917       vector<const SMDS_MeshNode *> poly_nodes;
918       vector<int> quantities (nbFaces);
919
920       // reverse each face of the polyedre
921       for (int iface = 1; iface <= nbFaces; iface++) {
922         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
923         quantities[iface - 1] = nbFaceNodes;
924
925         for (inode = nbFaceNodes; inode >= 1; inode--) {
926           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
927           poly_nodes.push_back(curNode);
928         }
929       }
930
931       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
932
933     }
934     else {
935       SMDS_VolumeTool vTool;
936       if ( !vTool.Set( theElem ))
937         return false;
938       vTool.Inverse();
939       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
940     }
941   }
942   default:;
943   }
944
945   return false;
946 }
947
948 //=======================================================================
949 //function : getBadRate
950 //purpose  :
951 //=======================================================================
952
953 static double getBadRate (const SMDS_MeshElement*               theElem,
954                           SMESH::Controls::NumericalFunctorPtr& theCrit)
955 {
956   SMESH::Controls::TSequenceOfXYZ P;
957   if ( !theElem || !theCrit->GetPoints( theElem, P ))
958     return 1e100;
959   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
960   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
961 }
962
963 //=======================================================================
964 //function : QuadToTri
965 //purpose  : Cut quadrangles into triangles.
966 //           theCrit is used to select a diagonal to cut
967 //=======================================================================
968
969 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
970                                   SMESH::Controls::NumericalFunctorPtr theCrit)
971 {
972   myLastCreatedElems.Clear();
973   myLastCreatedNodes.Clear();
974
975   MESSAGE( "::QuadToTri()" );
976
977   if ( !theCrit.get() )
978     return false;
979
980   SMESHDS_Mesh * aMesh = GetMeshDS();
981
982   Handle(Geom_Surface) surface;
983   SMESH_MesherHelper   helper( *GetMesh() );
984
985   TIDSortedElemSet::iterator itElem;
986   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
987     const SMDS_MeshElement* elem = *itElem;
988     if ( !elem || elem->GetType() != SMDSAbs_Face )
989       continue;
990     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
991       continue;
992
993     // retrieve element nodes
994     const SMDS_MeshNode* aNodes [8];
995     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
996     int i = 0;
997     while ( itN->more() )
998       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
999
1000     // compare two sets of possible triangles
1001     double aBadRate1, aBadRate2; // to what extent a set is bad
1002     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1003     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1004     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1005
1006     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1007     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1008     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1009
1010     int aShapeId = FindShape( elem );
1011     const SMDS_MeshElement* newElem = 0;
1012
1013     if( !elem->IsQuadratic() ) {
1014
1015       // split liner quadrangle
1016
1017       if ( aBadRate1 <= aBadRate2 ) {
1018         // tr1 + tr2 is better
1019         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1020         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1021       }
1022       else {
1023         // tr3 + tr4 is better
1024         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1025         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1026       }
1027     }
1028     else {
1029
1030       // split quadratic quadrangle
1031
1032       // get surface elem is on
1033       if ( aShapeId != helper.GetSubShapeID() ) {
1034         surface.Nullify();
1035         TopoDS_Shape shape;
1036         if ( aShapeId > 0 )
1037           shape = aMesh->IndexToShape( aShapeId );
1038         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1039           TopoDS_Face face = TopoDS::Face( shape );
1040           surface = BRep_Tool::Surface( face );
1041           if ( !surface.IsNull() )
1042             helper.SetSubShape( shape );
1043         }
1044       }
1045       // get elem nodes
1046       const SMDS_MeshNode* aNodes [8];
1047       const SMDS_MeshNode* inFaceNode = 0;
1048       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1049       int i = 0;
1050       while ( itN->more() ) {
1051         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1052         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1053              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1054         {
1055           inFaceNode = aNodes[ i-1 ];
1056         }
1057       }
1058       // find middle point for (0,1,2,3)
1059       // and create a node in this point;
1060       gp_XYZ p( 0,0,0 );
1061       if ( surface.IsNull() ) {
1062         for(i=0; i<4; i++)
1063           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1064         p /= 4;
1065       }
1066       else {
1067         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1068         gp_XY uv( 0,0 );
1069         for(i=0; i<4; i++)
1070           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1071         uv /= 4.;
1072         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1073       }
1074       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1075       myLastCreatedNodes.Append(newN);
1076
1077       // create a new element
1078       const SMDS_MeshNode* N[6];
1079       if ( aBadRate1 <= aBadRate2 ) {
1080         N[0] = aNodes[0];
1081         N[1] = aNodes[1];
1082         N[2] = aNodes[2];
1083         N[3] = aNodes[4];
1084         N[4] = aNodes[5];
1085         N[5] = newN;
1086         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1087                                  aNodes[6], aNodes[7], newN );
1088       }
1089       else {
1090         N[0] = aNodes[1];
1091         N[1] = aNodes[2];
1092         N[2] = aNodes[3];
1093         N[3] = aNodes[5];
1094         N[4] = aNodes[6];
1095         N[5] = newN;
1096         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1097                                  aNodes[7], aNodes[4], newN );
1098       }
1099       aMesh->ChangeElementNodes( elem, N, 6 );
1100
1101     } // quadratic case
1102
1103     // care of a new element
1104
1105     myLastCreatedElems.Append(newElem);
1106     AddToSameGroups( newElem, elem, aMesh );
1107
1108     // put a new triangle on the same shape
1109     if ( aShapeId )
1110       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1111   }
1112   return true;
1113 }
1114
1115 //=======================================================================
1116 //function : BestSplit
1117 //purpose  : Find better diagonal for cutting.
1118 //=======================================================================
1119
1120 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1121                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1122 {
1123   myLastCreatedElems.Clear();
1124   myLastCreatedNodes.Clear();
1125
1126   if (!theCrit.get())
1127     return -1;
1128
1129   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1130     return -1;
1131
1132   if( theQuad->NbNodes()==4 ||
1133       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1134
1135     // retrieve element nodes
1136     const SMDS_MeshNode* aNodes [4];
1137     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1138     int i = 0;
1139     //while (itN->more())
1140     while (i<4) {
1141       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1142     }
1143     // compare two sets of possible triangles
1144     double aBadRate1, aBadRate2; // to what extent a set is bad
1145     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1146     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1147     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1148
1149     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1150     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1151     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1152
1153     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1154       return 1; // diagonal 1-3
1155
1156     return 2; // diagonal 2-4
1157   }
1158   return -1;
1159 }
1160
1161 namespace
1162 {
1163   // Methods of splitting volumes into tetra
1164
1165   const int theHexTo5_1[5*4+1] =
1166     {
1167       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1168     };
1169   const int theHexTo5_2[5*4+1] =
1170     {
1171       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1172     };
1173   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1174
1175   const int theHexTo6_1[6*4+1] =
1176     {
1177       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
1178     };
1179   const int theHexTo6_2[6*4+1] =
1180     {
1181       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
1182     };
1183   const int theHexTo6_3[6*4+1] =
1184     {
1185       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
1186     };
1187   const int theHexTo6_4[6*4+1] =
1188     {
1189       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
1190     };
1191   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1192
1193   const int thePyraTo2_1[2*4+1] =
1194     {
1195       0, 1, 2, 4,    0, 2, 3, 4,   -1
1196     };
1197   const int thePyraTo2_2[2*4+1] =
1198     {
1199       1, 2, 3, 4,    1, 3, 0, 4,   -1
1200     };
1201   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1202
1203   const int thePentaTo3_1[3*4+1] =
1204     {
1205       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1206     };
1207   const int thePentaTo3_2[3*4+1] =
1208     {
1209       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1210     };
1211   const int thePentaTo3_3[3*4+1] =
1212     {
1213       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1214     };
1215   const int thePentaTo3_4[3*4+1] =
1216     {
1217       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1218     };
1219   const int thePentaTo3_5[3*4+1] =
1220     {
1221       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1222     };
1223   const int thePentaTo3_6[3*4+1] =
1224     {
1225       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1226     };
1227   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1228                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1229
1230   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1231   {
1232     int _n1, _n2, _n3;
1233     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1234     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1235     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1236   };
1237   struct TSplitMethod
1238   {
1239     int        _nbTetra;
1240     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1241     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1242     bool       _ownConn;      //!< to delete _connectivity in destructor
1243
1244     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1245       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1246     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1247     bool hasFacet( const TTriangleFacet& facet ) const
1248     {
1249       const int* tetConn = _connectivity;
1250       for ( ; tetConn[0] >= 0; tetConn += 4 )
1251         if (( facet.contains( tetConn[0] ) +
1252               facet.contains( tetConn[1] ) +
1253               facet.contains( tetConn[2] ) +
1254               facet.contains( tetConn[3] )) == 3 )
1255           return true;
1256       return false;
1257     }
1258   };
1259
1260   //=======================================================================
1261   /*!
1262    * \brief return TSplitMethod for the given element
1263    */
1264   //=======================================================================
1265
1266   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1267   {
1268     int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1269
1270     // Find out how adjacent volumes are split
1271
1272     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1273     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1274     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1275     {
1276       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1277       maxTetConnSize += 4 * ( nbNodes - 2 );
1278       if ( nbNodes < 4 ) continue;
1279
1280       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1281       const int* nInd = vol.GetFaceNodesIndices( iF );
1282       if ( nbNodes == 4 )
1283       {
1284         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1285         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1286         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1287         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1288       }
1289       else
1290       {
1291         int iCom = 0; // common node of triangle faces to split into
1292         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1293         {
1294           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1295                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1296                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1297           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1298                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1299                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1300           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1301           {
1302             triaSplits.push_back( t012 );
1303             triaSplits.push_back( t023 );
1304             break;
1305           }
1306         }
1307       }
1308       if ( !triaSplits.empty() )
1309         hasAdjacentSplits = true;
1310     }
1311
1312     // Among variants of split method select one compliant with adjacent volumes
1313
1314     TSplitMethod method;
1315     if ( !vol.Element()->IsPoly() )
1316     {
1317       int nbVariants = 2, nbTet = 0;
1318       const int** connVariants = 0;
1319       switch ( vol.Element()->GetEntityType() )
1320       {
1321       case SMDSEntity_Hexa:
1322       case SMDSEntity_Quad_Hexa:
1323         if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1324           connVariants = theHexTo5, nbTet = 5;
1325         else
1326           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1327         break;
1328       case SMDSEntity_Pyramid:
1329       case SMDSEntity_Quad_Pyramid:
1330         connVariants = thePyraTo2;  nbTet = 2;
1331         break;
1332       case SMDSEntity_Penta:
1333       case SMDSEntity_Quad_Penta:
1334         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1335         break;
1336       default:
1337         nbVariants = 0;
1338       }
1339       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1340       {
1341         // check method compliancy with adjacent tetras,
1342         // all found splits must be among facets of tetras described by this method
1343         method = TSplitMethod( nbTet, connVariants[variant] );
1344         if ( hasAdjacentSplits && method._nbTetra > 0 )
1345         {
1346           bool facetCreated = true;
1347           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1348           {
1349             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1350             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1351               facetCreated = method.hasFacet( *facet );
1352           }
1353           if ( !facetCreated )
1354             method = TSplitMethod(0); // incompatible method
1355         }
1356       }
1357     }
1358     if ( method._nbTetra < 1 )
1359     {
1360       // No standard method is applicable, use a generic solution:
1361       // each facet of a volume is split into triangles and
1362       // each of triangles and a volume barycenter form a tetrahedron.
1363
1364       int* connectivity = new int[ maxTetConnSize + 1 ];
1365       method._connectivity = connectivity;
1366       method._ownConn = true;
1367       method._baryNode = true;
1368
1369       int connSize = 0;
1370       int baryCenInd = vol.NbNodes();
1371       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1372       {
1373         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1374         const int*   nInd = vol.GetFaceNodesIndices( iF );
1375         // find common node of triangle facets of tetra to create
1376         int iCommon = 0; // index in linear numeration
1377         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1378         if ( !triaSplits.empty() )
1379         {
1380           // by found facets
1381           const TTriangleFacet* facet = &triaSplits.front();
1382           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1383             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1384                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1385               break;
1386         }
1387         else if ( nbNodes > 3 )
1388         {
1389           // find the best method of splitting into triangles by aspect ratio
1390           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1391           map< double, int > badness2iCommon;
1392           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1393           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1394           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1395             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1396             {
1397               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1398                                       nodes[ iQ*((iLast-1)%nbNodes)],
1399                                       nodes[ iQ*((iLast  )%nbNodes)]);
1400               double badness = getBadRate( &tria, aspectRatio );
1401               badness2iCommon.insert( make_pair( badness, iCommon ));
1402             }
1403           // use iCommon with lowest badness
1404           iCommon = badness2iCommon.begin()->second;
1405         }
1406         if ( iCommon >= nbNodes )
1407           iCommon = 0; // something wrong
1408         // fill connectivity of tetra
1409         int nbTet = nbNodes - 2;
1410         for ( int i = 0; i < nbTet; ++i )
1411         {
1412           int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1413           if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1414           connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1415           connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1416           connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1417           connectivity[ connSize++ ] = baryCenInd;
1418           ++method._nbTetra;
1419         }
1420       }
1421       connectivity[ connSize++ ] = -1;
1422     }
1423     return method;
1424   }
1425   //================================================================================
1426   /*!
1427    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1428    */
1429   //================================================================================
1430
1431   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1432   {
1433     // find the tetrahedron including the three nodes of facet
1434     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1435     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1436     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1437     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1438     while ( volIt1->more() )
1439     {
1440       const SMDS_MeshElement* v = volIt1->next();
1441       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1442         continue;
1443       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1444       while ( volIt2->more() )
1445         if ( v != volIt2->next() )
1446           continue;
1447       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1448       while ( volIt3->more() )
1449         if ( v == volIt3->next() )
1450           return true;
1451     }
1452     return false;
1453   }
1454 } // namespace
1455
1456 //=======================================================================
1457 //function : SplitVolumesIntoTetra
1458 //purpose  : Split volumic elements into tetrahedra.
1459 //=======================================================================
1460
1461 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1462                                               const int                theMethodFlags)
1463 {
1464   // std-like iterator on coordinates of nodes of mesh element
1465   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1466   NXyzIterator xyzEnd;
1467
1468   SMDS_VolumeTool    volTool;
1469   SMESH_MesherHelper helper( *GetMesh());
1470
1471   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1472   SMESHDS_SubMesh* fSubMesh = subMesh;
1473   
1474   SMESH_SequenceOfElemPtr newNodes, newElems;
1475
1476   TIDSortedElemSet::const_iterator elem = theElems.begin();
1477   for ( ; elem != theElems.end(); ++elem )
1478   {
1479     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1480     if ( geomType <= SMDSEntity_Quad_Tetra )
1481       continue; // tetra or face or ...
1482
1483     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1484
1485     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1486     if ( splitMethod._nbTetra < 1 ) continue;
1487
1488     // find submesh to add new tetras in
1489     if ( !subMesh || !subMesh->Contains( *elem ))
1490     {
1491       int shapeID = FindShape( *elem );
1492       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1493       subMesh = GetMeshDS()->MeshElements( shapeID );
1494     }
1495     int iQ;
1496     if ( (*elem)->IsQuadratic() )
1497     {
1498       iQ = 2;
1499       // add quadratic links to the helper
1500       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1501       {
1502         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1503         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1504           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1505       }
1506       helper.SetIsQuadratic( true );
1507     }
1508     else
1509     {
1510       iQ = 1;
1511       helper.SetIsQuadratic( false );
1512     }
1513     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1514     if ( splitMethod._baryNode )
1515     {
1516       // make a node at barycenter
1517       gp_XYZ gc( 0,0,0 );
1518       gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1519       SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1520       nodes.push_back( gcNode );
1521       newNodes.Append( gcNode );
1522     }
1523
1524     // make tetras
1525     helper.SetElementsOnShape( true );
1526     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1527     const int* tetConn = splitMethod._connectivity;
1528     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1529       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1530                                                        nodes[ tetConn[1] ],
1531                                                        nodes[ tetConn[2] ],
1532                                                        nodes[ tetConn[3] ]));
1533
1534     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1535
1536     // Split faces on sides of the split volume
1537
1538     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1539     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1540     {
1541       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1542       if ( nbNodes < 4 ) continue;
1543
1544       // find an existing face
1545       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1546                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1547       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1548       {
1549         // among possible triangles create ones discribed by split method
1550         const int* nInd = volTool.GetFaceNodesIndices( iF );
1551         int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1552         int iCom = 0; // common node of triangle faces to split into
1553         list< TTriangleFacet > facets;
1554         for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1555         {
1556           TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1557                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1558                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1559           TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1560                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1561                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1562           if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1563           {
1564             facets.push_back( t012 );
1565             facets.push_back( t023 );
1566             for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1567               facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1568                                                 nInd[ iQ * ((iLast-1)%nbNodes )],
1569                                                 nInd[ iQ * ((iLast  )%nbNodes )]));
1570             break;
1571           }
1572         }
1573         // find submesh to add new faces in
1574         if ( !fSubMesh || !fSubMesh->Contains( face ))
1575         {
1576           int shapeID = FindShape( face );
1577           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1578         }
1579         // make triangles
1580         helper.SetElementsOnShape( false );
1581         vector< const SMDS_MeshElement* > triangles;
1582         list< TTriangleFacet >::iterator facet = facets.begin();
1583         for ( ; facet != facets.end(); ++facet )
1584         {
1585           if ( !volTool.IsFaceExternal( iF ))
1586             swap( facet->_n2, facet->_n3 );
1587           triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1588                                                volNodes[ facet->_n2 ],
1589                                                volNodes[ facet->_n3 ]));
1590           if ( triangles.back() && fSubMesh )
1591             fSubMesh->AddElement( triangles.back());
1592           newElems.Append( triangles.back() );
1593         }
1594         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1595         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1596       }
1597
1598     } // loop on volume faces to split them into triangles
1599
1600     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1601
1602   } // loop on volumes to split
1603
1604   myLastCreatedNodes = newNodes;
1605   myLastCreatedElems = newElems;
1606 }
1607
1608 //=======================================================================
1609 //function : AddToSameGroups
1610 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1611 //=======================================================================
1612
1613 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1614                                         const SMDS_MeshElement* elemInGroups,
1615                                         SMESHDS_Mesh *          aMesh)
1616 {
1617   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1618   if (!groups.empty()) {
1619     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1620     for ( ; grIt != groups.end(); grIt++ ) {
1621       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1622       if ( group && group->Contains( elemInGroups ))
1623         group->SMDSGroup().Add( elemToAdd );
1624     }
1625   }
1626 }
1627
1628
1629 //=======================================================================
1630 //function : RemoveElemFromGroups
1631 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1632 //=======================================================================
1633 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1634                                              SMESHDS_Mesh *          aMesh)
1635 {
1636   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1637   if (!groups.empty())
1638   {
1639     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1640     for (; GrIt != groups.end(); GrIt++)
1641     {
1642       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1643       if (!grp || grp->IsEmpty()) continue;
1644       grp->SMDSGroup().Remove(removeelem);
1645     }
1646   }
1647 }
1648
1649 //================================================================================
1650 /*!
1651  * \brief Replace elemToRm by elemToAdd in the all groups
1652  */
1653 //================================================================================
1654
1655 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1656                                             const SMDS_MeshElement* elemToAdd,
1657                                             SMESHDS_Mesh *          aMesh)
1658 {
1659   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1660   if (!groups.empty()) {
1661     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1662     for ( ; grIt != groups.end(); grIt++ ) {
1663       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1664       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1665         group->SMDSGroup().Add( elemToAdd );
1666     }
1667   }
1668 }
1669
1670 //================================================================================
1671 /*!
1672  * \brief Replace elemToRm by elemToAdd in the all groups
1673  */
1674 //================================================================================
1675
1676 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1677                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1678                                             SMESHDS_Mesh *                         aMesh)
1679 {
1680   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1681   if (!groups.empty())
1682   {
1683     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1684     for ( ; grIt != groups.end(); grIt++ ) {
1685       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1686       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1687         for ( int i = 0; i < elemToAdd.size(); ++i )
1688           group->SMDSGroup().Add( elemToAdd[ i ] );
1689     }
1690   }
1691 }
1692
1693 //=======================================================================
1694 //function : QuadToTri
1695 //purpose  : Cut quadrangles into triangles.
1696 //           theCrit is used to select a diagonal to cut
1697 //=======================================================================
1698
1699 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1700                                   const bool         the13Diag)
1701 {
1702   myLastCreatedElems.Clear();
1703   myLastCreatedNodes.Clear();
1704
1705   MESSAGE( "::QuadToTri()" );
1706
1707   SMESHDS_Mesh * aMesh = GetMeshDS();
1708
1709   Handle(Geom_Surface) surface;
1710   SMESH_MesherHelper   helper( *GetMesh() );
1711
1712   TIDSortedElemSet::iterator itElem;
1713   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1714     const SMDS_MeshElement* elem = *itElem;
1715     if ( !elem || elem->GetType() != SMDSAbs_Face )
1716       continue;
1717     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1718     if(!isquad) continue;
1719
1720     if(elem->NbNodes()==4) {
1721       // retrieve element nodes
1722       const SMDS_MeshNode* aNodes [4];
1723       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1724       int i = 0;
1725       while ( itN->more() )
1726         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1727
1728       int aShapeId = FindShape( elem );
1729       const SMDS_MeshElement* newElem = 0;
1730       if ( the13Diag ) {
1731         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1732         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1733       }
1734       else {
1735         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1736         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1737       }
1738       myLastCreatedElems.Append(newElem);
1739       // put a new triangle on the same shape and add to the same groups
1740       if ( aShapeId )
1741         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1742       AddToSameGroups( newElem, elem, aMesh );
1743     }
1744
1745     // Quadratic quadrangle
1746
1747     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1748
1749       // get surface elem is on
1750       int aShapeId = FindShape( elem );
1751       if ( aShapeId != helper.GetSubShapeID() ) {
1752         surface.Nullify();
1753         TopoDS_Shape shape;
1754         if ( aShapeId > 0 )
1755           shape = aMesh->IndexToShape( aShapeId );
1756         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1757           TopoDS_Face face = TopoDS::Face( shape );
1758           surface = BRep_Tool::Surface( face );
1759           if ( !surface.IsNull() )
1760             helper.SetSubShape( shape );
1761         }
1762       }
1763
1764       const SMDS_MeshNode* aNodes [8];
1765       const SMDS_MeshNode* inFaceNode = 0;
1766       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1767       int i = 0;
1768       while ( itN->more() ) {
1769         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1770         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1771              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1772         {
1773           inFaceNode = aNodes[ i-1 ];
1774         }
1775       }
1776
1777       // find middle point for (0,1,2,3)
1778       // and create a node in this point;
1779       gp_XYZ p( 0,0,0 );
1780       if ( surface.IsNull() ) {
1781         for(i=0; i<4; i++)
1782           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1783         p /= 4;
1784       }
1785       else {
1786         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1787         gp_XY uv( 0,0 );
1788         for(i=0; i<4; i++)
1789           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1790         uv /= 4.;
1791         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1792       }
1793       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1794       myLastCreatedNodes.Append(newN);
1795
1796       // create a new element
1797       const SMDS_MeshElement* newElem = 0;
1798       const SMDS_MeshNode* N[6];
1799       if ( the13Diag ) {
1800         N[0] = aNodes[0];
1801         N[1] = aNodes[1];
1802         N[2] = aNodes[2];
1803         N[3] = aNodes[4];
1804         N[4] = aNodes[5];
1805         N[5] = newN;
1806         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1807                                  aNodes[6], aNodes[7], newN );
1808       }
1809       else {
1810         N[0] = aNodes[1];
1811         N[1] = aNodes[2];
1812         N[2] = aNodes[3];
1813         N[3] = aNodes[5];
1814         N[4] = aNodes[6];
1815         N[5] = newN;
1816         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1817                                  aNodes[7], aNodes[4], newN );
1818       }
1819       myLastCreatedElems.Append(newElem);
1820       aMesh->ChangeElementNodes( elem, N, 6 );
1821       // put a new triangle on the same shape and add to the same groups
1822       if ( aShapeId )
1823         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1824       AddToSameGroups( newElem, elem, aMesh );
1825     }
1826   }
1827
1828   return true;
1829 }
1830
1831 //=======================================================================
1832 //function : getAngle
1833 //purpose  :
1834 //=======================================================================
1835
1836 double getAngle(const SMDS_MeshElement * tr1,
1837                 const SMDS_MeshElement * tr2,
1838                 const SMDS_MeshNode *    n1,
1839                 const SMDS_MeshNode *    n2)
1840 {
1841   double angle = 2*PI; // bad angle
1842
1843   // get normals
1844   SMESH::Controls::TSequenceOfXYZ P1, P2;
1845   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1846        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1847     return angle;
1848   gp_Vec N1,N2;
1849   if(!tr1->IsQuadratic())
1850     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1851   else
1852     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1853   if ( N1.SquareMagnitude() <= gp::Resolution() )
1854     return angle;
1855   if(!tr2->IsQuadratic())
1856     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1857   else
1858     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1859   if ( N2.SquareMagnitude() <= gp::Resolution() )
1860     return angle;
1861
1862   // find the first diagonal node n1 in the triangles:
1863   // take in account a diagonal link orientation
1864   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1865   for ( int t = 0; t < 2; t++ ) {
1866     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1867     int i = 0, iDiag = -1;
1868     while ( it->more()) {
1869       const SMDS_MeshElement *n = it->next();
1870       if ( n == n1 || n == n2 )
1871         if ( iDiag < 0)
1872           iDiag = i;
1873         else {
1874           if ( i - iDiag == 1 )
1875             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1876           else
1877             nFirst[ t ] = n;
1878           break;
1879         }
1880       i++;
1881     }
1882   }
1883   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1884     N2.Reverse();
1885
1886   angle = N1.Angle( N2 );
1887   //SCRUTE( angle );
1888   return angle;
1889 }
1890
1891 // =================================================
1892 // class generating a unique ID for a pair of nodes
1893 // and able to return nodes by that ID
1894 // =================================================
1895 class LinkID_Gen {
1896 public:
1897
1898   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1899     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1900   {}
1901
1902   long GetLinkID (const SMDS_MeshNode * n1,
1903                   const SMDS_MeshNode * n2) const
1904   {
1905     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1906   }
1907
1908   bool GetNodes (const long             theLinkID,
1909                  const SMDS_MeshNode* & theNode1,
1910                  const SMDS_MeshNode* & theNode2) const
1911   {
1912     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1913     if ( !theNode1 ) return false;
1914     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1915     if ( !theNode2 ) return false;
1916     return true;
1917   }
1918
1919 private:
1920   LinkID_Gen();
1921   const SMESHDS_Mesh* myMesh;
1922   long                myMaxID;
1923 };
1924
1925
1926 //=======================================================================
1927 //function : TriToQuad
1928 //purpose  : Fuse neighbour triangles into quadrangles.
1929 //           theCrit is used to select a neighbour to fuse with.
1930 //           theMaxAngle is a max angle between element normals at which
1931 //           fusion is still performed.
1932 //=======================================================================
1933
1934 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1935                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1936                                   const double                         theMaxAngle)
1937 {
1938   myLastCreatedElems.Clear();
1939   myLastCreatedNodes.Clear();
1940
1941   MESSAGE( "::TriToQuad()" );
1942
1943   if ( !theCrit.get() )
1944     return false;
1945
1946   SMESHDS_Mesh * aMesh = GetMeshDS();
1947
1948   // Prepare data for algo: build
1949   // 1. map of elements with their linkIDs
1950   // 2. map of linkIDs with their elements
1951
1952   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1953   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1954   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
1955   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1956
1957   TIDSortedElemSet::iterator itElem;
1958   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1959     const SMDS_MeshElement* elem = *itElem;
1960     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1961     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1962     if(!IsTria) continue;
1963
1964     // retrieve element nodes
1965     const SMDS_MeshNode* aNodes [4];
1966     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1967     int i = 0;
1968     while ( i<3 )
1969       aNodes[ i++ ] = cast2Node( itN->next() );
1970     aNodes[ 3 ] = aNodes[ 0 ];
1971
1972     // fill maps
1973     for ( i = 0; i < 3; i++ ) {
1974       SMESH_TLink link( aNodes[i], aNodes[i+1] );
1975       // check if elements sharing a link can be fused
1976       itLE = mapLi_listEl.find( link );
1977       if ( itLE != mapLi_listEl.end() ) {
1978         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1979           continue;
1980         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1981         //if ( FindShape( elem ) != FindShape( elem2 ))
1982         //  continue; // do not fuse triangles laying on different shapes
1983         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1984           continue; // avoid making badly shaped quads
1985         (*itLE).second.push_back( elem );
1986       }
1987       else {
1988         mapLi_listEl[ link ].push_back( elem );
1989       }
1990       mapEl_setLi [ elem ].insert( link );
1991     }
1992   }
1993   // Clean the maps from the links shared by a sole element, ie
1994   // links to which only one element is bound in mapLi_listEl
1995
1996   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1997     int nbElems = (*itLE).second.size();
1998     if ( nbElems < 2  ) {
1999       const SMDS_MeshElement* elem = (*itLE).second.front();
2000       SMESH_TLink link = (*itLE).first;
2001       mapEl_setLi[ elem ].erase( link );
2002       if ( mapEl_setLi[ elem ].empty() )
2003         mapEl_setLi.erase( elem );
2004     }
2005   }
2006
2007   // Algo: fuse triangles into quadrangles
2008
2009   while ( ! mapEl_setLi.empty() ) {
2010     // Look for the start element:
2011     // the element having the least nb of shared links
2012     const SMDS_MeshElement* startElem = 0;
2013     int minNbLinks = 4;
2014     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2015       int nbLinks = (*itEL).second.size();
2016       if ( nbLinks < minNbLinks ) {
2017         startElem = (*itEL).first;
2018         minNbLinks = nbLinks;
2019         if ( minNbLinks == 1 )
2020           break;
2021       }
2022     }
2023
2024     // search elements to fuse starting from startElem or links of elements
2025     // fused earlyer - startLinks
2026     list< SMESH_TLink > startLinks;
2027     while ( startElem || !startLinks.empty() ) {
2028       while ( !startElem && !startLinks.empty() ) {
2029         // Get an element to start, by a link
2030         SMESH_TLink linkId = startLinks.front();
2031         startLinks.pop_front();
2032         itLE = mapLi_listEl.find( linkId );
2033         if ( itLE != mapLi_listEl.end() ) {
2034           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2035           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2036           for ( ; itE != listElem.end() ; itE++ )
2037             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2038               startElem = (*itE);
2039           mapLi_listEl.erase( itLE );
2040         }
2041       }
2042
2043       if ( startElem ) {
2044         // Get candidates to be fused
2045         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2046         const SMESH_TLink *link12, *link13;
2047         startElem = 0;
2048         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2049         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2050         ASSERT( !setLi.empty() );
2051         set< SMESH_TLink >::iterator itLi;
2052         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2053         {
2054           const SMESH_TLink & link = (*itLi);
2055           itLE = mapLi_listEl.find( link );
2056           if ( itLE == mapLi_listEl.end() )
2057             continue;
2058
2059           const SMDS_MeshElement* elem = (*itLE).second.front();
2060           if ( elem == tr1 )
2061             elem = (*itLE).second.back();
2062           mapLi_listEl.erase( itLE );
2063           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2064             continue;
2065           if ( tr2 ) {
2066             tr3 = elem;
2067             link13 = &link;
2068           }
2069           else {
2070             tr2 = elem;
2071             link12 = &link;
2072           }
2073
2074           // add other links of elem to list of links to re-start from
2075           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2076           set< SMESH_TLink >::iterator it;
2077           for ( it = links.begin(); it != links.end(); it++ ) {
2078             const SMESH_TLink& link2 = (*it);
2079             if ( link2 != link )
2080               startLinks.push_back( link2 );
2081           }
2082         }
2083
2084         // Get nodes of possible quadrangles
2085         const SMDS_MeshNode *n12 [4], *n13 [4];
2086         bool Ok12 = false, Ok13 = false;
2087         const SMDS_MeshNode *linkNode1, *linkNode2;
2088         if(tr2) {
2089           linkNode1 = link12->first;
2090           linkNode2 = link12->second;
2091           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2092             Ok12 = true;
2093         }
2094         if(tr3) {
2095           linkNode1 = link13->first;
2096           linkNode2 = link13->second;
2097           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2098             Ok13 = true;
2099         }
2100
2101         // Choose a pair to fuse
2102         if ( Ok12 && Ok13 ) {
2103           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2104           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2105           double aBadRate12 = getBadRate( &quad12, theCrit );
2106           double aBadRate13 = getBadRate( &quad13, theCrit );
2107           if (  aBadRate13 < aBadRate12 )
2108             Ok12 = false;
2109           else
2110             Ok13 = false;
2111         }
2112
2113         // Make quadrangles
2114         // and remove fused elems and removed links from the maps
2115         mapEl_setLi.erase( tr1 );
2116         if ( Ok12 ) {
2117           mapEl_setLi.erase( tr2 );
2118           mapLi_listEl.erase( *link12 );
2119           if(tr1->NbNodes()==3) {
2120             if( tr1->GetID() < tr2->GetID() ) {
2121               aMesh->ChangeElementNodes( tr1, n12, 4 );
2122               myLastCreatedElems.Append(tr1);
2123               aMesh->RemoveElement( tr2 );
2124             }
2125             else {
2126               aMesh->ChangeElementNodes( tr2, n12, 4 );
2127               myLastCreatedElems.Append(tr2);
2128               aMesh->RemoveElement( tr1);
2129             }
2130           }
2131           else {
2132             const SMDS_MeshNode* N1 [6];
2133             const SMDS_MeshNode* N2 [6];
2134             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2135             // now we receive following N1 and N2 (using numeration as above image)
2136             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2137             // i.e. first nodes from both arrays determ new diagonal
2138             const SMDS_MeshNode* aNodes[8];
2139             aNodes[0] = N1[0];
2140             aNodes[1] = N1[1];
2141             aNodes[2] = N2[0];
2142             aNodes[3] = N2[1];
2143             aNodes[4] = N1[3];
2144             aNodes[5] = N2[5];
2145             aNodes[6] = N2[3];
2146             aNodes[7] = N1[5];
2147             if( tr1->GetID() < tr2->GetID() ) {
2148               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2149               myLastCreatedElems.Append(tr1);
2150               GetMeshDS()->RemoveElement( tr2 );
2151             }
2152             else {
2153               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2154               myLastCreatedElems.Append(tr2);
2155               GetMeshDS()->RemoveElement( tr1 );
2156             }
2157             // remove middle node (9)
2158             GetMeshDS()->RemoveNode( N1[4] );
2159           }
2160         }
2161         else if ( Ok13 ) {
2162           mapEl_setLi.erase( tr3 );
2163           mapLi_listEl.erase( *link13 );
2164           if(tr1->NbNodes()==3) {
2165             if( tr1->GetID() < tr2->GetID() ) {
2166               aMesh->ChangeElementNodes( tr1, n13, 4 );
2167               myLastCreatedElems.Append(tr1);
2168               aMesh->RemoveElement( tr3 );
2169             }
2170             else {
2171               aMesh->ChangeElementNodes( tr3, n13, 4 );
2172               myLastCreatedElems.Append(tr3);
2173               aMesh->RemoveElement( tr1 );
2174             }
2175           }
2176           else {
2177             const SMDS_MeshNode* N1 [6];
2178             const SMDS_MeshNode* N2 [6];
2179             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2180             // now we receive following N1 and N2 (using numeration as above image)
2181             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2182             // i.e. first nodes from both arrays determ new diagonal
2183             const SMDS_MeshNode* aNodes[8];
2184             aNodes[0] = N1[0];
2185             aNodes[1] = N1[1];
2186             aNodes[2] = N2[0];
2187             aNodes[3] = N2[1];
2188             aNodes[4] = N1[3];
2189             aNodes[5] = N2[5];
2190             aNodes[6] = N2[3];
2191             aNodes[7] = N1[5];
2192             if( tr1->GetID() < tr2->GetID() ) {
2193               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2194               myLastCreatedElems.Append(tr1);
2195               GetMeshDS()->RemoveElement( tr3 );
2196             }
2197             else {
2198               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2199               myLastCreatedElems.Append(tr3);
2200               GetMeshDS()->RemoveElement( tr1 );
2201             }
2202             // remove middle node (9)
2203             GetMeshDS()->RemoveNode( N1[4] );
2204           }
2205         }
2206
2207         // Next element to fuse: the rejected one
2208         if ( tr3 )
2209           startElem = Ok12 ? tr3 : tr2;
2210
2211       } // if ( startElem )
2212     } // while ( startElem || !startLinks.empty() )
2213   } // while ( ! mapEl_setLi.empty() )
2214
2215   return true;
2216 }
2217
2218
2219 /*#define DUMPSO(txt) \
2220 //  cout << txt << endl;
2221 //=============================================================================
2222 //
2223 //
2224 //
2225 //=============================================================================
2226 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2227 {
2228 if ( i1 == i2 )
2229 return;
2230 int tmp = idNodes[ i1 ];
2231 idNodes[ i1 ] = idNodes[ i2 ];
2232 idNodes[ i2 ] = tmp;
2233 gp_Pnt Ptmp = P[ i1 ];
2234 P[ i1 ] = P[ i2 ];
2235 P[ i2 ] = Ptmp;
2236 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2237 }
2238
2239 //=======================================================================
2240 //function : SortQuadNodes
2241 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2242 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2243 //           1 or 2 else 0.
2244 //=======================================================================
2245
2246 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2247 int               idNodes[] )
2248 {
2249   gp_Pnt P[4];
2250   int i;
2251   for ( i = 0; i < 4; i++ ) {
2252     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2253     if ( !n ) return 0;
2254     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2255   }
2256
2257   gp_Vec V1(P[0], P[1]);
2258   gp_Vec V2(P[0], P[2]);
2259   gp_Vec V3(P[0], P[3]);
2260
2261   gp_Vec Cross1 = V1 ^ V2;
2262   gp_Vec Cross2 = V2 ^ V3;
2263
2264   i = 0;
2265   if (Cross1.Dot(Cross2) < 0)
2266   {
2267     Cross1 = V2 ^ V1;
2268     Cross2 = V1 ^ V3;
2269
2270     if (Cross1.Dot(Cross2) < 0)
2271       i = 2;
2272     else
2273       i = 1;
2274     swap ( i, i + 1, idNodes, P );
2275
2276     //     for ( int ii = 0; ii < 4; ii++ ) {
2277     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2278     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2279     //     }
2280   }
2281   return i;
2282 }
2283
2284 //=======================================================================
2285 //function : SortHexaNodes
2286 //purpose  : Set 8 nodes of a hexahedron in a good order.
2287 //           Return success status
2288 //=======================================================================
2289
2290 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2291                                       int               idNodes[] )
2292 {
2293   gp_Pnt P[8];
2294   int i;
2295   DUMPSO( "INPUT: ========================================");
2296   for ( i = 0; i < 8; i++ ) {
2297     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2298     if ( !n ) return false;
2299     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2300     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2301   }
2302   DUMPSO( "========================================");
2303
2304
2305   set<int> faceNodes;  // ids of bottom face nodes, to be found
2306   set<int> checkedId1; // ids of tried 2-nd nodes
2307   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2308   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2309   int iMin, iLoop1 = 0;
2310
2311   // Loop to try the 2-nd nodes
2312
2313   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2314   {
2315     // Find not checked 2-nd node
2316     for ( i = 1; i < 8; i++ )
2317       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2318         int id1 = idNodes[i];
2319         swap ( 1, i, idNodes, P );
2320         checkedId1.insert ( id1 );
2321         break;
2322       }
2323
2324     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2325     // ie that all but meybe one (id3 which is on the same face) nodes
2326     // lay on the same side from the triangle plane.
2327
2328     bool manyInPlane = false; // more than 4 nodes lay in plane
2329     int iLoop2 = 0;
2330     while ( ++iLoop2 < 6 ) {
2331
2332       // get 1-2-3 plane coeffs
2333       Standard_Real A, B, C, D;
2334       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2335       if ( N.SquareMagnitude() > gp::Resolution() )
2336       {
2337         gp_Pln pln ( P[0], N );
2338         pln.Coefficients( A, B, C, D );
2339
2340         // find the node (iMin) closest to pln
2341         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2342         set<int> idInPln;
2343         for ( i = 3; i < 8; i++ ) {
2344           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2345           if ( fabs( dist[i] ) < minDist ) {
2346             minDist = fabs( dist[i] );
2347             iMin = i;
2348           }
2349           if ( fabs( dist[i] ) <= tol )
2350             idInPln.insert( idNodes[i] );
2351         }
2352
2353         // there should not be more than 4 nodes in bottom plane
2354         if ( idInPln.size() > 1 )
2355         {
2356           DUMPSO( "### idInPln.size() = " << idInPln.size());
2357           // idInPlane does not contain the first 3 nodes
2358           if ( manyInPlane || idInPln.size() == 5)
2359             return false; // all nodes in one plane
2360           manyInPlane = true;
2361
2362           // set the 1-st node to be not in plane
2363           for ( i = 3; i < 8; i++ ) {
2364             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2365               DUMPSO( "### Reset 0-th node");
2366               swap( 0, i, idNodes, P );
2367               break;
2368             }
2369           }
2370
2371           // reset to re-check second nodes
2372           leastDist = DBL_MAX;
2373           faceNodes.clear();
2374           checkedId1.clear();
2375           iLoop1 = 0;
2376           break; // from iLoop2;
2377         }
2378
2379         // check that the other 4 nodes are on the same side
2380         bool sameSide = true;
2381         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2382         for ( i = 3; sameSide && i < 8; i++ ) {
2383           if ( i != iMin )
2384             sameSide = ( isNeg == dist[i] <= 0.);
2385         }
2386
2387         // keep best solution
2388         if ( sameSide && minDist < leastDist ) {
2389           leastDist = minDist;
2390           faceNodes.clear();
2391           faceNodes.insert( idNodes[ 1 ] );
2392           faceNodes.insert( idNodes[ 2 ] );
2393           faceNodes.insert( idNodes[ iMin ] );
2394           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2395                   << " leastDist = " << leastDist);
2396           if ( leastDist <= DBL_MIN )
2397             break;
2398         }
2399       }
2400
2401       // set next 3-d node to check
2402       int iNext = 2 + iLoop2;
2403       if ( iNext < 8 ) {
2404         DUMPSO( "Try 2-nd");
2405         swap ( 2, iNext, idNodes, P );
2406       }
2407     } // while ( iLoop2 < 6 )
2408   } // iLoop1
2409
2410   if ( faceNodes.empty() ) return false;
2411
2412   // Put the faceNodes in proper places
2413   for ( i = 4; i < 8; i++ ) {
2414     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2415       // find a place to put
2416       int iTo = 1;
2417       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2418         iTo++;
2419       DUMPSO( "Set faceNodes");
2420       swap ( iTo, i, idNodes, P );
2421     }
2422   }
2423
2424
2425   // Set nodes of the found bottom face in good order
2426   DUMPSO( " Found bottom face: ");
2427   i = SortQuadNodes( theMesh, idNodes );
2428   if ( i ) {
2429     gp_Pnt Ptmp = P[ i ];
2430     P[ i ] = P[ i+1 ];
2431     P[ i+1 ] = Ptmp;
2432   }
2433   //   else
2434   //     for ( int ii = 0; ii < 4; ii++ ) {
2435   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2436   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2437   //    }
2438
2439   // Gravity center of the top and bottom faces
2440   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2441   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2442
2443   // Get direction from the bottom to the top face
2444   gp_Vec upDir ( aGCb, aGCt );
2445   Standard_Real upDirSize = upDir.Magnitude();
2446   if ( upDirSize <= gp::Resolution() ) return false;
2447   upDir / upDirSize;
2448
2449   // Assure that the bottom face normal points up
2450   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2451   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2452   if ( Nb.Dot( upDir ) < 0 ) {
2453     DUMPSO( "Reverse bottom face");
2454     swap( 1, 3, idNodes, P );
2455   }
2456
2457   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2458   Standard_Real minDist = DBL_MAX;
2459   for ( i = 4; i < 8; i++ ) {
2460     // projection of P[i] to the plane defined by P[0] and upDir
2461     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2462     Standard_Real sqDist = P[0].SquareDistance( Pp );
2463     if ( sqDist < minDist ) {
2464       minDist = sqDist;
2465       iMin = i;
2466     }
2467   }
2468   DUMPSO( "Set 4-th");
2469   swap ( 4, iMin, idNodes, P );
2470
2471   // Set nodes of the top face in good order
2472   DUMPSO( "Sort top face");
2473   i = SortQuadNodes( theMesh, &idNodes[4] );
2474   if ( i ) {
2475     i += 4;
2476     gp_Pnt Ptmp = P[ i ];
2477     P[ i ] = P[ i+1 ];
2478     P[ i+1 ] = Ptmp;
2479   }
2480
2481   // Assure that direction of the top face normal is from the bottom face
2482   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2483   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2484   if ( Nt.Dot( upDir ) < 0 ) {
2485     DUMPSO( "Reverse top face");
2486     swap( 5, 7, idNodes, P );
2487   }
2488
2489   //   DUMPSO( "OUTPUT: ========================================");
2490   //   for ( i = 0; i < 8; i++ ) {
2491   //     float *p = ugrid->GetPoint(idNodes[i]);
2492   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2493   //   }
2494
2495   return true;
2496 }*/
2497
2498 //================================================================================
2499 /*!
2500  * \brief Return nodes linked to the given one
2501  * \param theNode - the node
2502  * \param linkedNodes - the found nodes
2503  * \param type - the type of elements to check
2504  *
2505  * Medium nodes are ignored
2506  */
2507 //================================================================================
2508
2509 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2510                                        TIDSortedElemSet &   linkedNodes,
2511                                        SMDSAbs_ElementType  type )
2512 {
2513   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2514   while ( elemIt->more() )
2515   {
2516     const SMDS_MeshElement* elem = elemIt->next();
2517     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2518     if ( elem->GetType() == SMDSAbs_Volume )
2519     {
2520       SMDS_VolumeTool vol( elem );
2521       while ( nodeIt->more() ) {
2522         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2523         if ( theNode != n && vol.IsLinked( theNode, n ))
2524           linkedNodes.insert( n );
2525       }
2526     }
2527     else
2528     {
2529       for ( int i = 0; nodeIt->more(); ++i ) {
2530         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2531         if ( n == theNode ) {
2532           int iBefore = i - 1;
2533           int iAfter  = i + 1;
2534           if ( elem->IsQuadratic() ) {
2535             int nb = elem->NbNodes() / 2;
2536             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2537             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2538           }
2539           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2540           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2541         }
2542       }
2543     }
2544   }
2545 }
2546
2547 //=======================================================================
2548 //function : laplacianSmooth
2549 //purpose  : pulls theNode toward the center of surrounding nodes directly
2550 //           connected to that node along an element edge
2551 //=======================================================================
2552
2553 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2554                      const Handle(Geom_Surface)&          theSurface,
2555                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2556 {
2557   // find surrounding nodes
2558
2559   TIDSortedElemSet nodeSet;
2560   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2561
2562   // compute new coodrs
2563
2564   double coord[] = { 0., 0., 0. };
2565   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2566   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2567     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2568     if ( theSurface.IsNull() ) { // smooth in 3D
2569       coord[0] += node->X();
2570       coord[1] += node->Y();
2571       coord[2] += node->Z();
2572     }
2573     else { // smooth in 2D
2574       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2575       gp_XY* uv = theUVMap[ node ];
2576       coord[0] += uv->X();
2577       coord[1] += uv->Y();
2578     }
2579   }
2580   int nbNodes = nodeSet.size();
2581   if ( !nbNodes )
2582     return;
2583   coord[0] /= nbNodes;
2584   coord[1] /= nbNodes;
2585
2586   if ( !theSurface.IsNull() ) {
2587     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2588     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2589     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2590     coord[0] = p3d.X();
2591     coord[1] = p3d.Y();
2592     coord[2] = p3d.Z();
2593   }
2594   else
2595     coord[2] /= nbNodes;
2596
2597   // move node
2598
2599   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2600 }
2601
2602 //=======================================================================
2603 //function : centroidalSmooth
2604 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2605 //           surrounding elements
2606 //=======================================================================
2607
2608 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2609                       const Handle(Geom_Surface)&          theSurface,
2610                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2611 {
2612   gp_XYZ aNewXYZ(0.,0.,0.);
2613   SMESH::Controls::Area anAreaFunc;
2614   double totalArea = 0.;
2615   int nbElems = 0;
2616
2617   // compute new XYZ
2618
2619   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2620   while ( elemIt->more() )
2621   {
2622     const SMDS_MeshElement* elem = elemIt->next();
2623     nbElems++;
2624
2625     gp_XYZ elemCenter(0.,0.,0.);
2626     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2627     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2628     int nn = elem->NbNodes();
2629     if(elem->IsQuadratic()) nn = nn/2;
2630     int i=0;
2631     //while ( itN->more() ) {
2632     while ( i<nn ) {
2633       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2634       i++;
2635       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2636       aNodePoints.push_back( aP );
2637       if ( !theSurface.IsNull() ) { // smooth in 2D
2638         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2639         gp_XY* uv = theUVMap[ aNode ];
2640         aP.SetCoord( uv->X(), uv->Y(), 0. );
2641       }
2642       elemCenter += aP;
2643     }
2644     double elemArea = anAreaFunc.GetValue( aNodePoints );
2645     totalArea += elemArea;
2646     elemCenter /= nn;
2647     aNewXYZ += elemCenter * elemArea;
2648   }
2649   aNewXYZ /= totalArea;
2650   if ( !theSurface.IsNull() ) {
2651     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2652     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2653   }
2654
2655   // move node
2656
2657   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2658 }
2659
2660 //=======================================================================
2661 //function : getClosestUV
2662 //purpose  : return UV of closest projection
2663 //=======================================================================
2664
2665 static bool getClosestUV (Extrema_GenExtPS& projector,
2666                           const gp_Pnt&     point,
2667                           gp_XY &           result)
2668 {
2669   projector.Perform( point );
2670   if ( projector.IsDone() ) {
2671     double u, v, minVal = DBL_MAX;
2672     for ( int i = projector.NbExt(); i > 0; i-- )
2673       if ( projector.Value( i ) < minVal ) {
2674         minVal = projector.Value( i );
2675         projector.Point( i ).Parameter( u, v );
2676       }
2677     result.SetCoord( u, v );
2678     return true;
2679   }
2680   return false;
2681 }
2682
2683 //=======================================================================
2684 //function : Smooth
2685 //purpose  : Smooth theElements during theNbIterations or until a worst
2686 //           element has aspect ratio <= theTgtAspectRatio.
2687 //           Aspect Ratio varies in range [1.0, inf].
2688 //           If theElements is empty, the whole mesh is smoothed.
2689 //           theFixedNodes contains additionally fixed nodes. Nodes built
2690 //           on edges and boundary nodes are always fixed.
2691 //=======================================================================
2692
2693 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2694                                set<const SMDS_MeshNode*> & theFixedNodes,
2695                                const SmoothMethod          theSmoothMethod,
2696                                const int                   theNbIterations,
2697                                double                      theTgtAspectRatio,
2698                                const bool                  the2D)
2699 {
2700   myLastCreatedElems.Clear();
2701   myLastCreatedNodes.Clear();
2702
2703   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2704
2705   if ( theTgtAspectRatio < 1.0 )
2706     theTgtAspectRatio = 1.0;
2707
2708   const double disttol = 1.e-16;
2709
2710   SMESH::Controls::AspectRatio aQualityFunc;
2711
2712   SMESHDS_Mesh* aMesh = GetMeshDS();
2713
2714   if ( theElems.empty() ) {
2715     // add all faces to theElems
2716     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2717     while ( fIt->more() ) {
2718       const SMDS_MeshElement* face = fIt->next();
2719       theElems.insert( face );
2720     }
2721   }
2722   // get all face ids theElems are on
2723   set< int > faceIdSet;
2724   TIDSortedElemSet::iterator itElem;
2725   if ( the2D )
2726     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2727       int fId = FindShape( *itElem );
2728       // check that corresponding submesh exists and a shape is face
2729       if (fId &&
2730           faceIdSet.find( fId ) == faceIdSet.end() &&
2731           aMesh->MeshElements( fId )) {
2732         TopoDS_Shape F = aMesh->IndexToShape( fId );
2733         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2734           faceIdSet.insert( fId );
2735       }
2736     }
2737   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2738
2739   // ===============================================
2740   // smooth elements on each TopoDS_Face separately
2741   // ===============================================
2742
2743   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2744   for ( ; fId != faceIdSet.rend(); ++fId ) {
2745     // get face surface and submesh
2746     Handle(Geom_Surface) surface;
2747     SMESHDS_SubMesh* faceSubMesh = 0;
2748     TopoDS_Face face;
2749     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2750     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2751     bool isUPeriodic = false, isVPeriodic = false;
2752     if ( *fId ) {
2753       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2754       surface = BRep_Tool::Surface( face );
2755       faceSubMesh = aMesh->MeshElements( *fId );
2756       fToler2 = BRep_Tool::Tolerance( face );
2757       fToler2 *= fToler2 * 10.;
2758       isUPeriodic = surface->IsUPeriodic();
2759       if ( isUPeriodic )
2760         vPeriod = surface->UPeriod();
2761       isVPeriodic = surface->IsVPeriodic();
2762       if ( isVPeriodic )
2763         uPeriod = surface->VPeriod();
2764       surface->Bounds( u1, u2, v1, v2 );
2765     }
2766     // ---------------------------------------------------------
2767     // for elements on a face, find movable and fixed nodes and
2768     // compute UV for them
2769     // ---------------------------------------------------------
2770     bool checkBoundaryNodes = false;
2771     bool isQuadratic = false;
2772     set<const SMDS_MeshNode*> setMovableNodes;
2773     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2774     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2775     list< const SMDS_MeshElement* > elemsOnFace;
2776
2777     Extrema_GenExtPS projector;
2778     GeomAdaptor_Surface surfAdaptor;
2779     if ( !surface.IsNull() ) {
2780       surfAdaptor.Load( surface );
2781       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2782     }
2783     int nbElemOnFace = 0;
2784     itElem = theElems.begin();
2785     // loop on not yet smoothed elements: look for elems on a face
2786     while ( itElem != theElems.end() ) {
2787       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2788         break; // all elements found
2789
2790       const SMDS_MeshElement* elem = *itElem;
2791       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2792            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2793         ++itElem;
2794         continue;
2795       }
2796       elemsOnFace.push_back( elem );
2797       theElems.erase( itElem++ );
2798       nbElemOnFace++;
2799
2800       if ( !isQuadratic )
2801         isQuadratic = elem->IsQuadratic();
2802
2803       // get movable nodes of elem
2804       const SMDS_MeshNode* node;
2805       SMDS_TypeOfPosition posType;
2806       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2807       int nn = 0, nbn =  elem->NbNodes();
2808       if(elem->IsQuadratic())
2809         nbn = nbn/2;
2810       while ( nn++ < nbn ) {
2811         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2812         const SMDS_PositionPtr& pos = node->GetPosition();
2813         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2814         if (posType != SMDS_TOP_EDGE &&
2815             posType != SMDS_TOP_VERTEX &&
2816             theFixedNodes.find( node ) == theFixedNodes.end())
2817         {
2818           // check if all faces around the node are on faceSubMesh
2819           // because a node on edge may be bound to face
2820           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2821           bool all = true;
2822           if ( faceSubMesh ) {
2823             while ( eIt->more() && all ) {
2824               const SMDS_MeshElement* e = eIt->next();
2825               all = faceSubMesh->Contains( e );
2826             }
2827           }
2828           if ( all )
2829             setMovableNodes.insert( node );
2830           else
2831             checkBoundaryNodes = true;
2832         }
2833         if ( posType == SMDS_TOP_3DSPACE )
2834           checkBoundaryNodes = true;
2835       }
2836
2837       if ( surface.IsNull() )
2838         continue;
2839
2840       // get nodes to check UV
2841       list< const SMDS_MeshNode* > uvCheckNodes;
2842       itN = elem->nodesIterator();
2843       nn = 0; nbn =  elem->NbNodes();
2844       if(elem->IsQuadratic())
2845         nbn = nbn/2;
2846       while ( nn++ < nbn ) {
2847         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2848         if ( uvMap.find( node ) == uvMap.end() )
2849           uvCheckNodes.push_back( node );
2850         // add nodes of elems sharing node
2851         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2852         //         while ( eIt->more() ) {
2853         //           const SMDS_MeshElement* e = eIt->next();
2854         //           if ( e != elem ) {
2855         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2856         //             while ( nIt->more() ) {
2857         //               const SMDS_MeshNode* n =
2858         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2859         //               if ( uvMap.find( n ) == uvMap.end() )
2860         //                 uvCheckNodes.push_back( n );
2861         //             }
2862         //           }
2863         //         }
2864       }
2865       // check UV on face
2866       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2867       for ( ; n != uvCheckNodes.end(); ++n ) {
2868         node = *n;
2869         gp_XY uv( 0, 0 );
2870         const SMDS_PositionPtr& pos = node->GetPosition();
2871         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2872         // get existing UV
2873         switch ( posType ) {
2874         case SMDS_TOP_FACE: {
2875           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2876           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2877           break;
2878         }
2879         case SMDS_TOP_EDGE: {
2880           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2881           Handle(Geom2d_Curve) pcurve;
2882           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2883             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2884           if ( !pcurve.IsNull() ) {
2885             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2886             uv = pcurve->Value( u ).XY();
2887           }
2888           break;
2889         }
2890         case SMDS_TOP_VERTEX: {
2891           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2892           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2893             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2894           break;
2895         }
2896         default:;
2897         }
2898         // check existing UV
2899         bool project = true;
2900         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2901         double dist1 = DBL_MAX, dist2 = 0;
2902         if ( posType != SMDS_TOP_3DSPACE ) {
2903           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2904           project = dist1 > fToler2;
2905         }
2906         if ( project ) { // compute new UV
2907           gp_XY newUV;
2908           if ( !getClosestUV( projector, pNode, newUV )) {
2909             MESSAGE("Node Projection Failed " << node);
2910           }
2911           else {
2912             if ( isUPeriodic )
2913               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2914             if ( isVPeriodic )
2915               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2916             // check new UV
2917             if ( posType != SMDS_TOP_3DSPACE )
2918               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2919             if ( dist2 < dist1 )
2920               uv = newUV;
2921           }
2922         }
2923         // store UV in the map
2924         listUV.push_back( uv );
2925         uvMap.insert( make_pair( node, &listUV.back() ));
2926       }
2927     } // loop on not yet smoothed elements
2928
2929     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2930       checkBoundaryNodes = true;
2931
2932     // fix nodes on mesh boundary
2933
2934     if ( checkBoundaryNodes ) {
2935       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2936       map< NLink, int >::iterator link_nb;
2937       // put all elements links to linkNbMap
2938       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2939       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2940         const SMDS_MeshElement* elem = (*elemIt);
2941         int nbn =  elem->NbNodes();
2942         if(elem->IsQuadratic())
2943           nbn = nbn/2;
2944         // loop on elem links: insert them in linkNbMap
2945         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2946         for ( int iN = 0; iN < nbn; ++iN ) {
2947           curNode = elem->GetNode( iN );
2948           NLink link;
2949           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2950           else                      link = make_pair( prevNode , curNode );
2951           prevNode = curNode;
2952           link_nb = linkNbMap.find( link );
2953           if ( link_nb == linkNbMap.end() )
2954             linkNbMap.insert( make_pair ( link, 1 ));
2955           else
2956             link_nb->second++;
2957         }
2958       }
2959       // remove nodes that are in links encountered only once from setMovableNodes
2960       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2961         if ( link_nb->second == 1 ) {
2962           setMovableNodes.erase( link_nb->first.first );
2963           setMovableNodes.erase( link_nb->first.second );
2964         }
2965       }
2966     }
2967
2968     // -----------------------------------------------------
2969     // for nodes on seam edge, compute one more UV ( uvMap2 );
2970     // find movable nodes linked to nodes on seam and which
2971     // are to be smoothed using the second UV ( uvMap2 )
2972     // -----------------------------------------------------
2973
2974     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2975     if ( !surface.IsNull() ) {
2976       TopExp_Explorer eExp( face, TopAbs_EDGE );
2977       for ( ; eExp.More(); eExp.Next() ) {
2978         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2979         if ( !BRep_Tool::IsClosed( edge, face ))
2980           continue;
2981         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2982         if ( !sm ) continue;
2983         // find out which parameter varies for a node on seam
2984         double f,l;
2985         gp_Pnt2d uv1, uv2;
2986         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2987         if ( pcurve.IsNull() ) continue;
2988         uv1 = pcurve->Value( f );
2989         edge.Reverse();
2990         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2991         if ( pcurve.IsNull() ) continue;
2992         uv2 = pcurve->Value( f );
2993         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2994         // assure uv1 < uv2
2995         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2996           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2997         }
2998         // get nodes on seam and its vertices
2999         list< const SMDS_MeshNode* > seamNodes;
3000         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3001         while ( nSeamIt->more() ) {
3002           const SMDS_MeshNode* node = nSeamIt->next();
3003           if ( !isQuadratic || !IsMedium( node ))
3004             seamNodes.push_back( node );
3005         }
3006         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3007         for ( ; vExp.More(); vExp.Next() ) {
3008           sm = aMesh->MeshElements( vExp.Current() );
3009           if ( sm ) {
3010             nSeamIt = sm->GetNodes();
3011             while ( nSeamIt->more() )
3012               seamNodes.push_back( nSeamIt->next() );
3013           }
3014         }
3015         // loop on nodes on seam
3016         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3017         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3018           const SMDS_MeshNode* nSeam = *noSeIt;
3019           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3020           if ( n_uv == uvMap.end() )
3021             continue;
3022           // set the first UV
3023           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3024           // set the second UV
3025           listUV.push_back( *n_uv->second );
3026           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3027           if ( uvMap2.empty() )
3028             uvMap2 = uvMap; // copy the uvMap contents
3029           uvMap2[ nSeam ] = &listUV.back();
3030
3031           // collect movable nodes linked to ones on seam in nodesNearSeam
3032           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3033           while ( eIt->more() ) {
3034             const SMDS_MeshElement* e = eIt->next();
3035             int nbUseMap1 = 0, nbUseMap2 = 0;
3036             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3037             int nn = 0, nbn =  e->NbNodes();
3038             if(e->IsQuadratic()) nbn = nbn/2;
3039             while ( nn++ < nbn )
3040             {
3041               const SMDS_MeshNode* n =
3042                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3043               if (n == nSeam ||
3044                   setMovableNodes.find( n ) == setMovableNodes.end() )
3045                 continue;
3046               // add only nodes being closer to uv2 than to uv1
3047               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3048                            0.5 * ( n->Y() + nSeam->Y() ),
3049                            0.5 * ( n->Z() + nSeam->Z() ));
3050               gp_XY uv;
3051               getClosestUV( projector, pMid, uv );
3052               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3053                 nodesNearSeam.insert( n );
3054                 nbUseMap2++;
3055               }
3056               else
3057                 nbUseMap1++;
3058             }
3059             // for centroidalSmooth all element nodes must
3060             // be on one side of a seam
3061             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3062               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3063               nn = 0;
3064               while ( nn++ < nbn ) {
3065                 const SMDS_MeshNode* n =
3066                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3067                 setMovableNodes.erase( n );
3068               }
3069             }
3070           }
3071         } // loop on nodes on seam
3072       } // loop on edge of a face
3073     } // if ( !face.IsNull() )
3074
3075     if ( setMovableNodes.empty() ) {
3076       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3077       continue; // goto next face
3078     }
3079
3080     // -------------
3081     // SMOOTHING //
3082     // -------------
3083
3084     int it = -1;
3085     double maxRatio = -1., maxDisplacement = -1.;
3086     set<const SMDS_MeshNode*>::iterator nodeToMove;
3087     for ( it = 0; it < theNbIterations; it++ ) {
3088       maxDisplacement = 0.;
3089       nodeToMove = setMovableNodes.begin();
3090       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3091         const SMDS_MeshNode* node = (*nodeToMove);
3092         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3093
3094         // smooth
3095         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3096         if ( theSmoothMethod == LAPLACIAN )
3097           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3098         else
3099           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3100
3101         // node displacement
3102         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3103         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3104         if ( aDispl > maxDisplacement )
3105           maxDisplacement = aDispl;
3106       }
3107       // no node movement => exit
3108       //if ( maxDisplacement < 1.e-16 ) {
3109       if ( maxDisplacement < disttol ) {
3110         MESSAGE("-- no node movement --");
3111         break;
3112       }
3113
3114       // check elements quality
3115       maxRatio  = 0;
3116       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3117       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3118         const SMDS_MeshElement* elem = (*elemIt);
3119         if ( !elem || elem->GetType() != SMDSAbs_Face )
3120           continue;
3121         SMESH::Controls::TSequenceOfXYZ aPoints;
3122         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3123           double aValue = aQualityFunc.GetValue( aPoints );
3124           if ( aValue > maxRatio )
3125             maxRatio = aValue;
3126         }
3127       }
3128       if ( maxRatio <= theTgtAspectRatio ) {
3129         MESSAGE("-- quality achived --");
3130         break;
3131       }
3132       if (it+1 == theNbIterations) {
3133         MESSAGE("-- Iteration limit exceeded --");
3134       }
3135     } // smoothing iterations
3136
3137     MESSAGE(" Face id: " << *fId <<
3138             " Nb iterstions: " << it <<
3139             " Displacement: " << maxDisplacement <<
3140             " Aspect Ratio " << maxRatio);
3141
3142     // ---------------------------------------
3143     // new nodes positions are computed,
3144     // record movement in DS and set new UV
3145     // ---------------------------------------
3146     nodeToMove = setMovableNodes.begin();
3147     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3148       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3149       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3150       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3151       if ( node_uv != uvMap.end() ) {
3152         gp_XY* uv = node_uv->second;
3153         node->SetPosition
3154           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3155       }
3156     }
3157
3158     // move medium nodes of quadratic elements
3159     if ( isQuadratic )
3160     {
3161       SMESH_MesherHelper helper( *GetMesh() );
3162       if ( !face.IsNull() )
3163         helper.SetSubShape( face );
3164       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3165       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3166         const SMDS_QuadraticFaceOfNodes* QF =
3167           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3168         if(QF) {
3169           vector<const SMDS_MeshNode*> Ns;
3170           Ns.reserve(QF->NbNodes()+1);
3171           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3172           while ( anIter->more() )
3173             Ns.push_back( anIter->next() );
3174           Ns.push_back( Ns[0] );
3175           double x, y, z;
3176           for(int i=0; i<QF->NbNodes(); i=i+2) {
3177             if ( !surface.IsNull() ) {
3178               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3179               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3180               gp_XY uv = ( uv1 + uv2 ) / 2.;
3181               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3182               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3183             }
3184             else {
3185               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3186               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3187               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3188             }
3189             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3190                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3191                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3192               // we have to move i+1 node
3193               aMesh->MoveNode( Ns[i+1], x, y, z );
3194             }
3195           }
3196         }
3197       }
3198     }
3199
3200   } // loop on face ids
3201
3202 }
3203
3204 //=======================================================================
3205 //function : isReverse
3206 //purpose  : Return true if normal of prevNodes is not co-directied with
3207 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3208 //           iNotSame is where prevNodes and nextNodes are different
3209 //=======================================================================
3210
3211 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3212                       vector<const SMDS_MeshNode*> nextNodes,
3213                       const int            nbNodes,
3214                       const int            iNotSame)
3215 {
3216   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3217   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3218
3219   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3220   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3221   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3222   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3223
3224   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3225   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3226   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3227   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3228
3229   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3230
3231   return (vA ^ vB) * vN < 0.0;
3232 }
3233
3234 //=======================================================================
3235 /*!
3236  * \brief Create elements by sweeping an element
3237  * \param elem - element to sweep
3238  * \param newNodesItVec - nodes generated from each node of the element
3239  * \param newElems - generated elements
3240  * \param nbSteps - number of sweeping steps
3241  * \param srcElements - to append elem for each generated element
3242  */
3243 //=======================================================================
3244
3245 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3246                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3247                                     list<const SMDS_MeshElement*>&        newElems,
3248                                     const int                             nbSteps,
3249                                     SMESH_SequenceOfElemPtr&              srcElements)
3250 {
3251   SMESHDS_Mesh* aMesh = GetMeshDS();
3252
3253   // Loop on elem nodes:
3254   // find new nodes and detect same nodes indices
3255   int nbNodes = elem->NbNodes();
3256   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3257   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3258   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3259   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3260
3261   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3262   vector<int> sames(nbNodes);
3263   vector<bool> issimple(nbNodes);
3264
3265   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3266     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3267     const SMDS_MeshNode*                 node         = nnIt->first;
3268     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3269     if ( listNewNodes.empty() ) {
3270       return;
3271     }
3272
3273     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3274
3275     itNN[ iNode ] = listNewNodes.begin();
3276     prevNod[ iNode ] = node;
3277     nextNod[ iNode ] = listNewNodes.front();
3278     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3279       if ( prevNod[ iNode ] != nextNod [ iNode ])
3280         iNotSameNode = iNode;
3281       else {
3282         iSameNode = iNode;
3283         //nbSame++;
3284         sames[nbSame++] = iNode;
3285       }
3286     }
3287   }
3288
3289   //cout<<"  nbSame = "<<nbSame<<endl;
3290   if ( nbSame == nbNodes || nbSame > 2) {
3291     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3292     //INFOS( " Too many same nodes of element " << elem->GetID() );
3293     return;
3294   }
3295
3296   //  if( elem->IsQuadratic() && nbSame>0 ) {
3297   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3298   //    return;
3299   //  }
3300
3301   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3302   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3303   if ( nbSame > 0 ) {
3304     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3305     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3306     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3307   }
3308
3309   //if(nbNodes==8)
3310   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3311   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3312   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3313   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3314
3315   // check element orientation
3316   int i0 = 0, i2 = 2;
3317   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3318     //MESSAGE("Reversed elem " << elem );
3319     i0 = 2;
3320     i2 = 0;
3321     if ( nbSame > 0 )
3322       std::swap( iBeforeSame, iAfterSame );
3323   }
3324
3325   // make new elements
3326   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3327     // get next nodes
3328     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3329       if(issimple[iNode]) {
3330         nextNod[ iNode ] = *itNN[ iNode ];
3331         itNN[ iNode ]++;
3332       }
3333       else {
3334         if( elem->GetType()==SMDSAbs_Node ) {
3335           // we have to use two nodes
3336           midlNod[ iNode ] = *itNN[ iNode ];
3337           itNN[ iNode ]++;
3338           nextNod[ iNode ] = *itNN[ iNode ];
3339           itNN[ iNode ]++;
3340         }
3341         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3342           // we have to use each second node
3343           //itNN[ iNode ]++;
3344           nextNod[ iNode ] = *itNN[ iNode ];
3345           itNN[ iNode ]++;
3346         }
3347         else {
3348           // we have to use two nodes
3349           midlNod[ iNode ] = *itNN[ iNode ];
3350           itNN[ iNode ]++;
3351           nextNod[ iNode ] = *itNN[ iNode ];
3352           itNN[ iNode ]++;
3353         }
3354       }
3355     }
3356     SMDS_MeshElement* aNewElem = 0;
3357     if(!elem->IsPoly()) {
3358       switch ( nbNodes ) {
3359       case 0:
3360         return;
3361       case 1: { // NODE
3362         if ( nbSame == 0 ) {
3363           if(issimple[0])
3364             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3365           else
3366             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3367         }
3368         break;
3369       }
3370       case 2: { // EDGE
3371         if ( nbSame == 0 )
3372           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3373                                     nextNod[ 1 ], nextNod[ 0 ] );
3374         else
3375           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3376                                     nextNod[ iNotSameNode ] );
3377         break;
3378       }
3379
3380       case 3: { // TRIANGLE or quadratic edge
3381         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3382
3383           if ( nbSame == 0 )       // --- pentahedron
3384             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3385                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3386
3387           else if ( nbSame == 1 )  // --- pyramid
3388             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3389                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3390                                          nextNod[ iSameNode ]);
3391
3392           else // 2 same nodes:      --- tetrahedron
3393             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3394                                          nextNod[ iNotSameNode ]);
3395         }
3396         else { // quadratic edge
3397           if(nbSame==0) {     // quadratic quadrangle
3398             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3399                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3400           }
3401           else if(nbSame==1) { // quadratic triangle
3402             if(sames[0]==2) {
3403               return; // medium node on axis
3404             }
3405             else if(sames[0]==0) {
3406               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3407                                         nextNod[2], midlNod[1], prevNod[2]);
3408             }
3409             else { // sames[0]==1
3410               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3411                                         midlNod[0], nextNod[2], prevNod[2]);
3412             }
3413           }
3414           else {
3415             return;
3416           }
3417         }
3418         break;
3419       }
3420       case 4: { // QUADRANGLE
3421
3422         if ( nbSame == 0 )       // --- hexahedron
3423           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3424                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3425
3426         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3427           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3428                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3429                                        nextNod[ iSameNode ]);
3430           newElems.push_back( aNewElem );
3431           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3432                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3433                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3434         }
3435         else if ( nbSame == 2 ) { // pentahedron
3436           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3437             // iBeforeSame is same too
3438             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3439                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3440                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3441           else
3442             // iAfterSame is same too
3443             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3444                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3445                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3446         }
3447         break;
3448       }
3449       case 6: { // quadratic triangle
3450         // create pentahedron with 15 nodes
3451         if(nbSame==0) {
3452           if(i0>0) { // reversed case
3453             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3454                                          nextNod[0], nextNod[2], nextNod[1],
3455                                          prevNod[5], prevNod[4], prevNod[3],
3456                                          nextNod[5], nextNod[4], nextNod[3],
3457                                          midlNod[0], midlNod[2], midlNod[1]);
3458           }
3459           else { // not reversed case
3460             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3461                                          nextNod[0], nextNod[1], nextNod[2],
3462                                          prevNod[3], prevNod[4], prevNod[5],
3463                                          nextNod[3], nextNod[4], nextNod[5],
3464                                          midlNod[0], midlNod[1], midlNod[2]);
3465           }
3466         }
3467         else if(nbSame==1) {
3468           // 2d order pyramid of 13 nodes
3469           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3470           //                                 int n12,int n23,int n34,int n41,
3471           //                                 int n15,int n25,int n35,int n45, int ID);
3472           int n5 = iSameNode;
3473           int n1,n4,n41,n15,n45;
3474           if(i0>0) { // reversed case
3475             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3476             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3477             n41 = n1 + 3;
3478             n15 = n5 + 3;
3479             n45 = n4 + 3;
3480           }
3481           else {
3482             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3483             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3484             n41 = n4 + 3;
3485             n15 = n1 + 3;
3486             n45 = n5 + 3;
3487           }
3488           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3489                                       nextNod[n4], prevNod[n4], prevNod[n5],
3490                                       midlNod[n1], nextNod[n41],
3491                                       midlNod[n4], prevNod[n41],
3492                                       prevNod[n15], nextNod[n15],
3493                                       nextNod[n45], prevNod[n45]);
3494         }
3495         else if(nbSame==2) {
3496           // 2d order tetrahedron of 10 nodes
3497           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3498           //                                 int n12,int n23,int n31,
3499           //                                 int n14,int n24,int n34, int ID);
3500           int n1 = iNotSameNode;
3501           int n2,n3,n12,n23,n31;
3502           if(i0>0) { // reversed case
3503             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3504             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3505             n12 = n2 + 3;
3506             n23 = n3 + 3;
3507             n31 = n1 + 3;
3508           }
3509           else {
3510             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3511             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3512             n12 = n1 + 3;
3513             n23 = n2 + 3;
3514             n31 = n3 + 3;
3515           }
3516           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3517                                        prevNod[n12], prevNod[n23], prevNod[n31],
3518                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3519         }
3520         break;
3521       }
3522       case 8: { // quadratic quadrangle
3523         if(nbSame==0) {
3524           // create hexahedron with 20 nodes
3525           if(i0>0) { // reversed case
3526             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3527                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3528                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3529                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3530                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3531           }
3532           else { // not reversed case
3533             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3534                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3535                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3536                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3537                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3538           }
3539         }
3540         else if(nbSame==1) { 
3541           // --- pyramid + pentahedron - can not be created since it is needed 
3542           // additional middle node ot the center of face
3543           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3544           return;
3545         }
3546         else if(nbSame==2) {
3547           // 2d order Pentahedron with 15 nodes
3548           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3549           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3550           //                                 int n14,int n25,int n36, int ID);
3551           int n1,n2,n4,n5;
3552           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3553             // iBeforeSame is same too
3554             n1 = iBeforeSame;
3555             n2 = iOpposSame;
3556             n4 = iSameNode;
3557             n5 = iAfterSame;
3558           }
3559           else {
3560             // iAfterSame is same too
3561             n1 = iSameNode;
3562             n2 = iBeforeSame;
3563             n4 = iAfterSame;
3564             n5 = iOpposSame;
3565           }
3566           int n12,n45,n14,n25;
3567           if(i0>0) { //reversed case
3568             n12 = n1 + 4;
3569             n45 = n5 + 4;
3570             n14 = n4 + 4;
3571             n25 = n2 + 4;
3572           }
3573           else {
3574             n12 = n2 + 4;
3575             n45 = n4 + 4;
3576             n14 = n1 + 4;
3577             n25 = n5 + 4;
3578           }
3579           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3580                                        prevNod[n4], prevNod[n5], nextNod[n5],
3581                                        prevNod[n12], midlNod[n2], nextNod[n12],
3582                                        prevNod[n45], midlNod[n5], nextNod[n45],
3583                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3584         }
3585         break;
3586       }
3587       default: {
3588         // realized for extrusion only
3589         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3590         //vector<int> quantities (nbNodes + 2);
3591
3592         //quantities[0] = nbNodes; // bottom of prism
3593         //for (int inode = 0; inode < nbNodes; inode++) {
3594         //  polyedre_nodes[inode] = prevNod[inode];
3595         //}
3596
3597         //quantities[1] = nbNodes; // top of prism
3598         //for (int inode = 0; inode < nbNodes; inode++) {
3599         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3600         //}
3601
3602         //for (int iface = 0; iface < nbNodes; iface++) {
3603         //  quantities[iface + 2] = 4;
3604         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3605         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3606         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3607         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3608         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3609         //}
3610         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3611         break;
3612       }
3613       }
3614     }
3615
3616     if(!aNewElem) {
3617       // realized for extrusion only
3618       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3619       vector<int> quantities (nbNodes + 2);
3620
3621       quantities[0] = nbNodes; // bottom of prism
3622       for (int inode = 0; inode < nbNodes; inode++) {
3623         polyedre_nodes[inode] = prevNod[inode];
3624       }
3625
3626       quantities[1] = nbNodes; // top of prism
3627       for (int inode = 0; inode < nbNodes; inode++) {
3628         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3629       }
3630
3631       for (int iface = 0; iface < nbNodes; iface++) {
3632         quantities[iface + 2] = 4;
3633         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3634         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3635         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3636         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3637         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3638       }
3639       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3640     }
3641
3642     if ( aNewElem ) {
3643       newElems.push_back( aNewElem );
3644       myLastCreatedElems.Append(aNewElem);
3645       srcElements.Append( elem );
3646     }
3647
3648     // set new prev nodes
3649     for ( iNode = 0; iNode < nbNodes; iNode++ )
3650       prevNod[ iNode ] = nextNod[ iNode ];
3651
3652   } // for steps
3653 }
3654
3655 //=======================================================================
3656 /*!
3657  * \brief Create 1D and 2D elements around swept elements
3658  * \param mapNewNodes - source nodes and ones generated from them
3659  * \param newElemsMap - source elements and ones generated from them
3660  * \param elemNewNodesMap - nodes generated from each node of each element
3661  * \param elemSet - all swept elements
3662  * \param nbSteps - number of sweeping steps
3663  * \param srcElements - to append elem for each generated element
3664  */
3665 //=======================================================================
3666
3667 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3668                                   TElemOfElemListMap &     newElemsMap,
3669                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3670                                   TIDSortedElemSet&        elemSet,
3671                                   const int                nbSteps,
3672                                   SMESH_SequenceOfElemPtr& srcElements)
3673 {
3674   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3675   SMESHDS_Mesh* aMesh = GetMeshDS();
3676
3677   // Find nodes belonging to only one initial element - sweep them to get edges.
3678
3679   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3680   for ( ; nList != mapNewNodes.end(); nList++ ) {
3681     const SMDS_MeshNode* node =
3682       static_cast<const SMDS_MeshNode*>( nList->first );
3683     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3684     int nbInitElems = 0;
3685     const SMDS_MeshElement* el = 0;
3686     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3687     while ( eIt->more() && nbInitElems < 2 ) {
3688       el = eIt->next();
3689       SMDSAbs_ElementType type = el->GetType();
3690       if ( type == SMDSAbs_Volume || type < highType ) continue;
3691       if ( type > highType ) {
3692         nbInitElems = 0;
3693         highType = type;
3694       }
3695       if ( elemSet.find(el) != elemSet.end() )
3696         nbInitElems++;
3697     }
3698     if ( nbInitElems < 2 ) {
3699       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3700       if(!NotCreateEdge) {
3701         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3702         list<const SMDS_MeshElement*> newEdges;
3703         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3704       }
3705     }
3706   }
3707
3708   // Make a ceiling for each element ie an equal element of last new nodes.
3709   // Find free links of faces - make edges and sweep them into faces.
3710
3711   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3712   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3713   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3714     const SMDS_MeshElement* elem = itElem->first;
3715     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3716
3717     if ( elem->GetType() == SMDSAbs_Edge ) {
3718       // create a ceiling edge
3719       if (!elem->IsQuadratic()) {
3720         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3721                                vecNewNodes[ 1 ]->second.back())) {
3722           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3723                                                    vecNewNodes[ 1 ]->second.back()));
3724           srcElements.Append( myLastCreatedElems.Last() );
3725         }
3726       }
3727       else {
3728         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3729                                vecNewNodes[ 1 ]->second.back(),
3730                                vecNewNodes[ 2 ]->second.back())) {
3731           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3732                                                    vecNewNodes[ 1 ]->second.back(),
3733                                                    vecNewNodes[ 2 ]->second.back()));
3734           srcElements.Append( myLastCreatedElems.Last() );
3735         }
3736       }
3737     }
3738     if ( elem->GetType() != SMDSAbs_Face )
3739       continue;
3740
3741     if(itElem->second.size()==0) continue;
3742
3743     bool hasFreeLinks = false;
3744
3745     TIDSortedElemSet avoidSet;
3746     avoidSet.insert( elem );
3747
3748     set<const SMDS_MeshNode*> aFaceLastNodes;
3749     int iNode, nbNodes = vecNewNodes.size();
3750     if(!elem->IsQuadratic()) {
3751       // loop on the face nodes
3752       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3753         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3754         // look for free links of the face
3755         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3756         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3757         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3758         // check if a link is free
3759         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3760           hasFreeLinks = true;
3761           // make an edge and a ceiling for a new edge
3762           if ( !aMesh->FindEdge( n1, n2 )) {
3763             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3764             srcElements.Append( myLastCreatedElems.Last() );
3765           }
3766           n1 = vecNewNodes[ iNode ]->second.back();
3767           n2 = vecNewNodes[ iNext ]->second.back();
3768           if ( !aMesh->FindEdge( n1, n2 )) {
3769             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3770             srcElements.Append( myLastCreatedElems.Last() );
3771           }
3772         }
3773       }
3774     }
3775     else { // elem is quadratic face
3776       int nbn = nbNodes/2;
3777       for ( iNode = 0; iNode < nbn; iNode++ ) {
3778         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3779         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3780         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3781         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3782         // check if a link is free
3783         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3784           hasFreeLinks = true;
3785           // make an edge and a ceiling for a new edge
3786           // find medium node
3787           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3788           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3789             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3790             srcElements.Append( myLastCreatedElems.Last() );
3791           }
3792           n1 = vecNewNodes[ iNode ]->second.back();
3793           n2 = vecNewNodes[ iNext ]->second.back();
3794           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3795           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3796             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3797             srcElements.Append( myLastCreatedElems.Last() );
3798           }
3799         }
3800       }
3801       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3802         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3803       }
3804     }
3805
3806     // sweep free links into faces
3807
3808     if ( hasFreeLinks )  {
3809       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3810       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3811
3812       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3813       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3814         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3815         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3816       }
3817       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3818         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3819         iVol = 0;
3820         while ( iVol++ < volNb ) v++;
3821         // find indices of free faces of a volume and their source edges
3822         list< int > freeInd;
3823         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3824         SMDS_VolumeTool vTool( *v );
3825         int iF, nbF = vTool.NbFaces();
3826         for ( iF = 0; iF < nbF; iF ++ ) {
3827           if (vTool.IsFreeFace( iF ) &&
3828               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3829               initNodeSet != faceNodeSet) // except an initial face
3830           {
3831             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3832               continue;
3833             freeInd.push_back( iF );
3834             // find source edge of a free face iF
3835             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3836             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3837             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3838                                    initNodeSet.begin(), initNodeSet.end(),
3839                                    commonNodes.begin());
3840             if ( (*v)->IsQuadratic() )
3841               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3842             else
3843               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3844 #ifdef _DEBUG_
3845             if ( !srcEdges.back() )
3846             {
3847               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3848                    << iF << " of volume #" << vTool.ID() << endl;
3849             }
3850 #endif
3851           }
3852         }
3853         if ( freeInd.empty() )
3854           continue;
3855
3856         // create faces for all steps;
3857         // if such a face has been already created by sweep of edge,
3858         // assure that its orientation is OK
3859         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3860           vTool.Set( *v );
3861           vTool.SetExternalNormal();
3862           list< int >::iterator ind = freeInd.begin();
3863           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3864           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3865           {
3866             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3867             int nbn = vTool.NbFaceNodes( *ind );
3868             switch ( nbn ) {
3869             case 3: { ///// triangle
3870               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3871               if ( !f )
3872                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3873               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3874                 aMesh->ChangeElementNodes( f, nodes, nbn );
3875               break;
3876             }
3877             case 4: { ///// quadrangle
3878               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3879               if ( !f )
3880                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3881               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3882                 aMesh->ChangeElementNodes( f, nodes, nbn );
3883               break;
3884             }
3885             default:
3886               if( (*v)->IsQuadratic() ) {
3887                 if(nbn==6) { /////// quadratic triangle
3888                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3889                                                              nodes[1], nodes[3], nodes[5] );
3890                   if ( !f ) {
3891                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3892                                                              nodes[1], nodes[3], nodes[5]));
3893                   }
3894                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3895                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3896                     tmpnodes[0] = nodes[0];
3897                     tmpnodes[1] = nodes[2];
3898                     tmpnodes[2] = nodes[4];
3899                     tmpnodes[3] = nodes[1];
3900                     tmpnodes[4] = nodes[3];
3901                     tmpnodes[5] = nodes[5];
3902                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3903                   }
3904                 }
3905                 else {       /////// quadratic quadrangle
3906                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3907                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3908                   if ( !f ) {
3909                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3910                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3911                   }
3912                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3913                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3914                     tmpnodes[0] = nodes[0];
3915                     tmpnodes[1] = nodes[2];
3916                     tmpnodes[2] = nodes[4];
3917                     tmpnodes[3] = nodes[6];
3918                     tmpnodes[4] = nodes[1];
3919                     tmpnodes[5] = nodes[3];
3920                     tmpnodes[6] = nodes[5];
3921                     tmpnodes[7] = nodes[7];
3922                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3923                   }
3924                 }
3925               }
3926               else { //////// polygon
3927                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3928                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3929                 if ( !f )
3930                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3931                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3932                   aMesh->ChangeElementNodes( f, nodes, nbn );
3933               }
3934             }
3935             while ( srcElements.Length() < myLastCreatedElems.Length() )
3936               srcElements.Append( *srcEdge );
3937
3938           }  // loop on free faces
3939
3940           // go to the next volume
3941           iVol = 0;
3942           while ( iVol++ < nbVolumesByStep ) v++;
3943         }
3944       }
3945     } // sweep free links into faces
3946
3947     // Make a ceiling face with a normal external to a volume
3948
3949     SMDS_VolumeTool lastVol( itElem->second.back() );
3950
3951     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3952     if ( iF >= 0 ) {
3953       lastVol.SetExternalNormal();
3954       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3955       int nbn = lastVol.NbFaceNodes( iF );
3956       switch ( nbn ) {
3957       case 3:
3958         if (!hasFreeLinks ||
3959             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3960           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3961         break;
3962       case 4:
3963         if (!hasFreeLinks ||
3964             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3965           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3966         break;
3967       default:
3968         if(itElem->second.back()->IsQuadratic()) {
3969           if(nbn==6) {
3970             if (!hasFreeLinks ||
3971                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3972                                  nodes[1], nodes[3], nodes[5]) ) {
3973               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3974                                                        nodes[1], nodes[3], nodes[5]));
3975             }
3976           }
3977           else { // nbn==8
3978             if (!hasFreeLinks ||
3979                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3980                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3981               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3982                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3983           }
3984         }
3985         else {
3986           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3987           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3988             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3989         }
3990       } // switch
3991
3992       while ( srcElements.Length() < myLastCreatedElems.Length() )
3993         srcElements.Append( myLastCreatedElems.Last() );
3994     }
3995   } // loop on swept elements
3996 }
3997
3998 //=======================================================================
3999 //function : RotationSweep
4000 //purpose  :
4001 //=======================================================================
4002
4003 SMESH_MeshEditor::PGroupIDs
4004 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4005                                 const gp_Ax1&      theAxis,
4006                                 const double       theAngle,
4007                                 const int          theNbSteps,
4008                                 const double       theTol,
4009                                 const bool         theMakeGroups,
4010                                 const bool         theMakeWalls)
4011 {
4012   myLastCreatedElems.Clear();
4013   myLastCreatedNodes.Clear();
4014
4015   // source elements for each generated one
4016   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4017
4018   MESSAGE( "RotationSweep()");
4019   gp_Trsf aTrsf;
4020   aTrsf.SetRotation( theAxis, theAngle );
4021   gp_Trsf aTrsf2;
4022   aTrsf2.SetRotation( theAxis, theAngle/2. );
4023
4024   gp_Lin aLine( theAxis );
4025   double aSqTol = theTol * theTol;
4026
4027   SMESHDS_Mesh* aMesh = GetMeshDS();
4028
4029   TNodeOfNodeListMap mapNewNodes;
4030   TElemOfVecOfNnlmiMap mapElemNewNodes;
4031   TElemOfElemListMap newElemsMap;
4032
4033   // loop on theElems
4034   TIDSortedElemSet::iterator itElem;
4035   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4036     const SMDS_MeshElement* elem = *itElem;
4037     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4038       continue;
4039     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4040     newNodesItVec.reserve( elem->NbNodes() );
4041
4042     // loop on elem nodes
4043     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4044     while ( itN->more() ) {
4045       // check if a node has been already sweeped
4046       const SMDS_MeshNode* node = cast2Node( itN->next() );
4047
4048       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4049       double coord[3];
4050       aXYZ.Coord( coord[0], coord[1], coord[2] );
4051       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4052
4053       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4054       if ( nIt == mapNewNodes.end() ) {
4055         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4056         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4057
4058         // make new nodes
4059         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4060         //double coord[3];
4061         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4062         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4063         const SMDS_MeshNode * newNode = node;
4064         for ( int i = 0; i < theNbSteps; i++ ) {
4065           if ( !isOnAxis ) {
4066             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4067               // create two nodes
4068               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4069               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4070               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4071               myLastCreatedNodes.Append(newNode);
4072               srcNodes.Append( node );
4073               listNewNodes.push_back( newNode );
4074               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4075               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4076             }
4077             else {
4078               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4079             }
4080             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4081             myLastCreatedNodes.Append(newNode);
4082             srcNodes.Append( node );
4083             listNewNodes.push_back( newNode );
4084           }
4085           else {
4086             listNewNodes.push_back( newNode );
4087             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4088               listNewNodes.push_back( newNode );
4089             }
4090           }
4091         }
4092       }
4093       /*
4094         else {
4095         // if current elem is quadratic and current node is not medium
4096         // we have to check - may be it is needed to insert additional nodes
4097         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4098         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4099         if(listNewNodes.size()==theNbSteps) {
4100         listNewNodes.clear();
4101         // make new nodes
4102         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4103         //double coord[3];
4104         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4105         const SMDS_MeshNode * newNode = node;
4106         if ( !isOnAxis ) {
4107         for(int i = 0; i<theNbSteps; i++) {
4108         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4109         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4110         cout<<"    3 AddNode:  "<<newNode;
4111         myLastCreatedNodes.Append(newNode);
4112         listNewNodes.push_back( newNode );
4113         srcNodes.Append( node );
4114         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4115         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4116         cout<<"    4 AddNode:  "<<newNode;
4117         myLastCreatedNodes.Append(newNode);
4118         srcNodes.Append( node );
4119         listNewNodes.push_back( newNode );
4120         }
4121         }
4122         else {
4123         listNewNodes.push_back( newNode );
4124         }
4125         }
4126         }
4127         }
4128       */
4129       newNodesItVec.push_back( nIt );
4130     }
4131     // make new elements
4132     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4133   }
4134
4135   if ( theMakeWalls )
4136     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4137
4138   PGroupIDs newGroupIDs;
4139   if ( theMakeGroups )
4140     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4141
4142   return newGroupIDs;
4143 }
4144
4145
4146 //=======================================================================
4147 //function : CreateNode
4148 //purpose  :
4149 //=======================================================================
4150 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4151                                                   const double y,
4152                                                   const double z,
4153                                                   const double tolnode,
4154                                                   SMESH_SequenceOfNode& aNodes)
4155 {
4156   myLastCreatedElems.Clear();
4157   myLastCreatedNodes.Clear();
4158
4159   gp_Pnt P1(x,y,z);
4160   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4161
4162   // try to search in sequence of existing nodes
4163   // if aNodes.Length()>0 we 'nave to use given sequence
4164   // else - use all nodes of mesh
4165   if(aNodes.Length()>0) {
4166     int i;
4167     for(i=1; i<=aNodes.Length(); i++) {
4168       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4169       if(P1.Distance(P2)<tolnode)
4170         return aNodes.Value(i);
4171     }
4172   }
4173   else {
4174     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4175     while(itn->more()) {
4176       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4177       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4178       if(P1.Distance(P2)<tolnode)
4179         return aN;
4180     }
4181   }
4182
4183   // create new node and return it
4184   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4185   myLastCreatedNodes.Append(NewNode);
4186   return NewNode;
4187 }
4188
4189
4190 //=======================================================================
4191 //function : ExtrusionSweep
4192 //purpose  :
4193 //=======================================================================
4194
4195 SMESH_MeshEditor::PGroupIDs
4196 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4197                                   const gp_Vec&       theStep,
4198                                   const int           theNbSteps,
4199                                   TElemOfElemListMap& newElemsMap,
4200                                   const bool          theMakeGroups,
4201                                   const int           theFlags,
4202                                   const double        theTolerance)
4203 {
4204   ExtrusParam aParams;
4205   aParams.myDir = gp_Dir(theStep);
4206   aParams.myNodes.Clear();
4207   aParams.mySteps = new TColStd_HSequenceOfReal;
4208   int i;
4209   for(i=1; i<=theNbSteps; i++)
4210     aParams.mySteps->Append(theStep.Magnitude());
4211
4212   return
4213     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4214 }
4215
4216
4217 //=======================================================================
4218 //function : ExtrusionSweep
4219 //purpose  :
4220 //=======================================================================
4221
4222 SMESH_MeshEditor::PGroupIDs
4223 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4224                                   ExtrusParam&        theParams,
4225                                   TElemOfElemListMap& newElemsMap,
4226                                   const bool          theMakeGroups,
4227                                   const int           theFlags,
4228                                   const double        theTolerance)
4229 {
4230   myLastCreatedElems.Clear();
4231   myLastCreatedNodes.Clear();
4232
4233   // source elements for each generated one
4234   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4235
4236   SMESHDS_Mesh* aMesh = GetMeshDS();
4237
4238   int nbsteps = theParams.mySteps->Length();
4239
4240   TNodeOfNodeListMap mapNewNodes;
4241   //TNodeOfNodeVecMap mapNewNodes;
4242   TElemOfVecOfNnlmiMap mapElemNewNodes;
4243   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4244
4245   // loop on theElems
4246   TIDSortedElemSet::iterator itElem;
4247   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4248     // check element type
4249     const SMDS_MeshElement* elem = *itElem;
4250     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4251       continue;
4252
4253     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4254     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4255     newNodesItVec.reserve( elem->NbNodes() );
4256
4257     // loop on elem nodes
4258     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4259     while ( itN->more() )
4260     {
4261       // check if a node has been already sweeped
4262       const SMDS_MeshNode* node = cast2Node( itN->next() );
4263       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4264       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4265       if ( nIt == mapNewNodes.end() ) {
4266         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4267         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4268         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4269         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4270         //vecNewNodes.reserve(nbsteps);
4271
4272         // make new nodes
4273         double coord[] = { node->X(), node->Y(), node->Z() };
4274         //int nbsteps = theParams.mySteps->Length();
4275         for ( int i = 0; i < nbsteps; i++ ) {
4276           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4277             // create additional node
4278             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4279             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4280             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4281             if( theFlags & EXTRUSION_FLAG_SEW ) {
4282               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4283                                                          theTolerance, theParams.myNodes);
4284               listNewNodes.push_back( newNode );
4285             }
4286             else {
4287               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4288               myLastCreatedNodes.Append(newNode);
4289               srcNodes.Append( node );
4290               listNewNodes.push_back( newNode );
4291             }
4292           }
4293           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4294           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4295           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4296           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4297           if( theFlags & EXTRUSION_FLAG_SEW ) {
4298             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4299                                                        theTolerance, theParams.myNodes);
4300             listNewNodes.push_back( newNode );
4301             //vecNewNodes[i]=newNode;
4302           }
4303           else {
4304             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4305             myLastCreatedNodes.Append(newNode);
4306             srcNodes.Append( node );
4307             listNewNodes.push_back( newNode );
4308             //vecNewNodes[i]=newNode;
4309           }
4310         }
4311       }
4312       else {
4313         // if current elem is quadratic and current node is not medium
4314         // we have to check - may be it is needed to insert additional nodes
4315         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4316           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4317           if(listNewNodes.size()==nbsteps) {
4318             listNewNodes.clear();
4319             double coord[] = { node->X(), node->Y(), node->Z() };
4320             for ( int i = 0; i < nbsteps; i++ ) {
4321               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4322               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4323               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4324               if( theFlags & EXTRUSION_FLAG_SEW ) {
4325                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4326                                                            theTolerance, theParams.myNodes);
4327                 listNewNodes.push_back( newNode );
4328               }
4329               else {
4330                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4331                 myLastCreatedNodes.Append(newNode);
4332                 srcNodes.Append( node );
4333                 listNewNodes.push_back( newNode );
4334               }
4335               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4336               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4337               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4338               if( theFlags & EXTRUSION_FLAG_SEW ) {
4339                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4340                                                            theTolerance, theParams.myNodes);
4341                 listNewNodes.push_back( newNode );
4342               }
4343               else {
4344                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4345                 myLastCreatedNodes.Append(newNode);
4346                 srcNodes.Append( node );
4347                 listNewNodes.push_back( newNode );
4348               }
4349             }
4350           }
4351         }
4352       }
4353       newNodesItVec.push_back( nIt );
4354     }
4355     // make new elements
4356     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4357   }
4358
4359   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4360     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4361   }
4362   PGroupIDs newGroupIDs;
4363   if ( theMakeGroups )
4364     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4365
4366   return newGroupIDs;
4367 }
4368
4369 /*
4370 //=======================================================================
4371 //class    : SMESH_MeshEditor_PathPoint
4372 //purpose  : auxiliary class
4373 //=======================================================================
4374 class SMESH_MeshEditor_PathPoint {
4375 public:
4376 SMESH_MeshEditor_PathPoint() {
4377 myPnt.SetCoord(99., 99., 99.);
4378 myTgt.SetCoord(1.,0.,0.);
4379 myAngle=0.;
4380 myPrm=0.;
4381 }
4382 void SetPnt(const gp_Pnt& aP3D){
4383 myPnt=aP3D;
4384 }
4385 void SetTangent(const gp_Dir& aTgt){
4386 myTgt=aTgt;
4387 }
4388 void SetAngle(const double& aBeta){
4389 myAngle=aBeta;
4390 }
4391 void SetParameter(const double& aPrm){
4392 myPrm=aPrm;
4393 }
4394 const gp_Pnt& Pnt()const{
4395 return myPnt;
4396 }
4397 const gp_Dir& Tangent()const{
4398 return myTgt;
4399 }
4400 double Angle()const{
4401 return myAngle;
4402 }
4403 double Parameter()const{
4404 return myPrm;
4405 }
4406
4407 protected:
4408 gp_Pnt myPnt;
4409 gp_Dir myTgt;
4410 double myAngle;
4411 double myPrm;
4412 };
4413 */
4414
4415 //=======================================================================
4416 //function : ExtrusionAlongTrack
4417 //purpose  :
4418 //=======================================================================
4419 SMESH_MeshEditor::Extrusion_Error
4420 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4421                                        SMESH_subMesh*       theTrack,
4422                                        const SMDS_MeshNode* theN1,
4423                                        const bool           theHasAngles,
4424                                        list<double>&        theAngles,
4425                                        const bool           theLinearVariation,
4426                                        const bool           theHasRefPoint,
4427                                        const gp_Pnt&        theRefPoint,
4428                                        const bool           theMakeGroups)
4429 {
4430   myLastCreatedElems.Clear();
4431   myLastCreatedNodes.Clear();
4432
4433   int aNbE;
4434   std::list<double> aPrms;
4435   TIDSortedElemSet::iterator itElem;
4436
4437   gp_XYZ aGC;
4438   TopoDS_Edge aTrackEdge;
4439   TopoDS_Vertex aV1, aV2;
4440
4441   SMDS_ElemIteratorPtr aItE;
4442   SMDS_NodeIteratorPtr aItN;
4443   SMDSAbs_ElementType aTypeE;
4444
4445   TNodeOfNodeListMap mapNewNodes;
4446
4447   // 1. Check data
4448   aNbE = theElements.size();
4449   // nothing to do
4450   if ( !aNbE )
4451     return EXTR_NO_ELEMENTS;
4452
4453   // 1.1 Track Pattern
4454   ASSERT( theTrack );
4455
4456   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4457
4458   aItE = pSubMeshDS->GetElements();
4459   while ( aItE->more() ) {
4460     const SMDS_MeshElement* pE = aItE->next();
4461     aTypeE = pE->GetType();
4462     // Pattern must contain links only
4463     if ( aTypeE != SMDSAbs_Edge )
4464       return EXTR_PATH_NOT_EDGE;
4465   }
4466
4467   list<SMESH_MeshEditor_PathPoint> fullList;
4468
4469   const TopoDS_Shape& aS = theTrack->GetSubShape();
4470   // Sub shape for the Pattern must be an Edge or Wire
4471   if( aS.ShapeType() == TopAbs_EDGE ) {
4472     aTrackEdge = TopoDS::Edge( aS );
4473     // the Edge must not be degenerated
4474     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4475       return EXTR_BAD_PATH_SHAPE;
4476     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4477     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4478     const SMDS_MeshNode* aN1 = aItN->next();
4479     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4480     const SMDS_MeshNode* aN2 = aItN->next();
4481     // starting node must be aN1 or aN2
4482     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4483       return EXTR_BAD_STARTING_NODE;
4484     aItN = pSubMeshDS->GetNodes();
4485     while ( aItN->more() ) {
4486       const SMDS_MeshNode* pNode = aItN->next();
4487       const SMDS_EdgePosition* pEPos =
4488         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4489       double aT = pEPos->GetUParameter();
4490       aPrms.push_back( aT );
4491     }
4492     //Extrusion_Error err =
4493     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4494   }
4495   else if( aS.ShapeType() == TopAbs_WIRE ) {
4496     list< SMESH_subMesh* > LSM;
4497     TopTools_SequenceOfShape Edges;
4498     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4499     while(itSM->more()) {
4500       SMESH_subMesh* SM = itSM->next();
4501       LSM.push_back(SM);
4502       const TopoDS_Shape& aS = SM->GetSubShape();
4503       Edges.Append(aS);
4504     }
4505     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4506     int startNid = theN1->GetID();
4507     TColStd_MapOfInteger UsedNums;
4508     int NbEdges = Edges.Length();
4509     int i = 1;
4510     for(; i<=NbEdges; i++) {
4511       int k = 0;
4512       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4513       for(; itLSM!=LSM.end(); itLSM++) {
4514         k++;
4515         if(UsedNums.Contains(k)) continue;
4516         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4517         SMESH_subMesh* locTrack = *itLSM;
4518         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4519         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4520         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4521         const SMDS_MeshNode* aN1 = aItN->next();
4522         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4523         const SMDS_MeshNode* aN2 = aItN->next();
4524         // starting node must be aN1 or aN2
4525         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4526         // 2. Collect parameters on the track edge
4527         aPrms.clear();
4528         aItN = locMeshDS->GetNodes();
4529         while ( aItN->more() ) {
4530           const SMDS_MeshNode* pNode = aItN->next();
4531           const SMDS_EdgePosition* pEPos =
4532             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4533           double aT = pEPos->GetUParameter();
4534           aPrms.push_back( aT );
4535         }
4536         list<SMESH_MeshEditor_PathPoint> LPP;
4537         //Extrusion_Error err =
4538         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4539         LLPPs.push_back(LPP);
4540         UsedNums.Add(k);
4541         // update startN for search following egde
4542         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4543         else startNid = aN1->GetID();
4544         break;
4545       }
4546     }
4547     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4548     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4549     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4550     for(; itPP!=firstList.end(); itPP++) {
4551       fullList.push_back( *itPP );
4552     }
4553     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4554     fullList.pop_back();
4555     itLLPP++;
4556     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4557       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4558       itPP = currList.begin();
4559       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4560       gp_Dir D1 = PP1.Tangent();
4561       gp_Dir D2 = PP2.Tangent();
4562       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4563                            (D1.Z()+D2.Z())/2 ) );
4564       PP1.SetTangent(Dnew);
4565       fullList.push_back(PP1);
4566       itPP++;
4567       for(; itPP!=firstList.end(); itPP++) {
4568         fullList.push_back( *itPP );
4569       }
4570       PP1 = fullList.back();
4571       fullList.pop_back();
4572     }
4573     // if wire not closed
4574     fullList.push_back(PP1);
4575     // else ???
4576   }
4577   else {
4578     return EXTR_BAD_PATH_SHAPE;
4579   }
4580
4581   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4582                           theHasRefPoint, theRefPoint, theMakeGroups);
4583 }
4584
4585
4586 //=======================================================================
4587 //function : ExtrusionAlongTrack
4588 //purpose  :
4589 //=======================================================================
4590 SMESH_MeshEditor::Extrusion_Error
4591 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4592                                        SMESH_Mesh*          theTrack,
4593                                        const SMDS_MeshNode* theN1,
4594                                        const bool           theHasAngles,
4595                                        list<double>&        theAngles,
4596                                        const bool           theLinearVariation,
4597                                        const bool           theHasRefPoint,
4598                                        const gp_Pnt&        theRefPoint,
4599                                        const bool           theMakeGroups)
4600 {
4601   myLastCreatedElems.Clear();
4602   myLastCreatedNodes.Clear();
4603
4604   int aNbE;
4605   std::list<double> aPrms;
4606   TIDSortedElemSet::iterator itElem;
4607
4608   gp_XYZ aGC;
4609   TopoDS_Edge aTrackEdge;
4610   TopoDS_Vertex aV1, aV2;
4611
4612   SMDS_ElemIteratorPtr aItE;
4613   SMDS_NodeIteratorPtr aItN;
4614   SMDSAbs_ElementType aTypeE;
4615
4616   TNodeOfNodeListMap mapNewNodes;
4617
4618   // 1. Check data
4619   aNbE = theElements.size();
4620   // nothing to do
4621   if ( !aNbE )
4622     return EXTR_NO_ELEMENTS;
4623
4624   // 1.1 Track Pattern
4625   ASSERT( theTrack );
4626
4627   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4628
4629   aItE = pMeshDS->elementsIterator();
4630   while ( aItE->more() ) {
4631     const SMDS_MeshElement* pE = aItE->next();
4632     aTypeE = pE->GetType();
4633     // Pattern must contain links only
4634     if ( aTypeE != SMDSAbs_Edge )
4635       return EXTR_PATH_NOT_EDGE;
4636   }
4637
4638   list<SMESH_MeshEditor_PathPoint> fullList;
4639
4640   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4641   // Sub shape for the Pattern must be an Edge or Wire
4642   if( aS.ShapeType() == TopAbs_EDGE ) {
4643     aTrackEdge = TopoDS::Edge( aS );
4644     // the Edge must not be degenerated
4645     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4646       return EXTR_BAD_PATH_SHAPE;
4647     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4648     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4649     const SMDS_MeshNode* aN1 = aItN->next();
4650     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4651     const SMDS_MeshNode* aN2 = aItN->next();
4652     // starting node must be aN1 or aN2
4653     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4654       return EXTR_BAD_STARTING_NODE;
4655     aItN = pMeshDS->nodesIterator();
4656     while ( aItN->more() ) {
4657       const SMDS_MeshNode* pNode = aItN->next();
4658       if( pNode==aN1 || pNode==aN2 ) continue;
4659       const SMDS_EdgePosition* pEPos =
4660         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4661       double aT = pEPos->GetUParameter();
4662       aPrms.push_back( aT );
4663     }
4664     //Extrusion_Error err =
4665     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4666   }
4667   else if( aS.ShapeType() == TopAbs_WIRE ) {
4668     list< SMESH_subMesh* > LSM;
4669     TopTools_SequenceOfShape Edges;
4670     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4671     for(; eExp.More(); eExp.Next()) {
4672       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4673       if( BRep_Tool::Degenerated(E) ) continue;
4674       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4675       if(SM) {
4676         LSM.push_back(SM);
4677         Edges.Append(E);
4678       }
4679     }
4680     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4681     int startNid = theN1->GetID();
4682     TColStd_MapOfInteger UsedNums;
4683     int NbEdges = Edges.Length();
4684     int i = 1;
4685     for(; i<=NbEdges; i++) {
4686       int k = 0;
4687       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4688       for(; itLSM!=LSM.end(); itLSM++) {
4689         k++;
4690         if(UsedNums.Contains(k)) continue;
4691         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4692         SMESH_subMesh* locTrack = *itLSM;
4693         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4694         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4695         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4696         const SMDS_MeshNode* aN1 = aItN->next();
4697         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4698         const SMDS_MeshNode* aN2 = aItN->next();
4699         // starting node must be aN1 or aN2
4700         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4701         // 2. Collect parameters on the track edge
4702         aPrms.clear();
4703         aItN = locMeshDS->GetNodes();
4704         while ( aItN->more() ) {
4705           const SMDS_MeshNode* pNode = aItN->next();
4706           const SMDS_EdgePosition* pEPos =
4707             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4708           double aT = pEPos->GetUParameter();
4709           aPrms.push_back( aT );
4710         }
4711         list<SMESH_MeshEditor_PathPoint> LPP;
4712         //Extrusion_Error err =
4713         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4714         LLPPs.push_back(LPP);
4715         UsedNums.Add(k);
4716         // update startN for search following egde
4717         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4718         else startNid = aN1->GetID();
4719         break;
4720       }
4721     }
4722     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4723     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4724     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4725     for(; itPP!=firstList.end(); itPP++) {
4726       fullList.push_back( *itPP );
4727     }
4728     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4729     fullList.pop_back();
4730     itLLPP++;
4731     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4732       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4733       itPP = currList.begin();
4734       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4735       gp_Pnt P1 = PP1.Pnt();
4736       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4737       gp_Pnt P2 = PP2.Pnt();
4738       gp_Dir D1 = PP1.Tangent();
4739       gp_Dir D2 = PP2.Tangent();
4740       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4741                            (D1.Z()+D2.Z())/2 ) );
4742       PP1.SetTangent(Dnew);
4743       fullList.push_back(PP1);
4744       itPP++;
4745       for(; itPP!=currList.end(); itPP++) {
4746         fullList.push_back( *itPP );
4747       }
4748       PP1 = fullList.back();
4749       fullList.pop_back();
4750     }
4751     // if wire not closed
4752     fullList.push_back(PP1);
4753     // else ???
4754   }
4755   else {
4756     return EXTR_BAD_PATH_SHAPE;
4757   }
4758
4759   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4760                           theHasRefPoint, theRefPoint, theMakeGroups);
4761 }
4762
4763
4764 //=======================================================================
4765 //function : MakeEdgePathPoints
4766 //purpose  : auxilary for ExtrusionAlongTrack
4767 //=======================================================================
4768 SMESH_MeshEditor::Extrusion_Error
4769 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4770                                      const TopoDS_Edge& aTrackEdge,
4771                                      bool FirstIsStart,
4772                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4773 {
4774   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4775   aTolVec=1.e-7;
4776   aTolVec2=aTolVec*aTolVec;
4777   double aT1, aT2;
4778   TopoDS_Vertex aV1, aV2;
4779   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4780   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4781   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4782   // 2. Collect parameters on the track edge
4783   aPrms.push_front( aT1 );
4784   aPrms.push_back( aT2 );
4785   // sort parameters
4786   aPrms.sort();
4787   if( FirstIsStart ) {
4788     if ( aT1 > aT2 ) {
4789       aPrms.reverse();
4790     }
4791   }
4792   else {
4793     if ( aT2 > aT1 ) {
4794       aPrms.reverse();
4795     }
4796   }
4797   // 3. Path Points
4798   SMESH_MeshEditor_PathPoint aPP;
4799   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4800   std::list<double>::iterator aItD = aPrms.begin();
4801   for(; aItD != aPrms.end(); ++aItD) {
4802     double aT = *aItD;
4803     gp_Pnt aP3D;
4804     gp_Vec aVec;
4805     aC3D->D1( aT, aP3D, aVec );
4806     aL2 = aVec.SquareMagnitude();
4807     if ( aL2 < aTolVec2 )
4808       return EXTR_CANT_GET_TANGENT;
4809     gp_Dir aTgt( aVec );
4810     aPP.SetPnt( aP3D );
4811     aPP.SetTangent( aTgt );
4812     aPP.SetParameter( aT );
4813     LPP.push_back(aPP);
4814   }
4815   return EXTR_OK;
4816 }
4817
4818
4819 //=======================================================================
4820 //function : MakeExtrElements
4821 //purpose  : auxilary for ExtrusionAlongTrack
4822 //=======================================================================
4823 SMESH_MeshEditor::Extrusion_Error
4824 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4825                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4826                                    const bool theHasAngles,
4827                                    list<double>& theAngles,
4828                                    const bool theLinearVariation,
4829                                    const bool theHasRefPoint,
4830                                    const gp_Pnt& theRefPoint,
4831                                    const bool theMakeGroups)
4832 {
4833   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4834   int aNbTP = fullList.size();
4835   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4836   // Angles
4837   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4838     LinearAngleVariation(aNbTP-1, theAngles);
4839   }
4840   vector<double> aAngles( aNbTP );
4841   int j = 0;
4842   for(; j<aNbTP; ++j) {
4843     aAngles[j] = 0.;
4844   }
4845   if ( theHasAngles ) {
4846     double anAngle;;
4847     std::list<double>::iterator aItD = theAngles.begin();
4848     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4849       anAngle = *aItD;
4850       aAngles[j] = anAngle;
4851     }
4852   }
4853   // fill vector of path points with angles
4854   //aPPs.resize(fullList.size());
4855   j = -1;
4856   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4857   for(; itPP!=fullList.end(); itPP++) {
4858     j++;
4859     SMESH_MeshEditor_PathPoint PP = *itPP;
4860     PP.SetAngle(aAngles[j]);
4861     aPPs[j] = PP;
4862   }
4863
4864   TNodeOfNodeListMap mapNewNodes;
4865   TElemOfVecOfNnlmiMap mapElemNewNodes;
4866   TElemOfElemListMap newElemsMap;
4867   TIDSortedElemSet::iterator itElem;
4868   double aX, aY, aZ;
4869   int aNb;
4870   SMDSAbs_ElementType aTypeE;
4871   // source elements for each generated one
4872   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4873
4874   // 3. Center of rotation aV0
4875   gp_Pnt aV0 = theRefPoint;
4876   gp_XYZ aGC;
4877   if ( !theHasRefPoint ) {
4878     aNb = 0;
4879     aGC.SetCoord( 0.,0.,0. );
4880
4881     itElem = theElements.begin();
4882     for ( ; itElem != theElements.end(); itElem++ ) {
4883       const SMDS_MeshElement* elem = *itElem;
4884
4885       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4886       while ( itN->more() ) {
4887         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4888         aX = node->X();
4889         aY = node->Y();
4890         aZ = node->Z();
4891
4892         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4893           list<const SMDS_MeshNode*> aLNx;
4894           mapNewNodes[node] = aLNx;
4895           //
4896           gp_XYZ aXYZ( aX, aY, aZ );
4897           aGC += aXYZ;
4898           ++aNb;
4899         }
4900       }
4901     }
4902     aGC /= aNb;
4903     aV0.SetXYZ( aGC );
4904   } // if (!theHasRefPoint) {
4905   mapNewNodes.clear();
4906
4907   // 4. Processing the elements
4908   SMESHDS_Mesh* aMesh = GetMeshDS();
4909
4910   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4911     // check element type
4912     const SMDS_MeshElement* elem = *itElem;
4913     aTypeE = elem->GetType();
4914     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4915       continue;
4916
4917     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4918     newNodesItVec.reserve( elem->NbNodes() );
4919
4920     // loop on elem nodes
4921     int nodeIndex = -1;
4922     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4923     while ( itN->more() )
4924     {
4925       ++nodeIndex;
4926       // check if a node has been already processed
4927       const SMDS_MeshNode* node =
4928         static_cast<const SMDS_MeshNode*>( itN->next() );
4929       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4930       if ( nIt == mapNewNodes.end() ) {
4931         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4932         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4933
4934         // make new nodes
4935         aX = node->X();  aY = node->Y(); aZ = node->Z();
4936
4937         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4938         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4939         gp_Ax1 anAx1, anAxT1T0;
4940         gp_Dir aDT1x, aDT0x, aDT1T0;
4941
4942         aTolAng=1.e-4;
4943
4944         aV0x = aV0;
4945         aPN0.SetCoord(aX, aY, aZ);
4946
4947         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4948         aP0x = aPP0.Pnt();
4949         aDT0x= aPP0.Tangent();
4950         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4951
4952         for ( j = 1; j < aNbTP; ++j ) {
4953           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4954           aP1x = aPP1.Pnt();
4955           aDT1x = aPP1.Tangent();
4956           aAngle1x = aPP1.Angle();
4957
4958           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4959           // Translation
4960           gp_Vec aV01x( aP0x, aP1x );
4961           aTrsf.SetTranslation( aV01x );
4962
4963           // traslated point
4964           aV1x = aV0x.Transformed( aTrsf );
4965           aPN1 = aPN0.Transformed( aTrsf );
4966
4967           // rotation 1 [ T1,T0 ]
4968           aAngleT1T0=-aDT1x.Angle( aDT0x );
4969           if (fabs(aAngleT1T0) > aTolAng) {
4970             aDT1T0=aDT1x^aDT0x;
4971             anAxT1T0.SetLocation( aV1x );
4972             anAxT1T0.SetDirection( aDT1T0 );
4973             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4974
4975             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4976           }
4977
4978           // rotation 2
4979           if ( theHasAngles ) {
4980             anAx1.SetLocation( aV1x );
4981             anAx1.SetDirection( aDT1x );
4982             aTrsfRot.SetRotation( anAx1, aAngle1x );
4983
4984             aPN1 = aPN1.Transformed( aTrsfRot );
4985           }
4986
4987           // make new node
4988           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4989             // create additional node
4990             double x = ( aPN1.X() + aPN0.X() )/2.;
4991             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4992             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4993             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4994             myLastCreatedNodes.Append(newNode);
4995             srcNodes.Append( node );
4996             listNewNodes.push_back( newNode );
4997           }
4998           aX = aPN1.X();
4999           aY = aPN1.Y();
5000           aZ = aPN1.Z();
5001           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5002           myLastCreatedNodes.Append(newNode);
5003           srcNodes.Append( node );
5004           listNewNodes.push_back( newNode );
5005
5006           aPN0 = aPN1;
5007           aP0x = aP1x;
5008           aV0x = aV1x;
5009           aDT0x = aDT1x;
5010         }
5011       }
5012
5013       else {
5014         // if current elem is quadratic and current node is not medium
5015         // we have to check - may be it is needed to insert additional nodes
5016         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5017           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5018           if(listNewNodes.size()==aNbTP-1) {
5019             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5020             gp_XYZ P(node->X(), node->Y(), node->Z());
5021             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5022             int i;
5023             for(i=0; i<aNbTP-1; i++) {
5024               const SMDS_MeshNode* N = *it;
5025               double x = ( N->X() + P.X() )/2.;
5026               double y = ( N->Y() + P.Y() )/2.;
5027               double z = ( N->Z() + P.Z() )/2.;
5028               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5029               srcNodes.Append( node );
5030               myLastCreatedNodes.Append(newN);
5031               aNodes[2*i] = newN;
5032               aNodes[2*i+1] = N;
5033               P = gp_XYZ(N->X(),N->Y(),N->Z());
5034             }
5035             listNewNodes.clear();
5036             for(i=0; i<2*(aNbTP-1); i++) {
5037               listNewNodes.push_back(aNodes[i]);
5038             }
5039           }
5040         }
5041       }
5042
5043       newNodesItVec.push_back( nIt );
5044     }
5045     // make new elements
5046     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5047     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5048     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5049   }
5050
5051   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5052
5053   if ( theMakeGroups )
5054     generateGroups( srcNodes, srcElems, "extruded");
5055
5056   return EXTR_OK;
5057 }
5058
5059
5060 //=======================================================================
5061 //function : LinearAngleVariation
5062 //purpose  : auxilary for ExtrusionAlongTrack
5063 //=======================================================================
5064 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5065                                             list<double>& Angles)
5066 {
5067   int nbAngles = Angles.size();
5068   if( nbSteps > nbAngles ) {
5069     vector<double> theAngles(nbAngles);
5070     list<double>::iterator it = Angles.begin();
5071     int i = -1;
5072     for(; it!=Angles.end(); it++) {
5073       i++;
5074       theAngles[i] = (*it);
5075     }
5076     list<double> res;
5077     double rAn2St = double( nbAngles ) / double( nbSteps );
5078     double angPrev = 0, angle;
5079     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5080       double angCur = rAn2St * ( iSt+1 );
5081       double angCurFloor  = floor( angCur );
5082       double angPrevFloor = floor( angPrev );
5083       if ( angPrevFloor == angCurFloor )
5084         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5085       else {
5086         int iP = int( angPrevFloor );
5087         double angPrevCeil = ceil(angPrev);
5088         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5089
5090         int iC = int( angCurFloor );
5091         if ( iC < nbAngles )
5092           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5093
5094         iP = int( angPrevCeil );
5095         while ( iC-- > iP )
5096           angle += theAngles[ iC ];
5097       }
5098       res.push_back(angle);
5099       angPrev = angCur;
5100     }
5101     Angles.clear();
5102     it = res.begin();
5103     for(; it!=res.end(); it++)
5104       Angles.push_back( *it );
5105   }
5106 }
5107
5108
5109 //=======================================================================
5110 //function : Transform
5111 //purpose  :
5112 //=======================================================================
5113
5114 SMESH_MeshEditor::PGroupIDs
5115 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5116                              const gp_Trsf&     theTrsf,
5117                              const bool         theCopy,
5118                              const bool         theMakeGroups,
5119                              SMESH_Mesh*        theTargetMesh)
5120 {
5121   myLastCreatedElems.Clear();
5122   myLastCreatedNodes.Clear();
5123
5124   bool needReverse = false;
5125   string groupPostfix;
5126   switch ( theTrsf.Form() ) {
5127   case gp_PntMirror:
5128   case gp_Ax1Mirror:
5129   case gp_Ax2Mirror:
5130     needReverse = true;
5131     groupPostfix = "mirrored";
5132     break;
5133   case gp_Rotation:
5134     groupPostfix = "rotated";
5135     break;
5136   case gp_Translation:
5137     groupPostfix = "translated";
5138     break;
5139   case gp_Scale:
5140     groupPostfix = "scaled";
5141     break;
5142   default:
5143     needReverse = false;
5144     groupPostfix = "transformed";
5145   }
5146
5147   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5148   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5149   SMESHDS_Mesh* aMesh    = GetMeshDS();
5150
5151
5152   // map old node to new one
5153   TNodeNodeMap nodeMap;
5154
5155   // elements sharing moved nodes; those of them which have all
5156   // nodes mirrored but are not in theElems are to be reversed
5157   TIDSortedElemSet inverseElemSet;
5158
5159   // source elements for each generated one
5160   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5161
5162   // loop on theElems
5163   TIDSortedElemSet::iterator itElem;
5164   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5165     const SMDS_MeshElement* elem = *itElem;
5166     if ( !elem )
5167       continue;
5168
5169     // loop on elem nodes
5170     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5171     while ( itN->more() ) {
5172
5173       // check if a node has been already transformed
5174       const SMDS_MeshNode* node = cast2Node( itN->next() );
5175       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5176         nodeMap.insert( make_pair ( node, node ));
5177       if ( !n2n_isnew.second )
5178         continue;
5179
5180       double coord[3];
5181       coord[0] = node->X();
5182       coord[1] = node->Y();
5183       coord[2] = node->Z();
5184       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5185       if ( theTargetMesh ) {
5186         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5187         n2n_isnew.first->second = newNode;
5188         myLastCreatedNodes.Append(newNode);
5189         srcNodes.Append( node );
5190       }
5191       else if ( theCopy ) {
5192         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5193         n2n_isnew.first->second = newNode;
5194         myLastCreatedNodes.Append(newNode);
5195         srcNodes.Append( node );
5196       }
5197       else {
5198         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5199         // node position on shape becomes invalid
5200         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5201           ( SMDS_SpacePosition::originSpacePosition() );
5202       }
5203
5204       // keep inverse elements
5205       if ( !theCopy && !theTargetMesh && needReverse ) {
5206         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5207         while ( invElemIt->more() ) {
5208           const SMDS_MeshElement* iel = invElemIt->next();
5209           inverseElemSet.insert( iel );
5210         }
5211       }
5212     }
5213   }
5214
5215   // either create new elements or reverse mirrored ones
5216   if ( !theCopy && !needReverse && !theTargetMesh )
5217     return PGroupIDs();
5218
5219   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5220   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5221     theElems.insert( *invElemIt );
5222
5223   // replicate or reverse elements
5224
5225   enum {
5226     REV_TETRA   = 0,  //  = nbNodes - 4
5227     REV_PYRAMID = 1,  //  = nbNodes - 4
5228     REV_PENTA   = 2,  //  = nbNodes - 4
5229     REV_FACE    = 3,
5230     REV_HEXA    = 4,  //  = nbNodes - 4
5231     FORWARD     = 5
5232   };
5233   int index[][8] = {
5234     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5235     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5236     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5237     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5238     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5239     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5240   };
5241
5242   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5243   {
5244     const SMDS_MeshElement* elem = *itElem;
5245     if ( !elem || elem->GetType() == SMDSAbs_Node )
5246       continue;
5247
5248     int nbNodes = elem->NbNodes();
5249     int elemType = elem->GetType();
5250
5251     if (elem->IsPoly()) {
5252       // Polygon or Polyhedral Volume
5253       switch ( elemType ) {
5254       case SMDSAbs_Face:
5255         {
5256           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5257           int iNode = 0;
5258           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5259           while (itN->more()) {
5260             const SMDS_MeshNode* node =
5261               static_cast<const SMDS_MeshNode*>(itN->next());
5262             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5263             if (nodeMapIt == nodeMap.end())
5264               break; // not all nodes transformed
5265             if (needReverse) {
5266               // reverse mirrored faces and volumes
5267               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5268             } else {
5269               poly_nodes[iNode] = (*nodeMapIt).second;
5270             }
5271             iNode++;
5272           }
5273           if ( iNode != nbNodes )
5274             continue; // not all nodes transformed
5275
5276           if ( theTargetMesh ) {
5277             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5278             srcElems.Append( elem );
5279           }
5280           else if ( theCopy ) {
5281             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5282             srcElems.Append( elem );
5283           }
5284           else {
5285             aMesh->ChangePolygonNodes(elem, poly_nodes);
5286           }
5287         }
5288         break;
5289       case SMDSAbs_Volume:
5290         {
5291           // ATTENTION: Reversing is not yet done!!!
5292           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5293             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5294           if (!aPolyedre) {
5295             MESSAGE("Warning: bad volumic element");
5296             continue;
5297           }
5298
5299           vector<const SMDS_MeshNode*> poly_nodes;
5300           vector<int> quantities;
5301
5302           bool allTransformed = true;
5303           int nbFaces = aPolyedre->NbFaces();
5304           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5305             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5306             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5307               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5308               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5309               if (nodeMapIt == nodeMap.end()) {
5310                 allTransformed = false; // not all nodes transformed
5311               } else {
5312                 poly_nodes.push_back((*nodeMapIt).second);
5313               }
5314             }
5315             quantities.push_back(nbFaceNodes);
5316           }
5317           if ( !allTransformed )
5318             continue; // not all nodes transformed
5319
5320           if ( theTargetMesh ) {
5321             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5322             srcElems.Append( elem );
5323           }
5324           else if ( theCopy ) {
5325             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5326             srcElems.Append( elem );
5327           }
5328           else {
5329             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5330           }
5331         }
5332         break;
5333       default:;
5334       }
5335       continue;
5336     }
5337
5338     // Regular elements
5339     int* i = index[ FORWARD ];
5340     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5341       if ( elemType == SMDSAbs_Face )
5342         i = index[ REV_FACE ];
5343       else
5344         i = index[ nbNodes - 4 ];
5345
5346     if(elem->IsQuadratic()) {
5347       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5348       i = anIds;
5349       if(needReverse) {
5350         if(nbNodes==3) { // quadratic edge
5351           static int anIds[] = {1,0,2};
5352           i = anIds;
5353         }
5354         else if(nbNodes==6) { // quadratic triangle
5355           static int anIds[] = {0,2,1,5,4,3};
5356           i = anIds;
5357         }
5358         else if(nbNodes==8) { // quadratic quadrangle
5359           static int anIds[] = {0,3,2,1,7,6,5,4};
5360           i = anIds;
5361         }
5362         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5363           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5364           i = anIds;
5365         }
5366         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5367           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5368           i = anIds;
5369         }
5370         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5371           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5372           i = anIds;
5373         }
5374         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5375           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5376           i = anIds;
5377         }
5378       }
5379     }
5380
5381     // find transformed nodes
5382     vector<const SMDS_MeshNode*> nodes(nbNodes);
5383     int iNode = 0;
5384     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5385     while ( itN->more() ) {
5386       const SMDS_MeshNode* node =
5387         static_cast<const SMDS_MeshNode*>( itN->next() );
5388       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5389       if ( nodeMapIt == nodeMap.end() )
5390         break; // not all nodes transformed
5391       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5392     }
5393     if ( iNode != nbNodes )
5394       continue; // not all nodes transformed
5395
5396     if ( theTargetMesh ) {
5397       if ( SMDS_MeshElement* copy =
5398            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5399         myLastCreatedElems.Append( copy );
5400         srcElems.Append( elem );
5401       }
5402     }
5403     else if ( theCopy ) {
5404       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5405         myLastCreatedElems.Append( copy );
5406         srcElems.Append( elem );
5407       }
5408     }
5409     else {
5410       // reverse element as it was reversed by transformation
5411       if ( nbNodes > 2 )
5412         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5413     }
5414   }
5415
5416   PGroupIDs newGroupIDs;
5417
5418   if ( theMakeGroups && theCopy ||
5419        theMakeGroups && theTargetMesh )
5420     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5421
5422   return newGroupIDs;
5423 }
5424
5425
5426 //=======================================================================
5427 //function : Scale
5428 //purpose  :
5429 //=======================================================================
5430
5431 SMESH_MeshEditor::PGroupIDs
5432 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5433                          const gp_Pnt&            thePoint,
5434                          const std::list<double>& theScaleFact,
5435                          const bool         theCopy,
5436                          const bool         theMakeGroups,
5437                          SMESH_Mesh*        theTargetMesh)
5438 {
5439   myLastCreatedElems.Clear();
5440   myLastCreatedNodes.Clear();
5441
5442   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5443   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5444   SMESHDS_Mesh* aMesh    = GetMeshDS();
5445
5446   double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5447   std::list<double>::const_iterator itS = theScaleFact.begin();
5448   scaleX = (*itS);
5449   if(theScaleFact.size()==1) {
5450     scaleY = (*itS);
5451     scaleZ= (*itS);
5452   }
5453   if(theScaleFact.size()==2) {
5454     itS++;
5455     scaleY = (*itS);
5456     scaleZ= (*itS);
5457   }
5458   if(theScaleFact.size()>2) {
5459     itS++;
5460     scaleY = (*itS);
5461     itS++;
5462     scaleZ= (*itS);
5463   }
5464   
5465   // map old node to new one
5466   TNodeNodeMap nodeMap;
5467
5468   // elements sharing moved nodes; those of them which have all
5469   // nodes mirrored but are not in theElems are to be reversed
5470   TIDSortedElemSet inverseElemSet;
5471
5472   // source elements for each generated one
5473   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5474
5475   // loop on theElems
5476   TIDSortedElemSet::iterator itElem;
5477   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5478     const SMDS_MeshElement* elem = *itElem;
5479     if ( !elem )
5480       continue;
5481
5482     // loop on elem nodes
5483     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5484     while ( itN->more() ) {
5485
5486       // check if a node has been already transformed
5487       const SMDS_MeshNode* node = cast2Node( itN->next() );
5488       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5489         nodeMap.insert( make_pair ( node, node ));
5490       if ( !n2n_isnew.second )
5491         continue;
5492
5493       //double coord[3];
5494       //coord[0] = node->X();
5495       //coord[1] = node->Y();
5496       //coord[2] = node->Z();
5497       //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5498       double dx = (node->X() - thePoint.X()) * scaleX;
5499       double dy = (node->Y() - thePoint.Y()) * scaleY;
5500       double dz = (node->Z() - thePoint.Z()) * scaleZ;
5501       if ( theTargetMesh ) {
5502         //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5503         const SMDS_MeshNode * newNode =
5504           aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5505         n2n_isnew.first->second = newNode;
5506         myLastCreatedNodes.Append(newNode);
5507         srcNodes.Append( node );
5508       }
5509       else if ( theCopy ) {
5510         //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5511         const SMDS_MeshNode * newNode =
5512           aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5513         n2n_isnew.first->second = newNode;
5514         myLastCreatedNodes.Append(newNode);
5515         srcNodes.Append( node );
5516       }
5517       else {
5518         //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5519         aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5520         // node position on shape becomes invalid
5521         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5522           ( SMDS_SpacePosition::originSpacePosition() );
5523       }
5524
5525       // keep inverse elements
5526       //if ( !theCopy && !theTargetMesh && needReverse ) {
5527       //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5528       //  while ( invElemIt->more() ) {
5529       //    const SMDS_MeshElement* iel = invElemIt->next();
5530       //    inverseElemSet.insert( iel );
5531       //  }
5532       //}
5533     }
5534   }
5535
5536   // either create new elements or reverse mirrored ones
5537   //if ( !theCopy && !needReverse && !theTargetMesh )
5538   if ( !theCopy && !theTargetMesh )
5539     return PGroupIDs();
5540
5541   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5542   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5543     theElems.insert( *invElemIt );
5544
5545   // replicate or reverse elements
5546
5547   enum {
5548     REV_TETRA   = 0,  //  = nbNodes - 4
5549     REV_PYRAMID = 1,  //  = nbNodes - 4
5550     REV_PENTA   = 2,  //  = nbNodes - 4
5551     REV_FACE    = 3,
5552     REV_HEXA    = 4,  //  = nbNodes - 4
5553     FORWARD     = 5
5554   };
5555   int index[][8] = {
5556     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5557     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5558     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5559     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5560     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5561     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5562   };
5563
5564   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5565   {
5566     const SMDS_MeshElement* elem = *itElem;
5567     if ( !elem || elem->GetType() == SMDSAbs_Node )
5568       continue;
5569
5570     int nbNodes = elem->NbNodes();
5571     int elemType = elem->GetType();
5572
5573     if (elem->IsPoly()) {
5574       // Polygon or Polyhedral Volume
5575       switch ( elemType ) {
5576       case SMDSAbs_Face:
5577         {
5578           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5579           int iNode = 0;
5580           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5581           while (itN->more()) {
5582             const SMDS_MeshNode* node =
5583               static_cast<const SMDS_MeshNode*>(itN->next());
5584             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5585             if (nodeMapIt == nodeMap.end())
5586               break; // not all nodes transformed
5587             //if (needReverse) {
5588             //  // reverse mirrored faces and volumes
5589             //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5590             //} else {
5591             poly_nodes[iNode] = (*nodeMapIt).second;
5592             //}
5593             iNode++;
5594           }
5595           if ( iNode != nbNodes )
5596             continue; // not all nodes transformed
5597
5598           if ( theTargetMesh ) {
5599             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5600             srcElems.Append( elem );
5601           }
5602           else if ( theCopy ) {
5603             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5604             srcElems.Append( elem );
5605           }
5606           else {
5607             aMesh->ChangePolygonNodes(elem, poly_nodes);
5608           }
5609         }
5610         break;
5611       case SMDSAbs_Volume:
5612         {
5613           // ATTENTION: Reversing is not yet done!!!
5614           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5615             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5616           if (!aPolyedre) {
5617             MESSAGE("Warning: bad volumic element");
5618             continue;
5619           }
5620
5621           vector<const SMDS_MeshNode*> poly_nodes;
5622           vector<int> quantities;
5623
5624           bool allTransformed = true;
5625           int nbFaces = aPolyedre->NbFaces();
5626           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5627             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5628             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5629               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5630               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5631               if (nodeMapIt == nodeMap.end()) {
5632                 allTransformed = false; // not all nodes transformed
5633               } else {
5634                 poly_nodes.push_back((*nodeMapIt).second);
5635               }
5636             }
5637             quantities.push_back(nbFaceNodes);
5638           }
5639           if ( !allTransformed )
5640             continue; // not all nodes transformed
5641
5642           if ( theTargetMesh ) {
5643             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5644             srcElems.Append( elem );
5645           }
5646           else if ( theCopy ) {
5647             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5648             srcElems.Append( elem );
5649           }
5650           else {
5651             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5652           }
5653         }
5654         break;
5655       default:;
5656       }
5657       continue;
5658     }
5659
5660     // Regular elements
5661     int* i = index[ FORWARD ];
5662     //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5663     //  if ( elemType == SMDSAbs_Face )
5664     //    i = index[ REV_FACE ];
5665     //  else
5666     //    i = index[ nbNodes - 4 ];
5667
5668     if(elem->IsQuadratic()) {
5669       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5670       i = anIds;
5671       //if(needReverse) {
5672       //  if(nbNodes==3) { // quadratic edge
5673       //    static int anIds[] = {1,0,2};
5674       //    i = anIds;
5675       //  }
5676       //  else if(nbNodes==6) { // quadratic triangle
5677       //    static int anIds[] = {0,2,1,5,4,3};
5678       //    i = anIds;
5679       //  }
5680       //  else if(nbNodes==8) { // quadratic quadrangle
5681       //    static int anIds[] = {0,3,2,1,7,6,5,4};
5682       //    i = anIds;
5683       //  }
5684       //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5685       //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5686       //    i = anIds;
5687       //  }
5688       //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5689       //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5690       //    i = anIds;
5691       //  }
5692       //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5693       //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5694       //    i = anIds;
5695       //  }
5696       //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5697       //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5698       //    i = anIds;
5699       //  }
5700       //}
5701     }
5702
5703     // find transformed nodes
5704     vector<const SMDS_MeshNode*> nodes(nbNodes);
5705     int iNode = 0;
5706     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5707     while ( itN->more() ) {
5708       const SMDS_MeshNode* node =
5709         static_cast<const SMDS_MeshNode*>( itN->next() );
5710       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5711       if ( nodeMapIt == nodeMap.end() )
5712         break; // not all nodes transformed
5713       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5714     }
5715     if ( iNode != nbNodes )
5716       continue; // not all nodes transformed
5717
5718     if ( theTargetMesh ) {
5719       if ( SMDS_MeshElement* copy =
5720            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5721         myLastCreatedElems.Append( copy );
5722         srcElems.Append( elem );
5723       }
5724     }
5725     else if ( theCopy ) {
5726       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5727         myLastCreatedElems.Append( copy );
5728         srcElems.Append( elem );
5729       }
5730     }
5731     else {
5732       // reverse element as it was reversed by transformation
5733       if ( nbNodes > 2 )
5734         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5735     }
5736   }
5737
5738   PGroupIDs newGroupIDs;
5739
5740   if ( theMakeGroups && theCopy ||
5741        theMakeGroups && theTargetMesh ) {
5742     string groupPostfix = "scaled";
5743     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5744   }
5745
5746   return newGroupIDs;
5747 }
5748
5749
5750 //=======================================================================
5751 /*!
5752  * \brief Create groups of elements made during transformation
5753  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5754  * \param elemGens - elements making corresponding myLastCreatedElems
5755  * \param postfix - to append to names of new groups
5756  */
5757 //=======================================================================
5758
5759 SMESH_MeshEditor::PGroupIDs
5760 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5761                                  const SMESH_SequenceOfElemPtr& elemGens,
5762                                  const std::string&             postfix,
5763                                  SMESH_Mesh*                    targetMesh)
5764 {
5765   PGroupIDs newGroupIDs( new list<int> );
5766   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5767
5768   // Sort existing groups by types and collect their names
5769
5770   // to store an old group and a generated new one
5771   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5772   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5773   // group names
5774   set< string > groupNames;
5775   //
5776   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5777   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5778   while ( groupIt->more() ) {
5779     SMESH_Group * group = groupIt->next();
5780     if ( !group ) continue;
5781     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5782     if ( !groupDS || groupDS->IsEmpty() ) continue;
5783     groupNames.insert( group->GetName() );
5784     groupDS->SetStoreName( group->GetName() );
5785     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5786   }
5787
5788   // Groups creation
5789
5790   // loop on nodes and elements
5791   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5792   {
5793     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5794     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5795     if ( gens.Length() != elems.Length() )
5796       throw SALOME_Exception(LOCALIZED("invalid args"));
5797
5798     // loop on created elements
5799     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5800     {
5801       const SMDS_MeshElement* sourceElem = gens( iElem );
5802       if ( !sourceElem ) {
5803         MESSAGE("generateGroups(): NULL source element");
5804         continue;
5805       }
5806       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5807       if ( groupsOldNew.empty() ) {
5808         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5809           ++iElem; // skip all elements made by sourceElem
5810         continue;
5811       }
5812       // collect all elements made by sourceElem
5813       list< const SMDS_MeshElement* > resultElems;
5814       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5815         if ( resElem != sourceElem )
5816           resultElems.push_back( resElem );
5817       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5818         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5819           if ( resElem != sourceElem )
5820             resultElems.push_back( resElem );
5821       // do not generate element groups from node ones
5822       if ( sourceElem->GetType() == SMDSAbs_Node &&
5823            elems( iElem )->GetType() != SMDSAbs_Node )
5824         continue;
5825
5826       // add resultElems to groups made by ones the sourceElem belongs to
5827       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5828       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5829       {
5830         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5831         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5832         {
5833           SMDS_MeshGroup* & newGroup = gOldNew->second;
5834           if ( !newGroup )// create a new group
5835           {
5836             // make a name
5837             string name = oldGroup->GetStoreName();
5838             if ( !targetMesh ) {
5839               name += "_";
5840               name += postfix;
5841               int nb = 0;
5842               while ( !groupNames.insert( name ).second ) // name exists
5843               {
5844                 if ( nb == 0 ) {
5845                   name += "_1";
5846                 }
5847                 else {
5848                   TCollection_AsciiString nbStr(nb+1);
5849                   name.resize( name.rfind('_')+1 );
5850                   name += nbStr.ToCString();
5851                 }
5852                 ++nb;
5853               }
5854             }
5855             // make a group
5856             int id;
5857             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5858                                                  name.c_str(), id );
5859             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5860             newGroup = & groupDS->SMDSGroup();
5861             newGroupIDs->push_back( id );
5862           }
5863
5864           // fill in a new group
5865           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5866           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5867             newGroup->Add( *resElemIt );
5868         }
5869       }
5870     } // loop on created elements
5871   }// loop on nodes and elements
5872
5873   return newGroupIDs;
5874 }
5875
5876 //================================================================================
5877 /*!
5878  * \brief Return list of group of nodes close to each other within theTolerance
5879  *        Search among theNodes or in the whole mesh if theNodes is empty using
5880  *        an Octree algorithm
5881  */
5882 //================================================================================
5883
5884 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5885                                             const double                theTolerance,
5886                                             TListOfListOfNodes &        theGroupsOfNodes)
5887 {
5888   myLastCreatedElems.Clear();
5889   myLastCreatedNodes.Clear();
5890
5891   set<const SMDS_MeshNode*> nodes;
5892   if ( theNodes.empty() )
5893   { // get all nodes in the mesh
5894     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5895     while ( nIt->more() )
5896       nodes.insert( nodes.end(),nIt->next());
5897   }
5898   else
5899     nodes=theNodes;
5900
5901   SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5902 }
5903
5904
5905 //=======================================================================
5906 /*!
5907  * \brief Implementation of search for the node closest to point
5908  */
5909 //=======================================================================
5910
5911 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5912 {
5913   //---------------------------------------------------------------------
5914   /*!
5915    * \brief Constructor
5916    */
5917   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5918   {
5919     myMesh = ( SMESHDS_Mesh* ) theMesh;
5920
5921     set<const SMDS_MeshNode*> nodes;
5922     if ( theMesh ) {
5923       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5924       while ( nIt->more() )
5925         nodes.insert( nodes.end(), nIt->next() );
5926     }
5927     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5928
5929     // get max size of a leaf box
5930     SMESH_OctreeNode* tree = myOctreeNode;
5931     while ( !tree->isLeaf() )
5932     {
5933       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5934       if ( cIt->more() )
5935         tree = cIt->next();
5936     }
5937     myHalfLeafSize = tree->maxSize() / 2.;
5938   }
5939
5940   //---------------------------------------------------------------------
5941   /*!
5942    * \brief Move node and update myOctreeNode accordingly
5943    */
5944   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5945   {
5946     myOctreeNode->UpdateByMoveNode( node, toPnt );
5947     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5948   }
5949
5950   //---------------------------------------------------------------------
5951   /*!
5952    * \brief Do it's job
5953    */
5954   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5955   {
5956     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5957     map<double, const SMDS_MeshNode*> dist2Nodes;
5958     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5959     if ( !dist2Nodes.empty() )
5960       return dist2Nodes.begin()->second;
5961     list<const SMDS_MeshNode*> nodes;
5962     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5963
5964     double minSqDist = DBL_MAX;
5965     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5966     {
5967       // sort leafs by their distance from thePnt
5968       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5969       TDistTreeMap treeMap;
5970       list< SMESH_OctreeNode* > treeList;
5971       list< SMESH_OctreeNode* >::iterator trIt;
5972       treeList.push_back( myOctreeNode );
5973
5974       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5975       bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
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 ( pointInside && !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_MeshEdge 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 }