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