Salome HOME
3d85b87e2c6a99f140d55915be6289cec7784460
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
48
49 #include "utilities.h"
50
51 #include <BRepAdaptor_Surface.hxx>
52 #include <BRepClass3d_SolidClassifier.hxx>
53 #include <BRep_Tool.hxx>
54 #include <ElCLib.hxx>
55 #include <Extrema_GenExtPS.hxx>
56 #include <Extrema_POnCurv.hxx>
57 #include <Extrema_POnSurf.hxx>
58 #include <GC_MakeSegment.hxx>
59 #include <Geom2d_Curve.hxx>
60 #include <GeomAPI_ExtremaCurveCurve.hxx>
61 #include <GeomAdaptor_Surface.hxx>
62 #include <Geom_Curve.hxx>
63 #include <Geom_Line.hxx>
64 #include <Geom_Surface.hxx>
65 #include <IntAna_IntConicQuad.hxx>
66 #include <IntAna_Quadric.hxx>
67 #include <Precision.hxx>
68 #include <TColStd_ListOfInteger.hxx>
69 #include <TopAbs_State.hxx>
70 #include <TopExp.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopTools_ListIteratorOfListOfShape.hxx>
73 #include <TopTools_ListOfShape.hxx>
74 #include <TopTools_SequenceOfShape.hxx>
75 #include <TopoDS.hxx>
76 #include <TopoDS_Face.hxx>
77 #include <gp.hxx>
78 #include <gp_Ax1.hxx>
79 #include <gp_Dir.hxx>
80 #include <gp_Lin.hxx>
81 #include <gp_Pln.hxx>
82 #include <gp_Trsf.hxx>
83 #include <gp_Vec.hxx>
84 #include <gp_XY.hxx>
85 #include <gp_XYZ.hxx>
86
87 #include <math.h>
88
89 #include <map>
90 #include <set>
91 #include <numeric>
92 #include <limits>
93
94 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
95
96 using namespace std;
97 using namespace SMESH::Controls;
98
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
101
102 //=======================================================================
103 //function : SMESH_MeshEditor
104 //purpose  :
105 //=======================================================================
106
107 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
108   :myMesh( theMesh ) // theMesh may be NULL
109 {
110 }
111
112 //=======================================================================
113 /*!
114  * \brief Add element
115  */
116 //=======================================================================
117
118 SMDS_MeshElement*
119 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
120                              const SMDSAbs_ElementType            type,
121                              const bool                           isPoly,
122                              const int                            ID)
123 {
124   SMDS_MeshElement* e = 0;
125   int nbnode = node.size();
126   SMESHDS_Mesh* mesh = GetMeshDS();
127   switch ( type ) {
128   case SMDSAbs_0DElement:
129     if ( nbnode == 1 )
130       if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
131       else      e = mesh->Add0DElement      (node[0] );
132     break;
133   case SMDSAbs_Edge:
134     if ( nbnode == 2 )
135       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
136       else      e = mesh->AddEdge      (node[0], node[1] );
137     else if ( nbnode == 3 )
138       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
139       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
140     break;
141   case SMDSAbs_Face:
142     if ( !isPoly ) {
143       if      (nbnode == 3)
144         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
145         else      e = mesh->AddFace      (node[0], node[1], node[2] );
146       else if (nbnode == 4) 
147         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
148         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
149       else if (nbnode == 6)
150         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
151                                           node[4], node[5], ID);
152         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
153                                           node[4], node[5] );
154       else if (nbnode == 8)
155         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
156                                           node[4], node[5], node[6], node[7], ID);
157         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
158                                           node[4], node[5], node[6], node[7] );
159     } else {
160       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
161       else      e = mesh->AddPolygonalFace      (node    );
162     }
163     break;
164   case SMDSAbs_Volume:
165     if ( !isPoly ) {
166       if      (nbnode == 4)
167         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
168         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
169       else if (nbnode == 5)
170         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171                                             node[4], ID);
172         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
173                                             node[4] );
174       else if (nbnode == 6)
175         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
176                                             node[4], node[5], ID);
177         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
178                                             node[4], node[5] );
179       else if (nbnode == 8)
180         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
181                                             node[4], node[5], node[6], node[7], ID);
182         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
183                                             node[4], node[5], node[6], node[7] );
184       else if (nbnode == 10)
185         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
186                                             node[4], node[5], node[6], node[7],
187                                             node[8], node[9], ID);
188         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
189                                             node[4], node[5], node[6], node[7],
190                                             node[8], node[9] );
191       else if (nbnode == 13)
192         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193                                             node[4], node[5], node[6], node[7],
194                                             node[8], node[9], node[10],node[11],
195                                             node[12],ID);
196         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
197                                             node[4], node[5], node[6], node[7],
198                                             node[8], node[9], node[10],node[11],
199                                             node[12] );
200       else if (nbnode == 15)
201         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
202                                             node[4], node[5], node[6], node[7],
203                                             node[8], node[9], node[10],node[11],
204                                             node[12],node[13],node[14],ID);
205         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
206                                             node[4], node[5], node[6], node[7],
207                                             node[8], node[9], node[10],node[11],
208                                             node[12],node[13],node[14] );
209       else if (nbnode == 20)
210         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
211                                             node[4], node[5], node[6], node[7],
212                                             node[8], node[9], node[10],node[11],
213                                             node[12],node[13],node[14],node[15],
214                                             node[16],node[17],node[18],node[19],ID);
215         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
216                                             node[4], node[5], node[6], node[7],
217                                             node[8], node[9], node[10],node[11],
218                                             node[12],node[13],node[14],node[15],
219                                             node[16],node[17],node[18],node[19] );
220     }
221   }
222   return e;
223 }
224
225 //=======================================================================
226 /*!
227  * \brief Add element
228  */
229 //=======================================================================
230
231 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
232                                                const SMDSAbs_ElementType type,
233                                                const bool                isPoly,
234                                                const int                 ID)
235 {
236   vector<const SMDS_MeshNode*> nodes;
237   nodes.reserve( nodeIDs.size() );
238   vector<int>::const_iterator id = nodeIDs.begin();
239   while ( id != nodeIDs.end() ) {
240     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
241       nodes.push_back( node );
242     else
243       return 0;
244   }
245   return AddElement( nodes, type, isPoly, ID );
246 }
247
248 //=======================================================================
249 //function : Remove
250 //purpose  : Remove a node or an element.
251 //           Modify a compute state of sub-meshes which become empty
252 //=======================================================================
253
254 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
255                               const bool         isNodes )
256 {
257   myLastCreatedElems.Clear();
258   myLastCreatedNodes.Clear();
259
260   SMESHDS_Mesh* aMesh = GetMeshDS();
261   set< SMESH_subMesh *> smmap;
262
263   int removed = 0;
264   list<int>::const_iterator it = theIDs.begin();
265   for ( ; it != theIDs.end(); it++ ) {
266     const SMDS_MeshElement * elem;
267     if ( isNodes )
268       elem = aMesh->FindNode( *it );
269     else
270       elem = aMesh->FindElement( *it );
271     if ( !elem )
272       continue;
273
274     // Notify VERTEX sub-meshes about modification
275     if ( isNodes ) {
276       const SMDS_MeshNode* node = cast2Node( elem );
277       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
278         if ( int aShapeID = node->GetPosition()->GetShapeId() )
279           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
280             smmap.insert( sm );
281     }
282     // Find sub-meshes to notify about modification
283     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
284     //     while ( nodeIt->more() ) {
285     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
286     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
287     //       if ( aPosition.get() ) {
288     //         if ( int aShapeID = aPosition->GetShapeId() ) {
289     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
290     //             smmap.insert( sm );
291     //         }
292     //       }
293     //     }
294
295     // Do remove
296     if ( isNodes )
297       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
298     else
299       aMesh->RemoveElement( elem );
300     removed++;
301   }
302
303   // Notify sub-meshes about modification
304   if ( !smmap.empty() ) {
305     set< SMESH_subMesh *>::iterator smIt;
306     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
307       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
308   }
309
310   //   // Check if the whole mesh becomes empty
311   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
312   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
313
314   return removed;
315 }
316
317 //=======================================================================
318 //function : FindShape
319 //purpose  : Return an index of the shape theElem is on
320 //           or zero if a shape not found
321 //=======================================================================
322
323 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
324 {
325   myLastCreatedElems.Clear();
326   myLastCreatedNodes.Clear();
327
328   SMESHDS_Mesh * aMesh = GetMeshDS();
329   if ( aMesh->ShapeToMesh().IsNull() )
330     return 0;
331
332   if ( theElem->GetType() == SMDSAbs_Node ) {
333     const SMDS_PositionPtr& aPosition =
334       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
335     if ( aPosition.get() )
336       return aPosition->GetShapeId();
337     else
338       return 0;
339   }
340
341   TopoDS_Shape aShape; // the shape a node is on
342   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
343   while ( nodeIt->more() ) {
344     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
345     const SMDS_PositionPtr& aPosition = node->GetPosition();
346     if ( aPosition.get() ) {
347       int aShapeID = aPosition->GetShapeId();
348       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
349       if ( sm ) {
350         if ( sm->Contains( theElem ))
351           return aShapeID;
352         if ( aShape.IsNull() )
353           aShape = aMesh->IndexToShape( aShapeID );
354       }
355       else {
356         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
357       }
358     }
359   }
360
361   // None of nodes is on a proper shape,
362   // find the shape among ancestors of aShape on which a node is
363   if ( aShape.IsNull() ) {
364     //MESSAGE ("::FindShape() - NONE node is on shape")
365     return 0;
366   }
367   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
368   for ( ; ancIt.More(); ancIt.Next() ) {
369     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
370     if ( sm && sm->Contains( theElem ))
371       return aMesh->ShapeToIndex( ancIt.Value() );
372   }
373
374   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
375   return 0;
376 }
377
378 //=======================================================================
379 //function : IsMedium
380 //purpose  :
381 //=======================================================================
382
383 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
384                                 const SMDSAbs_ElementType typeToCheck)
385 {
386   bool isMedium = false;
387   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
388   while (it->more() && !isMedium ) {
389     const SMDS_MeshElement* elem = it->next();
390     isMedium = elem->IsMediumNode(node);
391   }
392   return isMedium;
393 }
394
395 //=======================================================================
396 //function : ShiftNodesQuadTria
397 //purpose  : auxilary
398 //           Shift nodes in the array corresponded to quadratic triangle
399 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
400 //=======================================================================
401 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
402 {
403   const SMDS_MeshNode* nd1 = aNodes[0];
404   aNodes[0] = aNodes[1];
405   aNodes[1] = aNodes[2];
406   aNodes[2] = nd1;
407   const SMDS_MeshNode* nd2 = aNodes[3];
408   aNodes[3] = aNodes[4];
409   aNodes[4] = aNodes[5];
410   aNodes[5] = nd2;
411 }
412
413 //=======================================================================
414 //function : GetNodesFromTwoTria
415 //purpose  : auxilary
416 //           Shift nodes in the array corresponded to quadratic triangle
417 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
418 //=======================================================================
419 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
420                                 const SMDS_MeshElement * theTria2,
421                                 const SMDS_MeshNode* N1[],
422                                 const SMDS_MeshNode* N2[])
423 {
424   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
425   int i=0;
426   while(i<6) {
427     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
428     i++;
429   }
430   if(it->more()) return false;
431   it = theTria2->nodesIterator();
432   i=0;
433   while(i<6) {
434     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
435     i++;
436   }
437   if(it->more()) return false;
438
439   int sames[3] = {-1,-1,-1};
440   int nbsames = 0;
441   int j;
442   for(i=0; i<3; i++) {
443     for(j=0; j<3; j++) {
444       if(N1[i]==N2[j]) {
445         sames[i] = j;
446         nbsames++;
447         break;
448       }
449     }
450   }
451   if(nbsames!=2) return false;
452   if(sames[0]>-1) {
453     ShiftNodesQuadTria(N1);
454     if(sames[1]>-1) {
455       ShiftNodesQuadTria(N1);
456     }
457   }
458   i = sames[0] + sames[1] + sames[2];
459   for(; i<2; i++) {
460     ShiftNodesQuadTria(N2);
461   }
462   // now we receive following N1 and N2 (using numeration as above image)
463   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
464   // i.e. first nodes from both arrays determ new diagonal
465   return true;
466 }
467
468 //=======================================================================
469 //function : InverseDiag
470 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
471 //           but having other common link.
472 //           Return False if args are improper
473 //=======================================================================
474
475 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
476                                     const SMDS_MeshElement * theTria2 )
477 {
478   myLastCreatedElems.Clear();
479   myLastCreatedNodes.Clear();
480
481   if (!theTria1 || !theTria2)
482     return false;
483
484   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
485   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
486   if (F1 && F2) {
487
488     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
489     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
490     //    |/ |                                         | \|
491     //  B +--+ 2                                     B +--+ 2
492
493     // put nodes in array and find out indices of the same ones
494     const SMDS_MeshNode* aNodes [6];
495     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
496     int i = 0;
497     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
498     while ( it->more() ) {
499       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
500
501       if ( i > 2 ) // theTria2
502         // find same node of theTria1
503         for ( int j = 0; j < 3; j++ )
504           if ( aNodes[ i ] == aNodes[ j ]) {
505             sameInd[ j ] = i;
506             sameInd[ i ] = j;
507             break;
508           }
509       // next
510       i++;
511       if ( i == 3 ) {
512         if ( it->more() )
513           return false; // theTria1 is not a triangle
514         it = theTria2->nodesIterator();
515       }
516       if ( i == 6 && it->more() )
517         return false; // theTria2 is not a triangle
518     }
519
520     // find indices of 1,2 and of A,B in theTria1
521     int iA = 0, iB = 0, i1 = 0, i2 = 0;
522     for ( i = 0; i < 6; i++ ) {
523       if ( sameInd [ i ] == 0 )
524         if ( i < 3 ) i1 = i;
525         else         i2 = i;
526       else if (i < 3)
527         if ( iA ) iB = i;
528         else      iA = i;
529     }
530     // nodes 1 and 2 should not be the same
531     if ( aNodes[ i1 ] == aNodes[ i2 ] )
532       return false;
533
534     // theTria1: A->2
535     aNodes[ iA ] = aNodes[ i2 ];
536     // theTria2: B->1
537     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
538
539     //MESSAGE( theTria1 << theTria2 );
540
541     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
542     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
543
544     //MESSAGE( theTria1 << theTria2 );
545
546     return true;
547
548   } // end if(F1 && F2)
549
550   // check case of quadratic faces
551   const SMDS_QuadraticFaceOfNodes* QF1 =
552     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
553   if(!QF1) return false;
554   const SMDS_QuadraticFaceOfNodes* QF2 =
555     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
556   if(!QF2) return false;
557
558   //       5
559   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
560   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
561   //    |   / |
562   //  7 +  +  + 6
563   //    | /9  |
564   //    |/    |
565   //  4 +--+--+ 3
566   //       8
567
568   const SMDS_MeshNode* N1 [6];
569   const SMDS_MeshNode* N2 [6];
570   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
571     return false;
572   // now we receive following N1 and N2 (using numeration as above image)
573   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
574   // i.e. first nodes from both arrays determ new diagonal
575
576   const SMDS_MeshNode* N1new [6];
577   const SMDS_MeshNode* N2new [6];
578   N1new[0] = N1[0];
579   N1new[1] = N2[0];
580   N1new[2] = N2[1];
581   N1new[3] = N1[4];
582   N1new[4] = N2[3];
583   N1new[5] = N1[5];
584   N2new[0] = N1[0];
585   N2new[1] = N1[1];
586   N2new[2] = N2[0];
587   N2new[3] = N1[3];
588   N2new[4] = N2[5];
589   N2new[5] = N1[4];
590   // replaces nodes in faces
591   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
592   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
593
594   return true;
595 }
596
597 //=======================================================================
598 //function : findTriangles
599 //purpose  : find triangles sharing theNode1-theNode2 link
600 //=======================================================================
601
602 static bool findTriangles(const SMDS_MeshNode *    theNode1,
603                           const SMDS_MeshNode *    theNode2,
604                           const SMDS_MeshElement*& theTria1,
605                           const SMDS_MeshElement*& theTria2)
606 {
607   if ( !theNode1 || !theNode2 ) return false;
608
609   theTria1 = theTria2 = 0;
610
611   set< const SMDS_MeshElement* > emap;
612   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
613   while (it->more()) {
614     const SMDS_MeshElement* elem = it->next();
615     if ( elem->NbNodes() == 3 )
616       emap.insert( elem );
617   }
618   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
619   while (it->more()) {
620     const SMDS_MeshElement* elem = it->next();
621     if ( emap.find( elem ) != emap.end() )
622       if ( theTria1 ) {
623         // theTria1 must be element with minimum ID
624         if( theTria1->GetID() < elem->GetID() ) {
625           theTria2 = elem;
626         }
627         else {
628           theTria2 = theTria1;
629           theTria1 = elem;
630         }
631         break;
632       }
633       else {
634         theTria1 = elem;
635       }
636   }
637   return ( theTria1 && theTria2 );
638 }
639
640 //=======================================================================
641 //function : InverseDiag
642 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
643 //           with ones built on the same 4 nodes but having other common link.
644 //           Return false if proper faces not found
645 //=======================================================================
646
647 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
648                                     const SMDS_MeshNode * theNode2)
649 {
650   myLastCreatedElems.Clear();
651   myLastCreatedNodes.Clear();
652
653   MESSAGE( "::InverseDiag()" );
654
655   const SMDS_MeshElement *tr1, *tr2;
656   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
657     return false;
658
659   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
660   //if (!F1) return false;
661   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
662   //if (!F2) return false;
663   if (F1 && F2) {
664
665     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
666     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
667     //    |/ |                                    | \|
668     //  B +--+ 2                                B +--+ 2
669
670     // put nodes in array
671     // and find indices of 1,2 and of A in tr1 and of B in tr2
672     int i, iA1 = 0, i1 = 0;
673     const SMDS_MeshNode* aNodes1 [3];
674     SMDS_ElemIteratorPtr it;
675     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
676       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
677       if ( aNodes1[ i ] == theNode1 )
678         iA1 = i; // node A in tr1
679       else if ( aNodes1[ i ] != theNode2 )
680         i1 = i;  // node 1
681     }
682     int iB2 = 0, i2 = 0;
683     const SMDS_MeshNode* aNodes2 [3];
684     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
685       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
686       if ( aNodes2[ i ] == theNode2 )
687         iB2 = i; // node B in tr2
688       else if ( aNodes2[ i ] != theNode1 )
689         i2 = i;  // node 2
690     }
691
692     // nodes 1 and 2 should not be the same
693     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
694       return false;
695
696     // tr1: A->2
697     aNodes1[ iA1 ] = aNodes2[ i2 ];
698     // tr2: B->1
699     aNodes2[ iB2 ] = aNodes1[ i1 ];
700
701     //MESSAGE( tr1 << tr2 );
702
703     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
704     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
705
706     //MESSAGE( tr1 << tr2 );
707
708     return true;
709   }
710
711   // check case of quadratic faces
712   const SMDS_QuadraticFaceOfNodes* QF1 =
713     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
714   if(!QF1) return false;
715   const SMDS_QuadraticFaceOfNodes* QF2 =
716     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
717   if(!QF2) return false;
718   return InverseDiag(tr1,tr2);
719 }
720
721 //=======================================================================
722 //function : getQuadrangleNodes
723 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
724 //           fusion of triangles tr1 and tr2 having shared link on
725 //           theNode1 and theNode2
726 //=======================================================================
727
728 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
729                         const SMDS_MeshNode *    theNode1,
730                         const SMDS_MeshNode *    theNode2,
731                         const SMDS_MeshElement * tr1,
732                         const SMDS_MeshElement * tr2 )
733 {
734   if( tr1->NbNodes() != tr2->NbNodes() )
735     return false;
736   // find the 4-th node to insert into tr1
737   const SMDS_MeshNode* n4 = 0;
738   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
739   int i=0;
740   while ( !n4 && i<3 ) {
741     const SMDS_MeshNode * n = cast2Node( it->next() );
742     i++;
743     bool isDiag = ( n == theNode1 || n == theNode2 );
744     if ( !isDiag )
745       n4 = n;
746   }
747   // Make an array of nodes to be in a quadrangle
748   int iNode = 0, iFirstDiag = -1;
749   it = tr1->nodesIterator();
750   i=0;
751   while ( i<3 ) {
752     const SMDS_MeshNode * n = cast2Node( it->next() );
753     i++;
754     bool isDiag = ( n == theNode1 || n == theNode2 );
755     if ( isDiag ) {
756       if ( iFirstDiag < 0 )
757         iFirstDiag = iNode;
758       else if ( iNode - iFirstDiag == 1 )
759         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
760     }
761     else if ( n == n4 ) {
762       return false; // tr1 and tr2 should not have all the same nodes
763     }
764     theQuadNodes[ iNode++ ] = n;
765   }
766   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
767     theQuadNodes[ iNode ] = n4;
768
769   return true;
770 }
771
772 //=======================================================================
773 //function : DeleteDiag
774 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
775 //           with a quadrangle built on the same 4 nodes.
776 //           Return false if proper faces not found
777 //=======================================================================
778
779 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
780                                    const SMDS_MeshNode * theNode2)
781 {
782   myLastCreatedElems.Clear();
783   myLastCreatedNodes.Clear();
784
785   MESSAGE( "::DeleteDiag()" );
786
787   const SMDS_MeshElement *tr1, *tr2;
788   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
789     return false;
790
791   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
792   //if (!F1) return false;
793   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
794   //if (!F2) return false;
795   if (F1 && F2) {
796
797     const SMDS_MeshNode* aNodes [ 4 ];
798     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
799       return false;
800
801     //MESSAGE( endl << tr1 << tr2 );
802
803     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
804     myLastCreatedElems.Append(tr1);
805     GetMeshDS()->RemoveElement( tr2 );
806
807     //MESSAGE( endl << tr1 );
808
809     return true;
810   }
811
812   // check case of quadratic faces
813   const SMDS_QuadraticFaceOfNodes* QF1 =
814     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
815   if(!QF1) return false;
816   const SMDS_QuadraticFaceOfNodes* QF2 =
817     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
818   if(!QF2) return false;
819
820   //       5
821   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
822   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
823   //    |   / |
824   //  7 +  +  + 6
825   //    | /9  |
826   //    |/    |
827   //  4 +--+--+ 3
828   //       8
829
830   const SMDS_MeshNode* N1 [6];
831   const SMDS_MeshNode* N2 [6];
832   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
833     return false;
834   // now we receive following N1 and N2 (using numeration as above image)
835   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
836   // i.e. first nodes from both arrays determ new diagonal
837
838   const SMDS_MeshNode* aNodes[8];
839   aNodes[0] = N1[0];
840   aNodes[1] = N1[1];
841   aNodes[2] = N2[0];
842   aNodes[3] = N2[1];
843   aNodes[4] = N1[3];
844   aNodes[5] = N2[5];
845   aNodes[6] = N2[3];
846   aNodes[7] = N1[5];
847
848   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
849   myLastCreatedElems.Append(tr1);
850   GetMeshDS()->RemoveElement( tr2 );
851
852   // remove middle node (9)
853   GetMeshDS()->RemoveNode( N1[4] );
854
855   return true;
856 }
857
858 //=======================================================================
859 //function : Reorient
860 //purpose  : Reverse theElement orientation
861 //=======================================================================
862
863 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
864 {
865   myLastCreatedElems.Clear();
866   myLastCreatedNodes.Clear();
867
868   if (!theElem)
869     return false;
870   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
871   if ( !it || !it->more() )
872     return false;
873
874   switch ( theElem->GetType() ) {
875
876   case SMDSAbs_Edge:
877   case SMDSAbs_Face: {
878     if(!theElem->IsQuadratic()) {
879       int i = theElem->NbNodes();
880       vector<const SMDS_MeshNode*> aNodes( i );
881       while ( it->more() )
882         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
883       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
884     }
885     else {
886       // quadratic elements
887       if(theElem->GetType()==SMDSAbs_Edge) {
888         vector<const SMDS_MeshNode*> aNodes(3);
889         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
890         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
891         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
892         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
893       }
894       else {
895         int nbn = theElem->NbNodes();
896         vector<const SMDS_MeshNode*> aNodes(nbn);
897         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
898         int i=1;
899         for(; i<nbn/2; i++) {
900           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
901         }
902         for(i=0; i<nbn/2; i++) {
903           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
904         }
905         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
906       }
907     }
908   }
909   case SMDSAbs_Volume: {
910     if (theElem->IsPoly()) {
911       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
912         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
913       if (!aPolyedre) {
914         MESSAGE("Warning: bad volumic element");
915         return false;
916       }
917
918       int nbFaces = aPolyedre->NbFaces();
919       vector<const SMDS_MeshNode *> poly_nodes;
920       vector<int> quantities (nbFaces);
921
922       // reverse each face of the polyedre
923       for (int iface = 1; iface <= nbFaces; iface++) {
924         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
925         quantities[iface - 1] = nbFaceNodes;
926
927         for (inode = nbFaceNodes; inode >= 1; inode--) {
928           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
929           poly_nodes.push_back(curNode);
930         }
931       }
932
933       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
934
935     }
936     else {
937       SMDS_VolumeTool vTool;
938       if ( !vTool.Set( theElem ))
939         return false;
940       vTool.Inverse();
941       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
942     }
943   }
944   default:;
945   }
946
947   return false;
948 }
949
950 //=======================================================================
951 //function : getBadRate
952 //purpose  :
953 //=======================================================================
954
955 static double getBadRate (const SMDS_MeshElement*               theElem,
956                           SMESH::Controls::NumericalFunctorPtr& theCrit)
957 {
958   SMESH::Controls::TSequenceOfXYZ P;
959   if ( !theElem || !theCrit->GetPoints( theElem, P ))
960     return 1e100;
961   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
962   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
963 }
964
965 //=======================================================================
966 //function : QuadToTri
967 //purpose  : Cut quadrangles into triangles.
968 //           theCrit is used to select a diagonal to cut
969 //=======================================================================
970
971 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
972                                   SMESH::Controls::NumericalFunctorPtr theCrit)
973 {
974   myLastCreatedElems.Clear();
975   myLastCreatedNodes.Clear();
976
977   MESSAGE( "::QuadToTri()" );
978
979   if ( !theCrit.get() )
980     return false;
981
982   SMESHDS_Mesh * aMesh = GetMeshDS();
983
984   Handle(Geom_Surface) surface;
985   SMESH_MesherHelper   helper( *GetMesh() );
986
987   TIDSortedElemSet::iterator itElem;
988   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
989     const SMDS_MeshElement* elem = *itElem;
990     if ( !elem || elem->GetType() != SMDSAbs_Face )
991       continue;
992     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
993       continue;
994
995     // retrieve element nodes
996     const SMDS_MeshNode* aNodes [8];
997     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
998     int i = 0;
999     while ( itN->more() )
1000       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1001
1002     // compare two sets of possible triangles
1003     double aBadRate1, aBadRate2; // to what extent a set is bad
1004     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1005     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1006     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1007
1008     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1009     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1010     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1011
1012     int aShapeId = FindShape( elem );
1013     const SMDS_MeshElement* newElem = 0;
1014
1015     if( !elem->IsQuadratic() ) {
1016
1017       // split liner quadrangle
1018
1019       if ( aBadRate1 <= aBadRate2 ) {
1020         // tr1 + tr2 is better
1021         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1022         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1023       }
1024       else {
1025         // tr3 + tr4 is better
1026         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1027         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1028       }
1029     }
1030     else {
1031
1032       // split quadratic quadrangle
1033
1034       // get surface elem is on
1035       if ( aShapeId != helper.GetSubShapeID() ) {
1036         surface.Nullify();
1037         TopoDS_Shape shape;
1038         if ( aShapeId > 0 )
1039           shape = aMesh->IndexToShape( aShapeId );
1040         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1041           TopoDS_Face face = TopoDS::Face( shape );
1042           surface = BRep_Tool::Surface( face );
1043           if ( !surface.IsNull() )
1044             helper.SetSubShape( shape );
1045         }
1046       }
1047       // get elem nodes
1048       const SMDS_MeshNode* aNodes [8];
1049       const SMDS_MeshNode* inFaceNode = 0;
1050       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1051       int i = 0;
1052       while ( itN->more() ) {
1053         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1054         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1055              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1056         {
1057           inFaceNode = aNodes[ i-1 ];
1058         }
1059       }
1060       // find middle point for (0,1,2,3)
1061       // and create a node in this point;
1062       gp_XYZ p( 0,0,0 );
1063       if ( surface.IsNull() ) {
1064         for(i=0; i<4; i++)
1065           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1066         p /= 4;
1067       }
1068       else {
1069         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1070         gp_XY uv( 0,0 );
1071         for(i=0; i<4; i++)
1072           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1073         uv /= 4.;
1074         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1075       }
1076       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1077       myLastCreatedNodes.Append(newN);
1078
1079       // create a new element
1080       const SMDS_MeshNode* N[6];
1081       if ( aBadRate1 <= aBadRate2 ) {
1082         N[0] = aNodes[0];
1083         N[1] = aNodes[1];
1084         N[2] = aNodes[2];
1085         N[3] = aNodes[4];
1086         N[4] = aNodes[5];
1087         N[5] = newN;
1088         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1089                                  aNodes[6], aNodes[7], newN );
1090       }
1091       else {
1092         N[0] = aNodes[1];
1093         N[1] = aNodes[2];
1094         N[2] = aNodes[3];
1095         N[3] = aNodes[5];
1096         N[4] = aNodes[6];
1097         N[5] = newN;
1098         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1099                                  aNodes[7], aNodes[4], newN );
1100       }
1101       aMesh->ChangeElementNodes( elem, N, 6 );
1102
1103     } // quadratic case
1104
1105     // care of a new element
1106
1107     myLastCreatedElems.Append(newElem);
1108     AddToSameGroups( newElem, elem, aMesh );
1109
1110     // put a new triangle on the same shape
1111     if ( aShapeId )
1112       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1113   }
1114   return true;
1115 }
1116
1117 //=======================================================================
1118 //function : BestSplit
1119 //purpose  : Find better diagonal for cutting.
1120 //=======================================================================
1121
1122 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1123                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1124 {
1125   myLastCreatedElems.Clear();
1126   myLastCreatedNodes.Clear();
1127
1128   if (!theCrit.get())
1129     return -1;
1130
1131   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1132     return -1;
1133
1134   if( theQuad->NbNodes()==4 ||
1135       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1136
1137     // retrieve element nodes
1138     const SMDS_MeshNode* aNodes [4];
1139     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1140     int i = 0;
1141     //while (itN->more())
1142     while (i<4) {
1143       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1144     }
1145     // compare two sets of possible triangles
1146     double aBadRate1, aBadRate2; // to what extent a set is bad
1147     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1148     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1149     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1150
1151     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1152     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1153     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1154
1155     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1156       return 1; // diagonal 1-3
1157
1158     return 2; // diagonal 2-4
1159   }
1160   return -1;
1161 }
1162
1163 namespace
1164 {
1165   // Methods of splitting volumes into tetra
1166
1167   const int theHexTo5_1[5*4+1] =
1168     {
1169       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1170     };
1171   const int theHexTo5_2[5*4+1] =
1172     {
1173       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1174     };
1175   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1176
1177   const int theHexTo6_1[6*4+1] =
1178     {
1179       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1180     };
1181   const int theHexTo6_2[6*4+1] =
1182     {
1183       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1184     };
1185   const int theHexTo6_3[6*4+1] =
1186     {
1187       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1188     };
1189   const int theHexTo6_4[6*4+1] =
1190     {
1191       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1192     };
1193   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1194
1195   const int thePyraTo2_1[2*4+1] =
1196     {
1197       0, 1, 2, 4,    0, 2, 3, 4,   -1
1198     };
1199   const int thePyraTo2_2[2*4+1] =
1200     {
1201       1, 2, 3, 4,    1, 3, 0, 4,   -1
1202     };
1203   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1204
1205   const int thePentaTo3_1[3*4+1] =
1206     {
1207       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1208     };
1209   const int thePentaTo3_2[3*4+1] =
1210     {
1211       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1212     };
1213   const int thePentaTo3_3[3*4+1] =
1214     {
1215       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1216     };
1217   const int thePentaTo3_4[3*4+1] =
1218     {
1219       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1220     };
1221   const int thePentaTo3_5[3*4+1] =
1222     {
1223       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1224     };
1225   const int thePentaTo3_6[3*4+1] =
1226     {
1227       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1228     };
1229   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1230                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1231
1232   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1233   {
1234     int _n1, _n2, _n3;
1235     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1236     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1237     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1238   };
1239   struct TSplitMethod
1240   {
1241     int        _nbTetra;
1242     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1243     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1244     bool       _ownConn;      //!< to delete _connectivity in destructor
1245
1246     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1247       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1248     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1249     bool hasFacet( const TTriangleFacet& facet ) const
1250     {
1251       const int* tetConn = _connectivity;
1252       for ( ; tetConn[0] >= 0; tetConn += 4 )
1253         if (( facet.contains( tetConn[0] ) +
1254               facet.contains( tetConn[1] ) +
1255               facet.contains( tetConn[2] ) +
1256               facet.contains( tetConn[3] )) == 3 )
1257           return true;
1258       return false;
1259     }
1260   };
1261
1262   //=======================================================================
1263   /*!
1264    * \brief return TSplitMethod for the given element
1265    */
1266   //=======================================================================
1267
1268   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1269   {
1270     int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1271
1272     // Find out how adjacent volumes are split
1273
1274     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1275     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1276     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1277     {
1278       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1279       maxTetConnSize += 4 * ( nbNodes - 2 );
1280       if ( nbNodes < 4 ) continue;
1281
1282       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1283       const int* nInd = vol.GetFaceNodesIndices( iF );
1284       if ( nbNodes == 4 )
1285       {
1286         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1287         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1288         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1289         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1290       }
1291       else
1292       {
1293         int iCom = 0; // common node of triangle faces to split into
1294         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1295         {
1296           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1297                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1298                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1299           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1300                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1301                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1302           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1303           {
1304             triaSplits.push_back( t012 );
1305             triaSplits.push_back( t023 );
1306             break;
1307           }
1308         }
1309       }
1310       if ( !triaSplits.empty() )
1311         hasAdjacentSplits = true;
1312     }
1313
1314     // Among variants of split method select one compliant with adjacent volumes
1315
1316     TSplitMethod method;
1317     if ( !vol.Element()->IsPoly() )
1318     {
1319       int nbVariants = 2, nbTet = 0;
1320       const int** connVariants = 0;
1321       switch ( vol.Element()->GetEntityType() )
1322       {
1323       case SMDSEntity_Hexa:
1324       case SMDSEntity_Quad_Hexa:
1325         if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1326           connVariants = theHexTo5, nbTet = 5;
1327         else
1328           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1329         break;
1330       case SMDSEntity_Pyramid:
1331       case SMDSEntity_Quad_Pyramid:
1332         connVariants = thePyraTo2;  nbTet = 2;
1333         break;
1334       case SMDSEntity_Penta:
1335       case SMDSEntity_Quad_Penta:
1336         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1337         break;
1338       default:
1339         nbVariants = 0;
1340       }
1341       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1342       {
1343         // check method compliancy with adjacent tetras,
1344         // all found splits must be among facets of tetras described by this method
1345         method = TSplitMethod( nbTet, connVariants[variant] );
1346         if ( hasAdjacentSplits && method._nbTetra > 0 )
1347         {
1348           bool facetCreated = true;
1349           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1350           {
1351             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1352             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1353               facetCreated = method.hasFacet( *facet );
1354           }
1355           if ( !facetCreated )
1356             method = TSplitMethod(0); // incompatible method
1357         }
1358       }
1359     }
1360     if ( method._nbTetra < 1 )
1361     {
1362       // No standard method is applicable, use a generic solution:
1363       // each facet of a volume is split into triangles and
1364       // each of triangles and a volume barycenter form a tetrahedron.
1365
1366       int* connectivity = new int[ maxTetConnSize + 1 ];
1367       method._connectivity = connectivity;
1368       method._ownConn = true;
1369       method._baryNode = true;
1370
1371       int connSize = 0;
1372       int baryCenInd = vol.NbNodes();
1373       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1374       {
1375         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1376         const int*   nInd = vol.GetFaceNodesIndices( iF );
1377         // find common node of triangle facets of tetra to create
1378         int iCommon = 0; // index in linear numeration
1379         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1380         if ( !triaSplits.empty() )
1381         {
1382           // by found facets
1383           const TTriangleFacet* facet = &triaSplits.front();
1384           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1385             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1386                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1387               break;
1388         }
1389         else if ( nbNodes > 3 )
1390         {
1391           // find the best method of splitting into triangles by aspect ratio
1392           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1393           map< double, int > badness2iCommon;
1394           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1395           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1396           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1397             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1398             {
1399               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1400                                       nodes[ iQ*((iLast-1)%nbNodes)],
1401                                       nodes[ iQ*((iLast  )%nbNodes)]);
1402               double badness = getBadRate( &tria, aspectRatio );
1403               badness2iCommon.insert( make_pair( badness, iCommon ));
1404             }
1405           // use iCommon with lowest badness
1406           iCommon = badness2iCommon.begin()->second;
1407         }
1408         if ( iCommon >= nbNodes )
1409           iCommon = 0; // something wrong
1410         // fill connectivity of tetra
1411         int nbTet = nbNodes - 2;
1412         for ( int i = 0; i < nbTet; ++i )
1413         {
1414           int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1415           if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1416           connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1417           connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1418           connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1419           connectivity[ connSize++ ] = baryCenInd;
1420           ++method._nbTetra;
1421         }
1422       }
1423       connectivity[ connSize++ ] = -1;
1424     }
1425     return method;
1426   }
1427   //================================================================================
1428   /*!
1429    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1430    */
1431   //================================================================================
1432
1433   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1434   {
1435     // find the tetrahedron including the three nodes of facet
1436     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1437     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1438     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1439     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1440     while ( volIt1->more() )
1441     {
1442       const SMDS_MeshElement* v = volIt1->next();
1443       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1444         continue;
1445       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1446       while ( volIt2->more() )
1447         if ( v != volIt2->next() )
1448           continue;
1449       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1450       while ( volIt3->more() )
1451         if ( v == volIt3->next() )
1452           return true;
1453     }
1454     return false;
1455   }
1456 } // namespace
1457
1458 //=======================================================================
1459 //function : SplitVolumesIntoTetra
1460 //purpose  : Split volumic elements into tetrahedra.
1461 //=======================================================================
1462
1463 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1464                                               const int                theMethodFlags)
1465 {
1466   // std-like iterator on coordinates of nodes of mesh element
1467   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1468   NXyzIterator xyzEnd;
1469
1470   SMDS_VolumeTool    volTool;
1471   SMESH_MesherHelper helper( *GetMesh());
1472
1473   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1474   SMESHDS_SubMesh* fSubMesh = subMesh;
1475   
1476   SMESH_SequenceOfElemPtr newNodes, newElems;
1477
1478   TIDSortedElemSet::const_iterator elem = theElems.begin();
1479   for ( ; elem != theElems.end(); ++elem )
1480   {
1481     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1482     if ( geomType <= SMDSEntity_Quad_Tetra )
1483       continue; // tetra or face or ...
1484
1485     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1486
1487     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1488     if ( splitMethod._nbTetra < 1 ) continue;
1489
1490     // find submesh to add new tetras in
1491     if ( !subMesh || !subMesh->Contains( *elem ))
1492     {
1493       int shapeID = FindShape( *elem );
1494       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1495       subMesh = GetMeshDS()->MeshElements( shapeID );
1496     }
1497     int iQ;
1498     if ( (*elem)->IsQuadratic() )
1499     {
1500       iQ = 2;
1501       // add quadratic links to the helper
1502       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1503       {
1504         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1505         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1506           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1507       }
1508       helper.SetIsQuadratic( true );
1509     }
1510     else
1511     {
1512       iQ = 1;
1513       helper.SetIsQuadratic( false );
1514     }
1515     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1516     if ( splitMethod._baryNode )
1517     {
1518       // make a node at barycenter
1519       gp_XYZ gc( 0,0,0 );
1520       gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1521       SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1522       nodes.push_back( gcNode );
1523       newNodes.Append( gcNode );
1524     }
1525
1526     // make tetras
1527     helper.SetElementsOnShape( true );
1528     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1529     const int* tetConn = splitMethod._connectivity;
1530     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1531       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1532                                                        nodes[ tetConn[1] ],
1533                                                        nodes[ tetConn[2] ],
1534                                                        nodes[ tetConn[3] ]));
1535
1536     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1537
1538     // Split faces on sides of the split volume
1539
1540     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1541     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1542     {
1543       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1544       if ( nbNodes < 4 ) continue;
1545
1546       // find an existing face
1547       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1548                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1549       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1550       {
1551         // among possible triangles create ones discribed by split method
1552         const int* nInd = volTool.GetFaceNodesIndices( iF );
1553         int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1554         int iCom = 0; // common node of triangle faces to split into
1555         list< TTriangleFacet > facets;
1556         for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1557         {
1558           TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1559                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1560                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1561           TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1562                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1563                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1564           if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1565           {
1566             facets.push_back( t012 );
1567             facets.push_back( t023 );
1568             for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1569               facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1570                                                 nInd[ iQ * ((iLast-1)%nbNodes )],
1571                                                 nInd[ iQ * ((iLast  )%nbNodes )]));
1572             break;
1573           }
1574         }
1575         // find submesh to add new faces in
1576         if ( !fSubMesh || !fSubMesh->Contains( face ))
1577         {
1578           int shapeID = FindShape( face );
1579           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1580         }
1581         // make triangles
1582         helper.SetElementsOnShape( false );
1583         vector< const SMDS_MeshElement* > triangles;
1584         list< TTriangleFacet >::iterator facet = facets.begin();
1585         for ( ; facet != facets.end(); ++facet )
1586         {
1587           if ( !volTool.IsFaceExternal( iF ))
1588             swap( facet->_n2, facet->_n3 );
1589           triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1590                                                volNodes[ facet->_n2 ],
1591                                                volNodes[ facet->_n3 ]));
1592           if ( triangles.back() && fSubMesh )
1593             fSubMesh->AddElement( triangles.back());
1594           newElems.Append( triangles.back() );
1595         }
1596         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1597         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1598       }
1599
1600     } // loop on volume faces to split them into triangles
1601
1602     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1603
1604   } // loop on volumes to split
1605
1606   myLastCreatedNodes = newNodes;
1607   myLastCreatedElems = newElems;
1608 }
1609
1610 //=======================================================================
1611 //function : AddToSameGroups
1612 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1613 //=======================================================================
1614
1615 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1616                                         const SMDS_MeshElement* elemInGroups,
1617                                         SMESHDS_Mesh *          aMesh)
1618 {
1619   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1620   if (!groups.empty()) {
1621     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1622     for ( ; grIt != groups.end(); grIt++ ) {
1623       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1624       if ( group && group->Contains( elemInGroups ))
1625         group->SMDSGroup().Add( elemToAdd );
1626     }
1627   }
1628 }
1629
1630
1631 //=======================================================================
1632 //function : RemoveElemFromGroups
1633 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1634 //=======================================================================
1635 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1636                                              SMESHDS_Mesh *          aMesh)
1637 {
1638   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1639   if (!groups.empty())
1640   {
1641     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1642     for (; GrIt != groups.end(); GrIt++)
1643     {
1644       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1645       if (!grp || grp->IsEmpty()) continue;
1646       grp->SMDSGroup().Remove(removeelem);
1647     }
1648   }
1649 }
1650
1651 //================================================================================
1652 /*!
1653  * \brief Replace elemToRm by elemToAdd in the all groups
1654  */
1655 //================================================================================
1656
1657 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1658                                             const SMDS_MeshElement* elemToAdd,
1659                                             SMESHDS_Mesh *          aMesh)
1660 {
1661   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1662   if (!groups.empty()) {
1663     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1664     for ( ; grIt != groups.end(); grIt++ ) {
1665       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1666       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1667         group->SMDSGroup().Add( elemToAdd );
1668     }
1669   }
1670 }
1671
1672 //================================================================================
1673 /*!
1674  * \brief Replace elemToRm by elemToAdd in the all groups
1675  */
1676 //================================================================================
1677
1678 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1679                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1680                                             SMESHDS_Mesh *                         aMesh)
1681 {
1682   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1683   if (!groups.empty())
1684   {
1685     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1686     for ( ; grIt != groups.end(); grIt++ ) {
1687       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1688       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1689         for ( int i = 0; i < elemToAdd.size(); ++i )
1690           group->SMDSGroup().Add( elemToAdd[ i ] );
1691     }
1692   }
1693 }
1694
1695 //=======================================================================
1696 //function : QuadToTri
1697 //purpose  : Cut quadrangles into triangles.
1698 //           theCrit is used to select a diagonal to cut
1699 //=======================================================================
1700
1701 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1702                                   const bool         the13Diag)
1703 {
1704   myLastCreatedElems.Clear();
1705   myLastCreatedNodes.Clear();
1706
1707   MESSAGE( "::QuadToTri()" );
1708
1709   SMESHDS_Mesh * aMesh = GetMeshDS();
1710
1711   Handle(Geom_Surface) surface;
1712   SMESH_MesherHelper   helper( *GetMesh() );
1713
1714   TIDSortedElemSet::iterator itElem;
1715   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1716     const SMDS_MeshElement* elem = *itElem;
1717     if ( !elem || elem->GetType() != SMDSAbs_Face )
1718       continue;
1719     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1720     if(!isquad) continue;
1721
1722     if(elem->NbNodes()==4) {
1723       // retrieve element nodes
1724       const SMDS_MeshNode* aNodes [4];
1725       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1726       int i = 0;
1727       while ( itN->more() )
1728         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1729
1730       int aShapeId = FindShape( elem );
1731       const SMDS_MeshElement* newElem = 0;
1732       if ( the13Diag ) {
1733         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1734         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1735       }
1736       else {
1737         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1738         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1739       }
1740       myLastCreatedElems.Append(newElem);
1741       // put a new triangle on the same shape and add to the same groups
1742       if ( aShapeId )
1743         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1744       AddToSameGroups( newElem, elem, aMesh );
1745     }
1746
1747     // Quadratic quadrangle
1748
1749     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1750
1751       // get surface elem is on
1752       int aShapeId = FindShape( elem );
1753       if ( aShapeId != helper.GetSubShapeID() ) {
1754         surface.Nullify();
1755         TopoDS_Shape shape;
1756         if ( aShapeId > 0 )
1757           shape = aMesh->IndexToShape( aShapeId );
1758         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1759           TopoDS_Face face = TopoDS::Face( shape );
1760           surface = BRep_Tool::Surface( face );
1761           if ( !surface.IsNull() )
1762             helper.SetSubShape( shape );
1763         }
1764       }
1765
1766       const SMDS_MeshNode* aNodes [8];
1767       const SMDS_MeshNode* inFaceNode = 0;
1768       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1769       int i = 0;
1770       while ( itN->more() ) {
1771         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1772         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1773              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1774         {
1775           inFaceNode = aNodes[ i-1 ];
1776         }
1777       }
1778
1779       // find middle point for (0,1,2,3)
1780       // and create a node in this point;
1781       gp_XYZ p( 0,0,0 );
1782       if ( surface.IsNull() ) {
1783         for(i=0; i<4; i++)
1784           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1785         p /= 4;
1786       }
1787       else {
1788         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1789         gp_XY uv( 0,0 );
1790         for(i=0; i<4; i++)
1791           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1792         uv /= 4.;
1793         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1794       }
1795       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1796       myLastCreatedNodes.Append(newN);
1797
1798       // create a new element
1799       const SMDS_MeshElement* newElem = 0;
1800       const SMDS_MeshNode* N[6];
1801       if ( the13Diag ) {
1802         N[0] = aNodes[0];
1803         N[1] = aNodes[1];
1804         N[2] = aNodes[2];
1805         N[3] = aNodes[4];
1806         N[4] = aNodes[5];
1807         N[5] = newN;
1808         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1809                                  aNodes[6], aNodes[7], newN );
1810       }
1811       else {
1812         N[0] = aNodes[1];
1813         N[1] = aNodes[2];
1814         N[2] = aNodes[3];
1815         N[3] = aNodes[5];
1816         N[4] = aNodes[6];
1817         N[5] = newN;
1818         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1819                                  aNodes[7], aNodes[4], newN );
1820       }
1821       myLastCreatedElems.Append(newElem);
1822       aMesh->ChangeElementNodes( elem, N, 6 );
1823       // put a new triangle on the same shape and add to the same groups
1824       if ( aShapeId )
1825         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1826       AddToSameGroups( newElem, elem, aMesh );
1827     }
1828   }
1829
1830   return true;
1831 }
1832
1833 //=======================================================================
1834 //function : getAngle
1835 //purpose  :
1836 //=======================================================================
1837
1838 double getAngle(const SMDS_MeshElement * tr1,
1839                 const SMDS_MeshElement * tr2,
1840                 const SMDS_MeshNode *    n1,
1841                 const SMDS_MeshNode *    n2)
1842 {
1843   double angle = 2*PI; // bad angle
1844
1845   // get normals
1846   SMESH::Controls::TSequenceOfXYZ P1, P2;
1847   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1848        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1849     return angle;
1850   gp_Vec N1,N2;
1851   if(!tr1->IsQuadratic())
1852     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1853   else
1854     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1855   if ( N1.SquareMagnitude() <= gp::Resolution() )
1856     return angle;
1857   if(!tr2->IsQuadratic())
1858     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1859   else
1860     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1861   if ( N2.SquareMagnitude() <= gp::Resolution() )
1862     return angle;
1863
1864   // find the first diagonal node n1 in the triangles:
1865   // take in account a diagonal link orientation
1866   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1867   for ( int t = 0; t < 2; t++ ) {
1868     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1869     int i = 0, iDiag = -1;
1870     while ( it->more()) {
1871       const SMDS_MeshElement *n = it->next();
1872       if ( n == n1 || n == n2 )
1873         if ( iDiag < 0)
1874           iDiag = i;
1875         else {
1876           if ( i - iDiag == 1 )
1877             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1878           else
1879             nFirst[ t ] = n;
1880           break;
1881         }
1882       i++;
1883     }
1884   }
1885   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1886     N2.Reverse();
1887
1888   angle = N1.Angle( N2 );
1889   //SCRUTE( angle );
1890   return angle;
1891 }
1892
1893 // =================================================
1894 // class generating a unique ID for a pair of nodes
1895 // and able to return nodes by that ID
1896 // =================================================
1897 class LinkID_Gen {
1898 public:
1899
1900   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1901     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1902   {}
1903
1904   long GetLinkID (const SMDS_MeshNode * n1,
1905                   const SMDS_MeshNode * n2) const
1906   {
1907     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1908   }
1909
1910   bool GetNodes (const long             theLinkID,
1911                  const SMDS_MeshNode* & theNode1,
1912                  const SMDS_MeshNode* & theNode2) const
1913   {
1914     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1915     if ( !theNode1 ) return false;
1916     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1917     if ( !theNode2 ) return false;
1918     return true;
1919   }
1920
1921 private:
1922   LinkID_Gen();
1923   const SMESHDS_Mesh* myMesh;
1924   long                myMaxID;
1925 };
1926
1927
1928 //=======================================================================
1929 //function : TriToQuad
1930 //purpose  : Fuse neighbour triangles into quadrangles.
1931 //           theCrit is used to select a neighbour to fuse with.
1932 //           theMaxAngle is a max angle between element normals at which
1933 //           fusion is still performed.
1934 //=======================================================================
1935
1936 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1937                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1938                                   const double                         theMaxAngle)
1939 {
1940   myLastCreatedElems.Clear();
1941   myLastCreatedNodes.Clear();
1942
1943   MESSAGE( "::TriToQuad()" );
1944
1945   if ( !theCrit.get() )
1946     return false;
1947
1948   SMESHDS_Mesh * aMesh = GetMeshDS();
1949
1950   // Prepare data for algo: build
1951   // 1. map of elements with their linkIDs
1952   // 2. map of linkIDs with their elements
1953
1954   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1955   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1956   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
1957   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1958
1959   TIDSortedElemSet::iterator itElem;
1960   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1961     const SMDS_MeshElement* elem = *itElem;
1962     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1963     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1964     if(!IsTria) continue;
1965
1966     // retrieve element nodes
1967     const SMDS_MeshNode* aNodes [4];
1968     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1969     int i = 0;
1970     while ( i<3 )
1971       aNodes[ i++ ] = cast2Node( itN->next() );
1972     aNodes[ 3 ] = aNodes[ 0 ];
1973
1974     // fill maps
1975     for ( i = 0; i < 3; i++ ) {
1976       SMESH_TLink link( aNodes[i], aNodes[i+1] );
1977       // check if elements sharing a link can be fused
1978       itLE = mapLi_listEl.find( link );
1979       if ( itLE != mapLi_listEl.end() ) {
1980         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1981           continue;
1982         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1983         //if ( FindShape( elem ) != FindShape( elem2 ))
1984         //  continue; // do not fuse triangles laying on different shapes
1985         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1986           continue; // avoid making badly shaped quads
1987         (*itLE).second.push_back( elem );
1988       }
1989       else {
1990         mapLi_listEl[ link ].push_back( elem );
1991       }
1992       mapEl_setLi [ elem ].insert( link );
1993     }
1994   }
1995   // Clean the maps from the links shared by a sole element, ie
1996   // links to which only one element is bound in mapLi_listEl
1997
1998   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1999     int nbElems = (*itLE).second.size();
2000     if ( nbElems < 2  ) {
2001       const SMDS_MeshElement* elem = (*itLE).second.front();
2002       SMESH_TLink link = (*itLE).first;
2003       mapEl_setLi[ elem ].erase( link );
2004       if ( mapEl_setLi[ elem ].empty() )
2005         mapEl_setLi.erase( elem );
2006     }
2007   }
2008
2009   // Algo: fuse triangles into quadrangles
2010
2011   while ( ! mapEl_setLi.empty() ) {
2012     // Look for the start element:
2013     // the element having the least nb of shared links
2014     const SMDS_MeshElement* startElem = 0;
2015     int minNbLinks = 4;
2016     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2017       int nbLinks = (*itEL).second.size();
2018       if ( nbLinks < minNbLinks ) {
2019         startElem = (*itEL).first;
2020         minNbLinks = nbLinks;
2021         if ( minNbLinks == 1 )
2022           break;
2023       }
2024     }
2025
2026     // search elements to fuse starting from startElem or links of elements
2027     // fused earlyer - startLinks
2028     list< SMESH_TLink > startLinks;
2029     while ( startElem || !startLinks.empty() ) {
2030       while ( !startElem && !startLinks.empty() ) {
2031         // Get an element to start, by a link
2032         SMESH_TLink linkId = startLinks.front();
2033         startLinks.pop_front();
2034         itLE = mapLi_listEl.find( linkId );
2035         if ( itLE != mapLi_listEl.end() ) {
2036           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2037           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2038           for ( ; itE != listElem.end() ; itE++ )
2039             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2040               startElem = (*itE);
2041           mapLi_listEl.erase( itLE );
2042         }
2043       }
2044
2045       if ( startElem ) {
2046         // Get candidates to be fused
2047         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2048         const SMESH_TLink *link12, *link13;
2049         startElem = 0;
2050         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2051         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2052         ASSERT( !setLi.empty() );
2053         set< SMESH_TLink >::iterator itLi;
2054         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2055         {
2056           const SMESH_TLink & link = (*itLi);
2057           itLE = mapLi_listEl.find( link );
2058           if ( itLE == mapLi_listEl.end() )
2059             continue;
2060
2061           const SMDS_MeshElement* elem = (*itLE).second.front();
2062           if ( elem == tr1 )
2063             elem = (*itLE).second.back();
2064           mapLi_listEl.erase( itLE );
2065           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2066             continue;
2067           if ( tr2 ) {
2068             tr3 = elem;
2069             link13 = &link;
2070           }
2071           else {
2072             tr2 = elem;
2073             link12 = &link;
2074           }
2075
2076           // add other links of elem to list of links to re-start from
2077           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2078           set< SMESH_TLink >::iterator it;
2079           for ( it = links.begin(); it != links.end(); it++ ) {
2080             const SMESH_TLink& link2 = (*it);
2081             if ( link2 != link )
2082               startLinks.push_back( link2 );
2083           }
2084         }
2085
2086         // Get nodes of possible quadrangles
2087         const SMDS_MeshNode *n12 [4], *n13 [4];
2088         bool Ok12 = false, Ok13 = false;
2089         const SMDS_MeshNode *linkNode1, *linkNode2;
2090         if(tr2) {
2091           linkNode1 = link12->first;
2092           linkNode2 = link12->second;
2093           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2094             Ok12 = true;
2095         }
2096         if(tr3) {
2097           linkNode1 = link13->first;
2098           linkNode2 = link13->second;
2099           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2100             Ok13 = true;
2101         }
2102
2103         // Choose a pair to fuse
2104         if ( Ok12 && Ok13 ) {
2105           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2106           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2107           double aBadRate12 = getBadRate( &quad12, theCrit );
2108           double aBadRate13 = getBadRate( &quad13, theCrit );
2109           if (  aBadRate13 < aBadRate12 )
2110             Ok12 = false;
2111           else
2112             Ok13 = false;
2113         }
2114
2115         // Make quadrangles
2116         // and remove fused elems and removed links from the maps
2117         mapEl_setLi.erase( tr1 );
2118         if ( Ok12 ) {
2119           mapEl_setLi.erase( tr2 );
2120           mapLi_listEl.erase( *link12 );
2121           if(tr1->NbNodes()==3) {
2122             if( tr1->GetID() < tr2->GetID() ) {
2123               aMesh->ChangeElementNodes( tr1, n12, 4 );
2124               myLastCreatedElems.Append(tr1);
2125               aMesh->RemoveElement( tr2 );
2126             }
2127             else {
2128               aMesh->ChangeElementNodes( tr2, n12, 4 );
2129               myLastCreatedElems.Append(tr2);
2130               aMesh->RemoveElement( tr1);
2131             }
2132           }
2133           else {
2134             const SMDS_MeshNode* N1 [6];
2135             const SMDS_MeshNode* N2 [6];
2136             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2137             // now we receive following N1 and N2 (using numeration as above image)
2138             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2139             // i.e. first nodes from both arrays determ new diagonal
2140             const SMDS_MeshNode* aNodes[8];
2141             aNodes[0] = N1[0];
2142             aNodes[1] = N1[1];
2143             aNodes[2] = N2[0];
2144             aNodes[3] = N2[1];
2145             aNodes[4] = N1[3];
2146             aNodes[5] = N2[5];
2147             aNodes[6] = N2[3];
2148             aNodes[7] = N1[5];
2149             if( tr1->GetID() < tr2->GetID() ) {
2150               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2151               myLastCreatedElems.Append(tr1);
2152               GetMeshDS()->RemoveElement( tr2 );
2153             }
2154             else {
2155               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2156               myLastCreatedElems.Append(tr2);
2157               GetMeshDS()->RemoveElement( tr1 );
2158             }
2159             // remove middle node (9)
2160             GetMeshDS()->RemoveNode( N1[4] );
2161           }
2162         }
2163         else if ( Ok13 ) {
2164           mapEl_setLi.erase( tr3 );
2165           mapLi_listEl.erase( *link13 );
2166           if(tr1->NbNodes()==3) {
2167             if( tr1->GetID() < tr2->GetID() ) {
2168               aMesh->ChangeElementNodes( tr1, n13, 4 );
2169               myLastCreatedElems.Append(tr1);
2170               aMesh->RemoveElement( tr3 );
2171             }
2172             else {
2173               aMesh->ChangeElementNodes( tr3, n13, 4 );
2174               myLastCreatedElems.Append(tr3);
2175               aMesh->RemoveElement( tr1 );
2176             }
2177           }
2178           else {
2179             const SMDS_MeshNode* N1 [6];
2180             const SMDS_MeshNode* N2 [6];
2181             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2182             // now we receive following N1 and N2 (using numeration as above image)
2183             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2184             // i.e. first nodes from both arrays determ new diagonal
2185             const SMDS_MeshNode* aNodes[8];
2186             aNodes[0] = N1[0];
2187             aNodes[1] = N1[1];
2188             aNodes[2] = N2[0];
2189             aNodes[3] = N2[1];
2190             aNodes[4] = N1[3];
2191             aNodes[5] = N2[5];
2192             aNodes[6] = N2[3];
2193             aNodes[7] = N1[5];
2194             if( tr1->GetID() < tr2->GetID() ) {
2195               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2196               myLastCreatedElems.Append(tr1);
2197               GetMeshDS()->RemoveElement( tr3 );
2198             }
2199             else {
2200               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2201               myLastCreatedElems.Append(tr3);
2202               GetMeshDS()->RemoveElement( tr1 );
2203             }
2204             // remove middle node (9)
2205             GetMeshDS()->RemoveNode( N1[4] );
2206           }
2207         }
2208
2209         // Next element to fuse: the rejected one
2210         if ( tr3 )
2211           startElem = Ok12 ? tr3 : tr2;
2212
2213       } // if ( startElem )
2214     } // while ( startElem || !startLinks.empty() )
2215   } // while ( ! mapEl_setLi.empty() )
2216
2217   return true;
2218 }
2219
2220
2221 /*#define DUMPSO(txt) \
2222 //  cout << txt << endl;
2223 //=============================================================================
2224 //
2225 //
2226 //
2227 //=============================================================================
2228 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2229 {
2230 if ( i1 == i2 )
2231 return;
2232 int tmp = idNodes[ i1 ];
2233 idNodes[ i1 ] = idNodes[ i2 ];
2234 idNodes[ i2 ] = tmp;
2235 gp_Pnt Ptmp = P[ i1 ];
2236 P[ i1 ] = P[ i2 ];
2237 P[ i2 ] = Ptmp;
2238 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2239 }
2240
2241 //=======================================================================
2242 //function : SortQuadNodes
2243 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2244 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2245 //           1 or 2 else 0.
2246 //=======================================================================
2247
2248 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2249 int               idNodes[] )
2250 {
2251   gp_Pnt P[4];
2252   int i;
2253   for ( i = 0; i < 4; i++ ) {
2254     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2255     if ( !n ) return 0;
2256     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2257   }
2258
2259   gp_Vec V1(P[0], P[1]);
2260   gp_Vec V2(P[0], P[2]);
2261   gp_Vec V3(P[0], P[3]);
2262
2263   gp_Vec Cross1 = V1 ^ V2;
2264   gp_Vec Cross2 = V2 ^ V3;
2265
2266   i = 0;
2267   if (Cross1.Dot(Cross2) < 0)
2268   {
2269     Cross1 = V2 ^ V1;
2270     Cross2 = V1 ^ V3;
2271
2272     if (Cross1.Dot(Cross2) < 0)
2273       i = 2;
2274     else
2275       i = 1;
2276     swap ( i, i + 1, idNodes, P );
2277
2278     //     for ( int ii = 0; ii < 4; ii++ ) {
2279     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2280     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2281     //     }
2282   }
2283   return i;
2284 }
2285
2286 //=======================================================================
2287 //function : SortHexaNodes
2288 //purpose  : Set 8 nodes of a hexahedron in a good order.
2289 //           Return success status
2290 //=======================================================================
2291
2292 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2293                                       int               idNodes[] )
2294 {
2295   gp_Pnt P[8];
2296   int i;
2297   DUMPSO( "INPUT: ========================================");
2298   for ( i = 0; i < 8; i++ ) {
2299     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2300     if ( !n ) return false;
2301     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2302     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2303   }
2304   DUMPSO( "========================================");
2305
2306
2307   set<int> faceNodes;  // ids of bottom face nodes, to be found
2308   set<int> checkedId1; // ids of tried 2-nd nodes
2309   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2310   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2311   int iMin, iLoop1 = 0;
2312
2313   // Loop to try the 2-nd nodes
2314
2315   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2316   {
2317     // Find not checked 2-nd node
2318     for ( i = 1; i < 8; i++ )
2319       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2320         int id1 = idNodes[i];
2321         swap ( 1, i, idNodes, P );
2322         checkedId1.insert ( id1 );
2323         break;
2324       }
2325
2326     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2327     // ie that all but meybe one (id3 which is on the same face) nodes
2328     // lay on the same side from the triangle plane.
2329
2330     bool manyInPlane = false; // more than 4 nodes lay in plane
2331     int iLoop2 = 0;
2332     while ( ++iLoop2 < 6 ) {
2333
2334       // get 1-2-3 plane coeffs
2335       Standard_Real A, B, C, D;
2336       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2337       if ( N.SquareMagnitude() > gp::Resolution() )
2338       {
2339         gp_Pln pln ( P[0], N );
2340         pln.Coefficients( A, B, C, D );
2341
2342         // find the node (iMin) closest to pln
2343         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2344         set<int> idInPln;
2345         for ( i = 3; i < 8; i++ ) {
2346           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2347           if ( fabs( dist[i] ) < minDist ) {
2348             minDist = fabs( dist[i] );
2349             iMin = i;
2350           }
2351           if ( fabs( dist[i] ) <= tol )
2352             idInPln.insert( idNodes[i] );
2353         }
2354
2355         // there should not be more than 4 nodes in bottom plane
2356         if ( idInPln.size() > 1 )
2357         {
2358           DUMPSO( "### idInPln.size() = " << idInPln.size());
2359           // idInPlane does not contain the first 3 nodes
2360           if ( manyInPlane || idInPln.size() == 5)
2361             return false; // all nodes in one plane
2362           manyInPlane = true;
2363
2364           // set the 1-st node to be not in plane
2365           for ( i = 3; i < 8; i++ ) {
2366             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2367               DUMPSO( "### Reset 0-th node");
2368               swap( 0, i, idNodes, P );
2369               break;
2370             }
2371           }
2372
2373           // reset to re-check second nodes
2374           leastDist = DBL_MAX;
2375           faceNodes.clear();
2376           checkedId1.clear();
2377           iLoop1 = 0;
2378           break; // from iLoop2;
2379         }
2380
2381         // check that the other 4 nodes are on the same side
2382         bool sameSide = true;
2383         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2384         for ( i = 3; sameSide && i < 8; i++ ) {
2385           if ( i != iMin )
2386             sameSide = ( isNeg == dist[i] <= 0.);
2387         }
2388
2389         // keep best solution
2390         if ( sameSide && minDist < leastDist ) {
2391           leastDist = minDist;
2392           faceNodes.clear();
2393           faceNodes.insert( idNodes[ 1 ] );
2394           faceNodes.insert( idNodes[ 2 ] );
2395           faceNodes.insert( idNodes[ iMin ] );
2396           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2397                   << " leastDist = " << leastDist);
2398           if ( leastDist <= DBL_MIN )
2399             break;
2400         }
2401       }
2402
2403       // set next 3-d node to check
2404       int iNext = 2 + iLoop2;
2405       if ( iNext < 8 ) {
2406         DUMPSO( "Try 2-nd");
2407         swap ( 2, iNext, idNodes, P );
2408       }
2409     } // while ( iLoop2 < 6 )
2410   } // iLoop1
2411
2412   if ( faceNodes.empty() ) return false;
2413
2414   // Put the faceNodes in proper places
2415   for ( i = 4; i < 8; i++ ) {
2416     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2417       // find a place to put
2418       int iTo = 1;
2419       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2420         iTo++;
2421       DUMPSO( "Set faceNodes");
2422       swap ( iTo, i, idNodes, P );
2423     }
2424   }
2425
2426
2427   // Set nodes of the found bottom face in good order
2428   DUMPSO( " Found bottom face: ");
2429   i = SortQuadNodes( theMesh, idNodes );
2430   if ( i ) {
2431     gp_Pnt Ptmp = P[ i ];
2432     P[ i ] = P[ i+1 ];
2433     P[ i+1 ] = Ptmp;
2434   }
2435   //   else
2436   //     for ( int ii = 0; ii < 4; ii++ ) {
2437   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2438   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2439   //    }
2440
2441   // Gravity center of the top and bottom faces
2442   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2443   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2444
2445   // Get direction from the bottom to the top face
2446   gp_Vec upDir ( aGCb, aGCt );
2447   Standard_Real upDirSize = upDir.Magnitude();
2448   if ( upDirSize <= gp::Resolution() ) return false;
2449   upDir / upDirSize;
2450
2451   // Assure that the bottom face normal points up
2452   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2453   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2454   if ( Nb.Dot( upDir ) < 0 ) {
2455     DUMPSO( "Reverse bottom face");
2456     swap( 1, 3, idNodes, P );
2457   }
2458
2459   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2460   Standard_Real minDist = DBL_MAX;
2461   for ( i = 4; i < 8; i++ ) {
2462     // projection of P[i] to the plane defined by P[0] and upDir
2463     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2464     Standard_Real sqDist = P[0].SquareDistance( Pp );
2465     if ( sqDist < minDist ) {
2466       minDist = sqDist;
2467       iMin = i;
2468     }
2469   }
2470   DUMPSO( "Set 4-th");
2471   swap ( 4, iMin, idNodes, P );
2472
2473   // Set nodes of the top face in good order
2474   DUMPSO( "Sort top face");
2475   i = SortQuadNodes( theMesh, &idNodes[4] );
2476   if ( i ) {
2477     i += 4;
2478     gp_Pnt Ptmp = P[ i ];
2479     P[ i ] = P[ i+1 ];
2480     P[ i+1 ] = Ptmp;
2481   }
2482
2483   // Assure that direction of the top face normal is from the bottom face
2484   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2485   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2486   if ( Nt.Dot( upDir ) < 0 ) {
2487     DUMPSO( "Reverse top face");
2488     swap( 5, 7, idNodes, P );
2489   }
2490
2491   //   DUMPSO( "OUTPUT: ========================================");
2492   //   for ( i = 0; i < 8; i++ ) {
2493   //     float *p = ugrid->GetPoint(idNodes[i]);
2494   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2495   //   }
2496
2497   return true;
2498 }*/
2499
2500 //================================================================================
2501 /*!
2502  * \brief Return nodes linked to the given one
2503  * \param theNode - the node
2504  * \param linkedNodes - the found nodes
2505  * \param type - the type of elements to check
2506  *
2507  * Medium nodes are ignored
2508  */
2509 //================================================================================
2510
2511 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2512                                        TIDSortedElemSet &   linkedNodes,
2513                                        SMDSAbs_ElementType  type )
2514 {
2515   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2516   while ( elemIt->more() )
2517   {
2518     const SMDS_MeshElement* elem = elemIt->next();
2519     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2520     if ( elem->GetType() == SMDSAbs_Volume )
2521     {
2522       SMDS_VolumeTool vol( elem );
2523       while ( nodeIt->more() ) {
2524         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2525         if ( theNode != n && vol.IsLinked( theNode, n ))
2526           linkedNodes.insert( n );
2527       }
2528     }
2529     else
2530     {
2531       for ( int i = 0; nodeIt->more(); ++i ) {
2532         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2533         if ( n == theNode ) {
2534           int iBefore = i - 1;
2535           int iAfter  = i + 1;
2536           if ( elem->IsQuadratic() ) {
2537             int nb = elem->NbNodes() / 2;
2538             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2539             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2540           }
2541           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2542           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2543         }
2544       }
2545     }
2546   }
2547 }
2548
2549 //=======================================================================
2550 //function : laplacianSmooth
2551 //purpose  : pulls theNode toward the center of surrounding nodes directly
2552 //           connected to that node along an element edge
2553 //=======================================================================
2554
2555 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2556                      const Handle(Geom_Surface)&          theSurface,
2557                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2558 {
2559   // find surrounding nodes
2560
2561   TIDSortedElemSet nodeSet;
2562   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2563
2564   // compute new coodrs
2565
2566   double coord[] = { 0., 0., 0. };
2567   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2568   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2569     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2570     if ( theSurface.IsNull() ) { // smooth in 3D
2571       coord[0] += node->X();
2572       coord[1] += node->Y();
2573       coord[2] += node->Z();
2574     }
2575     else { // smooth in 2D
2576       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2577       gp_XY* uv = theUVMap[ node ];
2578       coord[0] += uv->X();
2579       coord[1] += uv->Y();
2580     }
2581   }
2582   int nbNodes = nodeSet.size();
2583   if ( !nbNodes )
2584     return;
2585   coord[0] /= nbNodes;
2586   coord[1] /= nbNodes;
2587
2588   if ( !theSurface.IsNull() ) {
2589     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2590     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2591     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2592     coord[0] = p3d.X();
2593     coord[1] = p3d.Y();
2594     coord[2] = p3d.Z();
2595   }
2596   else
2597     coord[2] /= nbNodes;
2598
2599   // move node
2600
2601   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2602 }
2603
2604 //=======================================================================
2605 //function : centroidalSmooth
2606 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2607 //           surrounding elements
2608 //=======================================================================
2609
2610 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2611                       const Handle(Geom_Surface)&          theSurface,
2612                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2613 {
2614   gp_XYZ aNewXYZ(0.,0.,0.);
2615   SMESH::Controls::Area anAreaFunc;
2616   double totalArea = 0.;
2617   int nbElems = 0;
2618
2619   // compute new XYZ
2620
2621   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2622   while ( elemIt->more() )
2623   {
2624     const SMDS_MeshElement* elem = elemIt->next();
2625     nbElems++;
2626
2627     gp_XYZ elemCenter(0.,0.,0.);
2628     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2629     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2630     int nn = elem->NbNodes();
2631     if(elem->IsQuadratic()) nn = nn/2;
2632     int i=0;
2633     //while ( itN->more() ) {
2634     while ( i<nn ) {
2635       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2636       i++;
2637       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2638       aNodePoints.push_back( aP );
2639       if ( !theSurface.IsNull() ) { // smooth in 2D
2640         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2641         gp_XY* uv = theUVMap[ aNode ];
2642         aP.SetCoord( uv->X(), uv->Y(), 0. );
2643       }
2644       elemCenter += aP;
2645     }
2646     double elemArea = anAreaFunc.GetValue( aNodePoints );
2647     totalArea += elemArea;
2648     elemCenter /= nn;
2649     aNewXYZ += elemCenter * elemArea;
2650   }
2651   aNewXYZ /= totalArea;
2652   if ( !theSurface.IsNull() ) {
2653     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2654     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2655   }
2656
2657   // move node
2658
2659   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2660 }
2661
2662 //=======================================================================
2663 //function : getClosestUV
2664 //purpose  : return UV of closest projection
2665 //=======================================================================
2666
2667 static bool getClosestUV (Extrema_GenExtPS& projector,
2668                           const gp_Pnt&     point,
2669                           gp_XY &           result)
2670 {
2671   projector.Perform( point );
2672   if ( projector.IsDone() ) {
2673     double u, v, minVal = DBL_MAX;
2674     for ( int i = projector.NbExt(); i > 0; i-- )
2675       if ( projector.Value( i ) < minVal ) {
2676         minVal = projector.Value( i );
2677         projector.Point( i ).Parameter( u, v );
2678       }
2679     result.SetCoord( u, v );
2680     return true;
2681   }
2682   return false;
2683 }
2684
2685 //=======================================================================
2686 //function : Smooth
2687 //purpose  : Smooth theElements during theNbIterations or until a worst
2688 //           element has aspect ratio <= theTgtAspectRatio.
2689 //           Aspect Ratio varies in range [1.0, inf].
2690 //           If theElements is empty, the whole mesh is smoothed.
2691 //           theFixedNodes contains additionally fixed nodes. Nodes built
2692 //           on edges and boundary nodes are always fixed.
2693 //=======================================================================
2694
2695 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2696                                set<const SMDS_MeshNode*> & theFixedNodes,
2697                                const SmoothMethod          theSmoothMethod,
2698                                const int                   theNbIterations,
2699                                double                      theTgtAspectRatio,
2700                                const bool                  the2D)
2701 {
2702   myLastCreatedElems.Clear();
2703   myLastCreatedNodes.Clear();
2704
2705   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2706
2707   if ( theTgtAspectRatio < 1.0 )
2708     theTgtAspectRatio = 1.0;
2709
2710   const double disttol = 1.e-16;
2711
2712   SMESH::Controls::AspectRatio aQualityFunc;
2713
2714   SMESHDS_Mesh* aMesh = GetMeshDS();
2715
2716   if ( theElems.empty() ) {
2717     // add all faces to theElems
2718     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2719     while ( fIt->more() ) {
2720       const SMDS_MeshElement* face = fIt->next();
2721       theElems.insert( face );
2722     }
2723   }
2724   // get all face ids theElems are on
2725   set< int > faceIdSet;
2726   TIDSortedElemSet::iterator itElem;
2727   if ( the2D )
2728     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2729       int fId = FindShape( *itElem );
2730       // check that corresponding submesh exists and a shape is face
2731       if (fId &&
2732           faceIdSet.find( fId ) == faceIdSet.end() &&
2733           aMesh->MeshElements( fId )) {
2734         TopoDS_Shape F = aMesh->IndexToShape( fId );
2735         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2736           faceIdSet.insert( fId );
2737       }
2738     }
2739   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2740
2741   // ===============================================
2742   // smooth elements on each TopoDS_Face separately
2743   // ===============================================
2744
2745   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2746   for ( ; fId != faceIdSet.rend(); ++fId ) {
2747     // get face surface and submesh
2748     Handle(Geom_Surface) surface;
2749     SMESHDS_SubMesh* faceSubMesh = 0;
2750     TopoDS_Face face;
2751     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2752     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2753     bool isUPeriodic = false, isVPeriodic = false;
2754     if ( *fId ) {
2755       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2756       surface = BRep_Tool::Surface( face );
2757       faceSubMesh = aMesh->MeshElements( *fId );
2758       fToler2 = BRep_Tool::Tolerance( face );
2759       fToler2 *= fToler2 * 10.;
2760       isUPeriodic = surface->IsUPeriodic();
2761       if ( isUPeriodic )
2762         vPeriod = surface->UPeriod();
2763       isVPeriodic = surface->IsVPeriodic();
2764       if ( isVPeriodic )
2765         uPeriod = surface->VPeriod();
2766       surface->Bounds( u1, u2, v1, v2 );
2767     }
2768     // ---------------------------------------------------------
2769     // for elements on a face, find movable and fixed nodes and
2770     // compute UV for them
2771     // ---------------------------------------------------------
2772     bool checkBoundaryNodes = false;
2773     bool isQuadratic = false;
2774     set<const SMDS_MeshNode*> setMovableNodes;
2775     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2776     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2777     list< const SMDS_MeshElement* > elemsOnFace;
2778
2779     Extrema_GenExtPS projector;
2780     GeomAdaptor_Surface surfAdaptor;
2781     if ( !surface.IsNull() ) {
2782       surfAdaptor.Load( surface );
2783       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2784     }
2785     int nbElemOnFace = 0;
2786     itElem = theElems.begin();
2787     // loop on not yet smoothed elements: look for elems on a face
2788     while ( itElem != theElems.end() ) {
2789       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2790         break; // all elements found
2791
2792       const SMDS_MeshElement* elem = *itElem;
2793       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2794            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2795         ++itElem;
2796         continue;
2797       }
2798       elemsOnFace.push_back( elem );
2799       theElems.erase( itElem++ );
2800       nbElemOnFace++;
2801
2802       if ( !isQuadratic )
2803         isQuadratic = elem->IsQuadratic();
2804
2805       // get movable nodes of elem
2806       const SMDS_MeshNode* node;
2807       SMDS_TypeOfPosition posType;
2808       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2809       int nn = 0, nbn =  elem->NbNodes();
2810       if(elem->IsQuadratic())
2811         nbn = nbn/2;
2812       while ( nn++ < nbn ) {
2813         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2814         const SMDS_PositionPtr& pos = node->GetPosition();
2815         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2816         if (posType != SMDS_TOP_EDGE &&
2817             posType != SMDS_TOP_VERTEX &&
2818             theFixedNodes.find( node ) == theFixedNodes.end())
2819         {
2820           // check if all faces around the node are on faceSubMesh
2821           // because a node on edge may be bound to face
2822           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2823           bool all = true;
2824           if ( faceSubMesh ) {
2825             while ( eIt->more() && all ) {
2826               const SMDS_MeshElement* e = eIt->next();
2827               all = faceSubMesh->Contains( e );
2828             }
2829           }
2830           if ( all )
2831             setMovableNodes.insert( node );
2832           else
2833             checkBoundaryNodes = true;
2834         }
2835         if ( posType == SMDS_TOP_3DSPACE )
2836           checkBoundaryNodes = true;
2837       }
2838
2839       if ( surface.IsNull() )
2840         continue;
2841
2842       // get nodes to check UV
2843       list< const SMDS_MeshNode* > uvCheckNodes;
2844       itN = elem->nodesIterator();
2845       nn = 0; nbn =  elem->NbNodes();
2846       if(elem->IsQuadratic())
2847         nbn = nbn/2;
2848       while ( nn++ < nbn ) {
2849         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2850         if ( uvMap.find( node ) == uvMap.end() )
2851           uvCheckNodes.push_back( node );
2852         // add nodes of elems sharing node
2853         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2854         //         while ( eIt->more() ) {
2855         //           const SMDS_MeshElement* e = eIt->next();
2856         //           if ( e != elem ) {
2857         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2858         //             while ( nIt->more() ) {
2859         //               const SMDS_MeshNode* n =
2860         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2861         //               if ( uvMap.find( n ) == uvMap.end() )
2862         //                 uvCheckNodes.push_back( n );
2863         //             }
2864         //           }
2865         //         }
2866       }
2867       // check UV on face
2868       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2869       for ( ; n != uvCheckNodes.end(); ++n ) {
2870         node = *n;
2871         gp_XY uv( 0, 0 );
2872         const SMDS_PositionPtr& pos = node->GetPosition();
2873         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2874         // get existing UV
2875         switch ( posType ) {
2876         case SMDS_TOP_FACE: {
2877           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2878           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2879           break;
2880         }
2881         case SMDS_TOP_EDGE: {
2882           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2883           Handle(Geom2d_Curve) pcurve;
2884           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2885             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2886           if ( !pcurve.IsNull() ) {
2887             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2888             uv = pcurve->Value( u ).XY();
2889           }
2890           break;
2891         }
2892         case SMDS_TOP_VERTEX: {
2893           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2894           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2895             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2896           break;
2897         }
2898         default:;
2899         }
2900         // check existing UV
2901         bool project = true;
2902         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2903         double dist1 = DBL_MAX, dist2 = 0;
2904         if ( posType != SMDS_TOP_3DSPACE ) {
2905           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2906           project = dist1 > fToler2;
2907         }
2908         if ( project ) { // compute new UV
2909           gp_XY newUV;
2910           if ( !getClosestUV( projector, pNode, newUV )) {
2911             MESSAGE("Node Projection Failed " << node);
2912           }
2913           else {
2914             if ( isUPeriodic )
2915               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2916             if ( isVPeriodic )
2917               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2918             // check new UV
2919             if ( posType != SMDS_TOP_3DSPACE )
2920               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2921             if ( dist2 < dist1 )
2922               uv = newUV;
2923           }
2924         }
2925         // store UV in the map
2926         listUV.push_back( uv );
2927         uvMap.insert( make_pair( node, &listUV.back() ));
2928       }
2929     } // loop on not yet smoothed elements
2930
2931     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2932       checkBoundaryNodes = true;
2933
2934     // fix nodes on mesh boundary
2935
2936     if ( checkBoundaryNodes ) {
2937       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2938       map< NLink, int >::iterator link_nb;
2939       // put all elements links to linkNbMap
2940       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2941       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2942         const SMDS_MeshElement* elem = (*elemIt);
2943         int nbn =  elem->NbNodes();
2944         if(elem->IsQuadratic())
2945           nbn = nbn/2;
2946         // loop on elem links: insert them in linkNbMap
2947         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2948         for ( int iN = 0; iN < nbn; ++iN ) {
2949           curNode = elem->GetNode( iN );
2950           NLink link;
2951           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2952           else                      link = make_pair( prevNode , curNode );
2953           prevNode = curNode;
2954           link_nb = linkNbMap.find( link );
2955           if ( link_nb == linkNbMap.end() )
2956             linkNbMap.insert( make_pair ( link, 1 ));
2957           else
2958             link_nb->second++;
2959         }
2960       }
2961       // remove nodes that are in links encountered only once from setMovableNodes
2962       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2963         if ( link_nb->second == 1 ) {
2964           setMovableNodes.erase( link_nb->first.first );
2965           setMovableNodes.erase( link_nb->first.second );
2966         }
2967       }
2968     }
2969
2970     // -----------------------------------------------------
2971     // for nodes on seam edge, compute one more UV ( uvMap2 );
2972     // find movable nodes linked to nodes on seam and which
2973     // are to be smoothed using the second UV ( uvMap2 )
2974     // -----------------------------------------------------
2975
2976     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2977     if ( !surface.IsNull() ) {
2978       TopExp_Explorer eExp( face, TopAbs_EDGE );
2979       for ( ; eExp.More(); eExp.Next() ) {
2980         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2981         if ( !BRep_Tool::IsClosed( edge, face ))
2982           continue;
2983         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2984         if ( !sm ) continue;
2985         // find out which parameter varies for a node on seam
2986         double f,l;
2987         gp_Pnt2d uv1, uv2;
2988         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2989         if ( pcurve.IsNull() ) continue;
2990         uv1 = pcurve->Value( f );
2991         edge.Reverse();
2992         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2993         if ( pcurve.IsNull() ) continue;
2994         uv2 = pcurve->Value( f );
2995         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2996         // assure uv1 < uv2
2997         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2998           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2999         }
3000         // get nodes on seam and its vertices
3001         list< const SMDS_MeshNode* > seamNodes;
3002         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3003         while ( nSeamIt->more() ) {
3004           const SMDS_MeshNode* node = nSeamIt->next();
3005           if ( !isQuadratic || !IsMedium( node ))
3006             seamNodes.push_back( node );
3007         }
3008         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3009         for ( ; vExp.More(); vExp.Next() ) {
3010           sm = aMesh->MeshElements( vExp.Current() );
3011           if ( sm ) {
3012             nSeamIt = sm->GetNodes();
3013             while ( nSeamIt->more() )
3014               seamNodes.push_back( nSeamIt->next() );
3015           }
3016         }
3017         // loop on nodes on seam
3018         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3019         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3020           const SMDS_MeshNode* nSeam = *noSeIt;
3021           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3022           if ( n_uv == uvMap.end() )
3023             continue;
3024           // set the first UV
3025           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3026           // set the second UV
3027           listUV.push_back( *n_uv->second );
3028           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3029           if ( uvMap2.empty() )
3030             uvMap2 = uvMap; // copy the uvMap contents
3031           uvMap2[ nSeam ] = &listUV.back();
3032
3033           // collect movable nodes linked to ones on seam in nodesNearSeam
3034           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3035           while ( eIt->more() ) {
3036             const SMDS_MeshElement* e = eIt->next();
3037             int nbUseMap1 = 0, nbUseMap2 = 0;
3038             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3039             int nn = 0, nbn =  e->NbNodes();
3040             if(e->IsQuadratic()) nbn = nbn/2;
3041             while ( nn++ < nbn )
3042             {
3043               const SMDS_MeshNode* n =
3044                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3045               if (n == nSeam ||
3046                   setMovableNodes.find( n ) == setMovableNodes.end() )
3047                 continue;
3048               // add only nodes being closer to uv2 than to uv1
3049               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3050                            0.5 * ( n->Y() + nSeam->Y() ),
3051                            0.5 * ( n->Z() + nSeam->Z() ));
3052               gp_XY uv;
3053               getClosestUV( projector, pMid, uv );
3054               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3055                 nodesNearSeam.insert( n );
3056                 nbUseMap2++;
3057               }
3058               else
3059                 nbUseMap1++;
3060             }
3061             // for centroidalSmooth all element nodes must
3062             // be on one side of a seam
3063             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3064               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3065               nn = 0;
3066               while ( nn++ < nbn ) {
3067                 const SMDS_MeshNode* n =
3068                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3069                 setMovableNodes.erase( n );
3070               }
3071             }
3072           }
3073         } // loop on nodes on seam
3074       } // loop on edge of a face
3075     } // if ( !face.IsNull() )
3076
3077     if ( setMovableNodes.empty() ) {
3078       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3079       continue; // goto next face
3080     }
3081
3082     // -------------
3083     // SMOOTHING //
3084     // -------------
3085
3086     int it = -1;
3087     double maxRatio = -1., maxDisplacement = -1.;
3088     set<const SMDS_MeshNode*>::iterator nodeToMove;
3089     for ( it = 0; it < theNbIterations; it++ ) {
3090       maxDisplacement = 0.;
3091       nodeToMove = setMovableNodes.begin();
3092       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3093         const SMDS_MeshNode* node = (*nodeToMove);
3094         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3095
3096         // smooth
3097         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3098         if ( theSmoothMethod == LAPLACIAN )
3099           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3100         else
3101           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3102
3103         // node displacement
3104         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3105         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3106         if ( aDispl > maxDisplacement )
3107           maxDisplacement = aDispl;
3108       }
3109       // no node movement => exit
3110       //if ( maxDisplacement < 1.e-16 ) {
3111       if ( maxDisplacement < disttol ) {
3112         MESSAGE("-- no node movement --");
3113         break;
3114       }
3115
3116       // check elements quality
3117       maxRatio  = 0;
3118       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3119       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3120         const SMDS_MeshElement* elem = (*elemIt);
3121         if ( !elem || elem->GetType() != SMDSAbs_Face )
3122           continue;
3123         SMESH::Controls::TSequenceOfXYZ aPoints;
3124         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3125           double aValue = aQualityFunc.GetValue( aPoints );
3126           if ( aValue > maxRatio )
3127             maxRatio = aValue;
3128         }
3129       }
3130       if ( maxRatio <= theTgtAspectRatio ) {
3131         MESSAGE("-- quality achived --");
3132         break;
3133       }
3134       if (it+1 == theNbIterations) {
3135         MESSAGE("-- Iteration limit exceeded --");
3136       }
3137     } // smoothing iterations
3138
3139     MESSAGE(" Face id: " << *fId <<
3140             " Nb iterstions: " << it <<
3141             " Displacement: " << maxDisplacement <<
3142             " Aspect Ratio " << maxRatio);
3143
3144     // ---------------------------------------
3145     // new nodes positions are computed,
3146     // record movement in DS and set new UV
3147     // ---------------------------------------
3148     nodeToMove = setMovableNodes.begin();
3149     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3150       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3151       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3152       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3153       if ( node_uv != uvMap.end() ) {
3154         gp_XY* uv = node_uv->second;
3155         node->SetPosition
3156           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3157       }
3158     }
3159
3160     // move medium nodes of quadratic elements
3161     if ( isQuadratic )
3162     {
3163       SMESH_MesherHelper helper( *GetMesh() );
3164       if ( !face.IsNull() )
3165         helper.SetSubShape( face );
3166       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3167       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3168         const SMDS_QuadraticFaceOfNodes* QF =
3169           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3170         if(QF) {
3171           vector<const SMDS_MeshNode*> Ns;
3172           Ns.reserve(QF->NbNodes()+1);
3173           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3174           while ( anIter->more() )
3175             Ns.push_back( anIter->next() );
3176           Ns.push_back( Ns[0] );
3177           double x, y, z;
3178           for(int i=0; i<QF->NbNodes(); i=i+2) {
3179             if ( !surface.IsNull() ) {
3180               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3181               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3182               gp_XY uv = ( uv1 + uv2 ) / 2.;
3183               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3184               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3185             }
3186             else {
3187               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3188               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3189               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3190             }
3191             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3192                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3193                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3194               // we have to move i+1 node
3195               aMesh->MoveNode( Ns[i+1], x, y, z );
3196             }
3197           }
3198         }
3199       }
3200     }
3201
3202   } // loop on face ids
3203
3204 }
3205
3206 //=======================================================================
3207 //function : isReverse
3208 //purpose  : Return true if normal of prevNodes is not co-directied with
3209 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3210 //           iNotSame is where prevNodes and nextNodes are different
3211 //=======================================================================
3212
3213 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3214                       vector<const SMDS_MeshNode*> nextNodes,
3215                       const int            nbNodes,
3216                       const int            iNotSame)
3217 {
3218   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3219   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3220
3221   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3222   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3223   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3224   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3225
3226   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3227   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3228   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3229   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3230
3231   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3232
3233   return (vA ^ vB) * vN < 0.0;
3234 }
3235
3236 //=======================================================================
3237 /*!
3238  * \brief Create elements by sweeping an element
3239  * \param elem - element to sweep
3240  * \param newNodesItVec - nodes generated from each node of the element
3241  * \param newElems - generated elements
3242  * \param nbSteps - number of sweeping steps
3243  * \param srcElements - to append elem for each generated element
3244  */
3245 //=======================================================================
3246
3247 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3248                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3249                                     list<const SMDS_MeshElement*>&        newElems,
3250                                     const int                             nbSteps,
3251                                     SMESH_SequenceOfElemPtr&              srcElements)
3252 {
3253   SMESHDS_Mesh* aMesh = GetMeshDS();
3254
3255   // Loop on elem nodes:
3256   // find new nodes and detect same nodes indices
3257   int nbNodes = elem->NbNodes();
3258   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3259   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3260   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3261   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3262
3263   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3264   vector<int> sames(nbNodes);
3265   vector<bool> issimple(nbNodes);
3266
3267   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3268     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3269     const SMDS_MeshNode*                 node         = nnIt->first;
3270     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3271     if ( listNewNodes.empty() ) {
3272       return;
3273     }
3274
3275     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3276
3277     itNN[ iNode ] = listNewNodes.begin();
3278     prevNod[ iNode ] = node;
3279     nextNod[ iNode ] = listNewNodes.front();
3280     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3281       if ( prevNod[ iNode ] != nextNod [ iNode ])
3282         iNotSameNode = iNode;
3283       else {
3284         iSameNode = iNode;
3285         //nbSame++;
3286         sames[nbSame++] = iNode;
3287       }
3288     }
3289   }
3290
3291   //cout<<"  nbSame = "<<nbSame<<endl;
3292   if ( nbSame == nbNodes || nbSame > 2) {
3293     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3294     //INFOS( " Too many same nodes of element " << elem->GetID() );
3295     return;
3296   }
3297
3298   //  if( elem->IsQuadratic() && nbSame>0 ) {
3299   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3300   //    return;
3301   //  }
3302
3303   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3304   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3305   if ( nbSame > 0 ) {
3306     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3307     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3308     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3309   }
3310
3311   //if(nbNodes==8)
3312   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3313   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3314   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3315   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3316
3317   // check element orientation
3318   int i0 = 0, i2 = 2;
3319   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3320     //MESSAGE("Reversed elem " << elem );
3321     i0 = 2;
3322     i2 = 0;
3323     if ( nbSame > 0 )
3324       std::swap( iBeforeSame, iAfterSame );
3325   }
3326
3327   // make new elements
3328   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3329     // get next nodes
3330     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3331       if(issimple[iNode]) {
3332         nextNod[ iNode ] = *itNN[ iNode ];
3333         itNN[ iNode ]++;
3334       }
3335       else {
3336         if( elem->GetType()==SMDSAbs_Node ) {
3337           // we have to use two nodes
3338           midlNod[ iNode ] = *itNN[ iNode ];
3339           itNN[ iNode ]++;
3340           nextNod[ iNode ] = *itNN[ iNode ];
3341           itNN[ iNode ]++;
3342         }
3343         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3344           // we have to use each second node
3345           //itNN[ iNode ]++;
3346           nextNod[ iNode ] = *itNN[ iNode ];
3347           itNN[ iNode ]++;
3348         }
3349         else {
3350           // we have to use two nodes
3351           midlNod[ iNode ] = *itNN[ iNode ];
3352           itNN[ iNode ]++;
3353           nextNod[ iNode ] = *itNN[ iNode ];
3354           itNN[ iNode ]++;
3355         }
3356       }
3357     }
3358     SMDS_MeshElement* aNewElem = 0;
3359     if(!elem->IsPoly()) {
3360       switch ( nbNodes ) {
3361       case 0:
3362         return;
3363       case 1: { // NODE
3364         if ( nbSame == 0 ) {
3365           if(issimple[0])
3366             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3367           else
3368             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3369         }
3370         break;
3371       }
3372       case 2: { // EDGE
3373         if ( nbSame == 0 )
3374           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3375                                     nextNod[ 1 ], nextNod[ 0 ] );
3376         else
3377           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3378                                     nextNod[ iNotSameNode ] );
3379         break;
3380       }
3381
3382       case 3: { // TRIANGLE or quadratic edge
3383         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3384
3385           if ( nbSame == 0 )       // --- pentahedron
3386             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3387                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3388
3389           else if ( nbSame == 1 )  // --- pyramid
3390             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3391                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3392                                          nextNod[ iSameNode ]);
3393
3394           else // 2 same nodes:      --- tetrahedron
3395             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3396                                          nextNod[ iNotSameNode ]);
3397         }
3398         else { // quadratic edge
3399           if(nbSame==0) {     // quadratic quadrangle
3400             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3401                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3402           }
3403           else if(nbSame==1) { // quadratic triangle
3404             if(sames[0]==2) {
3405               return; // medium node on axis
3406             }
3407             else if(sames[0]==0) {
3408               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3409                                         nextNod[2], midlNod[1], prevNod[2]);
3410             }
3411             else { // sames[0]==1
3412               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3413                                         midlNod[0], nextNod[2], prevNod[2]);
3414             }
3415           }
3416           else {
3417             return;
3418           }
3419         }
3420         break;
3421       }
3422       case 4: { // QUADRANGLE
3423
3424         if ( nbSame == 0 )       // --- hexahedron
3425           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3426                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3427
3428         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3429           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3430                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3431                                        nextNod[ iSameNode ]);
3432           newElems.push_back( aNewElem );
3433           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3434                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3435                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3436         }
3437         else if ( nbSame == 2 ) { // pentahedron
3438           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3439             // iBeforeSame is same too
3440             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3441                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3442                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3443           else
3444             // iAfterSame is same too
3445             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3446                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3447                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3448         }
3449         break;
3450       }
3451       case 6: { // quadratic triangle
3452         // create pentahedron with 15 nodes
3453         if(nbSame==0) {
3454           if(i0>0) { // reversed case
3455             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3456                                          nextNod[0], nextNod[2], nextNod[1],
3457                                          prevNod[5], prevNod[4], prevNod[3],
3458                                          nextNod[5], nextNod[4], nextNod[3],
3459                                          midlNod[0], midlNod[2], midlNod[1]);
3460           }
3461           else { // not reversed case
3462             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3463                                          nextNod[0], nextNod[1], nextNod[2],
3464                                          prevNod[3], prevNod[4], prevNod[5],
3465                                          nextNod[3], nextNod[4], nextNod[5],
3466                                          midlNod[0], midlNod[1], midlNod[2]);
3467           }
3468         }
3469         else if(nbSame==1) {
3470           // 2d order pyramid of 13 nodes
3471           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3472           //                                 int n12,int n23,int n34,int n41,
3473           //                                 int n15,int n25,int n35,int n45, int ID);
3474           int n5 = iSameNode;
3475           int n1,n4,n41,n15,n45;
3476           if(i0>0) { // reversed case
3477             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3478             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3479             n41 = n1 + 3;
3480             n15 = n5 + 3;
3481             n45 = n4 + 3;
3482           }
3483           else {
3484             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3485             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3486             n41 = n4 + 3;
3487             n15 = n1 + 3;
3488             n45 = n5 + 3;
3489           }
3490           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3491                                       nextNod[n4], prevNod[n4], prevNod[n5],
3492                                       midlNod[n1], nextNod[n41],
3493                                       midlNod[n4], prevNod[n41],
3494                                       prevNod[n15], nextNod[n15],
3495                                       nextNod[n45], prevNod[n45]);
3496         }
3497         else if(nbSame==2) {
3498           // 2d order tetrahedron of 10 nodes
3499           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3500           //                                 int n12,int n23,int n31,
3501           //                                 int n14,int n24,int n34, int ID);
3502           int n1 = iNotSameNode;
3503           int n2,n3,n12,n23,n31;
3504           if(i0>0) { // reversed case
3505             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3506             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3507             n12 = n2 + 3;
3508             n23 = n3 + 3;
3509             n31 = n1 + 3;
3510           }
3511           else {
3512             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3513             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3514             n12 = n1 + 3;
3515             n23 = n2 + 3;
3516             n31 = n3 + 3;
3517           }
3518           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3519                                        prevNod[n12], prevNod[n23], prevNod[n31],
3520                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3521         }
3522         break;
3523       }
3524       case 8: { // quadratic quadrangle
3525         if(nbSame==0) {
3526           // create hexahedron with 20 nodes
3527           if(i0>0) { // reversed case
3528             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3529                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3530                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3531                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3532                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3533           }
3534           else { // not reversed case
3535             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3536                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3537                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3538                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3539                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3540           }
3541         }
3542         else if(nbSame==1) { 
3543           // --- pyramid + pentahedron - can not be created since it is needed 
3544           // additional middle node ot the center of face
3545           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3546           return;
3547         }
3548         else if(nbSame==2) {
3549           // 2d order Pentahedron with 15 nodes
3550           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3551           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3552           //                                 int n14,int n25,int n36, int ID);
3553           int n1,n2,n4,n5;
3554           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3555             // iBeforeSame is same too
3556             n1 = iBeforeSame;
3557             n2 = iOpposSame;
3558             n4 = iSameNode;
3559             n5 = iAfterSame;
3560           }
3561           else {
3562             // iAfterSame is same too
3563             n1 = iSameNode;
3564             n2 = iBeforeSame;
3565             n4 = iAfterSame;
3566             n5 = iOpposSame;
3567           }
3568           int n12,n45,n14,n25;
3569           if(i0>0) { //reversed case
3570             n12 = n1 + 4;
3571             n45 = n5 + 4;
3572             n14 = n4 + 4;
3573             n25 = n2 + 4;
3574           }
3575           else {
3576             n12 = n2 + 4;
3577             n45 = n4 + 4;
3578             n14 = n1 + 4;
3579             n25 = n5 + 4;
3580           }
3581           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3582                                        prevNod[n4], prevNod[n5], nextNod[n5],
3583                                        prevNod[n12], midlNod[n2], nextNod[n12],
3584                                        prevNod[n45], midlNod[n5], nextNod[n45],
3585                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3586         }
3587         break;
3588       }
3589       default: {
3590         // realized for extrusion only
3591         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3592         //vector<int> quantities (nbNodes + 2);
3593
3594         //quantities[0] = nbNodes; // bottom of prism
3595         //for (int inode = 0; inode < nbNodes; inode++) {
3596         //  polyedre_nodes[inode] = prevNod[inode];
3597         //}
3598
3599         //quantities[1] = nbNodes; // top of prism
3600         //for (int inode = 0; inode < nbNodes; inode++) {
3601         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3602         //}
3603
3604         //for (int iface = 0; iface < nbNodes; iface++) {
3605         //  quantities[iface + 2] = 4;
3606         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3607         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3608         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3609         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3610         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3611         //}
3612         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3613         break;
3614       }
3615       }
3616     }
3617
3618     if(!aNewElem) {
3619       // realized for extrusion only
3620       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3621       vector<int> quantities (nbNodes + 2);
3622
3623       quantities[0] = nbNodes; // bottom of prism
3624       for (int inode = 0; inode < nbNodes; inode++) {
3625         polyedre_nodes[inode] = prevNod[inode];
3626       }
3627
3628       quantities[1] = nbNodes; // top of prism
3629       for (int inode = 0; inode < nbNodes; inode++) {
3630         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3631       }
3632
3633       for (int iface = 0; iface < nbNodes; iface++) {
3634         quantities[iface + 2] = 4;
3635         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3636         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3637         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3638         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3639         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3640       }
3641       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3642     }
3643
3644     if ( aNewElem ) {
3645       newElems.push_back( aNewElem );
3646       myLastCreatedElems.Append(aNewElem);
3647       srcElements.Append( elem );
3648     }
3649
3650     // set new prev nodes
3651     for ( iNode = 0; iNode < nbNodes; iNode++ )
3652       prevNod[ iNode ] = nextNod[ iNode ];
3653
3654   } // for steps
3655 }
3656
3657 //=======================================================================
3658 /*!
3659  * \brief Create 1D and 2D elements around swept elements
3660  * \param mapNewNodes - source nodes and ones generated from them
3661  * \param newElemsMap - source elements and ones generated from them
3662  * \param elemNewNodesMap - nodes generated from each node of each element
3663  * \param elemSet - all swept elements
3664  * \param nbSteps - number of sweeping steps
3665  * \param srcElements - to append elem for each generated element
3666  */
3667 //=======================================================================
3668
3669 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3670                                   TElemOfElemListMap &     newElemsMap,
3671                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3672                                   TIDSortedElemSet&        elemSet,
3673                                   const int                nbSteps,
3674                                   SMESH_SequenceOfElemPtr& srcElements)
3675 {
3676   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3677   SMESHDS_Mesh* aMesh = GetMeshDS();
3678
3679   // Find nodes belonging to only one initial element - sweep them to get edges.
3680
3681   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3682   for ( ; nList != mapNewNodes.end(); nList++ ) {
3683     const SMDS_MeshNode* node =
3684       static_cast<const SMDS_MeshNode*>( nList->first );
3685     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3686     int nbInitElems = 0;
3687     const SMDS_MeshElement* el = 0;
3688     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3689     while ( eIt->more() && nbInitElems < 2 ) {
3690       el = eIt->next();
3691       SMDSAbs_ElementType type = el->GetType();
3692       if ( type == SMDSAbs_Volume || type < highType ) continue;
3693       if ( type > highType ) {
3694         nbInitElems = 0;
3695         highType = type;
3696       }
3697       if ( elemSet.find(el) != elemSet.end() )
3698         nbInitElems++;
3699     }
3700     if ( nbInitElems < 2 ) {
3701       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3702       if(!NotCreateEdge) {
3703         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3704         list<const SMDS_MeshElement*> newEdges;
3705         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3706       }
3707     }
3708   }
3709
3710   // Make a ceiling for each element ie an equal element of last new nodes.
3711   // Find free links of faces - make edges and sweep them into faces.
3712
3713   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3714   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3715   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3716     const SMDS_MeshElement* elem = itElem->first;
3717     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3718
3719     if ( elem->GetType() == SMDSAbs_Edge ) {
3720       // create a ceiling edge
3721       if (!elem->IsQuadratic()) {
3722         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3723                                vecNewNodes[ 1 ]->second.back())) {
3724           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3725                                                    vecNewNodes[ 1 ]->second.back()));
3726           srcElements.Append( myLastCreatedElems.Last() );
3727         }
3728       }
3729       else {
3730         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3731                                vecNewNodes[ 1 ]->second.back(),
3732                                vecNewNodes[ 2 ]->second.back())) {
3733           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3734                                                    vecNewNodes[ 1 ]->second.back(),
3735                                                    vecNewNodes[ 2 ]->second.back()));
3736           srcElements.Append( myLastCreatedElems.Last() );
3737         }
3738       }
3739     }
3740     if ( elem->GetType() != SMDSAbs_Face )
3741       continue;
3742
3743     if(itElem->second.size()==0) continue;
3744
3745     bool hasFreeLinks = false;
3746
3747     TIDSortedElemSet avoidSet;
3748     avoidSet.insert( elem );
3749
3750     set<const SMDS_MeshNode*> aFaceLastNodes;
3751     int iNode, nbNodes = vecNewNodes.size();
3752     if(!elem->IsQuadratic()) {
3753       // loop on the face nodes
3754       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3755         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3756         // look for free links of the face
3757         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3758         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3759         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3760         // check if a link is free
3761         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3762           hasFreeLinks = true;
3763           // make an edge and a ceiling for a new edge
3764           if ( !aMesh->FindEdge( n1, n2 )) {
3765             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3766             srcElements.Append( myLastCreatedElems.Last() );
3767           }
3768           n1 = vecNewNodes[ iNode ]->second.back();
3769           n2 = vecNewNodes[ iNext ]->second.back();
3770           if ( !aMesh->FindEdge( n1, n2 )) {
3771             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3772             srcElements.Append( myLastCreatedElems.Last() );
3773           }
3774         }
3775       }
3776     }
3777     else { // elem is quadratic face
3778       int nbn = nbNodes/2;
3779       for ( iNode = 0; iNode < nbn; iNode++ ) {
3780         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3781         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3782         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3783         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3784         // check if a link is free
3785         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3786           hasFreeLinks = true;
3787           // make an edge and a ceiling for a new edge
3788           // find medium node
3789           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3790           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3791             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3792             srcElements.Append( myLastCreatedElems.Last() );
3793           }
3794           n1 = vecNewNodes[ iNode ]->second.back();
3795           n2 = vecNewNodes[ iNext ]->second.back();
3796           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3797           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3798             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3799             srcElements.Append( myLastCreatedElems.Last() );
3800           }
3801         }
3802       }
3803       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3804         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3805       }
3806     }
3807
3808     // sweep free links into faces
3809
3810     if ( hasFreeLinks )  {
3811       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3812       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3813
3814       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3815       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3816         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3817         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3818       }
3819       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3820         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3821         iVol = 0;
3822         while ( iVol++ < volNb ) v++;
3823         // find indices of free faces of a volume and their source edges
3824         list< int > freeInd;
3825         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3826         SMDS_VolumeTool vTool( *v );
3827         int iF, nbF = vTool.NbFaces();
3828         for ( iF = 0; iF < nbF; iF ++ ) {
3829           if (vTool.IsFreeFace( iF ) &&
3830               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3831               initNodeSet != faceNodeSet) // except an initial face
3832           {
3833             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3834               continue;
3835             freeInd.push_back( iF );
3836             // find source edge of a free face iF
3837             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3838             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3839             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3840                                    initNodeSet.begin(), initNodeSet.end(),
3841                                    commonNodes.begin());
3842             if ( (*v)->IsQuadratic() )
3843               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3844             else
3845               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3846 #ifdef _DEBUG_
3847             if ( !srcEdges.back() )
3848             {
3849               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3850                    << iF << " of volume #" << vTool.ID() << endl;
3851             }
3852 #endif
3853           }
3854         }
3855         if ( freeInd.empty() )
3856           continue;
3857
3858         // create faces for all steps;
3859         // if such a face has been already created by sweep of edge,
3860         // assure that its orientation is OK
3861         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3862           vTool.Set( *v );
3863           vTool.SetExternalNormal();
3864           list< int >::iterator ind = freeInd.begin();
3865           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3866           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3867           {
3868             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3869             int nbn = vTool.NbFaceNodes( *ind );
3870             switch ( nbn ) {
3871             case 3: { ///// triangle
3872               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3873               if ( !f )
3874                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3875               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3876                 aMesh->ChangeElementNodes( f, nodes, nbn );
3877               break;
3878             }
3879             case 4: { ///// quadrangle
3880               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3881               if ( !f )
3882                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3883               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3884                 aMesh->ChangeElementNodes( f, nodes, nbn );
3885               break;
3886             }
3887             default:
3888               if( (*v)->IsQuadratic() ) {
3889                 if(nbn==6) { /////// quadratic triangle
3890                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3891                                                              nodes[1], nodes[3], nodes[5] );
3892                   if ( !f ) {
3893                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3894                                                              nodes[1], nodes[3], nodes[5]));
3895                   }
3896                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3897                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3898                     tmpnodes[0] = nodes[0];
3899                     tmpnodes[1] = nodes[2];
3900                     tmpnodes[2] = nodes[4];
3901                     tmpnodes[3] = nodes[1];
3902                     tmpnodes[4] = nodes[3];
3903                     tmpnodes[5] = nodes[5];
3904                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3905                   }
3906                 }
3907                 else {       /////// quadratic quadrangle
3908                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3909                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3910                   if ( !f ) {
3911                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3912                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3913                   }
3914                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3915                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3916                     tmpnodes[0] = nodes[0];
3917                     tmpnodes[1] = nodes[2];
3918                     tmpnodes[2] = nodes[4];
3919                     tmpnodes[3] = nodes[6];
3920                     tmpnodes[4] = nodes[1];
3921                     tmpnodes[5] = nodes[3];
3922                     tmpnodes[6] = nodes[5];
3923                     tmpnodes[7] = nodes[7];
3924                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3925                   }
3926                 }
3927               }
3928               else { //////// polygon
3929                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3930                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3931                 if ( !f )
3932                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3933                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3934                   aMesh->ChangeElementNodes( f, nodes, nbn );
3935               }
3936             }
3937             while ( srcElements.Length() < myLastCreatedElems.Length() )
3938               srcElements.Append( *srcEdge );
3939
3940           }  // loop on free faces
3941
3942           // go to the next volume
3943           iVol = 0;
3944           while ( iVol++ < nbVolumesByStep ) v++;
3945         }
3946       }
3947     } // sweep free links into faces
3948
3949     // Make a ceiling face with a normal external to a volume
3950
3951     SMDS_VolumeTool lastVol( itElem->second.back() );
3952
3953     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3954     if ( iF >= 0 ) {
3955       lastVol.SetExternalNormal();
3956       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3957       int nbn = lastVol.NbFaceNodes( iF );
3958       switch ( nbn ) {
3959       case 3:
3960         if (!hasFreeLinks ||
3961             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3962           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3963         break;
3964       case 4:
3965         if (!hasFreeLinks ||
3966             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3967           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3968         break;
3969       default:
3970         if(itElem->second.back()->IsQuadratic()) {
3971           if(nbn==6) {
3972             if (!hasFreeLinks ||
3973                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3974                                  nodes[1], nodes[3], nodes[5]) ) {
3975               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3976                                                        nodes[1], nodes[3], nodes[5]));
3977             }
3978           }
3979           else { // nbn==8
3980             if (!hasFreeLinks ||
3981                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3982                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3983               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3984                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3985           }
3986         }
3987         else {
3988           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3989           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3990             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3991         }
3992       } // switch
3993
3994       while ( srcElements.Length() < myLastCreatedElems.Length() )
3995         srcElements.Append( myLastCreatedElems.Last() );
3996     }
3997   } // loop on swept elements
3998 }
3999
4000 //=======================================================================
4001 //function : RotationSweep
4002 //purpose  :
4003 //=======================================================================
4004
4005 SMESH_MeshEditor::PGroupIDs
4006 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4007                                 const gp_Ax1&      theAxis,
4008                                 const double       theAngle,
4009                                 const int          theNbSteps,
4010                                 const double       theTol,
4011                                 const bool         theMakeGroups,
4012                                 const bool         theMakeWalls)
4013 {
4014   myLastCreatedElems.Clear();
4015   myLastCreatedNodes.Clear();
4016
4017   // source elements for each generated one
4018   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4019
4020   MESSAGE( "RotationSweep()");
4021   gp_Trsf aTrsf;
4022   aTrsf.SetRotation( theAxis, theAngle );
4023   gp_Trsf aTrsf2;
4024   aTrsf2.SetRotation( theAxis, theAngle/2. );
4025
4026   gp_Lin aLine( theAxis );
4027   double aSqTol = theTol * theTol;
4028
4029   SMESHDS_Mesh* aMesh = GetMeshDS();
4030
4031   TNodeOfNodeListMap mapNewNodes;
4032   TElemOfVecOfNnlmiMap mapElemNewNodes;
4033   TElemOfElemListMap newElemsMap;
4034
4035   // loop on theElems
4036   TIDSortedElemSet::iterator itElem;
4037   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4038     const SMDS_MeshElement* elem = *itElem;
4039     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4040       continue;
4041     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4042     newNodesItVec.reserve( elem->NbNodes() );
4043
4044     // loop on elem nodes
4045     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4046     while ( itN->more() ) {
4047       // check if a node has been already sweeped
4048       const SMDS_MeshNode* node = cast2Node( itN->next() );
4049
4050       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4051       double coord[3];
4052       aXYZ.Coord( coord[0], coord[1], coord[2] );
4053       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4054
4055       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4056       if ( nIt == mapNewNodes.end() ) {
4057         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4058         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4059
4060         // make new nodes
4061         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4062         //double coord[3];
4063         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4064         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4065         const SMDS_MeshNode * newNode = node;
4066         for ( int i = 0; i < theNbSteps; i++ ) {
4067           if ( !isOnAxis ) {
4068             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4069               // create two nodes
4070               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4071               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4072               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4073               myLastCreatedNodes.Append(newNode);
4074               srcNodes.Append( node );
4075               listNewNodes.push_back( newNode );
4076               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4077               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4078             }
4079             else {
4080               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4081             }
4082             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4083             myLastCreatedNodes.Append(newNode);
4084             srcNodes.Append( node );
4085             listNewNodes.push_back( newNode );
4086           }
4087           else {
4088             listNewNodes.push_back( newNode );
4089             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4090               listNewNodes.push_back( newNode );
4091             }
4092           }
4093         }
4094       }
4095       /*
4096         else {
4097         // if current elem is quadratic and current node is not medium
4098         // we have to check - may be it is needed to insert additional nodes
4099         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4100         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4101         if(listNewNodes.size()==theNbSteps) {
4102         listNewNodes.clear();
4103         // make new nodes
4104         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4105         //double coord[3];
4106         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4107         const SMDS_MeshNode * newNode = node;
4108         if ( !isOnAxis ) {
4109         for(int i = 0; i<theNbSteps; i++) {
4110         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4111         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4112         cout<<"    3 AddNode:  "<<newNode;
4113         myLastCreatedNodes.Append(newNode);
4114         listNewNodes.push_back( newNode );
4115         srcNodes.Append( node );
4116         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4117         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4118         cout<<"    4 AddNode:  "<<newNode;
4119         myLastCreatedNodes.Append(newNode);
4120         srcNodes.Append( node );
4121         listNewNodes.push_back( newNode );
4122         }
4123         }
4124         else {
4125         listNewNodes.push_back( newNode );
4126         }
4127         }
4128         }
4129         }
4130       */
4131       newNodesItVec.push_back( nIt );
4132     }
4133     // make new elements
4134     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4135   }
4136
4137   if ( theMakeWalls )
4138     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4139
4140   PGroupIDs newGroupIDs;
4141   if ( theMakeGroups )
4142     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4143
4144   return newGroupIDs;
4145 }
4146
4147
4148 //=======================================================================
4149 //function : CreateNode
4150 //purpose  :
4151 //=======================================================================
4152 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4153                                                   const double y,
4154                                                   const double z,
4155                                                   const double tolnode,
4156                                                   SMESH_SequenceOfNode& aNodes)
4157 {
4158   myLastCreatedElems.Clear();
4159   myLastCreatedNodes.Clear();
4160
4161   gp_Pnt P1(x,y,z);
4162   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4163
4164   // try to search in sequence of existing nodes
4165   // if aNodes.Length()>0 we 'nave to use given sequence
4166   // else - use all nodes of mesh
4167   if(aNodes.Length()>0) {
4168     int i;
4169     for(i=1; i<=aNodes.Length(); i++) {
4170       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4171       if(P1.Distance(P2)<tolnode)
4172         return aNodes.Value(i);
4173     }
4174   }
4175   else {
4176     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4177     while(itn->more()) {
4178       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4179       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4180       if(P1.Distance(P2)<tolnode)
4181         return aN;
4182     }
4183   }
4184
4185   // create new node and return it
4186   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4187   myLastCreatedNodes.Append(NewNode);
4188   return NewNode;
4189 }
4190
4191
4192 //=======================================================================
4193 //function : ExtrusionSweep
4194 //purpose  :
4195 //=======================================================================
4196
4197 SMESH_MeshEditor::PGroupIDs
4198 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4199                                   const gp_Vec&       theStep,
4200                                   const int           theNbSteps,
4201                                   TElemOfElemListMap& newElemsMap,
4202                                   const bool          theMakeGroups,
4203                                   const int           theFlags,
4204                                   const double        theTolerance)
4205 {
4206   ExtrusParam aParams;
4207   aParams.myDir = gp_Dir(theStep);
4208   aParams.myNodes.Clear();
4209   aParams.mySteps = new TColStd_HSequenceOfReal;
4210   int i;
4211   for(i=1; i<=theNbSteps; i++)
4212     aParams.mySteps->Append(theStep.Magnitude());
4213
4214   return
4215     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4216 }
4217
4218
4219 //=======================================================================
4220 //function : ExtrusionSweep
4221 //purpose  :
4222 //=======================================================================
4223
4224 SMESH_MeshEditor::PGroupIDs
4225 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4226                                   ExtrusParam&        theParams,
4227                                   TElemOfElemListMap& newElemsMap,
4228                                   const bool          theMakeGroups,
4229                                   const int           theFlags,
4230                                   const double        theTolerance)
4231 {
4232   myLastCreatedElems.Clear();
4233   myLastCreatedNodes.Clear();
4234
4235   // source elements for each generated one
4236   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4237
4238   SMESHDS_Mesh* aMesh = GetMeshDS();
4239
4240   int nbsteps = theParams.mySteps->Length();
4241
4242   TNodeOfNodeListMap mapNewNodes;
4243   //TNodeOfNodeVecMap mapNewNodes;
4244   TElemOfVecOfNnlmiMap mapElemNewNodes;
4245   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4246
4247   // loop on theElems
4248   TIDSortedElemSet::iterator itElem;
4249   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4250     // check element type
4251     const SMDS_MeshElement* elem = *itElem;
4252     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4253       continue;
4254
4255     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4256     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4257     newNodesItVec.reserve( elem->NbNodes() );
4258
4259     // loop on elem nodes
4260     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4261     while ( itN->more() )
4262     {
4263       // check if a node has been already sweeped
4264       const SMDS_MeshNode* node = cast2Node( itN->next() );
4265       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4266       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4267       if ( nIt == mapNewNodes.end() ) {
4268         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4269         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4270         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4271         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4272         //vecNewNodes.reserve(nbsteps);
4273
4274         // make new nodes
4275         double coord[] = { node->X(), node->Y(), node->Z() };
4276         //int nbsteps = theParams.mySteps->Length();
4277         for ( int i = 0; i < nbsteps; i++ ) {
4278           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4279             // create additional node
4280             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4281             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4282             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4283             if( theFlags & EXTRUSION_FLAG_SEW ) {
4284               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4285                                                          theTolerance, theParams.myNodes);
4286               listNewNodes.push_back( newNode );
4287             }
4288             else {
4289               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4290               myLastCreatedNodes.Append(newNode);
4291               srcNodes.Append( node );
4292               listNewNodes.push_back( newNode );
4293             }
4294           }
4295           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4296           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4297           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4298           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4299           if( theFlags & EXTRUSION_FLAG_SEW ) {
4300             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4301                                                        theTolerance, theParams.myNodes);
4302             listNewNodes.push_back( newNode );
4303             //vecNewNodes[i]=newNode;
4304           }
4305           else {
4306             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4307             myLastCreatedNodes.Append(newNode);
4308             srcNodes.Append( node );
4309             listNewNodes.push_back( newNode );
4310             //vecNewNodes[i]=newNode;
4311           }
4312         }
4313       }
4314       else {
4315         // if current elem is quadratic and current node is not medium
4316         // we have to check - may be it is needed to insert additional nodes
4317         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4318           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4319           if(listNewNodes.size()==nbsteps) {
4320             listNewNodes.clear();
4321             double coord[] = { node->X(), node->Y(), node->Z() };
4322             for ( int i = 0; i < nbsteps; i++ ) {
4323               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4324               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4325               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4326               if( theFlags & EXTRUSION_FLAG_SEW ) {
4327                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4328                                                            theTolerance, theParams.myNodes);
4329                 listNewNodes.push_back( newNode );
4330               }
4331               else {
4332                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4333                 myLastCreatedNodes.Append(newNode);
4334                 srcNodes.Append( node );
4335                 listNewNodes.push_back( newNode );
4336               }
4337               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4338               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4339               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4340               if( theFlags & EXTRUSION_FLAG_SEW ) {
4341                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4342                                                            theTolerance, theParams.myNodes);
4343                 listNewNodes.push_back( newNode );
4344               }
4345               else {
4346                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4347                 myLastCreatedNodes.Append(newNode);
4348                 srcNodes.Append( node );
4349                 listNewNodes.push_back( newNode );
4350               }
4351             }
4352           }
4353         }
4354       }
4355       newNodesItVec.push_back( nIt );
4356     }
4357     // make new elements
4358     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4359   }
4360
4361   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4362     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4363   }
4364   PGroupIDs newGroupIDs;
4365   if ( theMakeGroups )
4366     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4367
4368   return newGroupIDs;
4369 }
4370
4371 /*
4372 //=======================================================================
4373 //class    : SMESH_MeshEditor_PathPoint
4374 //purpose  : auxiliary class
4375 //=======================================================================
4376 class SMESH_MeshEditor_PathPoint {
4377 public:
4378 SMESH_MeshEditor_PathPoint() {
4379 myPnt.SetCoord(99., 99., 99.);
4380 myTgt.SetCoord(1.,0.,0.);
4381 myAngle=0.;
4382 myPrm=0.;
4383 }
4384 void SetPnt(const gp_Pnt& aP3D){
4385 myPnt=aP3D;
4386 }
4387 void SetTangent(const gp_Dir& aTgt){
4388 myTgt=aTgt;
4389 }
4390 void SetAngle(const double& aBeta){
4391 myAngle=aBeta;
4392 }
4393 void SetParameter(const double& aPrm){
4394 myPrm=aPrm;
4395 }
4396 const gp_Pnt& Pnt()const{
4397 return myPnt;
4398 }
4399 const gp_Dir& Tangent()const{
4400 return myTgt;
4401 }
4402 double Angle()const{
4403 return myAngle;
4404 }
4405 double Parameter()const{
4406 return myPrm;
4407 }
4408
4409 protected:
4410 gp_Pnt myPnt;
4411 gp_Dir myTgt;
4412 double myAngle;
4413 double myPrm;
4414 };
4415 */
4416
4417 //=======================================================================
4418 //function : ExtrusionAlongTrack
4419 //purpose  :
4420 //=======================================================================
4421 SMESH_MeshEditor::Extrusion_Error
4422 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4423                                        SMESH_subMesh*       theTrack,
4424                                        const SMDS_MeshNode* theN1,
4425                                        const bool           theHasAngles,
4426                                        list<double>&        theAngles,
4427                                        const bool           theLinearVariation,
4428                                        const bool           theHasRefPoint,
4429                                        const gp_Pnt&        theRefPoint,
4430                                        const bool           theMakeGroups)
4431 {
4432   myLastCreatedElems.Clear();
4433   myLastCreatedNodes.Clear();
4434
4435   int aNbE;
4436   std::list<double> aPrms;
4437   TIDSortedElemSet::iterator itElem;
4438
4439   gp_XYZ aGC;
4440   TopoDS_Edge aTrackEdge;
4441   TopoDS_Vertex aV1, aV2;
4442
4443   SMDS_ElemIteratorPtr aItE;
4444   SMDS_NodeIteratorPtr aItN;
4445   SMDSAbs_ElementType aTypeE;
4446
4447   TNodeOfNodeListMap mapNewNodes;
4448
4449   // 1. Check data
4450   aNbE = theElements.size();
4451   // nothing to do
4452   if ( !aNbE )
4453     return EXTR_NO_ELEMENTS;
4454
4455   // 1.1 Track Pattern
4456   ASSERT( theTrack );
4457
4458   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4459
4460   aItE = pSubMeshDS->GetElements();
4461   while ( aItE->more() ) {
4462     const SMDS_MeshElement* pE = aItE->next();
4463     aTypeE = pE->GetType();
4464     // Pattern must contain links only
4465     if ( aTypeE != SMDSAbs_Edge )
4466       return EXTR_PATH_NOT_EDGE;
4467   }
4468
4469   list<SMESH_MeshEditor_PathPoint> fullList;
4470
4471   const TopoDS_Shape& aS = theTrack->GetSubShape();
4472   // Sub shape for the Pattern must be an Edge or Wire
4473   if( aS.ShapeType() == TopAbs_EDGE ) {
4474     aTrackEdge = TopoDS::Edge( aS );
4475     // the Edge must not be degenerated
4476     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4477       return EXTR_BAD_PATH_SHAPE;
4478     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4479     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4480     const SMDS_MeshNode* aN1 = aItN->next();
4481     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4482     const SMDS_MeshNode* aN2 = aItN->next();
4483     // starting node must be aN1 or aN2
4484     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4485       return EXTR_BAD_STARTING_NODE;
4486     aItN = pSubMeshDS->GetNodes();
4487     while ( aItN->more() ) {
4488       const SMDS_MeshNode* pNode = aItN->next();
4489       const SMDS_EdgePosition* pEPos =
4490         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4491       double aT = pEPos->GetUParameter();
4492       aPrms.push_back( aT );
4493     }
4494     //Extrusion_Error err =
4495     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4496   }
4497   else if( aS.ShapeType() == TopAbs_WIRE ) {
4498     list< SMESH_subMesh* > LSM;
4499     TopTools_SequenceOfShape Edges;
4500     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4501     while(itSM->more()) {
4502       SMESH_subMesh* SM = itSM->next();
4503       LSM.push_back(SM);
4504       const TopoDS_Shape& aS = SM->GetSubShape();
4505       Edges.Append(aS);
4506     }
4507     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4508     int startNid = theN1->GetID();
4509     TColStd_MapOfInteger UsedNums;
4510     int NbEdges = Edges.Length();
4511     int i = 1;
4512     for(; i<=NbEdges; i++) {
4513       int k = 0;
4514       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4515       for(; itLSM!=LSM.end(); itLSM++) {
4516         k++;
4517         if(UsedNums.Contains(k)) continue;
4518         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4519         SMESH_subMesh* locTrack = *itLSM;
4520         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4521         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4522         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4523         const SMDS_MeshNode* aN1 = aItN->next();
4524         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4525         const SMDS_MeshNode* aN2 = aItN->next();
4526         // starting node must be aN1 or aN2
4527         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4528         // 2. Collect parameters on the track edge
4529         aPrms.clear();
4530         aItN = locMeshDS->GetNodes();
4531         while ( aItN->more() ) {
4532           const SMDS_MeshNode* pNode = aItN->next();
4533           const SMDS_EdgePosition* pEPos =
4534             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4535           double aT = pEPos->GetUParameter();
4536           aPrms.push_back( aT );
4537         }
4538         list<SMESH_MeshEditor_PathPoint> LPP;
4539         //Extrusion_Error err =
4540         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4541         LLPPs.push_back(LPP);
4542         UsedNums.Add(k);
4543         // update startN for search following egde
4544         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4545         else startNid = aN1->GetID();
4546         break;
4547       }
4548     }
4549     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4550     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4551     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4552     for(; itPP!=firstList.end(); itPP++) {
4553       fullList.push_back( *itPP );
4554     }
4555     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4556     fullList.pop_back();
4557     itLLPP++;
4558     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4559       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4560       itPP = currList.begin();
4561       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4562       gp_Dir D1 = PP1.Tangent();
4563       gp_Dir D2 = PP2.Tangent();
4564       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4565                            (D1.Z()+D2.Z())/2 ) );
4566       PP1.SetTangent(Dnew);
4567       fullList.push_back(PP1);
4568       itPP++;
4569       for(; itPP!=firstList.end(); itPP++) {
4570         fullList.push_back( *itPP );
4571       }
4572       PP1 = fullList.back();
4573       fullList.pop_back();
4574     }
4575     // if wire not closed
4576     fullList.push_back(PP1);
4577     // else ???
4578   }
4579   else {
4580     return EXTR_BAD_PATH_SHAPE;
4581   }
4582
4583   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4584                           theHasRefPoint, theRefPoint, theMakeGroups);
4585 }
4586
4587
4588 //=======================================================================
4589 //function : ExtrusionAlongTrack
4590 //purpose  :
4591 //=======================================================================
4592 SMESH_MeshEditor::Extrusion_Error
4593 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4594                                        SMESH_Mesh*          theTrack,
4595                                        const SMDS_MeshNode* theN1,
4596                                        const bool           theHasAngles,
4597                                        list<double>&        theAngles,
4598                                        const bool           theLinearVariation,
4599                                        const bool           theHasRefPoint,
4600                                        const gp_Pnt&        theRefPoint,
4601                                        const bool           theMakeGroups)
4602 {
4603   myLastCreatedElems.Clear();
4604   myLastCreatedNodes.Clear();
4605
4606   int aNbE;
4607   std::list<double> aPrms;
4608   TIDSortedElemSet::iterator itElem;
4609
4610   gp_XYZ aGC;
4611   TopoDS_Edge aTrackEdge;
4612   TopoDS_Vertex aV1, aV2;
4613
4614   SMDS_ElemIteratorPtr aItE;
4615   SMDS_NodeIteratorPtr aItN;
4616   SMDSAbs_ElementType aTypeE;
4617
4618   TNodeOfNodeListMap mapNewNodes;
4619
4620   // 1. Check data
4621   aNbE = theElements.size();
4622   // nothing to do
4623   if ( !aNbE )
4624     return EXTR_NO_ELEMENTS;
4625
4626   // 1.1 Track Pattern
4627   ASSERT( theTrack );
4628
4629   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4630
4631   aItE = pMeshDS->elementsIterator();
4632   while ( aItE->more() ) {
4633     const SMDS_MeshElement* pE = aItE->next();
4634     aTypeE = pE->GetType();
4635     // Pattern must contain links only
4636     if ( aTypeE != SMDSAbs_Edge )
4637       return EXTR_PATH_NOT_EDGE;
4638   }
4639
4640   list<SMESH_MeshEditor_PathPoint> fullList;
4641
4642   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4643   // Sub shape for the Pattern must be an Edge or Wire
4644   if( aS.ShapeType() == TopAbs_EDGE ) {
4645     aTrackEdge = TopoDS::Edge( aS );
4646     // the Edge must not be degenerated
4647     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4648       return EXTR_BAD_PATH_SHAPE;
4649     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4650     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4651     const SMDS_MeshNode* aN1 = aItN->next();
4652     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4653     const SMDS_MeshNode* aN2 = aItN->next();
4654     // starting node must be aN1 or aN2
4655     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4656       return EXTR_BAD_STARTING_NODE;
4657     aItN = pMeshDS->nodesIterator();
4658     while ( aItN->more() ) {
4659       const SMDS_MeshNode* pNode = aItN->next();
4660       if( pNode==aN1 || pNode==aN2 ) continue;
4661       const SMDS_EdgePosition* pEPos =
4662         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4663       double aT = pEPos->GetUParameter();
4664       aPrms.push_back( aT );
4665     }
4666     //Extrusion_Error err =
4667     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4668   }
4669   else if( aS.ShapeType() == TopAbs_WIRE ) {
4670     list< SMESH_subMesh* > LSM;
4671     TopTools_SequenceOfShape Edges;
4672     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4673     for(; eExp.More(); eExp.Next()) {
4674       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4675       if( BRep_Tool::Degenerated(E) ) continue;
4676       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4677       if(SM) {
4678         LSM.push_back(SM);
4679         Edges.Append(E);
4680       }
4681     }
4682     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4683     int startNid = theN1->GetID();
4684     TColStd_MapOfInteger UsedNums;
4685     int NbEdges = Edges.Length();
4686     int i = 1;
4687     for(; i<=NbEdges; i++) {
4688       int k = 0;
4689       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4690       for(; itLSM!=LSM.end(); itLSM++) {
4691         k++;
4692         if(UsedNums.Contains(k)) continue;
4693         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4694         SMESH_subMesh* locTrack = *itLSM;
4695         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4696         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4697         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4698         const SMDS_MeshNode* aN1 = aItN->next();
4699         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4700         const SMDS_MeshNode* aN2 = aItN->next();
4701         // starting node must be aN1 or aN2
4702         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4703         // 2. Collect parameters on the track edge
4704         aPrms.clear();
4705         aItN = locMeshDS->GetNodes();
4706         while ( aItN->more() ) {
4707           const SMDS_MeshNode* pNode = aItN->next();
4708           const SMDS_EdgePosition* pEPos =
4709             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4710           double aT = pEPos->GetUParameter();
4711           aPrms.push_back( aT );
4712         }
4713         list<SMESH_MeshEditor_PathPoint> LPP;
4714         //Extrusion_Error err =
4715         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4716         LLPPs.push_back(LPP);
4717         UsedNums.Add(k);
4718         // update startN for search following egde
4719         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4720         else startNid = aN1->GetID();
4721         break;
4722       }
4723     }
4724     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4725     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4726     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4727     for(; itPP!=firstList.end(); itPP++) {
4728       fullList.push_back( *itPP );
4729     }
4730     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4731     fullList.pop_back();
4732     itLLPP++;
4733     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4734       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4735       itPP = currList.begin();
4736       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4737       gp_Pnt P1 = PP1.Pnt();
4738       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4739       gp_Pnt P2 = PP2.Pnt();
4740       gp_Dir D1 = PP1.Tangent();
4741       gp_Dir D2 = PP2.Tangent();
4742       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4743                            (D1.Z()+D2.Z())/2 ) );
4744       PP1.SetTangent(Dnew);
4745       fullList.push_back(PP1);
4746       itPP++;
4747       for(; itPP!=currList.end(); itPP++) {
4748         fullList.push_back( *itPP );
4749       }
4750       PP1 = fullList.back();
4751       fullList.pop_back();
4752     }
4753     // if wire not closed
4754     fullList.push_back(PP1);
4755     // else ???
4756   }
4757   else {
4758     return EXTR_BAD_PATH_SHAPE;
4759   }
4760
4761   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4762                           theHasRefPoint, theRefPoint, theMakeGroups);
4763 }
4764
4765
4766 //=======================================================================
4767 //function : MakeEdgePathPoints
4768 //purpose  : auxilary for ExtrusionAlongTrack
4769 //=======================================================================
4770 SMESH_MeshEditor::Extrusion_Error
4771 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4772                                      const TopoDS_Edge& aTrackEdge,
4773                                      bool FirstIsStart,
4774                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4775 {
4776   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4777   aTolVec=1.e-7;
4778   aTolVec2=aTolVec*aTolVec;
4779   double aT1, aT2;
4780   TopoDS_Vertex aV1, aV2;
4781   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4782   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4783   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4784   // 2. Collect parameters on the track edge
4785   aPrms.push_front( aT1 );
4786   aPrms.push_back( aT2 );
4787   // sort parameters
4788   aPrms.sort();
4789   if( FirstIsStart ) {
4790     if ( aT1 > aT2 ) {
4791       aPrms.reverse();
4792     }
4793   }
4794   else {
4795     if ( aT2 > aT1 ) {
4796       aPrms.reverse();
4797     }
4798   }
4799   // 3. Path Points
4800   SMESH_MeshEditor_PathPoint aPP;
4801   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4802   std::list<double>::iterator aItD = aPrms.begin();
4803   for(; aItD != aPrms.end(); ++aItD) {
4804     double aT = *aItD;
4805     gp_Pnt aP3D;
4806     gp_Vec aVec;
4807     aC3D->D1( aT, aP3D, aVec );
4808     aL2 = aVec.SquareMagnitude();
4809     if ( aL2 < aTolVec2 )
4810       return EXTR_CANT_GET_TANGENT;
4811     gp_Dir aTgt( aVec );
4812     aPP.SetPnt( aP3D );
4813     aPP.SetTangent( aTgt );
4814     aPP.SetParameter( aT );
4815     LPP.push_back(aPP);
4816   }
4817   return EXTR_OK;
4818 }
4819
4820
4821 //=======================================================================
4822 //function : MakeExtrElements
4823 //purpose  : auxilary for ExtrusionAlongTrack
4824 //=======================================================================
4825 SMESH_MeshEditor::Extrusion_Error
4826 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4827                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4828                                    const bool theHasAngles,
4829                                    list<double>& theAngles,
4830                                    const bool theLinearVariation,
4831                                    const bool theHasRefPoint,
4832                                    const gp_Pnt& theRefPoint,
4833                                    const bool theMakeGroups)
4834 {
4835   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4836   int aNbTP = fullList.size();
4837   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4838   // Angles
4839   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4840     LinearAngleVariation(aNbTP-1, theAngles);
4841   }
4842   vector<double> aAngles( aNbTP );
4843   int j = 0;
4844   for(; j<aNbTP; ++j) {
4845     aAngles[j] = 0.;
4846   }
4847   if ( theHasAngles ) {
4848     double anAngle;;
4849     std::list<double>::iterator aItD = theAngles.begin();
4850     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4851       anAngle = *aItD;
4852       aAngles[j] = anAngle;
4853     }
4854   }
4855   // fill vector of path points with angles
4856   //aPPs.resize(fullList.size());
4857   j = -1;
4858   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4859   for(; itPP!=fullList.end(); itPP++) {
4860     j++;
4861     SMESH_MeshEditor_PathPoint PP = *itPP;
4862     PP.SetAngle(aAngles[j]);
4863     aPPs[j] = PP;
4864   }
4865
4866   TNodeOfNodeListMap mapNewNodes;
4867   TElemOfVecOfNnlmiMap mapElemNewNodes;
4868   TElemOfElemListMap newElemsMap;
4869   TIDSortedElemSet::iterator itElem;
4870   double aX, aY, aZ;
4871   int aNb;
4872   SMDSAbs_ElementType aTypeE;
4873   // source elements for each generated one
4874   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4875
4876   // 3. Center of rotation aV0
4877   gp_Pnt aV0 = theRefPoint;
4878   gp_XYZ aGC;
4879   if ( !theHasRefPoint ) {
4880     aNb = 0;
4881     aGC.SetCoord( 0.,0.,0. );
4882
4883     itElem = theElements.begin();
4884     for ( ; itElem != theElements.end(); itElem++ ) {
4885       const SMDS_MeshElement* elem = *itElem;
4886
4887       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4888       while ( itN->more() ) {
4889         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4890         aX = node->X();
4891         aY = node->Y();
4892         aZ = node->Z();
4893
4894         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4895           list<const SMDS_MeshNode*> aLNx;
4896           mapNewNodes[node] = aLNx;
4897           //
4898           gp_XYZ aXYZ( aX, aY, aZ );
4899           aGC += aXYZ;
4900           ++aNb;
4901         }
4902       }
4903     }
4904     aGC /= aNb;
4905     aV0.SetXYZ( aGC );
4906   } // if (!theHasRefPoint) {
4907   mapNewNodes.clear();
4908
4909   // 4. Processing the elements
4910   SMESHDS_Mesh* aMesh = GetMeshDS();
4911
4912   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4913     // check element type
4914     const SMDS_MeshElement* elem = *itElem;
4915     aTypeE = elem->GetType();
4916     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4917       continue;
4918
4919     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4920     newNodesItVec.reserve( elem->NbNodes() );
4921
4922     // loop on elem nodes
4923     int nodeIndex = -1;
4924     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4925     while ( itN->more() )
4926     {
4927       ++nodeIndex;
4928       // check if a node has been already processed
4929       const SMDS_MeshNode* node =
4930         static_cast<const SMDS_MeshNode*>( itN->next() );
4931       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4932       if ( nIt == mapNewNodes.end() ) {
4933         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4934         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4935
4936         // make new nodes
4937         aX = node->X();  aY = node->Y(); aZ = node->Z();
4938
4939         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4940         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4941         gp_Ax1 anAx1, anAxT1T0;
4942         gp_Dir aDT1x, aDT0x, aDT1T0;
4943
4944         aTolAng=1.e-4;
4945
4946         aV0x = aV0;
4947         aPN0.SetCoord(aX, aY, aZ);
4948
4949         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4950         aP0x = aPP0.Pnt();
4951         aDT0x= aPP0.Tangent();
4952         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4953
4954         for ( j = 1; j < aNbTP; ++j ) {
4955           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4956           aP1x = aPP1.Pnt();
4957           aDT1x = aPP1.Tangent();
4958           aAngle1x = aPP1.Angle();
4959
4960           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4961           // Translation
4962           gp_Vec aV01x( aP0x, aP1x );
4963           aTrsf.SetTranslation( aV01x );
4964
4965           // traslated point
4966           aV1x = aV0x.Transformed( aTrsf );
4967           aPN1 = aPN0.Transformed( aTrsf );
4968
4969           // rotation 1 [ T1,T0 ]
4970           aAngleT1T0=-aDT1x.Angle( aDT0x );
4971           if (fabs(aAngleT1T0) > aTolAng) {
4972             aDT1T0=aDT1x^aDT0x;
4973             anAxT1T0.SetLocation( aV1x );
4974             anAxT1T0.SetDirection( aDT1T0 );
4975             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4976
4977             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4978           }
4979
4980           // rotation 2
4981           if ( theHasAngles ) {
4982             anAx1.SetLocation( aV1x );
4983             anAx1.SetDirection( aDT1x );
4984             aTrsfRot.SetRotation( anAx1, aAngle1x );
4985
4986             aPN1 = aPN1.Transformed( aTrsfRot );
4987           }
4988
4989           // make new node
4990           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4991             // create additional node
4992             double x = ( aPN1.X() + aPN0.X() )/2.;
4993             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4994             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4995             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4996             myLastCreatedNodes.Append(newNode);
4997             srcNodes.Append( node );
4998             listNewNodes.push_back( newNode );
4999           }
5000           aX = aPN1.X();
5001           aY = aPN1.Y();
5002           aZ = aPN1.Z();
5003           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5004           myLastCreatedNodes.Append(newNode);
5005           srcNodes.Append( node );
5006           listNewNodes.push_back( newNode );
5007
5008           aPN0 = aPN1;
5009           aP0x = aP1x;
5010           aV0x = aV1x;
5011           aDT0x = aDT1x;
5012         }
5013       }
5014
5015       else {
5016         // if current elem is quadratic and current node is not medium
5017         // we have to check - may be it is needed to insert additional nodes
5018         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5019           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5020           if(listNewNodes.size()==aNbTP-1) {
5021             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5022             gp_XYZ P(node->X(), node->Y(), node->Z());
5023             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5024             int i;
5025             for(i=0; i<aNbTP-1; i++) {
5026               const SMDS_MeshNode* N = *it;
5027               double x = ( N->X() + P.X() )/2.;
5028               double y = ( N->Y() + P.Y() )/2.;
5029               double z = ( N->Z() + P.Z() )/2.;
5030               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5031               srcNodes.Append( node );
5032               myLastCreatedNodes.Append(newN);
5033               aNodes[2*i] = newN;
5034               aNodes[2*i+1] = N;
5035               P = gp_XYZ(N->X(),N->Y(),N->Z());
5036             }
5037             listNewNodes.clear();
5038             for(i=0; i<2*(aNbTP-1); i++) {
5039               listNewNodes.push_back(aNodes[i]);
5040             }
5041           }
5042         }
5043       }
5044
5045       newNodesItVec.push_back( nIt );
5046     }
5047     // make new elements
5048     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5049     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5050     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5051   }
5052
5053   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5054
5055   if ( theMakeGroups )
5056     generateGroups( srcNodes, srcElems, "extruded");
5057
5058   return EXTR_OK;
5059 }
5060
5061
5062 //=======================================================================
5063 //function : LinearAngleVariation
5064 //purpose  : auxilary for ExtrusionAlongTrack
5065 //=======================================================================
5066 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5067                                             list<double>& Angles)
5068 {
5069   int nbAngles = Angles.size();
5070   if( nbSteps > nbAngles ) {
5071     vector<double> theAngles(nbAngles);
5072     list<double>::iterator it = Angles.begin();
5073     int i = -1;
5074     for(; it!=Angles.end(); it++) {
5075       i++;
5076       theAngles[i] = (*it);
5077     }
5078     list<double> res;
5079     double rAn2St = double( nbAngles ) / double( nbSteps );
5080     double angPrev = 0, angle;
5081     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5082       double angCur = rAn2St * ( iSt+1 );
5083       double angCurFloor  = floor( angCur );
5084       double angPrevFloor = floor( angPrev );
5085       if ( angPrevFloor == angCurFloor )
5086         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5087       else {
5088         int iP = int( angPrevFloor );
5089         double angPrevCeil = ceil(angPrev);
5090         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5091
5092         int iC = int( angCurFloor );
5093         if ( iC < nbAngles )
5094           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5095
5096         iP = int( angPrevCeil );
5097         while ( iC-- > iP )
5098           angle += theAngles[ iC ];
5099       }
5100       res.push_back(angle);
5101       angPrev = angCur;
5102     }
5103     Angles.clear();
5104     it = res.begin();
5105     for(; it!=res.end(); it++)
5106       Angles.push_back( *it );
5107   }
5108 }
5109
5110
5111 //================================================================================
5112 /*!
5113  * \brief Move or copy theElements applying theTrsf to their nodes
5114  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5115  *  \param theTrsf - transformation to apply
5116  *  \param theCopy - if true, create translated copies of theElems
5117  *  \param theMakeGroups - if true and theCopy, create translated groups
5118  *  \param theTargetMesh - mesh to copy translated elements into
5119  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5120  */
5121 //================================================================================
5122
5123 SMESH_MeshEditor::PGroupIDs
5124 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5125                              const gp_Trsf&     theTrsf,
5126                              const bool         theCopy,
5127                              const bool         theMakeGroups,
5128                              SMESH_Mesh*        theTargetMesh)
5129 {
5130   myLastCreatedElems.Clear();
5131   myLastCreatedNodes.Clear();
5132
5133   bool needReverse = false;
5134   string groupPostfix;
5135   switch ( theTrsf.Form() ) {
5136   case gp_PntMirror:
5137   case gp_Ax1Mirror:
5138   case gp_Ax2Mirror:
5139     needReverse = true;
5140     groupPostfix = "mirrored";
5141     break;
5142   case gp_Rotation:
5143     groupPostfix = "rotated";
5144     break;
5145   case gp_Translation:
5146     groupPostfix = "translated";
5147     break;
5148   case gp_Scale:
5149   case gp_CompoundTrsf: // different scale by axis
5150     groupPostfix = "scaled";
5151     break;
5152   default:
5153     needReverse = false;
5154     groupPostfix = "transformed";
5155   }
5156
5157   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5158   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5159   SMESHDS_Mesh* aMesh    = GetMeshDS();
5160
5161
5162   // map old node to new one
5163   TNodeNodeMap nodeMap;
5164
5165   // elements sharing moved nodes; those of them which have all
5166   // nodes mirrored but are not in theElems are to be reversed
5167   TIDSortedElemSet inverseElemSet;
5168
5169   // source elements for each generated one
5170   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5171
5172   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5173   list<SMDS_MeshNode>          orphanCopy; // copies of orphan nodes
5174   vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5175
5176   if ( theElems.empty() ) // transform the whole mesh
5177   {
5178     // add all elements
5179     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5180     while ( eIt->more() ) theElems.insert( eIt->next() );
5181     // add orphan nodes
5182     SMDS_MeshElementIDFactory idFactory;
5183     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5184     while ( nIt->more() )
5185     {
5186       const SMDS_MeshNode* node = nIt->next();
5187       if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5188       {
5189         // node was not inserted into theElems because an element with the same ID
5190         // is already there. As a work around we insert a copy of node with
5191         // an ID = -<index in orphanNode>
5192         orphanCopy.push_back( *node ); // copy node
5193         SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5194         int uniqueID = -orphanNode.size();
5195         orphanNode.push_back( node );
5196         idFactory.BindID( uniqueID, nodeCopy );
5197         theElems.insert( nodeCopy );
5198       }
5199     }
5200   }
5201   // loop on theElems to transorm nodes
5202   TIDSortedElemSet::iterator itElem;
5203   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5204     const SMDS_MeshElement* elem = *itElem;
5205     if ( !elem )
5206       continue;
5207
5208     // loop on elem nodes
5209     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5210     while ( itN->more() ) {
5211
5212       const SMDS_MeshNode* node = cast2Node( itN->next() );
5213       if ( node->GetID() < 0 )
5214         node = orphanNode[ -node->GetID() ];
5215       // check if a node has been already transformed
5216       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5217         nodeMap.insert( make_pair ( node, node ));
5218       if ( !n2n_isnew.second )
5219         continue;
5220
5221       double coord[3];
5222       coord[0] = node->X();
5223       coord[1] = node->Y();
5224       coord[2] = node->Z();
5225       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5226       if ( theTargetMesh ) {
5227         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5228         n2n_isnew.first->second = newNode;
5229         myLastCreatedNodes.Append(newNode);
5230         srcNodes.Append( node );
5231       }
5232       else if ( theCopy ) {
5233         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5234         n2n_isnew.first->second = newNode;
5235         myLastCreatedNodes.Append(newNode);
5236         srcNodes.Append( node );
5237       }
5238       else {
5239         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5240         // node position on shape becomes invalid
5241         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5242           ( SMDS_SpacePosition::originSpacePosition() );
5243       }
5244
5245       // keep inverse elements
5246       if ( !theCopy && !theTargetMesh && needReverse ) {
5247         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5248         while ( invElemIt->more() ) {
5249           const SMDS_MeshElement* iel = invElemIt->next();
5250           inverseElemSet.insert( iel );
5251         }
5252       }
5253     }
5254   }
5255
5256   // either create new elements or reverse mirrored ones
5257   if ( !theCopy && !needReverse && !theTargetMesh )
5258     return PGroupIDs();
5259
5260   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5261   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5262     theElems.insert( *invElemIt );
5263
5264   // replicate or reverse elements
5265
5266   enum {
5267     REV_TETRA   = 0,  //  = nbNodes - 4
5268     REV_PYRAMID = 1,  //  = nbNodes - 4
5269     REV_PENTA   = 2,  //  = nbNodes - 4
5270     REV_FACE    = 3,
5271     REV_HEXA    = 4,  //  = nbNodes - 4
5272     FORWARD     = 5
5273   };
5274   int index[][8] = {
5275     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5276     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5277     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5278     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5279     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5280     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5281   };
5282
5283   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5284   {
5285     const SMDS_MeshElement* elem = *itElem;
5286     if ( !elem || elem->GetType() == SMDSAbs_Node )
5287       continue;
5288
5289     int nbNodes = elem->NbNodes();
5290     int elemType = elem->GetType();
5291
5292     if (elem->IsPoly()) {
5293       // Polygon or Polyhedral Volume
5294       switch ( elemType ) {
5295       case SMDSAbs_Face:
5296         {
5297           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5298           int iNode = 0;
5299           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5300           while (itN->more()) {
5301             const SMDS_MeshNode* node =
5302               static_cast<const SMDS_MeshNode*>(itN->next());
5303             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5304             if (nodeMapIt == nodeMap.end())
5305               break; // not all nodes transformed
5306             if (needReverse) {
5307               // reverse mirrored faces and volumes
5308               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5309             } else {
5310               poly_nodes[iNode] = (*nodeMapIt).second;
5311             }
5312             iNode++;
5313           }
5314           if ( iNode != nbNodes )
5315             continue; // not all nodes transformed
5316
5317           if ( theTargetMesh ) {
5318             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5319             srcElems.Append( elem );
5320           }
5321           else if ( theCopy ) {
5322             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5323             srcElems.Append( elem );
5324           }
5325           else {
5326             aMesh->ChangePolygonNodes(elem, poly_nodes);
5327           }
5328         }
5329         break;
5330       case SMDSAbs_Volume:
5331         {
5332           // ATTENTION: Reversing is not yet done!!!
5333           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5334             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5335           if (!aPolyedre) {
5336             MESSAGE("Warning: bad volumic element");
5337             continue;
5338           }
5339
5340           vector<const SMDS_MeshNode*> poly_nodes;
5341           vector<int> quantities;
5342
5343           bool allTransformed = true;
5344           int nbFaces = aPolyedre->NbFaces();
5345           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5346             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5347             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5348               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5349               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5350               if (nodeMapIt == nodeMap.end()) {
5351                 allTransformed = false; // not all nodes transformed
5352               } else {
5353                 poly_nodes.push_back((*nodeMapIt).second);
5354               }
5355             }
5356             quantities.push_back(nbFaceNodes);
5357           }
5358           if ( !allTransformed )
5359             continue; // not all nodes transformed
5360
5361           if ( theTargetMesh ) {
5362             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5363             srcElems.Append( elem );
5364           }
5365           else if ( theCopy ) {
5366             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5367             srcElems.Append( elem );
5368           }
5369           else {
5370             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5371           }
5372         }
5373         break;
5374       default:;
5375       }
5376       continue;
5377     }
5378
5379     // Regular elements
5380     int* i = index[ FORWARD ];
5381     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5382       if ( elemType == SMDSAbs_Face )
5383         i = index[ REV_FACE ];
5384       else
5385         i = index[ nbNodes - 4 ];
5386
5387     if(elem->IsQuadratic()) {
5388       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5389       i = anIds;
5390       if(needReverse) {
5391         if(nbNodes==3) { // quadratic edge
5392           static int anIds[] = {1,0,2};
5393           i = anIds;
5394         }
5395         else if(nbNodes==6) { // quadratic triangle
5396           static int anIds[] = {0,2,1,5,4,3};
5397           i = anIds;
5398         }
5399         else if(nbNodes==8) { // quadratic quadrangle
5400           static int anIds[] = {0,3,2,1,7,6,5,4};
5401           i = anIds;
5402         }
5403         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5404           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5405           i = anIds;
5406         }
5407         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5408           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5409           i = anIds;
5410         }
5411         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5412           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5413           i = anIds;
5414         }
5415         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5416           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5417           i = anIds;
5418         }
5419       }
5420     }
5421
5422     // find transformed nodes
5423     vector<const SMDS_MeshNode*> nodes(nbNodes);
5424     int iNode = 0;
5425     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5426     while ( itN->more() ) {
5427       const SMDS_MeshNode* node =
5428         static_cast<const SMDS_MeshNode*>( itN->next() );
5429       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5430       if ( nodeMapIt == nodeMap.end() )
5431         break; // not all nodes transformed
5432       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5433     }
5434     if ( iNode != nbNodes )
5435       continue; // not all nodes transformed
5436
5437     if ( theTargetMesh ) {
5438       if ( SMDS_MeshElement* copy =
5439            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5440         myLastCreatedElems.Append( copy );
5441         srcElems.Append( elem );
5442       }
5443     }
5444     else if ( theCopy ) {
5445       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5446         myLastCreatedElems.Append( copy );
5447         srcElems.Append( elem );
5448       }
5449     }
5450     else {
5451       // reverse element as it was reversed by transformation
5452       if ( nbNodes > 2 )
5453         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5454     }
5455   }
5456
5457   PGroupIDs newGroupIDs;
5458
5459   if ( theMakeGroups && theCopy ||
5460        theMakeGroups && theTargetMesh )
5461     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5462
5463   return newGroupIDs;
5464 }
5465
5466 //=======================================================================
5467 /*!
5468  * \brief Create groups of elements made during transformation
5469  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5470  * \param elemGens - elements making corresponding myLastCreatedElems
5471  * \param postfix - to append to names of new groups
5472  */
5473 //=======================================================================
5474
5475 SMESH_MeshEditor::PGroupIDs
5476 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5477                                  const SMESH_SequenceOfElemPtr& elemGens,
5478                                  const std::string&             postfix,
5479                                  SMESH_Mesh*                    targetMesh)
5480 {
5481   PGroupIDs newGroupIDs( new list<int> );
5482   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5483
5484   // Sort existing groups by types and collect their names
5485
5486   // to store an old group and a generated new one
5487   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5488   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5489   // group names
5490   set< string > groupNames;
5491   //
5492   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5493   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5494   while ( groupIt->more() ) {
5495     SMESH_Group * group = groupIt->next();
5496     if ( !group ) continue;
5497     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5498     if ( !groupDS || groupDS->IsEmpty() ) continue;
5499     groupNames.insert( group->GetName() );
5500     groupDS->SetStoreName( group->GetName() );
5501     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5502   }
5503
5504   // Groups creation
5505
5506   // loop on nodes and elements
5507   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5508   {
5509     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5510     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5511     if ( gens.Length() != elems.Length() )
5512       throw SALOME_Exception(LOCALIZED("invalid args"));
5513
5514     // loop on created elements
5515     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5516     {
5517       const SMDS_MeshElement* sourceElem = gens( iElem );
5518       if ( !sourceElem ) {
5519         MESSAGE("generateGroups(): NULL source element");
5520         continue;
5521       }
5522       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5523       if ( groupsOldNew.empty() ) {
5524         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5525           ++iElem; // skip all elements made by sourceElem
5526         continue;
5527       }
5528       // collect all elements made by sourceElem
5529       list< const SMDS_MeshElement* > resultElems;
5530       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5531         if ( resElem != sourceElem )
5532           resultElems.push_back( resElem );
5533       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5534         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5535           if ( resElem != sourceElem )
5536             resultElems.push_back( resElem );
5537       // do not generate element groups from node ones
5538       if ( sourceElem->GetType() == SMDSAbs_Node &&
5539            elems( iElem )->GetType() != SMDSAbs_Node )
5540         continue;
5541
5542       // add resultElems to groups made by ones the sourceElem belongs to
5543       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5544       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5545       {
5546         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5547         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5548         {
5549           SMDS_MeshGroup* & newGroup = gOldNew->second;
5550           if ( !newGroup )// create a new group
5551           {
5552             // make a name
5553             string name = oldGroup->GetStoreName();
5554             if ( !targetMesh ) {
5555               name += "_";
5556               name += postfix;
5557               int nb = 0;
5558               while ( !groupNames.insert( name ).second ) // name exists
5559               {
5560                 if ( nb == 0 ) {
5561                   name += "_1";
5562                 }
5563                 else {
5564                   TCollection_AsciiString nbStr(nb+1);
5565                   name.resize( name.rfind('_')+1 );
5566                   name += nbStr.ToCString();
5567                 }
5568                 ++nb;
5569               }
5570             }
5571             // make a group
5572             int id;
5573             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5574                                                  name.c_str(), id );
5575             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5576             newGroup = & groupDS->SMDSGroup();
5577             newGroupIDs->push_back( id );
5578           }
5579
5580           // fill in a new group
5581           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5582           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5583             newGroup->Add( *resElemIt );
5584         }
5585       }
5586     } // loop on created elements
5587   }// loop on nodes and elements
5588
5589   return newGroupIDs;
5590 }
5591
5592 //================================================================================
5593 /*!
5594  * \brief Return list of group of nodes close to each other within theTolerance
5595  *        Search among theNodes or in the whole mesh if theNodes is empty using
5596  *        an Octree algorithm
5597  */
5598 //================================================================================
5599
5600 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5601                                             const double         theTolerance,
5602                                             TListOfListOfNodes & theGroupsOfNodes)
5603 {
5604   myLastCreatedElems.Clear();
5605   myLastCreatedNodes.Clear();
5606
5607   if ( theNodes.empty() )
5608   { // get all nodes in the mesh
5609     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5610     while ( nIt->more() )
5611       theNodes.insert( theNodes.end(),nIt->next());
5612   }
5613
5614   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5615 }
5616
5617
5618 //=======================================================================
5619 /*!
5620  * \brief Implementation of search for the node closest to point
5621  */
5622 //=======================================================================
5623
5624 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5625 {
5626   //---------------------------------------------------------------------
5627   /*!
5628    * \brief Constructor
5629    */
5630   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5631   {
5632     myMesh = ( SMESHDS_Mesh* ) theMesh;
5633
5634     TIDSortedNodeSet nodes;
5635     if ( theMesh ) {
5636       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5637       while ( nIt->more() )
5638         nodes.insert( nodes.end(), nIt->next() );
5639     }
5640     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5641
5642     // get max size of a leaf box
5643     SMESH_OctreeNode* tree = myOctreeNode;
5644     while ( !tree->isLeaf() )
5645     {
5646       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5647       if ( cIt->more() )
5648         tree = cIt->next();
5649     }
5650     myHalfLeafSize = tree->maxSize() / 2.;
5651   }
5652
5653   //---------------------------------------------------------------------
5654   /*!
5655    * \brief Move node and update myOctreeNode accordingly
5656    */
5657   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5658   {
5659     myOctreeNode->UpdateByMoveNode( node, toPnt );
5660     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5661   }
5662
5663   //---------------------------------------------------------------------
5664   /*!
5665    * \brief Do it's job
5666    */
5667   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5668   {
5669     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5670     map<double, const SMDS_MeshNode*> dist2Nodes;
5671     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5672     if ( !dist2Nodes.empty() )
5673       return dist2Nodes.begin()->second;
5674     list<const SMDS_MeshNode*> nodes;
5675     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5676
5677     double minSqDist = DBL_MAX;
5678     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5679     {
5680       // sort leafs by their distance from thePnt
5681       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5682       TDistTreeMap treeMap;
5683       list< SMESH_OctreeNode* > treeList;
5684       list< SMESH_OctreeNode* >::iterator trIt;
5685       treeList.push_back( myOctreeNode );
5686
5687       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5688       bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5689       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5690       {
5691         SMESH_OctreeNode* tree = *trIt;
5692         if ( !tree->isLeaf() ) // put children to the queue
5693         {
5694           if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5695           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5696           while ( cIt->more() )
5697             treeList.push_back( cIt->next() );
5698         }
5699         else if ( tree->NbNodes() ) // put a tree to the treeMap
5700         {
5701           const Bnd_B3d& box = tree->getBox();
5702           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5703           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5704           if ( !it_in.second ) // not unique distance to box center
5705             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5706         }
5707       }
5708       // find distance after which there is no sense to check tree's
5709       double sqLimit = DBL_MAX;
5710       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5711       if ( treeMap.size() > 5 ) {
5712         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5713         const Bnd_B3d& box = closestTree->getBox();
5714         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5715         sqLimit = limit * limit;
5716       }
5717       // get all nodes from trees
5718       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5719         if ( sqDist_tree->first > sqLimit )
5720           break;
5721         SMESH_OctreeNode* tree = sqDist_tree->second;
5722         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5723       }
5724     }
5725     // find closest among nodes
5726     minSqDist = DBL_MAX;
5727     const SMDS_MeshNode* closestNode = 0;
5728     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5729     for ( ; nIt != nodes.end(); ++nIt ) {
5730       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5731       if ( minSqDist > sqDist ) {
5732         closestNode = *nIt;
5733         minSqDist = sqDist;
5734       }
5735     }
5736     return closestNode;
5737   }
5738
5739   //---------------------------------------------------------------------
5740   /*!
5741    * \brief Destructor
5742    */
5743   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5744
5745   //---------------------------------------------------------------------
5746   /*!
5747    * \brief Return the node tree
5748    */
5749   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5750
5751 private:
5752   SMESH_OctreeNode* myOctreeNode;
5753   SMESHDS_Mesh*     myMesh;
5754   double            myHalfLeafSize; // max size of a leaf box
5755 };
5756
5757 //=======================================================================
5758 /*!
5759  * \brief Return SMESH_NodeSearcher
5760  */
5761 //=======================================================================
5762
5763 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
5764 {
5765   return new SMESH_NodeSearcherImpl( GetMeshDS() );
5766 }
5767
5768 // ========================================================================
5769 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5770 {
5771   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5772   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5773   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
5774
5775   //=======================================================================
5776   /*!
5777    * \brief Octal tree of bounding boxes of elements
5778    */
5779   //=======================================================================
5780
5781   class ElementBndBoxTree : public SMESH_Octree
5782   {
5783   public:
5784
5785     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5786     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5787     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5788     ~ElementBndBoxTree();
5789
5790   protected:
5791     ElementBndBoxTree() {}
5792     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5793     void buildChildrenData();
5794     Bnd_B3d* buildRootBox();
5795   private:
5796     //!< Bounding box of element
5797     struct ElementBox : public Bnd_B3d
5798     {
5799       const SMDS_MeshElement* _element;
5800       int                     _refCount; // an ElementBox can be included in several tree branches
5801       ElementBox(const SMDS_MeshElement* elem);
5802     };
5803     vector< ElementBox* > _elements;
5804   };
5805
5806   //================================================================================
5807   /*!
5808    * \brief ElementBndBoxTree creation
5809    */
5810   //================================================================================
5811
5812   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5813     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5814   {
5815     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5816     _elements.reserve( nbElems );
5817
5818     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5819     while ( elemIt->more() )
5820       _elements.push_back( new ElementBox( elemIt->next() ));
5821
5822     if ( _elements.size() > MaxNbElemsInLeaf )
5823       compute();
5824     else
5825       myIsLeaf = true;
5826   }
5827
5828   //================================================================================
5829   /*!
5830    * \brief Destructor
5831    */
5832   //================================================================================
5833
5834   ElementBndBoxTree::~ElementBndBoxTree()
5835   {
5836     for ( int i = 0; i < _elements.size(); ++i )
5837       if ( --_elements[i]->_refCount <= 0 )
5838         delete _elements[i];
5839   }
5840
5841   //================================================================================
5842   /*!
5843    * \brief Return the maximal box
5844    */
5845   //================================================================================
5846
5847   Bnd_B3d* ElementBndBoxTree::buildRootBox()
5848   {
5849     Bnd_B3d* box = new Bnd_B3d;
5850     for ( int i = 0; i < _elements.size(); ++i )
5851       box->Add( *_elements[i] );
5852     return box;
5853   }
5854
5855   //================================================================================
5856   /*!
5857    * \brief Redistrubute element boxes among children
5858    */
5859   //================================================================================
5860
5861   void ElementBndBoxTree::buildChildrenData()
5862   {
5863     for ( int i = 0; i < _elements.size(); ++i )
5864     {
5865       for (int j = 0; j < 8; j++)
5866       {
5867         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5868         {
5869           _elements[i]->_refCount++;
5870           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5871         }
5872       }
5873       _elements[i]->_refCount--;
5874     }
5875     _elements.clear();
5876
5877     for (int j = 0; j < 8; j++)
5878     {
5879       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5880       if ( child->_elements.size() <= MaxNbElemsInLeaf )
5881         child->myIsLeaf = true;
5882
5883       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5884         child->_elements.resize( child->_elements.size() ); // compact
5885     }
5886   }
5887
5888   //================================================================================
5889   /*!
5890    * \brief Return elements which can include the point
5891    */
5892   //================================================================================
5893
5894   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
5895                                                 TIDSortedElemSet& foundElems)
5896   {
5897     if ( level() && getBox().IsOut( point.XYZ() ))
5898       return;
5899
5900     if ( isLeaf() )
5901     {
5902       for ( int i = 0; i < _elements.size(); ++i )
5903         if ( !_elements[i]->IsOut( point.XYZ() ))
5904           foundElems.insert( _elements[i]->_element );
5905     }
5906     else
5907     {
5908       for (int i = 0; i < 8; i++)
5909         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5910     }
5911   }
5912
5913   //================================================================================
5914   /*!
5915    * \brief Return elements which can be intersected by the line
5916    */
5917   //================================================================================
5918
5919   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
5920                                                TIDSortedElemSet& foundElems)
5921   {
5922     if ( level() && getBox().IsOut( line ))
5923       return;
5924
5925     if ( isLeaf() )
5926     {
5927       for ( int i = 0; i < _elements.size(); ++i )
5928         if ( !_elements[i]->IsOut( line ))
5929           foundElems.insert( _elements[i]->_element );
5930     }
5931     else
5932     {
5933       for (int i = 0; i < 8; i++)
5934         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
5935     }
5936   }
5937
5938   //================================================================================
5939   /*!
5940    * \brief Construct the element box
5941    */
5942   //================================================================================
5943
5944   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5945   {
5946     _element  = elem;
5947     _refCount = 1;
5948     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5949     while ( nIt->more() )
5950       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
5951     Enlarge( NodeRadius );
5952   }
5953
5954 } // namespace
5955
5956 //=======================================================================
5957 /*!
5958  * \brief Implementation of search for the elements by point and
5959  *        of classification of point in 2D mesh
5960  */
5961 //=======================================================================
5962
5963 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5964 {
5965   SMESHDS_Mesh*                _mesh;
5966   ElementBndBoxTree*           _ebbTree;
5967   SMESH_NodeSearcherImpl*      _nodeSearcher;
5968   SMDSAbs_ElementType          _elementType;
5969   double                       _tolerance;
5970   bool                         _outerFacesFound;
5971   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
5972
5973   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
5974     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
5975   ~SMESH_ElementSearcherImpl()
5976   {
5977     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
5978     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5979   }
5980   virtual int FindElementsByPoint(const gp_Pnt&                      point,
5981                                   SMDSAbs_ElementType                type,
5982                                   vector< const SMDS_MeshElement* >& foundElements);
5983   virtual TopAbs_State GetPointState(const gp_Pnt& point);
5984
5985   void GetElementsNearLine( const gp_Ax1&                      line,
5986                             SMDSAbs_ElementType                type,
5987                             vector< const SMDS_MeshElement* >& foundElems);
5988   double getTolerance();
5989   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
5990                             const double tolerance, double & param);
5991   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
5992   bool isOuterBoundary(const SMDS_MeshElement* face) const
5993   {
5994     return _outerFaces.empty() || _outerFaces.count(face);
5995   }
5996   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
5997   {
5998     const SMDS_MeshElement* _face;
5999     gp_Vec                  _faceNorm;
6000     bool                    _coincides; //!< the line lays in face plane
6001     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6002       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6003   };
6004   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6005   {
6006     SMESH_TLink      _link;
6007     TIDSortedElemSet _faces;
6008     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6009       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6010   };
6011 };
6012
6013 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6014 {
6015   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6016              << ", _coincides="<<i._coincides << ")";
6017 }
6018
6019 //=======================================================================
6020 /*!
6021  * \brief define tolerance for search
6022  */
6023 //=======================================================================
6024
6025 double SMESH_ElementSearcherImpl::getTolerance()
6026 {
6027   if ( _tolerance < 0 )
6028   {
6029     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6030
6031     _tolerance = 0;
6032     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6033     {
6034       double boxSize = _nodeSearcher->getTree()->maxSize();
6035       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6036     }
6037     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6038     {
6039       double boxSize = _ebbTree->maxSize();
6040       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6041     }
6042     if ( _tolerance == 0 )
6043     {
6044       // define tolerance by size of a most complex element
6045       int complexType = SMDSAbs_Volume;
6046       while ( complexType > SMDSAbs_All &&
6047               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6048         --complexType;
6049       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6050
6051       double elemSize;
6052       if ( complexType == int( SMDSAbs_Node ))
6053       {
6054         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6055         elemSize = 1;
6056         if ( meshInfo.NbNodes() > 2 )
6057           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6058       }
6059       else
6060       {
6061         const SMDS_MeshElement* elem =
6062           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6063         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6064         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6065         while ( nodeIt->more() )
6066         {
6067           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6068           elemSize = max( dist, elemSize );
6069         }
6070       }
6071       _tolerance = 1e-6 * elemSize;
6072     }
6073   }
6074   return _tolerance;
6075 }
6076
6077 //================================================================================
6078 /*!
6079  * \brief Find intersection of the line and an edge of face and return parameter on line
6080  */
6081 //================================================================================
6082
6083 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6084                                                      const SMDS_MeshElement* face,
6085                                                      const double            tol,
6086                                                      double &                param)
6087 {
6088   int nbInts = 0;
6089   param = 0;
6090
6091   GeomAPI_ExtremaCurveCurve anExtCC;
6092   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6093   
6094   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6095   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6096   {
6097     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6098                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6099     anExtCC.Init( lineCurve, edge);
6100     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6101     {
6102       Quantity_Parameter pl, pe;
6103       anExtCC.LowerDistanceParameters( pl, pe );
6104       param += pl;
6105       if ( ++nbInts == 2 )
6106         break;
6107     }
6108   }
6109   if ( nbInts > 0 ) param /= nbInts;
6110   return nbInts > 0;
6111 }
6112 //================================================================================
6113 /*!
6114  * \brief Find all faces belonging to the outer boundary of mesh
6115  */
6116 //================================================================================
6117
6118 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6119 {
6120   if ( _outerFacesFound ) return;
6121
6122   // Collect all outer faces by passing from one outer face to another via their links
6123   // and BTW find out if there are internal faces at all.
6124
6125   // checked links and links where outer boundary meets internal one
6126   set< SMESH_TLink > visitedLinks, seamLinks;
6127
6128   // links to treat with already visited faces sharing them
6129   list < TFaceLink > startLinks;
6130
6131   // load startLinks with the first outerFace
6132   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6133   _outerFaces.insert( outerFace );
6134
6135   TIDSortedElemSet emptySet;
6136   while ( !startLinks.empty() )
6137   {
6138     const SMESH_TLink& link  = startLinks.front()._link;
6139     TIDSortedElemSet&  faces = startLinks.front()._faces;
6140
6141     outerFace = *faces.begin();
6142     // find other faces sharing the link
6143     const SMDS_MeshElement* f;
6144     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6145       faces.insert( f );
6146
6147     // select another outer face among the found 
6148     const SMDS_MeshElement* outerFace2 = 0;
6149     if ( faces.size() == 2 )
6150     {
6151       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6152     }
6153     else if ( faces.size() > 2 )
6154     {
6155       seamLinks.insert( link );
6156
6157       // link direction within the outerFace
6158       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6159                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6160       int i1 = outerFace->GetNodeIndex( link.node1() );
6161       int i2 = outerFace->GetNodeIndex( link.node2() );
6162       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6163       if ( rev ) n1n2.Reverse();
6164       // outerFace normal
6165       gp_XYZ ofNorm, fNorm;
6166       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6167       {
6168         // direction from the link inside outerFace
6169         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6170         // sort all other faces by angle with the dirInOF
6171         map< double, const SMDS_MeshElement* > angle2Face;
6172         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6173         for ( ; face != faces.end(); ++face )
6174         {
6175           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6176             continue;
6177           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6178           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6179           if ( angle < 0 ) angle += 2*PI;
6180           angle2Face.insert( make_pair( angle, *face ));
6181         }
6182         if ( !angle2Face.empty() )
6183           outerFace2 = angle2Face.begin()->second;
6184       }
6185     }
6186     // store the found outer face and add its links to continue seaching from
6187     if ( outerFace2 )
6188     {
6189       _outerFaces.insert( outerFace );
6190       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6191       for ( int i = 0; i < nbNodes; ++i )
6192       {
6193         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6194         if ( visitedLinks.insert( link2 ).second )
6195           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6196       }
6197     }
6198     startLinks.pop_front();
6199   }
6200   _outerFacesFound = true;
6201
6202   if ( !seamLinks.empty() )
6203   {
6204     // There are internal boundaries touching the outher one,
6205     // find all faces of internal boundaries in order to find
6206     // faces of boundaries of holes, if any.
6207     
6208   }
6209   else
6210   {
6211     _outerFaces.clear();
6212   }
6213 }
6214
6215 //=======================================================================
6216 /*!
6217  * \brief Find elements of given type where the given point is IN or ON.
6218  *        Returns nb of found elements and elements them-selves.
6219  *
6220  * 'ALL' type means elements of any type excluding nodes and 0D elements
6221  */
6222 //=======================================================================
6223
6224 int SMESH_ElementSearcherImpl::
6225 FindElementsByPoint(const gp_Pnt&                      point,
6226                     SMDSAbs_ElementType                type,
6227                     vector< const SMDS_MeshElement* >& foundElements)
6228 {
6229   foundElements.clear();
6230
6231   double tolerance = getTolerance();
6232
6233   // =================================================================================
6234   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6235   {
6236     if ( !_nodeSearcher )
6237       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6238
6239     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6240     if ( !closeNode ) return foundElements.size();
6241
6242     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6243       return foundElements.size(); // to far from any node
6244
6245     if ( type == SMDSAbs_Node )
6246     {
6247       foundElements.push_back( closeNode );
6248     }
6249     else
6250     {
6251       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6252       while ( elemIt->more() )
6253         foundElements.push_back( elemIt->next() );
6254     }
6255   }
6256   // =================================================================================
6257   else // elements more complex than 0D
6258   {
6259     if ( !_ebbTree || _elementType != type )
6260     {
6261       if ( _ebbTree ) delete _ebbTree;
6262       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6263     }
6264     TIDSortedElemSet suspectElems;
6265     _ebbTree->getElementsNearPoint( point, suspectElems );
6266     TIDSortedElemSet::iterator elem = suspectElems.begin();
6267     for ( ; elem != suspectElems.end(); ++elem )
6268       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6269         foundElements.push_back( *elem );
6270   }
6271   return foundElements.size();
6272 }
6273
6274 //================================================================================
6275 /*!
6276  * \brief Classify the given point in the closed 2D mesh
6277  */
6278 //================================================================================
6279
6280 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6281 {
6282   double tolerance = getTolerance();
6283   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6284   {
6285     if ( _ebbTree ) delete _ebbTree;
6286     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6287   }
6288   // Algo: analyse transition of a line starting at the point through mesh boundary;
6289   // try three lines parallel to axis of the coordinate system and perform rough
6290   // analysis. If solution is not clear perform thorough analysis.
6291
6292   const int nbAxes = 3;
6293   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6294   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6295   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6296   multimap< int, int > nbInt2Axis; // to find the simplest case
6297   for ( int axis = 0; axis < nbAxes; ++axis )
6298   {
6299     gp_Ax1 lineAxis( point, axisDir[axis]);
6300     gp_Lin line    ( lineAxis );
6301
6302     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6303     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6304
6305     // Intersect faces with the line
6306
6307     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6308     TIDSortedElemSet::iterator face = suspectFaces.begin();
6309     for ( ; face != suspectFaces.end(); ++face )
6310     {
6311       // get face plane
6312       gp_XYZ fNorm;
6313       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6314       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6315
6316       // perform intersection
6317       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6318       if ( !intersection.IsDone() )
6319         continue;
6320       if ( intersection.IsInQuadric() )
6321       {
6322         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6323       }
6324       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6325       {
6326         gp_Pnt intersectionPoint = intersection.Point(1);
6327         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6328           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6329       }
6330     }
6331     // Analyse intersections roughly
6332
6333     int nbInter = u2inters.size();
6334     if ( nbInter == 0 )
6335       return TopAbs_OUT; 
6336
6337     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6338     if ( nbInter == 1 ) // not closed mesh
6339       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6340
6341     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6342       return TopAbs_ON;
6343
6344     if ( (f<0) == (l<0) )
6345       return TopAbs_OUT;
6346
6347     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6348     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6349     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6350       return TopAbs_IN;
6351
6352     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6353
6354     if ( _outerFacesFound ) break; // pass to thorough analysis
6355
6356   } // three attempts - loop on CS axes
6357
6358   // Analyse intersections thoroughly.
6359   // We make two loops maximum, on the first one we only exclude touching intersections,
6360   // on the second, if situation is still unclear, we gather and use information on
6361   // position of faces (internal or outer). If faces position is already gathered,
6362   // we make the second loop right away.
6363
6364   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6365   {
6366     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6367     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6368     {
6369       int axis = nb_axis->second;
6370       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6371
6372       gp_Ax1 lineAxis( point, axisDir[axis]);
6373       gp_Lin line    ( lineAxis );
6374
6375       // add tangent intersections to u2inters
6376       double param;
6377       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6378       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6379         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6380           u2inters.insert(make_pair( param, *tgtInt ));
6381       tangentInters[ axis ].clear();
6382
6383       // Count intersections before and after the point excluding touching ones.
6384       // If hasPositionInfo we count intersections of outer boundary only
6385
6386       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6387       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6388       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6389       bool ok = ! u_int1->second._coincides;
6390       while ( ok && u_int1 != u2inters.end() )
6391       {
6392         double u = u_int1->first;
6393         bool touchingInt = false;
6394         if ( ++u_int2 != u2inters.end() )
6395         {
6396           // skip intersections at the same point (if the line passes through edge or node)
6397           int nbSamePnt = 0;
6398           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6399           {
6400             ++nbSamePnt;
6401             ++u_int2;
6402           }
6403
6404           // skip tangent intersections
6405           int nbTgt = 0;
6406           const SMDS_MeshElement* prevFace = u_int1->second._face;
6407           while ( ok && u_int2->second._coincides )
6408           {
6409             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6410               ok = false;
6411             else
6412             {
6413               nbTgt++;
6414               u_int2++;
6415               ok = ( u_int2 != u2inters.end() );
6416             }
6417           }
6418           if ( !ok ) break;
6419
6420           // skip intersections at the same point after tangent intersections
6421           if ( nbTgt > 0 )
6422           {
6423             double u2 = u_int2->first;
6424             ++u_int2;
6425             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6426             {
6427               ++nbSamePnt;
6428               ++u_int2;
6429             }
6430           }
6431           // decide if we skipped a touching intersection
6432           if ( nbSamePnt + nbTgt > 0 )
6433           {
6434             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6435             map< double, TInters >::iterator u_int = u_int1;
6436             for ( ; u_int != u_int2; ++u_int )
6437             {
6438               if ( u_int->second._coincides ) continue;
6439               double dot = u_int->second._faceNorm * line.Direction();
6440               if ( dot > maxDot ) maxDot = dot;
6441               if ( dot < minDot ) minDot = dot;
6442             }
6443             touchingInt = ( minDot*maxDot < 0 );
6444           }
6445         }
6446         if ( !touchingInt )
6447         {
6448           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6449           {
6450             if ( u < 0 )
6451               ++nbIntBeforePoint;
6452             else
6453               ++nbIntAfterPoint;
6454           }
6455           if ( u < f ) f = u;
6456           if ( u > l ) l = u;
6457         }
6458
6459         u_int1 = u_int2; // to next intersection
6460
6461       } // loop on intersections with one line
6462
6463       if ( ok )
6464       {
6465         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6466           return TopAbs_ON;
6467
6468         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6469           return TopAbs_OUT; 
6470
6471         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6472           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6473
6474         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6475           return TopAbs_IN;
6476
6477         if ( (f<0) == (l<0) )
6478           return TopAbs_OUT;
6479
6480         if ( hasPositionInfo )
6481           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6482       }
6483     } // loop on intersections of the tree lines - thorough analysis
6484
6485     if ( !hasPositionInfo )
6486     {
6487       // gather info on faces position - is face in the outer boundary or not
6488       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6489       findOuterBoundary( u2inters.begin()->second._face );
6490     }
6491
6492   } // two attempts - with and w/o faces position info in the mesh
6493
6494   return TopAbs_UNKNOWN;
6495 }
6496
6497 //=======================================================================
6498 /*!
6499  * \brief Return elements possibly intersecting the line
6500  */
6501 //=======================================================================
6502
6503 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6504                                                      SMDSAbs_ElementType                type,
6505                                                      vector< const SMDS_MeshElement* >& foundElems)
6506 {
6507   if ( !_ebbTree || _elementType != type )
6508   {
6509     if ( _ebbTree ) delete _ebbTree;
6510     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6511   }
6512   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6513   _ebbTree->getElementsNearLine( line, suspectFaces );
6514   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6515 }
6516
6517 //=======================================================================
6518 /*!
6519  * \brief Return SMESH_ElementSearcher
6520  */
6521 //=======================================================================
6522
6523 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6524 {
6525   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6526 }
6527
6528 //=======================================================================
6529 /*!
6530  * \brief Return true if the point is IN or ON of the element
6531  */
6532 //=======================================================================
6533
6534 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6535 {
6536   if ( element->GetType() == SMDSAbs_Volume)
6537   {
6538     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6539   }
6540
6541   // get ordered nodes
6542
6543   vector< gp_XYZ > xyz;
6544
6545   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6546   if ( element->IsQuadratic() )
6547     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6548       nodeIt = f->interlacedNodesElemIterator();
6549     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6550       nodeIt = e->interlacedNodesElemIterator();
6551
6552   while ( nodeIt->more() )
6553     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6554
6555   int i, nbNodes = element->NbNodes();
6556
6557   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6558   {
6559     // compute face normal
6560     gp_Vec faceNorm(0,0,0);
6561     xyz.push_back( xyz.front() );
6562     for ( i = 0; i < nbNodes; ++i )
6563     {
6564       gp_Vec edge1( xyz[i+1], xyz[i]);
6565       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6566       faceNorm += edge1 ^ edge2;
6567     }
6568     double normSize = faceNorm.Magnitude();
6569     if ( normSize <= tol )
6570     {
6571       // degenerated face: point is out if it is out of all face edges
6572       for ( i = 0; i < nbNodes; ++i )
6573       {
6574         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6575         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6576         SMDS_MeshEdge edge( &n1, &n2 );
6577         if ( !isOut( &edge, point, tol ))
6578           return false;
6579       }
6580       return true;
6581     }
6582     faceNorm /= normSize;
6583
6584     // check if the point lays on face plane
6585     gp_Vec n2p( xyz[0], point );
6586     if ( fabs( n2p * faceNorm ) > tol )
6587       return true; // not on face plane
6588
6589     // check if point is out of face boundary:
6590     // define it by closest transition of a ray point->infinity through face boundary
6591     // on the face plane.
6592     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6593     // to find intersections of the ray with the boundary.
6594     gp_Vec ray = n2p;
6595     gp_Vec plnNorm = ray ^ faceNorm;
6596     normSize = plnNorm.Magnitude();
6597     if ( normSize <= tol ) return false; // point coincides with the first node
6598     plnNorm /= normSize;
6599     // for each node of the face, compute its signed distance to the plane
6600     vector<double> dist( nbNodes + 1);
6601     for ( i = 0; i < nbNodes; ++i )
6602     {
6603       gp_Vec n2p( xyz[i], point );
6604       dist[i] = n2p * plnNorm;
6605     }
6606     dist.back() = dist.front();
6607     // find the closest intersection
6608     int    iClosest = -1;
6609     double rClosest, distClosest = 1e100;;
6610     gp_Pnt pClosest;
6611     for ( i = 0; i < nbNodes; ++i )
6612     {
6613       double r;
6614       if ( fabs( dist[i]) < tol )
6615         r = 0.;
6616       else if ( fabs( dist[i+1]) < tol )
6617         r = 1.;
6618       else if ( dist[i] * dist[i+1] < 0 )
6619         r = dist[i] / ( dist[i] - dist[i+1] );
6620       else
6621         continue; // no intersection
6622       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6623       gp_Vec p2int ( point, pInt);
6624       if ( p2int * ray > -tol ) // right half-space
6625       {
6626         double intDist = p2int.SquareMagnitude();
6627         if ( intDist < distClosest )
6628         {
6629           iClosest = i;
6630           rClosest = r;
6631           pClosest = pInt;
6632           distClosest = intDist;
6633         }
6634       }
6635     }
6636     if ( iClosest < 0 )
6637       return true; // no intesections - out
6638
6639     // analyse transition
6640     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6641     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6642     gp_Vec p2int ( point, pClosest );
6643     bool out = (edgeNorm * p2int) < -tol;
6644     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6645       return out;
6646
6647     // ray pass through a face node; analyze transition through an adjacent edge
6648     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6649     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6650     gp_Vec edgeAdjacent( p1, p2 );
6651     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6652     bool out2 = (edgeNorm2 * p2int) < -tol;
6653
6654     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6655     return covexCorner ? (out || out2) : (out && out2);
6656   }
6657   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6658   {
6659     // point is out of edge if it is NOT ON any straight part of edge
6660     // (we consider quadratic edge as being composed of two straight parts)
6661     for ( i = 1; i < nbNodes; ++i )
6662     {
6663       gp_Vec edge( xyz[i-1], xyz[i]);
6664       gp_Vec n1p ( xyz[i-1], point);
6665       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6666       if ( dist > tol )
6667         continue;
6668       gp_Vec n2p( xyz[i], point );
6669       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6670         continue;
6671       return false; // point is ON this part
6672     }
6673     return true;
6674   }
6675   // Node or 0D element -------------------------------------------------------------------------
6676   {
6677     gp_Vec n2p ( xyz[0], point );
6678     return n2p.Magnitude() <= tol;
6679   }
6680   return true;
6681 }
6682
6683 //=======================================================================
6684 //function : SimplifyFace
6685 //purpose  :
6686 //=======================================================================
6687 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6688                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6689                                     vector<int>&                        quantities) const
6690 {
6691   int nbNodes = faceNodes.size();
6692
6693   if (nbNodes < 3)
6694     return 0;
6695
6696   set<const SMDS_MeshNode*> nodeSet;
6697
6698   // get simple seq of nodes
6699   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6700   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6701   int iSimple = 0, nbUnique = 0;
6702
6703   simpleNodes[iSimple++] = faceNodes[0];
6704   nbUnique++;
6705   for (int iCur = 1; iCur < nbNodes; iCur++) {
6706     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6707       simpleNodes[iSimple++] = faceNodes[iCur];
6708       if (nodeSet.insert( faceNodes[iCur] ).second)
6709         nbUnique++;
6710     }
6711   }
6712   int nbSimple = iSimple;
6713   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6714     nbSimple--;
6715     iSimple--;
6716   }
6717
6718   if (nbUnique < 3)
6719     return 0;
6720
6721   // separate loops
6722   int nbNew = 0;
6723   bool foundLoop = (nbSimple > nbUnique);
6724   while (foundLoop) {
6725     foundLoop = false;
6726     set<const SMDS_MeshNode*> loopSet;
6727     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6728       const SMDS_MeshNode* n = simpleNodes[iSimple];
6729       if (!loopSet.insert( n ).second) {
6730         foundLoop = true;
6731
6732         // separate loop
6733         int iC = 0, curLast = iSimple;
6734         for (; iC < curLast; iC++) {
6735           if (simpleNodes[iC] == n) break;
6736         }
6737         int loopLen = curLast - iC;
6738         if (loopLen > 2) {
6739           // create sub-element
6740           nbNew++;
6741           quantities.push_back(loopLen);
6742           for (; iC < curLast; iC++) {
6743             poly_nodes.push_back(simpleNodes[iC]);
6744           }
6745         }
6746         // shift the rest nodes (place from the first loop position)
6747         for (iC = curLast + 1; iC < nbSimple; iC++) {
6748           simpleNodes[iC - loopLen] = simpleNodes[iC];
6749         }
6750         nbSimple -= loopLen;
6751         iSimple -= loopLen;
6752       }
6753     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6754   } // while (foundLoop)
6755
6756   if (iSimple > 2) {
6757     nbNew++;
6758     quantities.push_back(iSimple);
6759     for (int i = 0; i < iSimple; i++)
6760       poly_nodes.push_back(simpleNodes[i]);
6761   }
6762
6763   return nbNew;
6764 }
6765
6766 //=======================================================================
6767 //function : MergeNodes
6768 //purpose  : In each group, the cdr of nodes are substituted by the first one
6769 //           in all elements.
6770 //=======================================================================
6771
6772 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6773 {
6774   myLastCreatedElems.Clear();
6775   myLastCreatedNodes.Clear();
6776
6777   SMESHDS_Mesh* aMesh = GetMeshDS();
6778
6779   TNodeNodeMap nodeNodeMap; // node to replace - new node
6780   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6781   list< int > rmElemIds, rmNodeIds;
6782
6783   // Fill nodeNodeMap and elems
6784
6785   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6786   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6787     list<const SMDS_MeshNode*>& nodes = *grIt;
6788     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6789     const SMDS_MeshNode* nToKeep = *nIt;
6790     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6791       const SMDS_MeshNode* nToRemove = *nIt;
6792       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6793       if ( nToRemove != nToKeep ) {
6794         rmNodeIds.push_back( nToRemove->GetID() );
6795         AddToSameGroups( nToKeep, nToRemove, aMesh );
6796       }
6797
6798       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6799       while ( invElemIt->more() ) {
6800         const SMDS_MeshElement* elem = invElemIt->next();
6801         elems.insert(elem);
6802       }
6803     }
6804   }
6805   // Change element nodes or remove an element
6806
6807   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6808   for ( ; eIt != elems.end(); eIt++ ) {
6809     const SMDS_MeshElement* elem = *eIt;
6810     int nbNodes = elem->NbNodes();
6811     int aShapeId = FindShape( elem );
6812
6813     set<const SMDS_MeshNode*> nodeSet;
6814     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6815     int iUnique = 0, iCur = 0, nbRepl = 0;
6816     vector<int> iRepl( nbNodes );
6817
6818     // get new seq of nodes
6819     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6820     while ( itN->more() ) {
6821       const SMDS_MeshNode* n =
6822         static_cast<const SMDS_MeshNode*>( itN->next() );
6823
6824       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6825       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6826         n = (*nnIt).second;
6827         // BUG 0020185: begin
6828         {
6829           bool stopRecur = false;
6830           set<const SMDS_MeshNode*> nodesRecur;
6831           nodesRecur.insert(n);
6832           while (!stopRecur) {
6833             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6834             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6835               n = (*nnIt_i).second;
6836               if (!nodesRecur.insert(n).second) {
6837                 // error: recursive dependancy
6838                 stopRecur = true;
6839               }
6840             }
6841             else
6842               stopRecur = true;
6843           }
6844         }
6845         // BUG 0020185: end
6846         iRepl[ nbRepl++ ] = iCur;
6847       }
6848       curNodes[ iCur ] = n;
6849       bool isUnique = nodeSet.insert( n ).second;
6850       if ( isUnique )
6851         uniqueNodes[ iUnique++ ] = n;
6852       iCur++;
6853     }
6854
6855     // Analyse element topology after replacement
6856
6857     bool isOk = true;
6858     int nbUniqueNodes = nodeSet.size();
6859     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6860       // Polygons and Polyhedral volumes
6861       if (elem->IsPoly()) {
6862
6863         if (elem->GetType() == SMDSAbs_Face) {
6864           // Polygon
6865           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6866           int inode = 0;
6867           for (; inode < nbNodes; inode++) {
6868             face_nodes[inode] = curNodes[inode];
6869           }
6870
6871           vector<const SMDS_MeshNode *> polygons_nodes;
6872           vector<int> quantities;
6873           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6874
6875           if (nbNew > 0) {
6876             inode = 0;
6877             for (int iface = 0; iface < nbNew - 1; iface++) {
6878               int nbNodes = quantities[iface];
6879               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6880               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6881                 poly_nodes[ii] = polygons_nodes[inode];
6882               }
6883               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6884               myLastCreatedElems.Append(newElem);
6885               if (aShapeId)
6886                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6887             }
6888             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6889           }
6890           else {
6891             rmElemIds.push_back(elem->GetID());
6892           }
6893
6894         }
6895         else if (elem->GetType() == SMDSAbs_Volume) {
6896           // Polyhedral volume
6897           if (nbUniqueNodes < 4) {
6898             rmElemIds.push_back(elem->GetID());
6899           }
6900           else {
6901             // each face has to be analized in order to check volume validity
6902             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6903               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6904             if (aPolyedre) {
6905               int nbFaces = aPolyedre->NbFaces();
6906
6907               vector<const SMDS_MeshNode *> poly_nodes;
6908               vector<int> quantities;
6909
6910               for (int iface = 1; iface <= nbFaces; iface++) {
6911                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6912                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6913
6914                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6915                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6916                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6917                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6918                     faceNode = (*nnIt).second;
6919                   }
6920                   faceNodes[inode - 1] = faceNode;
6921                 }
6922
6923                 SimplifyFace(faceNodes, poly_nodes, quantities);
6924               }
6925
6926               if (quantities.size() > 3) {
6927                 // to be done: remove coincident faces
6928               }
6929
6930               if (quantities.size() > 3)
6931                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6932               else
6933                 rmElemIds.push_back(elem->GetID());
6934
6935             }
6936             else {
6937               rmElemIds.push_back(elem->GetID());
6938             }
6939           }
6940         }
6941         else {
6942         }
6943
6944         continue;
6945       }
6946
6947       // Regular elements
6948       switch ( nbNodes ) {
6949       case 2: ///////////////////////////////////// EDGE
6950         isOk = false; break;
6951       case 3: ///////////////////////////////////// TRIANGLE
6952         isOk = false; break;
6953       case 4:
6954         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6955           isOk = false;
6956         else { //////////////////////////////////// QUADRANGLE
6957           if ( nbUniqueNodes < 3 )
6958             isOk = false;
6959           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6960             isOk = false; // opposite nodes stick
6961         }
6962         break;
6963       case 6: ///////////////////////////////////// PENTAHEDRON
6964         if ( nbUniqueNodes == 4 ) {
6965           // ---------------------------------> tetrahedron
6966           if (nbRepl == 3 &&
6967               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6968             // all top nodes stick: reverse a bottom
6969             uniqueNodes[ 0 ] = curNodes [ 1 ];
6970             uniqueNodes[ 1 ] = curNodes [ 0 ];
6971           }
6972           else if (nbRepl == 3 &&
6973                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6974             // all bottom nodes stick: set a top before
6975             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6976             uniqueNodes[ 0 ] = curNodes [ 3 ];
6977             uniqueNodes[ 1 ] = curNodes [ 4 ];
6978             uniqueNodes[ 2 ] = curNodes [ 5 ];
6979           }
6980           else if (nbRepl == 4 &&
6981                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6982             // a lateral face turns into a line: reverse a bottom
6983             uniqueNodes[ 0 ] = curNodes [ 1 ];
6984             uniqueNodes[ 1 ] = curNodes [ 0 ];
6985           }
6986           else
6987             isOk = false;
6988         }
6989         else if ( nbUniqueNodes == 5 ) {
6990           // PENTAHEDRON --------------------> 2 tetrahedrons
6991           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6992             // a bottom node sticks with a linked top one
6993             // 1.
6994             SMDS_MeshElement* newElem =
6995               aMesh->AddVolume(curNodes[ 3 ],
6996                                curNodes[ 4 ],
6997                                curNodes[ 5 ],
6998                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6999             myLastCreatedElems.Append(newElem);
7000             if ( aShapeId )
7001               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7002             // 2. : reverse a bottom
7003             uniqueNodes[ 0 ] = curNodes [ 1 ];
7004             uniqueNodes[ 1 ] = curNodes [ 0 ];
7005             nbUniqueNodes = 4;
7006           }
7007           else
7008             isOk = false;
7009         }
7010         else
7011           isOk = false;
7012         break;
7013       case 8: {
7014         if(elem->IsQuadratic()) { // Quadratic quadrangle
7015           //   1    5    2
7016           //    +---+---+
7017           //    |       |
7018           //    |       |
7019           //   4+       +6
7020           //    |       |
7021           //    |       |
7022           //    +---+---+
7023           //   0    7    3
7024           isOk = false;
7025           if(nbRepl==3) {
7026             nbUniqueNodes = 6;
7027             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7028               uniqueNodes[0] = curNodes[0];
7029               uniqueNodes[1] = curNodes[2];
7030               uniqueNodes[2] = curNodes[3];
7031               uniqueNodes[3] = curNodes[5];
7032               uniqueNodes[4] = curNodes[6];
7033               uniqueNodes[5] = curNodes[7];
7034               isOk = true;
7035             }
7036             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7037               uniqueNodes[0] = curNodes[0];
7038               uniqueNodes[1] = curNodes[1];
7039               uniqueNodes[2] = curNodes[2];
7040               uniqueNodes[3] = curNodes[4];
7041               uniqueNodes[4] = curNodes[5];
7042               uniqueNodes[5] = curNodes[6];
7043               isOk = true;
7044             }
7045             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7046               uniqueNodes[0] = curNodes[1];
7047               uniqueNodes[1] = curNodes[2];
7048               uniqueNodes[2] = curNodes[3];
7049               uniqueNodes[3] = curNodes[5];
7050               uniqueNodes[4] = curNodes[6];
7051               uniqueNodes[5] = curNodes[0];
7052               isOk = true;
7053             }
7054             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7055               uniqueNodes[0] = curNodes[0];
7056               uniqueNodes[1] = curNodes[1];
7057               uniqueNodes[2] = curNodes[3];
7058               uniqueNodes[3] = curNodes[4];
7059               uniqueNodes[4] = curNodes[6];
7060               uniqueNodes[5] = curNodes[7];
7061               isOk = true;
7062             }
7063             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7064               uniqueNodes[0] = curNodes[0];
7065               uniqueNodes[1] = curNodes[2];
7066               uniqueNodes[2] = curNodes[3];
7067               uniqueNodes[3] = curNodes[1];
7068               uniqueNodes[4] = curNodes[6];
7069               uniqueNodes[5] = curNodes[7];
7070               isOk = true;
7071             }
7072             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7073               uniqueNodes[0] = curNodes[0];
7074               uniqueNodes[1] = curNodes[1];
7075               uniqueNodes[2] = curNodes[2];
7076               uniqueNodes[3] = curNodes[4];
7077               uniqueNodes[4] = curNodes[5];
7078               uniqueNodes[5] = curNodes[7];
7079               isOk = true;
7080             }
7081             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7082               uniqueNodes[0] = curNodes[0];
7083               uniqueNodes[1] = curNodes[1];
7084               uniqueNodes[2] = curNodes[3];
7085               uniqueNodes[3] = curNodes[4];
7086               uniqueNodes[4] = curNodes[2];
7087               uniqueNodes[5] = curNodes[7];
7088               isOk = true;
7089             }
7090             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7091               uniqueNodes[0] = curNodes[0];
7092               uniqueNodes[1] = curNodes[1];
7093               uniqueNodes[2] = curNodes[2];
7094               uniqueNodes[3] = curNodes[4];
7095               uniqueNodes[4] = curNodes[5];
7096               uniqueNodes[5] = curNodes[3];
7097               isOk = true;
7098             }
7099           }
7100           break;
7101         }
7102         //////////////////////////////////// HEXAHEDRON
7103         isOk = false;
7104         SMDS_VolumeTool hexa (elem);
7105         hexa.SetExternalNormal();
7106         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7107           //////////////////////// ---> tetrahedron
7108           for ( int iFace = 0; iFace < 6; iFace++ ) {
7109             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7110             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7111                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7112                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7113               // one face turns into a point ...
7114               int iOppFace = hexa.GetOppFaceIndex( iFace );
7115               ind = hexa.GetFaceNodesIndices( iOppFace );
7116               int nbStick = 0;
7117               iUnique = 2; // reverse a tetrahedron bottom
7118               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7119                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7120                   nbStick++;
7121                 else if ( iUnique >= 0 )
7122                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7123               }
7124               if ( nbStick == 1 ) {
7125                 // ... and the opposite one - into a triangle.
7126                 // set a top node
7127                 ind = hexa.GetFaceNodesIndices( iFace );
7128                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7129                 isOk = true;
7130               }
7131               break;
7132             }
7133           }
7134         }
7135         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7136           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7137           for ( int iFace = 0; iFace < 6; iFace++ ) {
7138             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7139             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7140                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7141                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7142               // one face turns into a point ...
7143               int iOppFace = hexa.GetOppFaceIndex( iFace );
7144               ind = hexa.GetFaceNodesIndices( iOppFace );
7145               int nbStick = 0;
7146               iUnique = 2;  // reverse a tetrahedron 1 bottom
7147               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7148                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7149                   nbStick++;
7150                 else if ( iUnique >= 0 )
7151                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7152               }
7153               if ( nbStick == 0 ) {
7154                 // ... and the opposite one is a quadrangle
7155                 // set a top node
7156                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7157                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7158                 nbUniqueNodes = 4;
7159                 // tetrahedron 2
7160                 SMDS_MeshElement* newElem =
7161                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7162                                    curNodes[ind[ 3 ]],
7163                                    curNodes[ind[ 2 ]],
7164                                    curNodes[indTop[ 0 ]]);
7165                 myLastCreatedElems.Append(newElem);
7166                 if ( aShapeId )
7167                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7168                 isOk = true;
7169               }
7170               break;
7171             }
7172           }
7173         }
7174         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7175           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7176           // find indices of quad and tri faces
7177           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7178           for ( iFace = 0; iFace < 6; iFace++ ) {
7179             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7180             nodeSet.clear();
7181             for ( iCur = 0; iCur < 4; iCur++ )
7182               nodeSet.insert( curNodes[ind[ iCur ]] );
7183             nbUniqueNodes = nodeSet.size();
7184             if ( nbUniqueNodes == 3 )
7185               iTriFace[ nbTri++ ] = iFace;
7186             else if ( nbUniqueNodes == 4 )
7187               iQuadFace[ nbQuad++ ] = iFace;
7188           }
7189           if (nbQuad == 2 && nbTri == 4 &&
7190               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7191             // 2 opposite quadrangles stuck with a diagonal;
7192             // sample groups of merged indices: (0-4)(2-6)
7193             // --------------------------------------------> 2 tetrahedrons
7194             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7195             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7196             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7197             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7198                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7199               // stuck with 0-2 diagonal
7200               i0  = ind1[ 3 ];
7201               i1d = ind1[ 0 ];
7202               i2  = ind1[ 1 ];
7203               i3d = ind1[ 2 ];
7204               i0t = ind2[ 1 ];
7205               i2t = ind2[ 3 ];
7206             }
7207             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7208                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7209               // stuck with 1-3 diagonal
7210               i0  = ind1[ 0 ];
7211               i1d = ind1[ 1 ];
7212               i2  = ind1[ 2 ];
7213               i3d = ind1[ 3 ];
7214               i0t = ind2[ 0 ];
7215               i2t = ind2[ 1 ];
7216             }
7217             else {
7218               ASSERT(0);
7219             }
7220             // tetrahedron 1
7221             uniqueNodes[ 0 ] = curNodes [ i0 ];
7222             uniqueNodes[ 1 ] = curNodes [ i1d ];
7223             uniqueNodes[ 2 ] = curNodes [ i3d ];
7224             uniqueNodes[ 3 ] = curNodes [ i0t ];
7225             nbUniqueNodes = 4;
7226             // tetrahedron 2
7227             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7228                                                          curNodes[ i2 ],
7229                                                          curNodes[ i3d ],
7230                                                          curNodes[ i2t ]);
7231             myLastCreatedElems.Append(newElem);
7232             if ( aShapeId )
7233               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7234             isOk = true;
7235           }
7236           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7237                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7238             // --------------------------------------------> prism
7239             // find 2 opposite triangles
7240             nbUniqueNodes = 6;
7241             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7242               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7243                 // find indices of kept and replaced nodes
7244                 // and fill unique nodes of 2 opposite triangles
7245                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7246                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7247                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7248                 // fill unique nodes
7249                 iUnique = 0;
7250                 isOk = true;
7251                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7252                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7253                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7254                   if ( n == nInit ) {
7255                     // iCur of a linked node of the opposite face (make normals co-directed):
7256                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7257                     // check that correspondent corners of triangles are linked
7258                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7259                       isOk = false;
7260                     else {
7261                       uniqueNodes[ iUnique ] = n;
7262                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7263                       iUnique++;
7264                     }
7265                   }
7266                 }
7267                 break;
7268               }
7269             }
7270           }
7271         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7272         break;
7273       } // HEXAHEDRON
7274
7275       default:
7276         isOk = false;
7277       } // switch ( nbNodes )
7278
7279     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7280
7281     if ( isOk ) {
7282       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7283         // Change nodes of polyedre
7284         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7285           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7286         if (aPolyedre) {
7287           int nbFaces = aPolyedre->NbFaces();
7288
7289           vector<const SMDS_MeshNode *> poly_nodes;
7290           vector<int> quantities (nbFaces);
7291
7292           for (int iface = 1; iface <= nbFaces; iface++) {
7293             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7294             quantities[iface - 1] = nbFaceNodes;
7295
7296             for (inode = 1; inode <= nbFaceNodes; inode++) {
7297               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7298
7299               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7300               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7301                 curNode = (*nnIt).second;
7302               }
7303               poly_nodes.push_back(curNode);
7304             }
7305           }
7306           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7307         }
7308       }
7309       else {
7310         // Change regular element or polygon
7311         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7312       }
7313     }
7314     else {
7315       // Remove invalid regular element or invalid polygon
7316       rmElemIds.push_back( elem->GetID() );
7317     }
7318
7319   } // loop on elements
7320
7321   // Remove equal nodes and bad elements
7322
7323   Remove( rmNodeIds, true );
7324   Remove( rmElemIds, false );
7325
7326 }
7327
7328
7329 // ========================================================
7330 // class   : SortableElement
7331 // purpose : allow sorting elements basing on their nodes
7332 // ========================================================
7333 class SortableElement : public set <const SMDS_MeshElement*>
7334 {
7335 public:
7336
7337   SortableElement( const SMDS_MeshElement* theElem )
7338   {
7339     myElem = theElem;
7340     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7341     while ( nodeIt->more() )
7342       this->insert( nodeIt->next() );
7343   }
7344
7345   const SMDS_MeshElement* Get() const
7346   { return myElem; }
7347
7348   void Set(const SMDS_MeshElement* e) const
7349   { myElem = e; }
7350
7351
7352 private:
7353   mutable const SMDS_MeshElement* myElem;
7354 };
7355
7356 //=======================================================================
7357 //function : FindEqualElements
7358 //purpose  : Return list of group of elements built on the same nodes.
7359 //           Search among theElements or in the whole mesh if theElements is empty
7360 //=======================================================================
7361 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7362                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7363 {
7364   myLastCreatedElems.Clear();
7365   myLastCreatedNodes.Clear();
7366
7367   typedef set<const SMDS_MeshElement*> TElemsSet;
7368   typedef map< SortableElement, int > TMapOfNodeSet;
7369   typedef list<int> TGroupOfElems;
7370
7371   TElemsSet elems;
7372   if ( theElements.empty() )
7373   { // get all elements in the mesh
7374     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7375     while ( eIt->more() )
7376       elems.insert( elems.end(), eIt->next());
7377   }
7378   else
7379     elems = theElements;
7380
7381   vector< TGroupOfElems > arrayOfGroups;
7382   TGroupOfElems groupOfElems;
7383   TMapOfNodeSet mapOfNodeSet;
7384
7385   TElemsSet::iterator elemIt = elems.begin();
7386   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7387     const SMDS_MeshElement* curElem = *elemIt;
7388     SortableElement SE(curElem);
7389     int ind = -1;
7390     // check uniqueness
7391     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7392     if( !(pp.second) ) {
7393       TMapOfNodeSet::iterator& itSE = pp.first;
7394       ind = (*itSE).second;
7395       arrayOfGroups[ind].push_back(curElem->GetID());
7396     }
7397     else {
7398       groupOfElems.clear();
7399       groupOfElems.push_back(curElem->GetID());
7400       arrayOfGroups.push_back(groupOfElems);
7401       i++;
7402     }
7403   }
7404
7405   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7406   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7407     groupOfElems = *groupIt;
7408     if ( groupOfElems.size() > 1 ) {
7409       groupOfElems.sort();
7410       theGroupsOfElementsID.push_back(groupOfElems);
7411     }
7412   }
7413 }
7414
7415 //=======================================================================
7416 //function : MergeElements
7417 //purpose  : In each given group, substitute all elements by the first one.
7418 //=======================================================================
7419
7420 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7421 {
7422   myLastCreatedElems.Clear();
7423   myLastCreatedNodes.Clear();
7424
7425   typedef list<int> TListOfIDs;
7426   TListOfIDs rmElemIds; // IDs of elems to remove
7427
7428   SMESHDS_Mesh* aMesh = GetMeshDS();
7429
7430   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7431   while ( groupsIt != theGroupsOfElementsID.end() ) {
7432     TListOfIDs& aGroupOfElemID = *groupsIt;
7433     aGroupOfElemID.sort();
7434     int elemIDToKeep = aGroupOfElemID.front();
7435     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7436     aGroupOfElemID.pop_front();
7437     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7438     while ( idIt != aGroupOfElemID.end() ) {
7439       int elemIDToRemove = *idIt;
7440       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7441       // add the kept element in groups of removed one (PAL15188)
7442       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7443       rmElemIds.push_back( elemIDToRemove );
7444       ++idIt;
7445     }
7446     ++groupsIt;
7447   }
7448
7449   Remove( rmElemIds, false );
7450 }
7451
7452 //=======================================================================
7453 //function : MergeEqualElements
7454 //purpose  : Remove all but one of elements built on the same nodes.
7455 //=======================================================================
7456
7457 void SMESH_MeshEditor::MergeEqualElements()
7458 {
7459   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7460                                                  to merge equal elements in the whole mesh */
7461   TListOfListOfElementsID aGroupsOfElementsID;
7462   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7463   MergeElements(aGroupsOfElementsID);
7464 }
7465
7466 //=======================================================================
7467 //function : FindFaceInSet
7468 //purpose  : Return a face having linked nodes n1 and n2 and which is
7469 //           - not in avoidSet,
7470 //           - in elemSet provided that !elemSet.empty()
7471 //           i1 and i2 optionally returns indices of n1 and n2
7472 //=======================================================================
7473
7474 const SMDS_MeshElement*
7475 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7476                                 const SMDS_MeshNode*    n2,
7477                                 const TIDSortedElemSet& elemSet,
7478                                 const TIDSortedElemSet& avoidSet,
7479                                 int*                    n1ind,
7480                                 int*                    n2ind)
7481
7482 {
7483   int i1, i2;
7484   const SMDS_MeshElement* face = 0;
7485
7486   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7487   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7488   {
7489     const SMDS_MeshElement* elem = invElemIt->next();
7490     if (avoidSet.count( elem ))
7491       continue;
7492     if ( !elemSet.empty() && !elemSet.count( elem ))
7493       continue;
7494     // index of n1
7495     i1 = elem->GetNodeIndex( n1 );
7496     // find a n2 linked to n1
7497     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7498     for ( int di = -1; di < 2 && !face; di += 2 )
7499     {
7500       i2 = (i1+di+nbN) % nbN;
7501       if ( elem->GetNode( i2 ) == n2 )
7502         face = elem;
7503     }
7504     if ( !face && elem->IsQuadratic())
7505     {
7506       // analysis for quadratic elements using all nodes
7507       const SMDS_QuadraticFaceOfNodes* F =
7508         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7509       // use special nodes iterator
7510       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7511       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7512       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7513       {
7514         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7515         if ( n1 == prevN && n2 == n )
7516         {
7517           face = elem;
7518         }
7519         else if ( n2 == prevN && n1 == n )
7520         {
7521           face = elem; swap( i1, i2 );
7522         }
7523         prevN = n;
7524       }
7525     }
7526   }
7527   if ( n1ind ) *n1ind = i1;
7528   if ( n2ind ) *n2ind = i2;
7529   return face;
7530 }
7531
7532 //=======================================================================
7533 //function : findAdjacentFace
7534 //purpose  :
7535 //=======================================================================
7536
7537 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7538                                                 const SMDS_MeshNode* n2,
7539                                                 const SMDS_MeshElement* elem)
7540 {
7541   TIDSortedElemSet elemSet, avoidSet;
7542   if ( elem )
7543     avoidSet.insert ( elem );
7544   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7545 }
7546
7547 //=======================================================================
7548 //function : FindFreeBorder
7549 //purpose  :
7550 //=======================================================================
7551
7552 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7553
7554 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7555                                        const SMDS_MeshNode*             theSecondNode,
7556                                        const SMDS_MeshNode*             theLastNode,
7557                                        list< const SMDS_MeshNode* > &   theNodes,
7558                                        list< const SMDS_MeshElement* >& theFaces)
7559 {
7560   if ( !theFirstNode || !theSecondNode )
7561     return false;
7562   // find border face between theFirstNode and theSecondNode
7563   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7564   if ( !curElem )
7565     return false;
7566
7567   theFaces.push_back( curElem );
7568   theNodes.push_back( theFirstNode );
7569   theNodes.push_back( theSecondNode );
7570
7571   //vector<const SMDS_MeshNode*> nodes;
7572   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7573   TIDSortedElemSet foundElems;
7574   bool needTheLast = ( theLastNode != 0 );
7575
7576   while ( nStart != theLastNode ) {
7577     if ( nStart == theFirstNode )
7578       return !needTheLast;
7579
7580     // find all free border faces sharing form nStart
7581
7582     list< const SMDS_MeshElement* > curElemList;
7583     list< const SMDS_MeshNode* > nStartList;
7584     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7585     while ( invElemIt->more() ) {
7586       const SMDS_MeshElement* e = invElemIt->next();
7587       if ( e == curElem || foundElems.insert( e ).second ) {
7588         // get nodes
7589         int iNode = 0, nbNodes = e->NbNodes();
7590         //const SMDS_MeshNode* nodes[nbNodes+1];
7591         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7592
7593         if(e->IsQuadratic()) {
7594           const SMDS_QuadraticFaceOfNodes* F =
7595             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7596           // use special nodes iterator
7597           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7598           while( anIter->more() ) {
7599             nodes[ iNode++ ] = anIter->next();
7600           }
7601         }
7602         else {
7603           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7604           while ( nIt->more() )
7605             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7606         }
7607         nodes[ iNode ] = nodes[ 0 ];
7608         // check 2 links
7609         for ( iNode = 0; iNode < nbNodes; iNode++ )
7610           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7611                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7612               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7613           {
7614             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7615             curElemList.push_back( e );
7616           }
7617       }
7618     }
7619     // analyse the found
7620
7621     int nbNewBorders = curElemList.size();
7622     if ( nbNewBorders == 0 ) {
7623       // no free border furthermore
7624       return !needTheLast;
7625     }
7626     else if ( nbNewBorders == 1 ) {
7627       // one more element found
7628       nIgnore = nStart;
7629       nStart = nStartList.front();
7630       curElem = curElemList.front();
7631       theFaces.push_back( curElem );
7632       theNodes.push_back( nStart );
7633     }
7634     else {
7635       // several continuations found
7636       list< const SMDS_MeshElement* >::iterator curElemIt;
7637       list< const SMDS_MeshNode* >::iterator nStartIt;
7638       // check if one of them reached the last node
7639       if ( needTheLast ) {
7640         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7641              curElemIt!= curElemList.end();
7642              curElemIt++, nStartIt++ )
7643           if ( *nStartIt == theLastNode ) {
7644             theFaces.push_back( *curElemIt );
7645             theNodes.push_back( *nStartIt );
7646             return true;
7647           }
7648       }
7649       // find the best free border by the continuations
7650       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7651       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7652       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7653            curElemIt!= curElemList.end();
7654            curElemIt++, nStartIt++ )
7655       {
7656         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7657         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7658         // find one more free border
7659         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7660           cNL->clear();
7661           cFL->clear();
7662         }
7663         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7664           // choice: clear a worse one
7665           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7666           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7667           contNodes[ iWorse ].clear();
7668           contFaces[ iWorse ].clear();
7669         }
7670       }
7671       if ( contNodes[0].empty() && contNodes[1].empty() )
7672         return false;
7673
7674       // append the best free border
7675       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7676       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7677       theNodes.pop_back(); // remove nIgnore
7678       theNodes.pop_back(); // remove nStart
7679       theFaces.pop_back(); // remove curElem
7680       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7681       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7682       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7683       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7684       return true;
7685
7686     } // several continuations found
7687   } // while ( nStart != theLastNode )
7688
7689   return true;
7690 }
7691
7692 //=======================================================================
7693 //function : CheckFreeBorderNodes
7694 //purpose  : Return true if the tree nodes are on a free border
7695 //=======================================================================
7696
7697 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7698                                             const SMDS_MeshNode* theNode2,
7699                                             const SMDS_MeshNode* theNode3)
7700 {
7701   list< const SMDS_MeshNode* > nodes;
7702   list< const SMDS_MeshElement* > faces;
7703   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7704 }
7705
7706 //=======================================================================
7707 //function : SewFreeBorder
7708 //purpose  :
7709 //=======================================================================
7710
7711 SMESH_MeshEditor::Sew_Error
7712 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7713                                  const SMDS_MeshNode* theBordSecondNode,
7714                                  const SMDS_MeshNode* theBordLastNode,
7715                                  const SMDS_MeshNode* theSideFirstNode,
7716                                  const SMDS_MeshNode* theSideSecondNode,
7717                                  const SMDS_MeshNode* theSideThirdNode,
7718                                  const bool           theSideIsFreeBorder,
7719                                  const bool           toCreatePolygons,
7720                                  const bool           toCreatePolyedrs)
7721 {
7722   myLastCreatedElems.Clear();
7723   myLastCreatedNodes.Clear();
7724
7725   MESSAGE("::SewFreeBorder()");
7726   Sew_Error aResult = SEW_OK;
7727
7728   // ====================================
7729   //    find side nodes and elements
7730   // ====================================
7731
7732   list< const SMDS_MeshNode* > nSide[ 2 ];
7733   list< const SMDS_MeshElement* > eSide[ 2 ];
7734   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7735   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7736
7737   // Free border 1
7738   // --------------
7739   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7740                       nSide[0], eSide[0])) {
7741     MESSAGE(" Free Border 1 not found " );
7742     aResult = SEW_BORDER1_NOT_FOUND;
7743   }
7744   if (theSideIsFreeBorder) {
7745     // Free border 2
7746     // --------------
7747     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7748                         nSide[1], eSide[1])) {
7749       MESSAGE(" Free Border 2 not found " );
7750       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7751     }
7752   }
7753   if ( aResult != SEW_OK )
7754     return aResult;
7755
7756   if (!theSideIsFreeBorder) {
7757     // Side 2
7758     // --------------
7759
7760     // -------------------------------------------------------------------------
7761     // Algo:
7762     // 1. If nodes to merge are not coincident, move nodes of the free border
7763     //    from the coord sys defined by the direction from the first to last
7764     //    nodes of the border to the correspondent sys of the side 2
7765     // 2. On the side 2, find the links most co-directed with the correspondent
7766     //    links of the free border
7767     // -------------------------------------------------------------------------
7768
7769     // 1. Since sewing may brake if there are volumes to split on the side 2,
7770     //    we wont move nodes but just compute new coordinates for them
7771     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7772     TNodeXYZMap nBordXYZ;
7773     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7774     list< const SMDS_MeshNode* >::iterator nBordIt;
7775
7776     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7777     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7778     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7779     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7780     double tol2 = 1.e-8;
7781     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7782     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7783       // Need node movement.
7784
7785       // find X and Z axes to create trsf
7786       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7787       gp_Vec X = Zs ^ Zb;
7788       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7789         // Zb || Zs
7790         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7791
7792       // coord systems
7793       gp_Ax3 toBordAx( Pb1, Zb, X );
7794       gp_Ax3 fromSideAx( Ps1, Zs, X );
7795       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7796       // set trsf
7797       gp_Trsf toBordSys, fromSide2Sys;
7798       toBordSys.SetTransformation( toBordAx );
7799       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7800       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7801
7802       // move
7803       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7804         const SMDS_MeshNode* n = *nBordIt;
7805         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7806         toBordSys.Transforms( xyz );
7807         fromSide2Sys.Transforms( xyz );
7808         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7809       }
7810     }
7811     else {
7812       // just insert nodes XYZ in the nBordXYZ map
7813       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7814         const SMDS_MeshNode* n = *nBordIt;
7815         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7816       }
7817     }
7818
7819     // 2. On the side 2, find the links most co-directed with the correspondent
7820     //    links of the free border
7821
7822     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7823     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7824     sideNodes.push_back( theSideFirstNode );
7825
7826     bool hasVolumes = false;
7827     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7828     set<long> foundSideLinkIDs, checkedLinkIDs;
7829     SMDS_VolumeTool volume;
7830     //const SMDS_MeshNode* faceNodes[ 4 ];
7831
7832     const SMDS_MeshNode*    sideNode;
7833     const SMDS_MeshElement* sideElem;
7834     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7835     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7836     nBordIt = bordNodes.begin();
7837     nBordIt++;
7838     // border node position and border link direction to compare with
7839     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7840     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7841     // choose next side node by link direction or by closeness to
7842     // the current border node:
7843     bool searchByDir = ( *nBordIt != theBordLastNode );
7844     do {
7845       // find the next node on the Side 2
7846       sideNode = 0;
7847       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7848       long linkID;
7849       checkedLinkIDs.clear();
7850       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7851
7852       // loop on inverse elements of current node (prevSideNode) on the Side 2
7853       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7854       while ( invElemIt->more() )
7855       {
7856         const SMDS_MeshElement* elem = invElemIt->next();
7857         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7858         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7859         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7860         bool isVolume = volume.Set( elem );
7861         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7862         if ( isVolume ) // --volume
7863           hasVolumes = true;
7864         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7865           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7866           if(elem->IsQuadratic()) {
7867             const SMDS_QuadraticFaceOfNodes* F =
7868               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7869             // use special nodes iterator
7870             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7871             while( anIter->more() ) {
7872               nodes[ iNode ] = anIter->next();
7873               if ( nodes[ iNode++ ] == prevSideNode )
7874                 iPrevNode = iNode - 1;
7875             }
7876           }
7877           else {
7878             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7879             while ( nIt->more() ) {
7880               nodes[ iNode ] = cast2Node( nIt->next() );
7881               if ( nodes[ iNode++ ] == prevSideNode )
7882                 iPrevNode = iNode - 1;
7883             }
7884           }
7885           // there are 2 links to check
7886           nbNodes = 2;
7887         }
7888         else // --edge
7889           continue;
7890         // loop on links, to be precise, on the second node of links
7891         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7892           const SMDS_MeshNode* n = nodes[ iNode ];
7893           if ( isVolume ) {
7894             if ( !volume.IsLinked( n, prevSideNode ))
7895               continue;
7896           }
7897           else {
7898             if ( iNode ) // a node before prevSideNode
7899               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7900             else         // a node after prevSideNode
7901               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7902           }
7903           // check if this link was already used
7904           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7905           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7906           if (!isJustChecked &&
7907               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7908           {
7909             // test a link geometrically
7910             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7911             bool linkIsBetter = false;
7912             double dot = 0.0, dist = 0.0;
7913             if ( searchByDir ) { // choose most co-directed link
7914               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7915               linkIsBetter = ( dot > maxDot );
7916             }
7917             else { // choose link with the node closest to bordPos
7918               dist = ( nextXYZ - bordPos ).SquareModulus();
7919               linkIsBetter = ( dist < minDist );
7920             }
7921             if ( linkIsBetter ) {
7922               maxDot = dot;
7923               minDist = dist;
7924               linkID = iLink;
7925               sideNode = n;
7926               sideElem = elem;
7927             }
7928           }
7929         }
7930       } // loop on inverse elements of prevSideNode
7931
7932       if ( !sideNode ) {
7933         MESSAGE(" Cant find path by links of the Side 2 ");
7934         return SEW_BAD_SIDE_NODES;
7935       }
7936       sideNodes.push_back( sideNode );
7937       sideElems.push_back( sideElem );
7938       foundSideLinkIDs.insert ( linkID );
7939       prevSideNode = sideNode;
7940
7941       if ( *nBordIt == theBordLastNode )
7942         searchByDir = false;
7943       else {
7944         // find the next border link to compare with
7945         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7946         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7947         // move to next border node if sideNode is before forward border node (bordPos)
7948         while ( *nBordIt != theBordLastNode && !searchByDir ) {
7949           prevBordNode = *nBordIt;
7950           nBordIt++;
7951           bordPos = nBordXYZ[ *nBordIt ];
7952           bordDir = bordPos - nBordXYZ[ prevBordNode ];
7953           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7954         }
7955       }
7956     }
7957     while ( sideNode != theSideSecondNode );
7958
7959     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7960       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7961       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7962     }
7963   } // end nodes search on the side 2
7964
7965   // ============================
7966   // sew the border to the side 2
7967   // ============================
7968
7969   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
7970   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7971
7972   TListOfListOfNodes nodeGroupsToMerge;
7973   if ( nbNodes[0] == nbNodes[1] ||
7974        ( theSideIsFreeBorder && !theSideThirdNode)) {
7975
7976     // all nodes are to be merged
7977
7978     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7979          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7980          nIt[0]++, nIt[1]++ )
7981     {
7982       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7983       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7984       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7985     }
7986   }
7987   else {
7988
7989     // insert new nodes into the border and the side to get equal nb of segments
7990
7991     // get normalized parameters of nodes on the borders
7992     //double param[ 2 ][ maxNbNodes ];
7993     double* param[ 2 ];
7994     param[0] = new double [ maxNbNodes ];
7995     param[1] = new double [ maxNbNodes ];
7996     int iNode, iBord;
7997     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7998       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7999       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8000       const SMDS_MeshNode* nPrev = *nIt;
8001       double bordLength = 0;
8002       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8003         const SMDS_MeshNode* nCur = *nIt;
8004         gp_XYZ segment (nCur->X() - nPrev->X(),
8005                         nCur->Y() - nPrev->Y(),
8006                         nCur->Z() - nPrev->Z());
8007         double segmentLen = segment.Modulus();
8008         bordLength += segmentLen;
8009         param[ iBord ][ iNode ] = bordLength;
8010         nPrev = nCur;
8011       }
8012       // normalize within [0,1]
8013       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8014         param[ iBord ][ iNode ] /= bordLength;
8015       }
8016     }
8017
8018     // loop on border segments
8019     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8020     int i[ 2 ] = { 0, 0 };
8021     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8022     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8023
8024     TElemOfNodeListMap insertMap;
8025     TElemOfNodeListMap::iterator insertMapIt;
8026     // insertMap is
8027     // key:   elem to insert nodes into
8028     // value: 2 nodes to insert between + nodes to be inserted
8029     do {
8030       bool next[ 2 ] = { false, false };
8031
8032       // find min adjacent segment length after sewing
8033       double nextParam = 10., prevParam = 0;
8034       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8035         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8036           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8037         if ( i[ iBord ] > 0 )
8038           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8039       }
8040       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8041       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8042       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8043
8044       // choose to insert or to merge nodes
8045       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8046       if ( Abs( du ) <= minSegLen * 0.2 ) {
8047         // merge
8048         // ------
8049         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8050         const SMDS_MeshNode* n0 = *nIt[0];
8051         const SMDS_MeshNode* n1 = *nIt[1];
8052         nodeGroupsToMerge.back().push_back( n1 );
8053         nodeGroupsToMerge.back().push_back( n0 );
8054         // position of node of the border changes due to merge
8055         param[ 0 ][ i[0] ] += du;
8056         // move n1 for the sake of elem shape evaluation during insertion.
8057         // n1 will be removed by MergeNodes() anyway
8058         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8059         next[0] = next[1] = true;
8060       }
8061       else {
8062         // insert
8063         // ------
8064         int intoBord = ( du < 0 ) ? 0 : 1;
8065         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8066         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8067         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8068         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8069         if ( intoBord == 1 ) {
8070           // move node of the border to be on a link of elem of the side
8071           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8072           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8073           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8074           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8075           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8076         }
8077         insertMapIt = insertMap.find( elem );
8078         bool notFound = ( insertMapIt == insertMap.end() );
8079         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8080         if ( otherLink ) {
8081           // insert into another link of the same element:
8082           // 1. perform insertion into the other link of the elem
8083           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8084           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8085           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8086           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8087           // 2. perform insertion into the link of adjacent faces
8088           while (true) {
8089             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8090             if ( adjElem )
8091               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8092             else
8093               break;
8094           }
8095           if (toCreatePolyedrs) {
8096             // perform insertion into the links of adjacent volumes
8097             UpdateVolumes(n12, n22, nodeList);
8098           }
8099           // 3. find an element appeared on n1 and n2 after the insertion
8100           insertMap.erase( elem );
8101           elem = findAdjacentFace( n1, n2, 0 );
8102         }
8103         if ( notFound || otherLink ) {
8104           // add element and nodes of the side into the insertMap
8105           insertMapIt = insertMap.insert
8106             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8107           (*insertMapIt).second.push_back( n1 );
8108           (*insertMapIt).second.push_back( n2 );
8109         }
8110         // add node to be inserted into elem
8111         (*insertMapIt).second.push_back( nIns );
8112         next[ 1 - intoBord ] = true;
8113       }
8114
8115       // go to the next segment
8116       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8117         if ( next[ iBord ] ) {
8118           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8119             eIt[ iBord ]++;
8120           nPrev[ iBord ] = *nIt[ iBord ];
8121           nIt[ iBord ]++; i[ iBord ]++;
8122         }
8123       }
8124     }
8125     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8126
8127     // perform insertion of nodes into elements
8128
8129     for (insertMapIt = insertMap.begin();
8130          insertMapIt != insertMap.end();
8131          insertMapIt++ )
8132     {
8133       const SMDS_MeshElement* elem = (*insertMapIt).first;
8134       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8135       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8136       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8137
8138       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8139
8140       if ( !theSideIsFreeBorder ) {
8141         // look for and insert nodes into the faces adjacent to elem
8142         while (true) {
8143           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8144           if ( adjElem )
8145             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8146           else
8147             break;
8148         }
8149       }
8150       if (toCreatePolyedrs) {
8151         // perform insertion into the links of adjacent volumes
8152         UpdateVolumes(n1, n2, nodeList);
8153       }
8154     }
8155
8156     delete param[0];
8157     delete param[1];
8158   } // end: insert new nodes
8159
8160   MergeNodes ( nodeGroupsToMerge );
8161
8162   return aResult;
8163 }
8164
8165 //=======================================================================
8166 //function : InsertNodesIntoLink
8167 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8168 //           and theBetweenNode2 and split theElement
8169 //=======================================================================
8170
8171 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8172                                            const SMDS_MeshNode*        theBetweenNode1,
8173                                            const SMDS_MeshNode*        theBetweenNode2,
8174                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8175                                            const bool                  toCreatePoly)
8176 {
8177   if ( theFace->GetType() != SMDSAbs_Face ) return;
8178
8179   // find indices of 2 link nodes and of the rest nodes
8180   int iNode = 0, il1, il2, i3, i4;
8181   il1 = il2 = i3 = i4 = -1;
8182   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8183   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8184
8185   if(theFace->IsQuadratic()) {
8186     const SMDS_QuadraticFaceOfNodes* F =
8187       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8188     // use special nodes iterator
8189     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8190     while( anIter->more() ) {
8191       const SMDS_MeshNode* n = anIter->next();
8192       if ( n == theBetweenNode1 )
8193         il1 = iNode;
8194       else if ( n == theBetweenNode2 )
8195         il2 = iNode;
8196       else if ( i3 < 0 )
8197         i3 = iNode;
8198       else
8199         i4 = iNode;
8200       nodes[ iNode++ ] = n;
8201     }
8202   }
8203   else {
8204     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8205     while ( nodeIt->more() ) {
8206       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8207       if ( n == theBetweenNode1 )
8208         il1 = iNode;
8209       else if ( n == theBetweenNode2 )
8210         il2 = iNode;
8211       else if ( i3 < 0 )
8212         i3 = iNode;
8213       else
8214         i4 = iNode;
8215       nodes[ iNode++ ] = n;
8216     }
8217   }
8218   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8219     return ;
8220
8221   // arrange link nodes to go one after another regarding the face orientation
8222   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8223   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8224   if ( reverse ) {
8225     iNode = il1;
8226     il1 = il2;
8227     il2 = iNode;
8228     aNodesToInsert.reverse();
8229   }
8230   // check that not link nodes of a quadrangles are in good order
8231   int nbFaceNodes = theFace->NbNodes();
8232   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8233     iNode = i3;
8234     i3 = i4;
8235     i4 = iNode;
8236   }
8237
8238   if (toCreatePoly || theFace->IsPoly()) {
8239
8240     iNode = 0;
8241     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8242
8243     // add nodes of face up to first node of link
8244     bool isFLN = false;
8245
8246     if(theFace->IsQuadratic()) {
8247       const SMDS_QuadraticFaceOfNodes* F =
8248         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8249       // use special nodes iterator
8250       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8251       while( anIter->more()  && !isFLN ) {
8252         const SMDS_MeshNode* n = anIter->next();
8253         poly_nodes[iNode++] = n;
8254         if (n == nodes[il1]) {
8255           isFLN = true;
8256         }
8257       }
8258       // add nodes to insert
8259       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8260       for (; nIt != aNodesToInsert.end(); nIt++) {
8261         poly_nodes[iNode++] = *nIt;
8262       }
8263       // add nodes of face starting from last node of link
8264       while ( anIter->more() ) {
8265         poly_nodes[iNode++] = anIter->next();
8266       }
8267     }
8268     else {
8269       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8270       while ( nodeIt->more() && !isFLN ) {
8271         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8272         poly_nodes[iNode++] = n;
8273         if (n == nodes[il1]) {
8274           isFLN = true;
8275         }
8276       }
8277       // add nodes to insert
8278       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8279       for (; nIt != aNodesToInsert.end(); nIt++) {
8280         poly_nodes[iNode++] = *nIt;
8281       }
8282       // add nodes of face starting from last node of link
8283       while ( nodeIt->more() ) {
8284         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8285         poly_nodes[iNode++] = n;
8286       }
8287     }
8288
8289     // edit or replace the face
8290     SMESHDS_Mesh *aMesh = GetMeshDS();
8291
8292     if (theFace->IsPoly()) {
8293       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8294     }
8295     else {
8296       int aShapeId = FindShape( theFace );
8297
8298       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8299       myLastCreatedElems.Append(newElem);
8300       if ( aShapeId && newElem )
8301         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8302
8303       aMesh->RemoveElement(theFace);
8304     }
8305     return;
8306   }
8307
8308   if( !theFace->IsQuadratic() ) {
8309
8310     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8311     int nbLinkNodes = 2 + aNodesToInsert.size();
8312     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8313     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8314     linkNodes[ 0 ] = nodes[ il1 ];
8315     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8316     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8317     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8318       linkNodes[ iNode++ ] = *nIt;
8319     }
8320     // decide how to split a quadrangle: compare possible variants
8321     // and choose which of splits to be a quadrangle
8322     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8323     if ( nbFaceNodes == 3 ) {
8324       iBestQuad = nbSplits;
8325       i4 = i3;
8326     }
8327     else if ( nbFaceNodes == 4 ) {
8328       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8329       double aBestRate = DBL_MAX;
8330       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8331         i1 = 0; i2 = 1;
8332         double aBadRate = 0;
8333         // evaluate elements quality
8334         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8335           if ( iSplit == iQuad ) {
8336             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8337                                    linkNodes[ i2++ ],
8338                                    nodes[ i3 ],
8339                                    nodes[ i4 ]);
8340             aBadRate += getBadRate( &quad, aCrit );
8341           }
8342           else {
8343             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8344                                    linkNodes[ i2++ ],
8345                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8346             aBadRate += getBadRate( &tria, aCrit );
8347           }
8348         }
8349         // choice
8350         if ( aBadRate < aBestRate ) {
8351           iBestQuad = iQuad;
8352           aBestRate = aBadRate;
8353         }
8354       }
8355     }
8356
8357     // create new elements
8358     SMESHDS_Mesh *aMesh = GetMeshDS();
8359     int aShapeId = FindShape( theFace );
8360
8361     i1 = 0; i2 = 1;
8362     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8363       SMDS_MeshElement* newElem = 0;
8364       if ( iSplit == iBestQuad )
8365         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8366                                   linkNodes[ i2++ ],
8367                                   nodes[ i3 ],
8368                                   nodes[ i4 ]);
8369       else
8370         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8371                                   linkNodes[ i2++ ],
8372                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8373       myLastCreatedElems.Append(newElem);
8374       if ( aShapeId && newElem )
8375         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8376     }
8377
8378     // change nodes of theFace
8379     const SMDS_MeshNode* newNodes[ 4 ];
8380     newNodes[ 0 ] = linkNodes[ i1 ];
8381     newNodes[ 1 ] = linkNodes[ i2 ];
8382     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8383     newNodes[ 3 ] = nodes[ i4 ];
8384     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8385   } // end if(!theFace->IsQuadratic())
8386   else { // theFace is quadratic
8387     // we have to split theFace on simple triangles and one simple quadrangle
8388     int tmp = il1/2;
8389     int nbshift = tmp*2;
8390     // shift nodes in nodes[] by nbshift
8391     int i,j;
8392     for(i=0; i<nbshift; i++) {
8393       const SMDS_MeshNode* n = nodes[0];
8394       for(j=0; j<nbFaceNodes-1; j++) {
8395         nodes[j] = nodes[j+1];
8396       }
8397       nodes[nbFaceNodes-1] = n;
8398     }
8399     il1 = il1 - nbshift;
8400     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8401     //   n0      n1     n2    n0      n1     n2
8402     //     +-----+-----+        +-----+-----+
8403     //      \         /         |           |
8404     //       \       /          |           |
8405     //      n5+     +n3       n7+           +n3
8406     //         \   /            |           |
8407     //          \ /             |           |
8408     //           +              +-----+-----+
8409     //           n4           n6      n5     n4
8410
8411     // create new elements
8412     SMESHDS_Mesh *aMesh = GetMeshDS();
8413     int aShapeId = FindShape( theFace );
8414
8415     int n1,n2,n3;
8416     if(nbFaceNodes==6) { // quadratic triangle
8417       SMDS_MeshElement* newElem =
8418         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8419       myLastCreatedElems.Append(newElem);
8420       if ( aShapeId && newElem )
8421         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8422       if(theFace->IsMediumNode(nodes[il1])) {
8423         // create quadrangle
8424         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8425         myLastCreatedElems.Append(newElem);
8426         if ( aShapeId && newElem )
8427           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8428         n1 = 1;
8429         n2 = 2;
8430         n3 = 3;
8431       }
8432       else {
8433         // create quadrangle
8434         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8435         myLastCreatedElems.Append(newElem);
8436         if ( aShapeId && newElem )
8437           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8438         n1 = 0;
8439         n2 = 1;
8440         n3 = 5;
8441       }
8442     }
8443     else { // nbFaceNodes==8 - quadratic quadrangle
8444       SMDS_MeshElement* newElem =
8445         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8446       myLastCreatedElems.Append(newElem);
8447       if ( aShapeId && newElem )
8448         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8449       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8450       myLastCreatedElems.Append(newElem);
8451       if ( aShapeId && newElem )
8452         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8453       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8454       myLastCreatedElems.Append(newElem);
8455       if ( aShapeId && newElem )
8456         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8457       if(theFace->IsMediumNode(nodes[il1])) {
8458         // create quadrangle
8459         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8460         myLastCreatedElems.Append(newElem);
8461         if ( aShapeId && newElem )
8462           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8463         n1 = 1;
8464         n2 = 2;
8465         n3 = 3;
8466       }
8467       else {
8468         // create quadrangle
8469         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8470         myLastCreatedElems.Append(newElem);
8471         if ( aShapeId && newElem )
8472           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8473         n1 = 0;
8474         n2 = 1;
8475         n3 = 7;
8476       }
8477     }
8478     // create needed triangles using n1,n2,n3 and inserted nodes
8479     int nbn = 2 + aNodesToInsert.size();
8480     //const SMDS_MeshNode* aNodes[nbn];
8481     vector<const SMDS_MeshNode*> aNodes(nbn);
8482     aNodes[0] = nodes[n1];
8483     aNodes[nbn-1] = nodes[n2];
8484     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8485     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8486       aNodes[iNode++] = *nIt;
8487     }
8488     for(i=1; i<nbn; i++) {
8489       SMDS_MeshElement* newElem =
8490         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8491       myLastCreatedElems.Append(newElem);
8492       if ( aShapeId && newElem )
8493         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8494     }
8495     // remove old quadratic face
8496     aMesh->RemoveElement(theFace);
8497   }
8498 }
8499
8500 //=======================================================================
8501 //function : UpdateVolumes
8502 //purpose  :
8503 //=======================================================================
8504 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8505                                       const SMDS_MeshNode*        theBetweenNode2,
8506                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8507 {
8508   myLastCreatedElems.Clear();
8509   myLastCreatedNodes.Clear();
8510
8511   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8512   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8513     const SMDS_MeshElement* elem = invElemIt->next();
8514
8515     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8516     SMDS_VolumeTool aVolume (elem);
8517     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8518       continue;
8519
8520     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8521     int iface, nbFaces = aVolume.NbFaces();
8522     vector<const SMDS_MeshNode *> poly_nodes;
8523     vector<int> quantities (nbFaces);
8524
8525     for (iface = 0; iface < nbFaces; iface++) {
8526       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8527       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8528       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8529
8530       for (int inode = 0; inode < nbFaceNodes; inode++) {
8531         poly_nodes.push_back(faceNodes[inode]);
8532
8533         if (nbInserted == 0) {
8534           if (faceNodes[inode] == theBetweenNode1) {
8535             if (faceNodes[inode + 1] == theBetweenNode2) {
8536               nbInserted = theNodesToInsert.size();
8537
8538               // add nodes to insert
8539               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8540               for (; nIt != theNodesToInsert.end(); nIt++) {
8541                 poly_nodes.push_back(*nIt);
8542               }
8543             }
8544           }
8545           else if (faceNodes[inode] == theBetweenNode2) {
8546             if (faceNodes[inode + 1] == theBetweenNode1) {
8547               nbInserted = theNodesToInsert.size();
8548
8549               // add nodes to insert in reversed order
8550               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8551               nIt--;
8552               for (; nIt != theNodesToInsert.begin(); nIt--) {
8553                 poly_nodes.push_back(*nIt);
8554               }
8555               poly_nodes.push_back(*nIt);
8556             }
8557           }
8558           else {
8559           }
8560         }
8561       }
8562       quantities[iface] = nbFaceNodes + nbInserted;
8563     }
8564
8565     // Replace or update the volume
8566     SMESHDS_Mesh *aMesh = GetMeshDS();
8567
8568     if (elem->IsPoly()) {
8569       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8570
8571     }
8572     else {
8573       int aShapeId = FindShape( elem );
8574
8575       SMDS_MeshElement* newElem =
8576         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8577       myLastCreatedElems.Append(newElem);
8578       if (aShapeId && newElem)
8579         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8580
8581       aMesh->RemoveElement(elem);
8582     }
8583   }
8584 }
8585
8586 //=======================================================================
8587 /*!
8588  * \brief Convert elements contained in a submesh to quadratic
8589  * \retval int - nb of checked elements
8590  */
8591 //=======================================================================
8592
8593 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8594                                              SMESH_MesherHelper& theHelper,
8595                                              const bool          theForce3d)
8596 {
8597   int nbElem = 0;
8598   if( !theSm ) return nbElem;
8599
8600   const bool notFromGroups = false;
8601   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8602   while(ElemItr->more())
8603   {
8604     nbElem++;
8605     const SMDS_MeshElement* elem = ElemItr->next();
8606     if( !elem || elem->IsQuadratic() ) continue;
8607
8608     int id = elem->GetID();
8609     int nbNodes = elem->NbNodes();
8610     vector<const SMDS_MeshNode *> aNds (nbNodes);
8611
8612     for(int i = 0; i < nbNodes; i++)
8613     {
8614       aNds[i] = elem->GetNode(i);
8615     }
8616     SMDSAbs_ElementType aType = elem->GetType();
8617
8618     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8619
8620     const SMDS_MeshElement* NewElem = 0;
8621
8622     switch( aType )
8623     {
8624     case SMDSAbs_Edge :
8625       {
8626         NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8627         break;
8628       }
8629     case SMDSAbs_Face :
8630       {
8631         switch(nbNodes)
8632         {
8633         case 3:
8634           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8635           break;
8636         case 4:
8637           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8638           break;
8639         default:
8640           continue;
8641         }
8642         break;
8643       }
8644     case SMDSAbs_Volume :
8645       {
8646         switch(nbNodes)
8647         {
8648         case 4:
8649           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8650           break;
8651         case 5:
8652           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8653           break;
8654         case 6:
8655           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8656           break;
8657         case 8:
8658           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8659                                         aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8660           break;
8661         default:
8662           continue;
8663         }
8664         break;
8665       }
8666     default :
8667       continue;
8668     }
8669     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8670     if( NewElem )
8671       theSm->AddElement( NewElem );
8672   }
8673   return nbElem;
8674 }
8675
8676 //=======================================================================
8677 //function : ConvertToQuadratic
8678 //purpose  :
8679 //=======================================================================
8680 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8681 {
8682   SMESHDS_Mesh* meshDS = GetMeshDS();
8683
8684   SMESH_MesherHelper aHelper(*myMesh);
8685   aHelper.SetIsQuadratic( true );
8686   const bool notFromGroups = false;
8687
8688   int nbCheckedElems = 0;
8689   if ( myMesh->HasShapeToMesh() )
8690   {
8691     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8692     {
8693       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8694       while ( smIt->more() ) {
8695         SMESH_subMesh* sm = smIt->next();
8696         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8697           aHelper.SetSubShape( sm->GetSubShape() );
8698           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8699         }
8700       }
8701     }
8702   }
8703   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8704   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8705   {
8706     SMESHDS_SubMesh *smDS = 0;
8707     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8708     while(aEdgeItr->more())
8709     {
8710       const SMDS_MeshEdge* edge = aEdgeItr->next();
8711       if(edge && !edge->IsQuadratic())
8712       {
8713         int id = edge->GetID();
8714         const SMDS_MeshNode* n1 = edge->GetNode(0);
8715         const SMDS_MeshNode* n2 = edge->GetNode(1);
8716
8717         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8718
8719         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8720         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8721       }
8722     }
8723     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8724     while(aFaceItr->more())
8725     {
8726       const SMDS_MeshFace* face = aFaceItr->next();
8727       if(!face || face->IsQuadratic() ) continue;
8728
8729       int id = face->GetID();
8730       int nbNodes = face->NbNodes();
8731       vector<const SMDS_MeshNode *> aNds (nbNodes);
8732
8733       for(int i = 0; i < nbNodes; i++)
8734       {
8735         aNds[i] = face->GetNode(i);
8736       }
8737
8738       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
8739
8740       SMDS_MeshFace * NewFace = 0;
8741       switch(nbNodes)
8742       {
8743       case 3:
8744         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8745         break;
8746       case 4:
8747         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8748         break;
8749       default:
8750         continue;
8751       }
8752       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8753     }
8754     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8755     while(aVolumeItr->more())
8756     {
8757       const SMDS_MeshVolume* volume = aVolumeItr->next();
8758       if(!volume || volume->IsQuadratic() ) continue;
8759
8760       int id = volume->GetID();
8761       int nbNodes = volume->NbNodes();
8762       vector<const SMDS_MeshNode *> aNds (nbNodes);
8763
8764       for(int i = 0; i < nbNodes; i++)
8765       {
8766         aNds[i] = volume->GetNode(i);
8767       }
8768
8769       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
8770
8771       SMDS_MeshVolume * NewVolume = 0;
8772       switch(nbNodes)
8773       {
8774       case 4:
8775         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8776                                       aNds[3], id, theForce3d );
8777         break;
8778       case 5:
8779         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8780                                       aNds[3], aNds[4], id, theForce3d);
8781         break;
8782       case 6:
8783         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8784                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
8785         break;
8786       case 8:
8787         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8788                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8789         break;
8790       default:
8791         continue;
8792       }
8793       ReplaceElemInGroups(volume, NewVolume, meshDS);
8794     }
8795   }
8796   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
8797   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8798     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8799     aHelper.FixQuadraticElements();
8800   }
8801 }
8802
8803 //=======================================================================
8804 /*!
8805  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8806  * \retval int - nb of checked elements
8807  */
8808 //=======================================================================
8809
8810 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8811                                      SMDS_ElemIteratorPtr theItr,
8812                                      const int            theShapeID)
8813 {
8814   int nbElem = 0;
8815   SMESHDS_Mesh* meshDS = GetMeshDS();
8816   const bool notFromGroups = false;
8817
8818   while( theItr->more() )
8819   {
8820     const SMDS_MeshElement* elem = theItr->next();
8821     nbElem++;
8822     if( elem && elem->IsQuadratic())
8823     {
8824       int id = elem->GetID();
8825       int nbNodes = elem->NbNodes();
8826       vector<const SMDS_MeshNode *> aNds, mediumNodes;
8827       aNds.reserve( nbNodes );
8828       mediumNodes.reserve( nbNodes );
8829
8830       for(int i = 0; i < nbNodes; i++)
8831       {
8832         const SMDS_MeshNode* n = elem->GetNode(i);
8833
8834         if( elem->IsMediumNode( n ) )
8835           mediumNodes.push_back( n );
8836         else
8837           aNds.push_back( n );
8838       }
8839       if( aNds.empty() ) continue;
8840       SMDSAbs_ElementType aType = elem->GetType();
8841
8842       //remove old quadratic element
8843       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8844
8845       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
8846       ReplaceElemInGroups(elem, NewElem, meshDS);
8847       if( theSm && NewElem )
8848         theSm->AddElement( NewElem );
8849
8850       // remove medium nodes
8851       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8852       for ( ; nIt != mediumNodes.end(); ++nIt ) {
8853         const SMDS_MeshNode* n = *nIt;
8854         if ( n->NbInverseElements() == 0 ) {
8855           if ( n->GetPosition()->GetShapeId() != theShapeID )
8856             meshDS->RemoveFreeNode( n, meshDS->MeshElements
8857                                     ( n->GetPosition()->GetShapeId() ));
8858           else
8859             meshDS->RemoveFreeNode( n, theSm );
8860         }
8861       }
8862     }
8863   }
8864   return nbElem;
8865 }
8866
8867 //=======================================================================
8868 //function : ConvertFromQuadratic
8869 //purpose  :
8870 //=======================================================================
8871 bool  SMESH_MeshEditor::ConvertFromQuadratic()
8872 {
8873   int nbCheckedElems = 0;
8874   if ( myMesh->HasShapeToMesh() )
8875   {
8876     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8877     {
8878       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8879       while ( smIt->more() ) {
8880         SMESH_subMesh* sm = smIt->next();
8881         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8882           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8883       }
8884     }
8885   }
8886
8887   int totalNbElems =
8888     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8889   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8890   {
8891     SMESHDS_SubMesh *aSM = 0;
8892     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8893   }
8894
8895   return true;
8896 }
8897
8898 //=======================================================================
8899 //function : SewSideElements
8900 //purpose  :
8901 //=======================================================================
8902
8903 SMESH_MeshEditor::Sew_Error
8904 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
8905                                    TIDSortedElemSet&    theSide2,
8906                                    const SMDS_MeshNode* theFirstNode1,
8907                                    const SMDS_MeshNode* theFirstNode2,
8908                                    const SMDS_MeshNode* theSecondNode1,
8909                                    const SMDS_MeshNode* theSecondNode2)
8910 {
8911   myLastCreatedElems.Clear();
8912   myLastCreatedNodes.Clear();
8913
8914   MESSAGE ("::::SewSideElements()");
8915   if ( theSide1.size() != theSide2.size() )
8916     return SEW_DIFF_NB_OF_ELEMENTS;
8917
8918   Sew_Error aResult = SEW_OK;
8919   // Algo:
8920   // 1. Build set of faces representing each side
8921   // 2. Find which nodes of the side 1 to merge with ones on the side 2
8922   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8923
8924   // =======================================================================
8925   // 1. Build set of faces representing each side:
8926   // =======================================================================
8927   // a. build set of nodes belonging to faces
8928   // b. complete set of faces: find missing fices whose nodes are in set of nodes
8929   // c. create temporary faces representing side of volumes if correspondent
8930   //    face does not exist
8931
8932   SMESHDS_Mesh* aMesh = GetMeshDS();
8933   SMDS_Mesh aTmpFacesMesh;
8934   set<const SMDS_MeshElement*> faceSet1, faceSet2;
8935   set<const SMDS_MeshElement*> volSet1,  volSet2;
8936   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
8937   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
8938   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
8939   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8940   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
8941   int iSide, iFace, iNode;
8942
8943   for ( iSide = 0; iSide < 2; iSide++ ) {
8944     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
8945     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
8946     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8947     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
8948     set<const SMDS_MeshElement*>::iterator vIt;
8949     TIDSortedElemSet::iterator eIt;
8950     set<const SMDS_MeshNode*>::iterator    nIt;
8951
8952     // check that given nodes belong to given elements
8953     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8954     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8955     int firstIndex = -1, secondIndex = -1;
8956     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8957       const SMDS_MeshElement* elem = *eIt;
8958       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
8959       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8960       if ( firstIndex > -1 && secondIndex > -1 ) break;
8961     }
8962     if ( firstIndex < 0 || secondIndex < 0 ) {
8963       // we can simply return until temporary faces created
8964       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8965     }
8966
8967     // -----------------------------------------------------------
8968     // 1a. Collect nodes of existing faces
8969     //     and build set of face nodes in order to detect missing
8970     //     faces corresponing to sides of volumes
8971     // -----------------------------------------------------------
8972
8973     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8974
8975     // loop on the given element of a side
8976     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8977       //const SMDS_MeshElement* elem = *eIt;
8978       const SMDS_MeshElement* elem = *eIt;
8979       if ( elem->GetType() == SMDSAbs_Face ) {
8980         faceSet->insert( elem );
8981         set <const SMDS_MeshNode*> faceNodeSet;
8982         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8983         while ( nodeIt->more() ) {
8984           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8985           nodeSet->insert( n );
8986           faceNodeSet.insert( n );
8987         }
8988         setOfFaceNodeSet.insert( faceNodeSet );
8989       }
8990       else if ( elem->GetType() == SMDSAbs_Volume )
8991         volSet->insert( elem );
8992     }
8993     // ------------------------------------------------------------------------------
8994     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8995     // ------------------------------------------------------------------------------
8996
8997     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8998       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8999       while ( fIt->more() ) { // loop on faces sharing a node
9000         const SMDS_MeshElement* f = fIt->next();
9001         if ( faceSet->find( f ) == faceSet->end() ) {
9002           // check if all nodes are in nodeSet and
9003           // complete setOfFaceNodeSet if they are
9004           set <const SMDS_MeshNode*> faceNodeSet;
9005           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9006           bool allInSet = true;
9007           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9008             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9009             if ( nodeSet->find( n ) == nodeSet->end() )
9010               allInSet = false;
9011             else
9012               faceNodeSet.insert( n );
9013           }
9014           if ( allInSet ) {
9015             faceSet->insert( f );
9016             setOfFaceNodeSet.insert( faceNodeSet );
9017           }
9018         }
9019       }
9020     }
9021
9022     // -------------------------------------------------------------------------
9023     // 1c. Create temporary faces representing sides of volumes if correspondent
9024     //     face does not exist
9025     // -------------------------------------------------------------------------
9026
9027     if ( !volSet->empty() ) {
9028       //int nodeSetSize = nodeSet->size();
9029
9030       // loop on given volumes
9031       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9032         SMDS_VolumeTool vol (*vIt);
9033         // loop on volume faces: find free faces
9034         // --------------------------------------
9035         list<const SMDS_MeshElement* > freeFaceList;
9036         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9037           if ( !vol.IsFreeFace( iFace ))
9038             continue;
9039           // check if there is already a face with same nodes in a face set
9040           const SMDS_MeshElement* aFreeFace = 0;
9041           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9042           int nbNodes = vol.NbFaceNodes( iFace );
9043           set <const SMDS_MeshNode*> faceNodeSet;
9044           vol.GetFaceNodes( iFace, faceNodeSet );
9045           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9046           if ( isNewFace ) {
9047             // no such a face is given but it still can exist, check it
9048             if ( nbNodes == 3 ) {
9049               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9050             }
9051             else if ( nbNodes == 4 ) {
9052               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9053             }
9054             else {
9055               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9056               aFreeFace = aMesh->FindFace(poly_nodes);
9057             }
9058           }
9059           if ( !aFreeFace ) {
9060             // create a temporary face
9061             if ( nbNodes == 3 ) {
9062               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9063             }
9064             else if ( nbNodes == 4 ) {
9065               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9066             }
9067             else {
9068               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9069               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9070             }
9071           }
9072           if ( aFreeFace )
9073             freeFaceList.push_back( aFreeFace );
9074
9075         } // loop on faces of a volume
9076
9077         // choose one of several free faces
9078         // --------------------------------------
9079         if ( freeFaceList.size() > 1 ) {
9080           // choose a face having max nb of nodes shared by other elems of a side
9081           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9082           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9083           while ( fIt != freeFaceList.end() ) { // loop on free faces
9084             int nbSharedNodes = 0;
9085             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9086             while ( nodeIt->more() ) { // loop on free face nodes
9087               const SMDS_MeshNode* n =
9088                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9089               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9090               while ( invElemIt->more() ) {
9091                 const SMDS_MeshElement* e = invElemIt->next();
9092                 if ( faceSet->find( e ) != faceSet->end() )
9093                   nbSharedNodes++;
9094                 if ( elemSet->find( e ) != elemSet->end() )
9095                   nbSharedNodes++;
9096               }
9097             }
9098             if ( nbSharedNodes >= maxNbNodes ) {
9099               maxNbNodes = nbSharedNodes;
9100               fIt++;
9101             }
9102             else
9103               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9104           }
9105           if ( freeFaceList.size() > 1 )
9106           {
9107             // could not choose one face, use another way
9108             // choose a face most close to the bary center of the opposite side
9109             gp_XYZ aBC( 0., 0., 0. );
9110             set <const SMDS_MeshNode*> addedNodes;
9111             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9112             eIt = elemSet2->begin();
9113             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9114               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9115               while ( nodeIt->more() ) { // loop on free face nodes
9116                 const SMDS_MeshNode* n =
9117                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9118                 if ( addedNodes.insert( n ).second )
9119                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9120               }
9121             }
9122             aBC /= addedNodes.size();
9123             double minDist = DBL_MAX;
9124             fIt = freeFaceList.begin();
9125             while ( fIt != freeFaceList.end() ) { // loop on free faces
9126               double dist = 0;
9127               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9128               while ( nodeIt->more() ) { // loop on free face nodes
9129                 const SMDS_MeshNode* n =
9130                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9131                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9132                 dist += ( aBC - p ).SquareModulus();
9133               }
9134               if ( dist < minDist ) {
9135                 minDist = dist;
9136                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9137               }
9138               else
9139                 fIt = freeFaceList.erase( fIt++ );
9140             }
9141           }
9142         } // choose one of several free faces of a volume
9143
9144         if ( freeFaceList.size() == 1 ) {
9145           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9146           faceSet->insert( aFreeFace );
9147           // complete a node set with nodes of a found free face
9148           //           for ( iNode = 0; iNode < ; iNode++ )
9149           //             nodeSet->insert( fNodes[ iNode ] );
9150         }
9151
9152       } // loop on volumes of a side
9153
9154       //       // complete a set of faces if new nodes in a nodeSet appeared
9155       //       // ----------------------------------------------------------
9156       //       if ( nodeSetSize != nodeSet->size() ) {
9157       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9158       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9159       //           while ( fIt->more() ) { // loop on faces sharing a node
9160       //             const SMDS_MeshElement* f = fIt->next();
9161       //             if ( faceSet->find( f ) == faceSet->end() ) {
9162       //               // check if all nodes are in nodeSet and
9163       //               // complete setOfFaceNodeSet if they are
9164       //               set <const SMDS_MeshNode*> faceNodeSet;
9165       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9166       //               bool allInSet = true;
9167       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9168       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9169       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9170       //                   allInSet = false;
9171       //                 else
9172       //                   faceNodeSet.insert( n );
9173       //               }
9174       //               if ( allInSet ) {
9175       //                 faceSet->insert( f );
9176       //                 setOfFaceNodeSet.insert( faceNodeSet );
9177       //               }
9178       //             }
9179       //           }
9180       //         }
9181       //       }
9182     } // Create temporary faces, if there are volumes given
9183   } // loop on sides
9184
9185   if ( faceSet1.size() != faceSet2.size() ) {
9186     // delete temporary faces: they are in reverseElements of actual nodes
9187     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9188     while ( tmpFaceIt->more() )
9189       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9190     MESSAGE("Diff nb of faces");
9191     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9192   }
9193
9194   // ============================================================
9195   // 2. Find nodes to merge:
9196   //              bind a node to remove to a node to put instead
9197   // ============================================================
9198
9199   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9200   if ( theFirstNode1 != theFirstNode2 )
9201     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9202   if ( theSecondNode1 != theSecondNode2 )
9203     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9204
9205   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9206   set< long > linkIdSet; // links to process
9207   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9208
9209   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9210   list< NLink > linkList[2];
9211   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9212   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9213   // loop on links in linkList; find faces by links and append links
9214   // of the found faces to linkList
9215   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9216   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9217     NLink link[] = { *linkIt[0], *linkIt[1] };
9218     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9219     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9220       continue;
9221
9222     // by links, find faces in the face sets,
9223     // and find indices of link nodes in the found faces;
9224     // in a face set, there is only one or no face sharing a link
9225     // ---------------------------------------------------------------
9226
9227     const SMDS_MeshElement* face[] = { 0, 0 };
9228     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9229     vector<const SMDS_MeshNode*> fnodes1(9);
9230     vector<const SMDS_MeshNode*> fnodes2(9);
9231     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9232     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9233     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9234     int iLinkNode[2][2];
9235     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9236       const SMDS_MeshNode* n1 = link[iSide].first;
9237       const SMDS_MeshNode* n2 = link[iSide].second;
9238       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9239       set< const SMDS_MeshElement* > fMap;
9240       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9241         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9242         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9243         while ( fIt->more() ) { // loop on faces sharing a node
9244           const SMDS_MeshElement* f = fIt->next();
9245           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9246               ! fMap.insert( f ).second ) // f encounters twice
9247           {
9248             if ( face[ iSide ] ) {
9249               MESSAGE( "2 faces per link " );
9250               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9251               break;
9252             }
9253             face[ iSide ] = f;
9254             faceSet->erase( f );
9255             // get face nodes and find ones of a link
9256             iNode = 0;
9257             int nbl = -1;
9258             if(f->IsPoly()) {
9259               if(iSide==0) {
9260                 fnodes1.resize(f->NbNodes()+1);
9261                 notLinkNodes1.resize(f->NbNodes()-2);
9262               }
9263               else {
9264                 fnodes2.resize(f->NbNodes()+1);
9265                 notLinkNodes2.resize(f->NbNodes()-2);
9266               }
9267             }
9268             if(!f->IsQuadratic()) {
9269               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9270               while ( nIt->more() ) {
9271                 const SMDS_MeshNode* n =
9272                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9273                 if ( n == n1 ) {
9274                   iLinkNode[ iSide ][ 0 ] = iNode;
9275                 }
9276                 else if ( n == n2 ) {
9277                   iLinkNode[ iSide ][ 1 ] = iNode;
9278                 }
9279                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9280                 //  notLinkNodes[ iSide ][ 1 ] = n;
9281                 //else
9282                 //  notLinkNodes[ iSide ][ 0 ] = n;
9283                 else {
9284                   nbl++;
9285                   if(iSide==0)
9286                     notLinkNodes1[nbl] = n;
9287                   //notLinkNodes1.push_back(n);
9288                   else
9289                     notLinkNodes2[nbl] = n;
9290                   //notLinkNodes2.push_back(n);
9291                 }
9292                 //faceNodes[ iSide ][ iNode++ ] = n;
9293                 if(iSide==0) {
9294                   fnodes1[iNode++] = n;
9295                 }
9296                 else {
9297                   fnodes2[iNode++] = n;
9298                 }
9299               }
9300             }
9301             else { // f->IsQuadratic()
9302               const SMDS_QuadraticFaceOfNodes* F =
9303                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9304               // use special nodes iterator
9305               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9306               while ( anIter->more() ) {
9307                 const SMDS_MeshNode* n =
9308                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9309                 if ( n == n1 ) {
9310                   iLinkNode[ iSide ][ 0 ] = iNode;
9311                 }
9312                 else if ( n == n2 ) {
9313                   iLinkNode[ iSide ][ 1 ] = iNode;
9314                 }
9315                 else {
9316                   nbl++;
9317                   if(iSide==0) {
9318                     notLinkNodes1[nbl] = n;
9319                   }
9320                   else {
9321                     notLinkNodes2[nbl] = n;
9322                   }
9323                 }
9324                 if(iSide==0) {
9325                   fnodes1[iNode++] = n;
9326                 }
9327                 else {
9328                   fnodes2[iNode++] = n;
9329                 }
9330               }
9331             }
9332             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9333             if(iSide==0) {
9334               fnodes1[iNode] = fnodes1[0];
9335             }
9336             else {
9337               fnodes2[iNode] = fnodes1[0];
9338             }
9339           }
9340         }
9341       }
9342     }
9343
9344     // check similarity of elements of the sides
9345     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9346       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9347       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9348         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9349       }
9350       else {
9351         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9352       }
9353       break; // do not return because it s necessary to remove tmp faces
9354     }
9355
9356     // set nodes to merge
9357     // -------------------
9358
9359     if ( face[0] && face[1] )  {
9360       int nbNodes = face[0]->NbNodes();
9361       if ( nbNodes != face[1]->NbNodes() ) {
9362         MESSAGE("Diff nb of face nodes");
9363         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9364         break; // do not return because it s necessary to remove tmp faces
9365       }
9366       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9367       if ( nbNodes == 3 ) {
9368         //nReplaceMap.insert( TNodeNodeMap::value_type
9369         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9370         nReplaceMap.insert( TNodeNodeMap::value_type
9371                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9372       }
9373       else {
9374         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9375           // analyse link orientation in faces
9376           int i1 = iLinkNode[ iSide ][ 0 ];
9377           int i2 = iLinkNode[ iSide ][ 1 ];
9378           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9379           // if notLinkNodes are the first and the last ones, then
9380           // their order does not correspond to the link orientation
9381           if (( i1 == 1 && i2 == 2 ) ||
9382               ( i1 == 2 && i2 == 1 ))
9383             reverse[ iSide ] = !reverse[ iSide ];
9384         }
9385         if ( reverse[0] == reverse[1] ) {
9386           //nReplaceMap.insert( TNodeNodeMap::value_type
9387           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9388           //nReplaceMap.insert( TNodeNodeMap::value_type
9389           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9390           for(int nn=0; nn<nbNodes-2; nn++) {
9391             nReplaceMap.insert( TNodeNodeMap::value_type
9392                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9393           }
9394         }
9395         else {
9396           //nReplaceMap.insert( TNodeNodeMap::value_type
9397           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9398           //nReplaceMap.insert( TNodeNodeMap::value_type
9399           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9400           for(int nn=0; nn<nbNodes-2; nn++) {
9401             nReplaceMap.insert( TNodeNodeMap::value_type
9402                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9403           }
9404         }
9405       }
9406
9407       // add other links of the faces to linkList
9408       // -----------------------------------------
9409
9410       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9411       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9412         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9413         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9414         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9415         if ( !iter_isnew.second ) { // already in a set: no need to process
9416           linkIdSet.erase( iter_isnew.first );
9417         }
9418         else // new in set == encountered for the first time: add
9419         {
9420           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9421           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9422           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9423           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9424           linkList[0].push_back ( NLink( n1, n2 ));
9425           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9426         }
9427       }
9428     } // 2 faces found
9429   } // loop on link lists
9430
9431   if ( aResult == SEW_OK &&
9432        ( linkIt[0] != linkList[0].end() ||
9433          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9434     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9435              " " << (faceSetPtr[1]->empty()));
9436     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9437   }
9438
9439   // ====================================================================
9440   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9441   // ====================================================================
9442
9443   // delete temporary faces: they are in reverseElements of actual nodes
9444   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9445   while ( tmpFaceIt->more() )
9446     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9447
9448   if ( aResult != SEW_OK)
9449     return aResult;
9450
9451   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9452   // loop on nodes replacement map
9453   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9454   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9455     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9456       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9457       nodeIDsToRemove.push_back( nToRemove->GetID() );
9458       // loop on elements sharing nToRemove
9459       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9460       while ( invElemIt->more() ) {
9461         const SMDS_MeshElement* e = invElemIt->next();
9462         // get a new suite of nodes: make replacement
9463         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9464         vector< const SMDS_MeshNode*> nodes( nbNodes );
9465         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9466         while ( nIt->more() ) {
9467           const SMDS_MeshNode* n =
9468             static_cast<const SMDS_MeshNode*>( nIt->next() );
9469           nnIt = nReplaceMap.find( n );
9470           if ( nnIt != nReplaceMap.end() ) {
9471             nbReplaced++;
9472             n = (*nnIt).second;
9473           }
9474           nodes[ i++ ] = n;
9475         }
9476         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9477         //         elemIDsToRemove.push_back( e->GetID() );
9478         //       else
9479         if ( nbReplaced )
9480           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9481       }
9482     }
9483
9484   Remove( nodeIDsToRemove, true );
9485
9486   return aResult;
9487 }
9488
9489 //================================================================================
9490 /*!
9491  * \brief Find corresponding nodes in two sets of faces
9492  * \param theSide1 - first face set
9493  * \param theSide2 - second first face
9494  * \param theFirstNode1 - a boundary node of set 1
9495  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9496  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9497  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9498  * \param nReplaceMap - output map of corresponding nodes
9499  * \retval bool  - is a success or not
9500  */
9501 //================================================================================
9502
9503 #ifdef _DEBUG_
9504 //#define DEBUG_MATCHING_NODES
9505 #endif
9506
9507 SMESH_MeshEditor::Sew_Error
9508 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9509                                     set<const SMDS_MeshElement*>& theSide2,
9510                                     const SMDS_MeshNode*          theFirstNode1,
9511                                     const SMDS_MeshNode*          theFirstNode2,
9512                                     const SMDS_MeshNode*          theSecondNode1,
9513                                     const SMDS_MeshNode*          theSecondNode2,
9514                                     TNodeNodeMap &                nReplaceMap)
9515 {
9516   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9517
9518   nReplaceMap.clear();
9519   if ( theFirstNode1 != theFirstNode2 )
9520     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9521   if ( theSecondNode1 != theSecondNode2 )
9522     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9523
9524   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9525   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9526
9527   list< NLink > linkList[2];
9528   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9529   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9530
9531   // loop on links in linkList; find faces by links and append links
9532   // of the found faces to linkList
9533   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9534   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9535     NLink link[] = { *linkIt[0], *linkIt[1] };
9536     if ( linkSet.find( link[0] ) == linkSet.end() )
9537       continue;
9538
9539     // by links, find faces in the face sets,
9540     // and find indices of link nodes in the found faces;
9541     // in a face set, there is only one or no face sharing a link
9542     // ---------------------------------------------------------------
9543
9544     const SMDS_MeshElement* face[] = { 0, 0 };
9545     list<const SMDS_MeshNode*> notLinkNodes[2];
9546     //bool reverse[] = { false, false }; // order of notLinkNodes
9547     int nbNodes[2];
9548     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9549     {
9550       const SMDS_MeshNode* n1 = link[iSide].first;
9551       const SMDS_MeshNode* n2 = link[iSide].second;
9552       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9553       set< const SMDS_MeshElement* > facesOfNode1;
9554       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9555       {
9556         // during a loop of the first node, we find all faces around n1,
9557         // during a loop of the second node, we find one face sharing both n1 and n2
9558         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9559         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9560         while ( fIt->more() ) { // loop on faces sharing a node
9561           const SMDS_MeshElement* f = fIt->next();
9562           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9563               ! facesOfNode1.insert( f ).second ) // f encounters twice
9564           {
9565             if ( face[ iSide ] ) {
9566               MESSAGE( "2 faces per link " );
9567               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9568             }
9569             face[ iSide ] = f;
9570             faceSet->erase( f );
9571
9572             // get not link nodes
9573             int nbN = f->NbNodes();
9574             if ( f->IsQuadratic() )
9575               nbN /= 2;
9576             nbNodes[ iSide ] = nbN;
9577             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9578             int i1 = f->GetNodeIndex( n1 );
9579             int i2 = f->GetNodeIndex( n2 );
9580             int iEnd = nbN, iBeg = -1, iDelta = 1;
9581             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9582             if ( reverse ) {
9583               std::swap( iEnd, iBeg ); iDelta = -1;
9584             }
9585             int i = i2;
9586             while ( true ) {
9587               i += iDelta;
9588               if ( i == iEnd ) i = iBeg + iDelta;
9589               if ( i == i1 ) break;
9590               nodes.push_back ( f->GetNode( i ) );
9591             }
9592           }
9593         }
9594       }
9595     }
9596     // check similarity of elements of the sides
9597     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9598       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9599       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9600         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9601       }
9602       else {
9603         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9604       }
9605     }
9606
9607     // set nodes to merge
9608     // -------------------
9609
9610     if ( face[0] && face[1] )  {
9611       if ( nbNodes[0] != nbNodes[1] ) {
9612         MESSAGE("Diff nb of face nodes");
9613         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9614       }
9615 #ifdef DEBUG_MATCHING_NODES
9616       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9617                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9618                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9619 #endif
9620       int nbN = nbNodes[0];
9621       {
9622         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9623         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9624         for ( int i = 0 ; i < nbN - 2; ++i ) {
9625 #ifdef DEBUG_MATCHING_NODES
9626           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9627 #endif
9628           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9629         }
9630       }
9631
9632       // add other links of the face 1 to linkList
9633       // -----------------------------------------
9634
9635       const SMDS_MeshElement* f0 = face[0];
9636       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9637       for ( int i = 0; i < nbN; i++ )
9638       {
9639         const SMDS_MeshNode* n2 = f0->GetNode( i );
9640         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9641           linkSet.insert( SMESH_TLink( n1, n2 ));
9642         if ( !iter_isnew.second ) { // already in a set: no need to process
9643           linkSet.erase( iter_isnew.first );
9644         }
9645         else // new in set == encountered for the first time: add
9646         {
9647 #ifdef DEBUG_MATCHING_NODES
9648           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9649                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9650 #endif
9651           linkList[0].push_back ( NLink( n1, n2 ));
9652           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9653         }
9654         n1 = n2;
9655       }
9656     } // 2 faces found
9657   } // loop on link lists
9658
9659   return SEW_OK;
9660 }
9661
9662 //================================================================================
9663 /*!
9664   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9665   \param theElems - the list of elements (edges or faces) to be replicated
9666   The nodes for duplication could be found from these elements
9667   \param theNodesNot - list of nodes to NOT replicate
9668   \param theAffectedElems - the list of elements (cells and edges) to which the 
9669   replicated nodes should be associated to.
9670   \return TRUE if operation has been completed successfully, FALSE otherwise
9671 */
9672 //================================================================================
9673
9674 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9675                                     const TIDSortedElemSet& theNodesNot,
9676                                     const TIDSortedElemSet& theAffectedElems )
9677 {
9678   myLastCreatedElems.Clear();
9679   myLastCreatedNodes.Clear();
9680
9681   if ( theElems.size() == 0 )
9682     return false;
9683
9684   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9685   if ( !aMeshDS )
9686     return false;
9687
9688   bool res = false;
9689   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9690   // duplicate elements and nodes
9691   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9692   // replce nodes by duplications
9693   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9694   return res;
9695 }
9696
9697 //================================================================================
9698 /*!
9699   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9700   \param theMeshDS - mesh instance
9701   \param theElems - the elements replicated or modified (nodes should be changed)
9702   \param theNodesNot - nodes to NOT replicate
9703   \param theNodeNodeMap - relation of old node to new created node
9704   \param theIsDoubleElem - flag os to replicate element or modify
9705   \return TRUE if operation has been completed successfully, FALSE otherwise
9706 */
9707 //================================================================================
9708
9709 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9710                                     const TIDSortedElemSet& theElems,
9711                                     const TIDSortedElemSet& theNodesNot,
9712                                     std::map< const SMDS_MeshNode*,
9713                                     const SMDS_MeshNode* >& theNodeNodeMap,
9714                                     const bool theIsDoubleElem )
9715 {
9716   // iterate on through element and duplicate them (by nodes duplication)
9717   bool res = false;
9718   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9719   for ( ;  elemItr != theElems.end(); ++elemItr )
9720   {
9721     const SMDS_MeshElement* anElem = *elemItr;
9722     if (!anElem)
9723       continue;
9724
9725     bool isDuplicate = false;
9726     // duplicate nodes to duplicate element
9727     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9728     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9729     int ind = 0;
9730     while ( anIter->more() ) 
9731     { 
9732
9733       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9734       SMDS_MeshNode* aNewNode = aCurrNode;
9735       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9736         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9737       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9738       {
9739         // duplicate node
9740         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9741         theNodeNodeMap[ aCurrNode ] = aNewNode;
9742         myLastCreatedNodes.Append( aNewNode );
9743       }
9744       isDuplicate |= (aCurrNode != aNewNode);
9745       newNodes[ ind++ ] = aNewNode;
9746     }
9747     if ( !isDuplicate )
9748       continue;
9749
9750     if ( theIsDoubleElem )
9751       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
9752     else
9753       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9754
9755     res = true;
9756   }
9757   return res;
9758 }
9759
9760 //================================================================================
9761 /*!
9762   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9763   \param theNodes - identifiers of nodes to be doubled
9764   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
9765          nodes. If list of element identifiers is empty then nodes are doubled but 
9766          they not assigned to elements
9767   \return TRUE if operation has been completed successfully, FALSE otherwise
9768 */
9769 //================================================================================
9770
9771 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
9772                                     const std::list< int >& theListOfModifiedElems )
9773 {
9774   myLastCreatedElems.Clear();
9775   myLastCreatedNodes.Clear();
9776
9777   if ( theListOfNodes.size() == 0 )
9778     return false;
9779
9780   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9781   if ( !aMeshDS )
9782     return false;
9783
9784   // iterate through nodes and duplicate them
9785
9786   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9787
9788   std::list< int >::const_iterator aNodeIter;
9789   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9790   {
9791     int aCurr = *aNodeIter;
9792     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9793     if ( !aNode )
9794       continue;
9795
9796     // duplicate node
9797
9798     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9799     if ( aNewNode )
9800     {
9801       anOldNodeToNewNode[ aNode ] = aNewNode;
9802       myLastCreatedNodes.Append( aNewNode );
9803     }
9804   }
9805
9806   // Create map of new nodes for modified elements
9807
9808   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9809
9810   std::list< int >::const_iterator anElemIter;
9811   for ( anElemIter = theListOfModifiedElems.begin(); 
9812         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9813   {
9814     int aCurr = *anElemIter;
9815     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9816     if ( !anElem )
9817       continue;
9818
9819     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9820
9821     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9822     int ind = 0;
9823     while ( anIter->more() ) 
9824     { 
9825       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9826       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9827       {
9828         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9829         aNodeArr[ ind++ ] = aNewNode;
9830       }
9831       else
9832         aNodeArr[ ind++ ] = aCurrNode;
9833     }
9834     anElemToNodes[ anElem ] = aNodeArr;
9835   }
9836
9837   // Change nodes of elements  
9838
9839   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9840     anElemToNodesIter = anElemToNodes.begin();
9841   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9842   {
9843     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9844     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9845     if ( anElem )
9846       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9847   }
9848
9849   return true;
9850 }
9851
9852 namespace {
9853
9854   //================================================================================
9855   /*!
9856   \brief Check if element located inside shape
9857   \return TRUE if IN or ON shape, FALSE otherwise
9858   */
9859   //================================================================================
9860
9861   template<class Classifier>
9862   bool isInside(const SMDS_MeshElement* theElem,
9863                 Classifier&             theClassifier,
9864                 const double            theTol)
9865   {
9866     gp_XYZ centerXYZ (0, 0, 0);
9867     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9868     while (aNodeItr->more())
9869       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9870
9871     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9872     theClassifier.Perform(aPnt, theTol);
9873     TopAbs_State aState = theClassifier.State();
9874     return (aState == TopAbs_IN || aState == TopAbs_ON );
9875   }
9876
9877   //================================================================================
9878   /*!
9879    * \brief Classifier of the 3D point on the TopoDS_Face
9880    *        with interaface suitable for isInside()
9881    */
9882   //================================================================================
9883
9884   struct _FaceClassifier
9885   {
9886     Extrema_ExtPS       _extremum;
9887     BRepAdaptor_Surface _surface;
9888     TopAbs_State        _state;
9889
9890     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9891     {
9892       _extremum.Initialize( _surface,
9893                             _surface.FirstUParameter(), _surface.LastUParameter(),
9894                             _surface.FirstVParameter(), _surface.LastVParameter(),
9895                             _surface.Tolerance(), _surface.Tolerance() );
9896     }
9897     void Perform(const gp_Pnt& aPnt, double theTol)
9898     {
9899       _state = TopAbs_OUT;
9900       _extremum.Perform(aPnt);
9901       if ( _extremum.IsDone() )
9902         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9903           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9904     }
9905     TopAbs_State State() const
9906     {
9907       return _state;
9908     }
9909   };
9910 }
9911
9912 //================================================================================
9913 /*!
9914   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9915   \param theElems - group of of elements (edges or faces) to be replicated
9916   \param theNodesNot - group of nodes not to replicate
9917   \param theShape - shape to detect affected elements (element which geometric center
9918   located on or inside shape).
9919   The replicated nodes should be associated to affected elements.
9920   \return TRUE if operation has been completed successfully, FALSE otherwise
9921 */
9922 //================================================================================
9923
9924 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
9925                                             const TIDSortedElemSet& theNodesNot,
9926                                             const TopoDS_Shape&     theShape )
9927 {
9928   if ( theShape.IsNull() )
9929     return false;
9930
9931   const double aTol = Precision::Confusion();
9932   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9933   auto_ptr<_FaceClassifier>              aFaceClassifier;
9934   if ( theShape.ShapeType() == TopAbs_SOLID )
9935   {
9936     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9937     bsc3d->PerformInfinitePoint(aTol);
9938   }
9939   else if (theShape.ShapeType() == TopAbs_FACE )
9940   {
9941     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9942   }
9943
9944   // iterates on indicated elements and get elements by back references from their nodes
9945   TIDSortedElemSet anAffected;
9946   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9947   for ( ;  elemItr != theElems.end(); ++elemItr )
9948   {
9949     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9950     if (!anElem)
9951       continue;
9952
9953     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9954     while ( nodeItr->more() )
9955     {
9956       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9957       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9958         continue;
9959       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9960       while ( backElemItr->more() )
9961       {
9962         const SMDS_MeshElement* curElem = backElemItr->next();
9963         if ( curElem && theElems.find(curElem) == theElems.end() &&
9964              ( bsc3d.get() ?
9965                isInside( curElem, *bsc3d, aTol ) :
9966                isInside( curElem, *aFaceClassifier, aTol )))
9967           anAffected.insert( curElem );
9968       }
9969     }
9970   }
9971   return DoubleNodes( theElems, theNodesNot, anAffected );
9972 }
9973
9974 //================================================================================
9975 /*!
9976  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
9977  * The created 2D mesh elements based on nodes of free faces of boundary volumes
9978  * \return TRUE if operation has been completed successfully, FALSE otherwise
9979  */
9980 //================================================================================
9981
9982 bool SMESH_MeshEditor::Make2DMeshFrom3D()
9983 {
9984   // iterates on volume elements and detect all free faces on them
9985   SMESHDS_Mesh* aMesh = GetMeshDS();
9986   if (!aMesh)
9987     return false;
9988   //bool res = false;
9989   int nbFree = 0, nbExisted = 0, nbCreated = 0;
9990   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
9991   while(vIt->more())
9992   {
9993     const SMDS_MeshVolume* volume = vIt->next();
9994     SMDS_VolumeTool vTool( volume );
9995     vTool.SetExternalNormal();
9996     const bool isPoly = volume->IsPoly();
9997     const bool isQuad = volume->IsQuadratic();
9998     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9999     {
10000       if (!vTool.IsFreeFace(iface))
10001         continue;
10002       nbFree++;
10003       vector<const SMDS_MeshNode *> nodes;
10004       int nbFaceNodes = vTool.NbFaceNodes(iface);
10005       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10006       int inode = 0;
10007       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10008         nodes.push_back(faceNodes[inode]);
10009       if (isQuad)
10010         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10011           nodes.push_back(faceNodes[inode]);
10012
10013       // add new face based on volume nodes
10014       if (aMesh->FindFace( nodes ) ) {
10015         nbExisted++;
10016         continue; // face already exsist
10017       }
10018       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10019       nbCreated++;
10020     }
10021   }
10022   return ( nbFree==(nbExisted+nbCreated) );
10023 }