Salome HOME
0020889: EDF 1433 SMESH: SplitHexaToTetra: add the 24 tetras mode
[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     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1246
1247     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1248       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1249     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1250     bool hasFacet( const TTriangleFacet& facet ) const
1251     {
1252       const int* tetConn = _connectivity;
1253       for ( ; tetConn[0] >= 0; tetConn += 4 )
1254         if (( facet.contains( tetConn[0] ) +
1255               facet.contains( tetConn[1] ) +
1256               facet.contains( tetConn[2] ) +
1257               facet.contains( tetConn[3] )) == 3 )
1258           return true;
1259       return false;
1260     }
1261   };
1262
1263   //=======================================================================
1264   /*!
1265    * \brief return TSplitMethod for the given element
1266    */
1267   //=======================================================================
1268
1269   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1270   {
1271     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1272
1273     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1274     // an edge and a face barycenter; tertaherdons are based on triangles and
1275     // a volume barycenter
1276     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1277
1278     // Find out how adjacent volumes are split
1279
1280     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1281     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1282     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1283     {
1284       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1285       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1286       if ( nbNodes < 4 ) continue;
1287
1288       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1289       const int* nInd = vol.GetFaceNodesIndices( iF );
1290       if ( nbNodes == 4 )
1291       {
1292         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1293         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1294         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1295         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1296       }
1297       else
1298       {
1299         int iCom = 0; // common node of triangle faces to split into
1300         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1301         {
1302           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1303                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1304                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1305           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1306                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1307                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1308           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1309           {
1310             triaSplits.push_back( t012 );
1311             triaSplits.push_back( t023 );
1312             break;
1313           }
1314         }
1315       }
1316       if ( !triaSplits.empty() )
1317         hasAdjacentSplits = true;
1318     }
1319
1320     // Among variants of split method select one compliant with adjacent volumes
1321
1322     TSplitMethod method;
1323     if ( !vol.Element()->IsPoly() && !is24TetMode )
1324     {
1325       int nbVariants = 2, nbTet = 0;
1326       const int** connVariants = 0;
1327       switch ( vol.Element()->GetEntityType() )
1328       {
1329       case SMDSEntity_Hexa:
1330       case SMDSEntity_Quad_Hexa:
1331         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1332           connVariants = theHexTo5, nbTet = 5;
1333         else
1334           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1335         break;
1336       case SMDSEntity_Pyramid:
1337       case SMDSEntity_Quad_Pyramid:
1338         connVariants = thePyraTo2;  nbTet = 2;
1339         break;
1340       case SMDSEntity_Penta:
1341       case SMDSEntity_Quad_Penta:
1342         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1343         break;
1344       default:
1345         nbVariants = 0;
1346       }
1347       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1348       {
1349         // check method compliancy with adjacent tetras,
1350         // all found splits must be among facets of tetras described by this method
1351         method = TSplitMethod( nbTet, connVariants[variant] );
1352         if ( hasAdjacentSplits && method._nbTetra > 0 )
1353         {
1354           bool facetCreated = true;
1355           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1356           {
1357             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1358             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1359               facetCreated = method.hasFacet( *facet );
1360           }
1361           if ( !facetCreated )
1362             method = TSplitMethod(0); // incompatible method
1363         }
1364       }
1365     }
1366     if ( method._nbTetra < 1 )
1367     {
1368       // No standard method is applicable, use a generic solution:
1369       // each facet of a volume is split into triangles and
1370       // each of triangles and a volume barycenter form a tetrahedron.
1371
1372       int* connectivity = new int[ maxTetConnSize + 1 ];
1373       method._connectivity = connectivity;
1374       method._ownConn = true;
1375       method._baryNode = true;
1376
1377       int connSize = 0;
1378       int baryCenInd = vol.NbNodes();
1379       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1380       {
1381         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1382         const int*   nInd = vol.GetFaceNodesIndices( iF );
1383         // find common node of triangle facets of tetra to create
1384         int iCommon = 0; // index in linear numeration
1385         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1386         if ( !triaSplits.empty() )
1387         {
1388           // by found facets
1389           const TTriangleFacet* facet = &triaSplits.front();
1390           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1391             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1392                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1393               break;
1394         }
1395         else if ( nbNodes > 3 && !is24TetMode )
1396         {
1397           // find the best method of splitting into triangles by aspect ratio
1398           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1399           map< double, int > badness2iCommon;
1400           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1401           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1402           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1403             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1404             {
1405               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1406                                       nodes[ iQ*((iLast-1)%nbNodes)],
1407                                       nodes[ iQ*((iLast  )%nbNodes)]);
1408               double badness = getBadRate( &tria, aspectRatio );
1409               badness2iCommon.insert( make_pair( badness, iCommon ));
1410             }
1411           // use iCommon with lowest badness
1412           iCommon = badness2iCommon.begin()->second;
1413         }
1414         if ( iCommon >= nbNodes )
1415           iCommon = 0; // something wrong
1416
1417         // fill connectivity of tetrahedra based on a current face
1418         int nbTet = nbNodes - 2;
1419         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1420         {
1421           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1422           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1423           nbTet = nbNodes;
1424           for ( int i = 0; i < nbTet; ++i )
1425           {
1426             int i1 = i, i2 = (i+1) % nbNodes;
1427             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1428             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1429             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1430             connectivity[ connSize++ ] = faceBaryCenInd;
1431             connectivity[ connSize++ ] = baryCenInd;
1432           }
1433         }
1434         else
1435         {
1436           for ( int i = 0; i < nbTet; ++i )
1437           {
1438             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1439             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1440             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1441             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1442             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1443             connectivity[ connSize++ ] = baryCenInd;
1444           }
1445         }
1446         method._nbTetra += nbTet;
1447       }
1448       connectivity[ connSize++ ] = -1;
1449     }
1450     return method;
1451   }
1452   //================================================================================
1453   /*!
1454    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1455    */
1456   //================================================================================
1457
1458   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1459   {
1460     // find the tetrahedron including the three nodes of facet
1461     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1462     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1463     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1464     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1465     while ( volIt1->more() )
1466     {
1467       const SMDS_MeshElement* v = volIt1->next();
1468       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1469         continue;
1470       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1471       while ( volIt2->more() )
1472         if ( v != volIt2->next() )
1473           continue;
1474       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1475       while ( volIt3->more() )
1476         if ( v == volIt3->next() )
1477           return true;
1478     }
1479     return false;
1480   }
1481
1482   //=======================================================================
1483   /*!
1484    * \brief A key of a face of volume
1485    */
1486   //=======================================================================
1487
1488   struct TVolumeFaceKey: pair< int, pair< int, int> >
1489   {
1490     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1491     {
1492       TIDSortedNodeSet sortedNodes;
1493       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1494       int nbNodes = vol.NbFaceNodes( iF );
1495       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1496       for ( int i = 0; i < nbNodes; i += iQ )
1497         sortedNodes.insert( fNodes[i] );
1498       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1499       first = (*(n++))->GetID();
1500       second.first = (*(n++))->GetID();
1501       second.second = (*(n++))->GetID();
1502     }
1503   };
1504 } // namespace
1505
1506 //=======================================================================
1507 //function : SplitVolumesIntoTetra
1508 //purpose  : Split volumic elements into tetrahedra.
1509 //=======================================================================
1510
1511 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1512                                               const int                theMethodFlags)
1513 {
1514   // std-like iterator on coordinates of nodes of mesh element
1515   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1516   NXyzIterator xyzEnd;
1517
1518   SMDS_VolumeTool    volTool;
1519   SMESH_MesherHelper helper( *GetMesh());
1520
1521   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1522   SMESHDS_SubMesh* fSubMesh = subMesh;
1523   
1524   SMESH_SequenceOfElemPtr newNodes, newElems;
1525
1526   // map face of volume to it's baricenrtic node
1527   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1528   double bc[3];
1529
1530   TIDSortedElemSet::const_iterator elem = theElems.begin();
1531   for ( ; elem != theElems.end(); ++elem )
1532   {
1533     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1534     if ( geomType <= SMDSEntity_Quad_Tetra )
1535       continue; // tetra or face or ...
1536
1537     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1538
1539     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1540     if ( splitMethod._nbTetra < 1 ) continue;
1541
1542     // find submesh to add new tetras to
1543     if ( !subMesh || !subMesh->Contains( *elem ))
1544     {
1545       int shapeID = FindShape( *elem );
1546       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1547       subMesh = GetMeshDS()->MeshElements( shapeID );
1548     }
1549     int iQ;
1550     if ( (*elem)->IsQuadratic() )
1551     {
1552       iQ = 2;
1553       // add quadratic links to the helper
1554       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1555       {
1556         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1557         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1558           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1559       }
1560       helper.SetIsQuadratic( true );
1561     }
1562     else
1563     {
1564       iQ = 1;
1565       helper.SetIsQuadratic( false );
1566     }
1567     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1568     if ( splitMethod._baryNode )
1569     {
1570       // make a node at barycenter
1571       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1572       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1573       nodes.push_back( gcNode );
1574       newNodes.Append( gcNode );
1575     }
1576     if ( !splitMethod._faceBaryNode.empty() )
1577     {
1578       // make or find baricentric nodes of faces
1579       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1580       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1581       {
1582         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1583           volFace2BaryNode.insert
1584           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1585         if ( !f_n->second )
1586         {
1587           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1588           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1589         }
1590         nodes.push_back( iF_n->second = f_n->second );
1591       }
1592     }
1593
1594     // make tetras
1595     helper.SetElementsOnShape( true );
1596     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1597     const int* tetConn = splitMethod._connectivity;
1598     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1599       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1600                                                        nodes[ tetConn[1] ],
1601                                                        nodes[ tetConn[2] ],
1602                                                        nodes[ tetConn[3] ]));
1603
1604     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1605
1606     // Split faces on sides of the split volume
1607
1608     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1609     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1610     {
1611       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1612       if ( nbNodes < 4 ) continue;
1613
1614       // find an existing face
1615       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1616                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1617       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1618       {
1619         // make triangles
1620         helper.SetElementsOnShape( false );
1621         vector< const SMDS_MeshElement* > triangles;
1622
1623         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1624         if ( iF_n != splitMethod._faceBaryNode.end() )
1625         {
1626           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1627           {
1628             const SMDS_MeshNode* n1 = fNodes[iN];
1629             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1630             const SMDS_MeshNode *n3 = iF_n->second;
1631             if ( !volTool.IsFaceExternal( iF ))
1632               swap( n2, n3 );
1633             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1634           }
1635         }
1636         else
1637         {
1638           // among possible triangles create ones discribed by split method
1639           const int* nInd = volTool.GetFaceNodesIndices( iF );
1640           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1641           int iCom = 0; // common node of triangle faces to split into
1642           list< TTriangleFacet > facets;
1643           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1644           {
1645             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1646                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1647                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1648             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1649                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1650                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1651             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1652             {
1653               facets.push_back( t012 );
1654               facets.push_back( t023 );
1655               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1656                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1657                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1658                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1659               break;
1660             }
1661           }
1662           list< TTriangleFacet >::iterator facet = facets.begin();
1663           for ( ; facet != facets.end(); ++facet )
1664           {
1665             if ( !volTool.IsFaceExternal( iF ))
1666               swap( facet->_n2, facet->_n3 );
1667             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1668                                                  volNodes[ facet->_n2 ],
1669                                                  volNodes[ facet->_n3 ]));
1670           }
1671         }
1672         // find submesh to add new triangles in
1673         if ( !fSubMesh || !fSubMesh->Contains( face ))
1674         {
1675           int shapeID = FindShape( face );
1676           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1677         }
1678         for ( int i = 0; i < triangles.size(); ++i )
1679         {
1680           if ( !triangles.back() ) continue;
1681           if ( fSubMesh )
1682             fSubMesh->AddElement( triangles.back());
1683           newElems.Append( triangles.back() );
1684         }
1685         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1686         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1687       }
1688
1689     } // loop on volume faces to split them into triangles
1690
1691     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1692
1693   } // loop on volumes to split
1694
1695   myLastCreatedNodes = newNodes;
1696   myLastCreatedElems = newElems;
1697 }
1698
1699 //=======================================================================
1700 //function : AddToSameGroups
1701 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1702 //=======================================================================
1703
1704 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1705                                         const SMDS_MeshElement* elemInGroups,
1706                                         SMESHDS_Mesh *          aMesh)
1707 {
1708   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1709   if (!groups.empty()) {
1710     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1711     for ( ; grIt != groups.end(); grIt++ ) {
1712       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1713       if ( group && group->Contains( elemInGroups ))
1714         group->SMDSGroup().Add( elemToAdd );
1715     }
1716   }
1717 }
1718
1719
1720 //=======================================================================
1721 //function : RemoveElemFromGroups
1722 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1723 //=======================================================================
1724 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1725                                              SMESHDS_Mesh *          aMesh)
1726 {
1727   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1728   if (!groups.empty())
1729   {
1730     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1731     for (; GrIt != groups.end(); GrIt++)
1732     {
1733       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1734       if (!grp || grp->IsEmpty()) continue;
1735       grp->SMDSGroup().Remove(removeelem);
1736     }
1737   }
1738 }
1739
1740 //================================================================================
1741 /*!
1742  * \brief Replace elemToRm by elemToAdd in the all groups
1743  */
1744 //================================================================================
1745
1746 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1747                                             const SMDS_MeshElement* elemToAdd,
1748                                             SMESHDS_Mesh *          aMesh)
1749 {
1750   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1751   if (!groups.empty()) {
1752     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1753     for ( ; grIt != groups.end(); grIt++ ) {
1754       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1755       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1756         group->SMDSGroup().Add( elemToAdd );
1757     }
1758   }
1759 }
1760
1761 //================================================================================
1762 /*!
1763  * \brief Replace elemToRm by elemToAdd in the all groups
1764  */
1765 //================================================================================
1766
1767 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1768                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1769                                             SMESHDS_Mesh *                         aMesh)
1770 {
1771   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1772   if (!groups.empty())
1773   {
1774     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1775     for ( ; grIt != groups.end(); grIt++ ) {
1776       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1777       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1778         for ( int i = 0; i < elemToAdd.size(); ++i )
1779           group->SMDSGroup().Add( elemToAdd[ i ] );
1780     }
1781   }
1782 }
1783
1784 //=======================================================================
1785 //function : QuadToTri
1786 //purpose  : Cut quadrangles into triangles.
1787 //           theCrit is used to select a diagonal to cut
1788 //=======================================================================
1789
1790 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1791                                   const bool         the13Diag)
1792 {
1793   myLastCreatedElems.Clear();
1794   myLastCreatedNodes.Clear();
1795
1796   MESSAGE( "::QuadToTri()" );
1797
1798   SMESHDS_Mesh * aMesh = GetMeshDS();
1799
1800   Handle(Geom_Surface) surface;
1801   SMESH_MesherHelper   helper( *GetMesh() );
1802
1803   TIDSortedElemSet::iterator itElem;
1804   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1805     const SMDS_MeshElement* elem = *itElem;
1806     if ( !elem || elem->GetType() != SMDSAbs_Face )
1807       continue;
1808     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1809     if(!isquad) continue;
1810
1811     if(elem->NbNodes()==4) {
1812       // retrieve element nodes
1813       const SMDS_MeshNode* aNodes [4];
1814       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1815       int i = 0;
1816       while ( itN->more() )
1817         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1818
1819       int aShapeId = FindShape( elem );
1820       const SMDS_MeshElement* newElem = 0;
1821       if ( the13Diag ) {
1822         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1823         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1824       }
1825       else {
1826         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1827         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1828       }
1829       myLastCreatedElems.Append(newElem);
1830       // put a new triangle on the same shape and add to the same groups
1831       if ( aShapeId )
1832         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1833       AddToSameGroups( newElem, elem, aMesh );
1834     }
1835
1836     // Quadratic quadrangle
1837
1838     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1839
1840       // get surface elem is on
1841       int aShapeId = FindShape( elem );
1842       if ( aShapeId != helper.GetSubShapeID() ) {
1843         surface.Nullify();
1844         TopoDS_Shape shape;
1845         if ( aShapeId > 0 )
1846           shape = aMesh->IndexToShape( aShapeId );
1847         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1848           TopoDS_Face face = TopoDS::Face( shape );
1849           surface = BRep_Tool::Surface( face );
1850           if ( !surface.IsNull() )
1851             helper.SetSubShape( shape );
1852         }
1853       }
1854
1855       const SMDS_MeshNode* aNodes [8];
1856       const SMDS_MeshNode* inFaceNode = 0;
1857       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1858       int i = 0;
1859       while ( itN->more() ) {
1860         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1861         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1862              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1863         {
1864           inFaceNode = aNodes[ i-1 ];
1865         }
1866       }
1867
1868       // find middle point for (0,1,2,3)
1869       // and create a node in this point;
1870       gp_XYZ p( 0,0,0 );
1871       if ( surface.IsNull() ) {
1872         for(i=0; i<4; i++)
1873           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1874         p /= 4;
1875       }
1876       else {
1877         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1878         gp_XY uv( 0,0 );
1879         for(i=0; i<4; i++)
1880           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1881         uv /= 4.;
1882         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1883       }
1884       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1885       myLastCreatedNodes.Append(newN);
1886
1887       // create a new element
1888       const SMDS_MeshElement* newElem = 0;
1889       const SMDS_MeshNode* N[6];
1890       if ( the13Diag ) {
1891         N[0] = aNodes[0];
1892         N[1] = aNodes[1];
1893         N[2] = aNodes[2];
1894         N[3] = aNodes[4];
1895         N[4] = aNodes[5];
1896         N[5] = newN;
1897         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1898                                  aNodes[6], aNodes[7], newN );
1899       }
1900       else {
1901         N[0] = aNodes[1];
1902         N[1] = aNodes[2];
1903         N[2] = aNodes[3];
1904         N[3] = aNodes[5];
1905         N[4] = aNodes[6];
1906         N[5] = newN;
1907         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1908                                  aNodes[7], aNodes[4], newN );
1909       }
1910       myLastCreatedElems.Append(newElem);
1911       aMesh->ChangeElementNodes( elem, N, 6 );
1912       // put a new triangle on the same shape and add to the same groups
1913       if ( aShapeId )
1914         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1915       AddToSameGroups( newElem, elem, aMesh );
1916     }
1917   }
1918
1919   return true;
1920 }
1921
1922 //=======================================================================
1923 //function : getAngle
1924 //purpose  :
1925 //=======================================================================
1926
1927 double getAngle(const SMDS_MeshElement * tr1,
1928                 const SMDS_MeshElement * tr2,
1929                 const SMDS_MeshNode *    n1,
1930                 const SMDS_MeshNode *    n2)
1931 {
1932   double angle = 2*PI; // bad angle
1933
1934   // get normals
1935   SMESH::Controls::TSequenceOfXYZ P1, P2;
1936   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1937        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1938     return angle;
1939   gp_Vec N1,N2;
1940   if(!tr1->IsQuadratic())
1941     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1942   else
1943     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1944   if ( N1.SquareMagnitude() <= gp::Resolution() )
1945     return angle;
1946   if(!tr2->IsQuadratic())
1947     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1948   else
1949     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1950   if ( N2.SquareMagnitude() <= gp::Resolution() )
1951     return angle;
1952
1953   // find the first diagonal node n1 in the triangles:
1954   // take in account a diagonal link orientation
1955   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1956   for ( int t = 0; t < 2; t++ ) {
1957     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1958     int i = 0, iDiag = -1;
1959     while ( it->more()) {
1960       const SMDS_MeshElement *n = it->next();
1961       if ( n == n1 || n == n2 )
1962         if ( iDiag < 0)
1963           iDiag = i;
1964         else {
1965           if ( i - iDiag == 1 )
1966             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1967           else
1968             nFirst[ t ] = n;
1969           break;
1970         }
1971       i++;
1972     }
1973   }
1974   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1975     N2.Reverse();
1976
1977   angle = N1.Angle( N2 );
1978   //SCRUTE( angle );
1979   return angle;
1980 }
1981
1982 // =================================================
1983 // class generating a unique ID for a pair of nodes
1984 // and able to return nodes by that ID
1985 // =================================================
1986 class LinkID_Gen {
1987 public:
1988
1989   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1990     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1991   {}
1992
1993   long GetLinkID (const SMDS_MeshNode * n1,
1994                   const SMDS_MeshNode * n2) const
1995   {
1996     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1997   }
1998
1999   bool GetNodes (const long             theLinkID,
2000                  const SMDS_MeshNode* & theNode1,
2001                  const SMDS_MeshNode* & theNode2) const
2002   {
2003     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2004     if ( !theNode1 ) return false;
2005     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2006     if ( !theNode2 ) return false;
2007     return true;
2008   }
2009
2010 private:
2011   LinkID_Gen();
2012   const SMESHDS_Mesh* myMesh;
2013   long                myMaxID;
2014 };
2015
2016
2017 //=======================================================================
2018 //function : TriToQuad
2019 //purpose  : Fuse neighbour triangles into quadrangles.
2020 //           theCrit is used to select a neighbour to fuse with.
2021 //           theMaxAngle is a max angle between element normals at which
2022 //           fusion is still performed.
2023 //=======================================================================
2024
2025 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2026                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2027                                   const double                         theMaxAngle)
2028 {
2029   myLastCreatedElems.Clear();
2030   myLastCreatedNodes.Clear();
2031
2032   MESSAGE( "::TriToQuad()" );
2033
2034   if ( !theCrit.get() )
2035     return false;
2036
2037   SMESHDS_Mesh * aMesh = GetMeshDS();
2038
2039   // Prepare data for algo: build
2040   // 1. map of elements with their linkIDs
2041   // 2. map of linkIDs with their elements
2042
2043   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2044   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2045   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2046   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2047
2048   TIDSortedElemSet::iterator itElem;
2049   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2050     const SMDS_MeshElement* elem = *itElem;
2051     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2052     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2053     if(!IsTria) continue;
2054
2055     // retrieve element nodes
2056     const SMDS_MeshNode* aNodes [4];
2057     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2058     int i = 0;
2059     while ( i<3 )
2060       aNodes[ i++ ] = cast2Node( itN->next() );
2061     aNodes[ 3 ] = aNodes[ 0 ];
2062
2063     // fill maps
2064     for ( i = 0; i < 3; i++ ) {
2065       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2066       // check if elements sharing a link can be fused
2067       itLE = mapLi_listEl.find( link );
2068       if ( itLE != mapLi_listEl.end() ) {
2069         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2070           continue;
2071         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2072         //if ( FindShape( elem ) != FindShape( elem2 ))
2073         //  continue; // do not fuse triangles laying on different shapes
2074         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2075           continue; // avoid making badly shaped quads
2076         (*itLE).second.push_back( elem );
2077       }
2078       else {
2079         mapLi_listEl[ link ].push_back( elem );
2080       }
2081       mapEl_setLi [ elem ].insert( link );
2082     }
2083   }
2084   // Clean the maps from the links shared by a sole element, ie
2085   // links to which only one element is bound in mapLi_listEl
2086
2087   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2088     int nbElems = (*itLE).second.size();
2089     if ( nbElems < 2  ) {
2090       const SMDS_MeshElement* elem = (*itLE).second.front();
2091       SMESH_TLink link = (*itLE).first;
2092       mapEl_setLi[ elem ].erase( link );
2093       if ( mapEl_setLi[ elem ].empty() )
2094         mapEl_setLi.erase( elem );
2095     }
2096   }
2097
2098   // Algo: fuse triangles into quadrangles
2099
2100   while ( ! mapEl_setLi.empty() ) {
2101     // Look for the start element:
2102     // the element having the least nb of shared links
2103     const SMDS_MeshElement* startElem = 0;
2104     int minNbLinks = 4;
2105     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2106       int nbLinks = (*itEL).second.size();
2107       if ( nbLinks < minNbLinks ) {
2108         startElem = (*itEL).first;
2109         minNbLinks = nbLinks;
2110         if ( minNbLinks == 1 )
2111           break;
2112       }
2113     }
2114
2115     // search elements to fuse starting from startElem or links of elements
2116     // fused earlyer - startLinks
2117     list< SMESH_TLink > startLinks;
2118     while ( startElem || !startLinks.empty() ) {
2119       while ( !startElem && !startLinks.empty() ) {
2120         // Get an element to start, by a link
2121         SMESH_TLink linkId = startLinks.front();
2122         startLinks.pop_front();
2123         itLE = mapLi_listEl.find( linkId );
2124         if ( itLE != mapLi_listEl.end() ) {
2125           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2126           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2127           for ( ; itE != listElem.end() ; itE++ )
2128             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2129               startElem = (*itE);
2130           mapLi_listEl.erase( itLE );
2131         }
2132       }
2133
2134       if ( startElem ) {
2135         // Get candidates to be fused
2136         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2137         const SMESH_TLink *link12, *link13;
2138         startElem = 0;
2139         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2140         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2141         ASSERT( !setLi.empty() );
2142         set< SMESH_TLink >::iterator itLi;
2143         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2144         {
2145           const SMESH_TLink & link = (*itLi);
2146           itLE = mapLi_listEl.find( link );
2147           if ( itLE == mapLi_listEl.end() )
2148             continue;
2149
2150           const SMDS_MeshElement* elem = (*itLE).second.front();
2151           if ( elem == tr1 )
2152             elem = (*itLE).second.back();
2153           mapLi_listEl.erase( itLE );
2154           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2155             continue;
2156           if ( tr2 ) {
2157             tr3 = elem;
2158             link13 = &link;
2159           }
2160           else {
2161             tr2 = elem;
2162             link12 = &link;
2163           }
2164
2165           // add other links of elem to list of links to re-start from
2166           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2167           set< SMESH_TLink >::iterator it;
2168           for ( it = links.begin(); it != links.end(); it++ ) {
2169             const SMESH_TLink& link2 = (*it);
2170             if ( link2 != link )
2171               startLinks.push_back( link2 );
2172           }
2173         }
2174
2175         // Get nodes of possible quadrangles
2176         const SMDS_MeshNode *n12 [4], *n13 [4];
2177         bool Ok12 = false, Ok13 = false;
2178         const SMDS_MeshNode *linkNode1, *linkNode2;
2179         if(tr2) {
2180           linkNode1 = link12->first;
2181           linkNode2 = link12->second;
2182           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2183             Ok12 = true;
2184         }
2185         if(tr3) {
2186           linkNode1 = link13->first;
2187           linkNode2 = link13->second;
2188           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2189             Ok13 = true;
2190         }
2191
2192         // Choose a pair to fuse
2193         if ( Ok12 && Ok13 ) {
2194           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2195           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2196           double aBadRate12 = getBadRate( &quad12, theCrit );
2197           double aBadRate13 = getBadRate( &quad13, theCrit );
2198           if (  aBadRate13 < aBadRate12 )
2199             Ok12 = false;
2200           else
2201             Ok13 = false;
2202         }
2203
2204         // Make quadrangles
2205         // and remove fused elems and removed links from the maps
2206         mapEl_setLi.erase( tr1 );
2207         if ( Ok12 ) {
2208           mapEl_setLi.erase( tr2 );
2209           mapLi_listEl.erase( *link12 );
2210           if(tr1->NbNodes()==3) {
2211             if( tr1->GetID() < tr2->GetID() ) {
2212               aMesh->ChangeElementNodes( tr1, n12, 4 );
2213               myLastCreatedElems.Append(tr1);
2214               aMesh->RemoveElement( tr2 );
2215             }
2216             else {
2217               aMesh->ChangeElementNodes( tr2, n12, 4 );
2218               myLastCreatedElems.Append(tr2);
2219               aMesh->RemoveElement( tr1);
2220             }
2221           }
2222           else {
2223             const SMDS_MeshNode* N1 [6];
2224             const SMDS_MeshNode* N2 [6];
2225             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2226             // now we receive following N1 and N2 (using numeration as above image)
2227             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2228             // i.e. first nodes from both arrays determ new diagonal
2229             const SMDS_MeshNode* aNodes[8];
2230             aNodes[0] = N1[0];
2231             aNodes[1] = N1[1];
2232             aNodes[2] = N2[0];
2233             aNodes[3] = N2[1];
2234             aNodes[4] = N1[3];
2235             aNodes[5] = N2[5];
2236             aNodes[6] = N2[3];
2237             aNodes[7] = N1[5];
2238             if( tr1->GetID() < tr2->GetID() ) {
2239               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2240               myLastCreatedElems.Append(tr1);
2241               GetMeshDS()->RemoveElement( tr2 );
2242             }
2243             else {
2244               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2245               myLastCreatedElems.Append(tr2);
2246               GetMeshDS()->RemoveElement( tr1 );
2247             }
2248             // remove middle node (9)
2249             GetMeshDS()->RemoveNode( N1[4] );
2250           }
2251         }
2252         else if ( Ok13 ) {
2253           mapEl_setLi.erase( tr3 );
2254           mapLi_listEl.erase( *link13 );
2255           if(tr1->NbNodes()==3) {
2256             if( tr1->GetID() < tr2->GetID() ) {
2257               aMesh->ChangeElementNodes( tr1, n13, 4 );
2258               myLastCreatedElems.Append(tr1);
2259               aMesh->RemoveElement( tr3 );
2260             }
2261             else {
2262               aMesh->ChangeElementNodes( tr3, n13, 4 );
2263               myLastCreatedElems.Append(tr3);
2264               aMesh->RemoveElement( tr1 );
2265             }
2266           }
2267           else {
2268             const SMDS_MeshNode* N1 [6];
2269             const SMDS_MeshNode* N2 [6];
2270             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2271             // now we receive following N1 and N2 (using numeration as above image)
2272             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2273             // i.e. first nodes from both arrays determ new diagonal
2274             const SMDS_MeshNode* aNodes[8];
2275             aNodes[0] = N1[0];
2276             aNodes[1] = N1[1];
2277             aNodes[2] = N2[0];
2278             aNodes[3] = N2[1];
2279             aNodes[4] = N1[3];
2280             aNodes[5] = N2[5];
2281             aNodes[6] = N2[3];
2282             aNodes[7] = N1[5];
2283             if( tr1->GetID() < tr2->GetID() ) {
2284               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2285               myLastCreatedElems.Append(tr1);
2286               GetMeshDS()->RemoveElement( tr3 );
2287             }
2288             else {
2289               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2290               myLastCreatedElems.Append(tr3);
2291               GetMeshDS()->RemoveElement( tr1 );
2292             }
2293             // remove middle node (9)
2294             GetMeshDS()->RemoveNode( N1[4] );
2295           }
2296         }
2297
2298         // Next element to fuse: the rejected one
2299         if ( tr3 )
2300           startElem = Ok12 ? tr3 : tr2;
2301
2302       } // if ( startElem )
2303     } // while ( startElem || !startLinks.empty() )
2304   } // while ( ! mapEl_setLi.empty() )
2305
2306   return true;
2307 }
2308
2309
2310 /*#define DUMPSO(txt) \
2311 //  cout << txt << endl;
2312 //=============================================================================
2313 //
2314 //
2315 //
2316 //=============================================================================
2317 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2318 {
2319 if ( i1 == i2 )
2320 return;
2321 int tmp = idNodes[ i1 ];
2322 idNodes[ i1 ] = idNodes[ i2 ];
2323 idNodes[ i2 ] = tmp;
2324 gp_Pnt Ptmp = P[ i1 ];
2325 P[ i1 ] = P[ i2 ];
2326 P[ i2 ] = Ptmp;
2327 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2328 }
2329
2330 //=======================================================================
2331 //function : SortQuadNodes
2332 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2333 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2334 //           1 or 2 else 0.
2335 //=======================================================================
2336
2337 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2338 int               idNodes[] )
2339 {
2340   gp_Pnt P[4];
2341   int i;
2342   for ( i = 0; i < 4; i++ ) {
2343     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2344     if ( !n ) return 0;
2345     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2346   }
2347
2348   gp_Vec V1(P[0], P[1]);
2349   gp_Vec V2(P[0], P[2]);
2350   gp_Vec V3(P[0], P[3]);
2351
2352   gp_Vec Cross1 = V1 ^ V2;
2353   gp_Vec Cross2 = V2 ^ V3;
2354
2355   i = 0;
2356   if (Cross1.Dot(Cross2) < 0)
2357   {
2358     Cross1 = V2 ^ V1;
2359     Cross2 = V1 ^ V3;
2360
2361     if (Cross1.Dot(Cross2) < 0)
2362       i = 2;
2363     else
2364       i = 1;
2365     swap ( i, i + 1, idNodes, P );
2366
2367     //     for ( int ii = 0; ii < 4; ii++ ) {
2368     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2369     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2370     //     }
2371   }
2372   return i;
2373 }
2374
2375 //=======================================================================
2376 //function : SortHexaNodes
2377 //purpose  : Set 8 nodes of a hexahedron in a good order.
2378 //           Return success status
2379 //=======================================================================
2380
2381 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2382                                       int               idNodes[] )
2383 {
2384   gp_Pnt P[8];
2385   int i;
2386   DUMPSO( "INPUT: ========================================");
2387   for ( i = 0; i < 8; i++ ) {
2388     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2389     if ( !n ) return false;
2390     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2391     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2392   }
2393   DUMPSO( "========================================");
2394
2395
2396   set<int> faceNodes;  // ids of bottom face nodes, to be found
2397   set<int> checkedId1; // ids of tried 2-nd nodes
2398   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2399   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2400   int iMin, iLoop1 = 0;
2401
2402   // Loop to try the 2-nd nodes
2403
2404   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2405   {
2406     // Find not checked 2-nd node
2407     for ( i = 1; i < 8; i++ )
2408       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2409         int id1 = idNodes[i];
2410         swap ( 1, i, idNodes, P );
2411         checkedId1.insert ( id1 );
2412         break;
2413       }
2414
2415     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2416     // ie that all but meybe one (id3 which is on the same face) nodes
2417     // lay on the same side from the triangle plane.
2418
2419     bool manyInPlane = false; // more than 4 nodes lay in plane
2420     int iLoop2 = 0;
2421     while ( ++iLoop2 < 6 ) {
2422
2423       // get 1-2-3 plane coeffs
2424       Standard_Real A, B, C, D;
2425       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2426       if ( N.SquareMagnitude() > gp::Resolution() )
2427       {
2428         gp_Pln pln ( P[0], N );
2429         pln.Coefficients( A, B, C, D );
2430
2431         // find the node (iMin) closest to pln
2432         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2433         set<int> idInPln;
2434         for ( i = 3; i < 8; i++ ) {
2435           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2436           if ( fabs( dist[i] ) < minDist ) {
2437             minDist = fabs( dist[i] );
2438             iMin = i;
2439           }
2440           if ( fabs( dist[i] ) <= tol )
2441             idInPln.insert( idNodes[i] );
2442         }
2443
2444         // there should not be more than 4 nodes in bottom plane
2445         if ( idInPln.size() > 1 )
2446         {
2447           DUMPSO( "### idInPln.size() = " << idInPln.size());
2448           // idInPlane does not contain the first 3 nodes
2449           if ( manyInPlane || idInPln.size() == 5)
2450             return false; // all nodes in one plane
2451           manyInPlane = true;
2452
2453           // set the 1-st node to be not in plane
2454           for ( i = 3; i < 8; i++ ) {
2455             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2456               DUMPSO( "### Reset 0-th node");
2457               swap( 0, i, idNodes, P );
2458               break;
2459             }
2460           }
2461
2462           // reset to re-check second nodes
2463           leastDist = DBL_MAX;
2464           faceNodes.clear();
2465           checkedId1.clear();
2466           iLoop1 = 0;
2467           break; // from iLoop2;
2468         }
2469
2470         // check that the other 4 nodes are on the same side
2471         bool sameSide = true;
2472         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2473         for ( i = 3; sameSide && i < 8; i++ ) {
2474           if ( i != iMin )
2475             sameSide = ( isNeg == dist[i] <= 0.);
2476         }
2477
2478         // keep best solution
2479         if ( sameSide && minDist < leastDist ) {
2480           leastDist = minDist;
2481           faceNodes.clear();
2482           faceNodes.insert( idNodes[ 1 ] );
2483           faceNodes.insert( idNodes[ 2 ] );
2484           faceNodes.insert( idNodes[ iMin ] );
2485           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2486                   << " leastDist = " << leastDist);
2487           if ( leastDist <= DBL_MIN )
2488             break;
2489         }
2490       }
2491
2492       // set next 3-d node to check
2493       int iNext = 2 + iLoop2;
2494       if ( iNext < 8 ) {
2495         DUMPSO( "Try 2-nd");
2496         swap ( 2, iNext, idNodes, P );
2497       }
2498     } // while ( iLoop2 < 6 )
2499   } // iLoop1
2500
2501   if ( faceNodes.empty() ) return false;
2502
2503   // Put the faceNodes in proper places
2504   for ( i = 4; i < 8; i++ ) {
2505     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2506       // find a place to put
2507       int iTo = 1;
2508       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2509         iTo++;
2510       DUMPSO( "Set faceNodes");
2511       swap ( iTo, i, idNodes, P );
2512     }
2513   }
2514
2515
2516   // Set nodes of the found bottom face in good order
2517   DUMPSO( " Found bottom face: ");
2518   i = SortQuadNodes( theMesh, idNodes );
2519   if ( i ) {
2520     gp_Pnt Ptmp = P[ i ];
2521     P[ i ] = P[ i+1 ];
2522     P[ i+1 ] = Ptmp;
2523   }
2524   //   else
2525   //     for ( int ii = 0; ii < 4; ii++ ) {
2526   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2527   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2528   //    }
2529
2530   // Gravity center of the top and bottom faces
2531   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2532   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2533
2534   // Get direction from the bottom to the top face
2535   gp_Vec upDir ( aGCb, aGCt );
2536   Standard_Real upDirSize = upDir.Magnitude();
2537   if ( upDirSize <= gp::Resolution() ) return false;
2538   upDir / upDirSize;
2539
2540   // Assure that the bottom face normal points up
2541   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2542   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2543   if ( Nb.Dot( upDir ) < 0 ) {
2544     DUMPSO( "Reverse bottom face");
2545     swap( 1, 3, idNodes, P );
2546   }
2547
2548   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2549   Standard_Real minDist = DBL_MAX;
2550   for ( i = 4; i < 8; i++ ) {
2551     // projection of P[i] to the plane defined by P[0] and upDir
2552     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2553     Standard_Real sqDist = P[0].SquareDistance( Pp );
2554     if ( sqDist < minDist ) {
2555       minDist = sqDist;
2556       iMin = i;
2557     }
2558   }
2559   DUMPSO( "Set 4-th");
2560   swap ( 4, iMin, idNodes, P );
2561
2562   // Set nodes of the top face in good order
2563   DUMPSO( "Sort top face");
2564   i = SortQuadNodes( theMesh, &idNodes[4] );
2565   if ( i ) {
2566     i += 4;
2567     gp_Pnt Ptmp = P[ i ];
2568     P[ i ] = P[ i+1 ];
2569     P[ i+1 ] = Ptmp;
2570   }
2571
2572   // Assure that direction of the top face normal is from the bottom face
2573   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2574   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2575   if ( Nt.Dot( upDir ) < 0 ) {
2576     DUMPSO( "Reverse top face");
2577     swap( 5, 7, idNodes, P );
2578   }
2579
2580   //   DUMPSO( "OUTPUT: ========================================");
2581   //   for ( i = 0; i < 8; i++ ) {
2582   //     float *p = ugrid->GetPoint(idNodes[i]);
2583   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2584   //   }
2585
2586   return true;
2587 }*/
2588
2589 //================================================================================
2590 /*!
2591  * \brief Return nodes linked to the given one
2592  * \param theNode - the node
2593  * \param linkedNodes - the found nodes
2594  * \param type - the type of elements to check
2595  *
2596  * Medium nodes are ignored
2597  */
2598 //================================================================================
2599
2600 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2601                                        TIDSortedElemSet &   linkedNodes,
2602                                        SMDSAbs_ElementType  type )
2603 {
2604   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2605   while ( elemIt->more() )
2606   {
2607     const SMDS_MeshElement* elem = elemIt->next();
2608     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2609     if ( elem->GetType() == SMDSAbs_Volume )
2610     {
2611       SMDS_VolumeTool vol( elem );
2612       while ( nodeIt->more() ) {
2613         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2614         if ( theNode != n && vol.IsLinked( theNode, n ))
2615           linkedNodes.insert( n );
2616       }
2617     }
2618     else
2619     {
2620       for ( int i = 0; nodeIt->more(); ++i ) {
2621         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2622         if ( n == theNode ) {
2623           int iBefore = i - 1;
2624           int iAfter  = i + 1;
2625           if ( elem->IsQuadratic() ) {
2626             int nb = elem->NbNodes() / 2;
2627             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2628             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2629           }
2630           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2631           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2632         }
2633       }
2634     }
2635   }
2636 }
2637
2638 //=======================================================================
2639 //function : laplacianSmooth
2640 //purpose  : pulls theNode toward the center of surrounding nodes directly
2641 //           connected to that node along an element edge
2642 //=======================================================================
2643
2644 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2645                      const Handle(Geom_Surface)&          theSurface,
2646                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2647 {
2648   // find surrounding nodes
2649
2650   TIDSortedElemSet nodeSet;
2651   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2652
2653   // compute new coodrs
2654
2655   double coord[] = { 0., 0., 0. };
2656   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2657   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2658     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2659     if ( theSurface.IsNull() ) { // smooth in 3D
2660       coord[0] += node->X();
2661       coord[1] += node->Y();
2662       coord[2] += node->Z();
2663     }
2664     else { // smooth in 2D
2665       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2666       gp_XY* uv = theUVMap[ node ];
2667       coord[0] += uv->X();
2668       coord[1] += uv->Y();
2669     }
2670   }
2671   int nbNodes = nodeSet.size();
2672   if ( !nbNodes )
2673     return;
2674   coord[0] /= nbNodes;
2675   coord[1] /= nbNodes;
2676
2677   if ( !theSurface.IsNull() ) {
2678     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2679     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2680     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2681     coord[0] = p3d.X();
2682     coord[1] = p3d.Y();
2683     coord[2] = p3d.Z();
2684   }
2685   else
2686     coord[2] /= nbNodes;
2687
2688   // move node
2689
2690   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2691 }
2692
2693 //=======================================================================
2694 //function : centroidalSmooth
2695 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2696 //           surrounding elements
2697 //=======================================================================
2698
2699 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2700                       const Handle(Geom_Surface)&          theSurface,
2701                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2702 {
2703   gp_XYZ aNewXYZ(0.,0.,0.);
2704   SMESH::Controls::Area anAreaFunc;
2705   double totalArea = 0.;
2706   int nbElems = 0;
2707
2708   // compute new XYZ
2709
2710   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2711   while ( elemIt->more() )
2712   {
2713     const SMDS_MeshElement* elem = elemIt->next();
2714     nbElems++;
2715
2716     gp_XYZ elemCenter(0.,0.,0.);
2717     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2718     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2719     int nn = elem->NbNodes();
2720     if(elem->IsQuadratic()) nn = nn/2;
2721     int i=0;
2722     //while ( itN->more() ) {
2723     while ( i<nn ) {
2724       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2725       i++;
2726       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2727       aNodePoints.push_back( aP );
2728       if ( !theSurface.IsNull() ) { // smooth in 2D
2729         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2730         gp_XY* uv = theUVMap[ aNode ];
2731         aP.SetCoord( uv->X(), uv->Y(), 0. );
2732       }
2733       elemCenter += aP;
2734     }
2735     double elemArea = anAreaFunc.GetValue( aNodePoints );
2736     totalArea += elemArea;
2737     elemCenter /= nn;
2738     aNewXYZ += elemCenter * elemArea;
2739   }
2740   aNewXYZ /= totalArea;
2741   if ( !theSurface.IsNull() ) {
2742     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2743     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2744   }
2745
2746   // move node
2747
2748   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2749 }
2750
2751 //=======================================================================
2752 //function : getClosestUV
2753 //purpose  : return UV of closest projection
2754 //=======================================================================
2755
2756 static bool getClosestUV (Extrema_GenExtPS& projector,
2757                           const gp_Pnt&     point,
2758                           gp_XY &           result)
2759 {
2760   projector.Perform( point );
2761   if ( projector.IsDone() ) {
2762     double u, v, minVal = DBL_MAX;
2763     for ( int i = projector.NbExt(); i > 0; i-- )
2764       if ( projector.Value( i ) < minVal ) {
2765         minVal = projector.Value( i );
2766         projector.Point( i ).Parameter( u, v );
2767       }
2768     result.SetCoord( u, v );
2769     return true;
2770   }
2771   return false;
2772 }
2773
2774 //=======================================================================
2775 //function : Smooth
2776 //purpose  : Smooth theElements during theNbIterations or until a worst
2777 //           element has aspect ratio <= theTgtAspectRatio.
2778 //           Aspect Ratio varies in range [1.0, inf].
2779 //           If theElements is empty, the whole mesh is smoothed.
2780 //           theFixedNodes contains additionally fixed nodes. Nodes built
2781 //           on edges and boundary nodes are always fixed.
2782 //=======================================================================
2783
2784 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2785                                set<const SMDS_MeshNode*> & theFixedNodes,
2786                                const SmoothMethod          theSmoothMethod,
2787                                const int                   theNbIterations,
2788                                double                      theTgtAspectRatio,
2789                                const bool                  the2D)
2790 {
2791   myLastCreatedElems.Clear();
2792   myLastCreatedNodes.Clear();
2793
2794   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2795
2796   if ( theTgtAspectRatio < 1.0 )
2797     theTgtAspectRatio = 1.0;
2798
2799   const double disttol = 1.e-16;
2800
2801   SMESH::Controls::AspectRatio aQualityFunc;
2802
2803   SMESHDS_Mesh* aMesh = GetMeshDS();
2804
2805   if ( theElems.empty() ) {
2806     // add all faces to theElems
2807     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2808     while ( fIt->more() ) {
2809       const SMDS_MeshElement* face = fIt->next();
2810       theElems.insert( face );
2811     }
2812   }
2813   // get all face ids theElems are on
2814   set< int > faceIdSet;
2815   TIDSortedElemSet::iterator itElem;
2816   if ( the2D )
2817     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2818       int fId = FindShape( *itElem );
2819       // check that corresponding submesh exists and a shape is face
2820       if (fId &&
2821           faceIdSet.find( fId ) == faceIdSet.end() &&
2822           aMesh->MeshElements( fId )) {
2823         TopoDS_Shape F = aMesh->IndexToShape( fId );
2824         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2825           faceIdSet.insert( fId );
2826       }
2827     }
2828   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2829
2830   // ===============================================
2831   // smooth elements on each TopoDS_Face separately
2832   // ===============================================
2833
2834   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2835   for ( ; fId != faceIdSet.rend(); ++fId ) {
2836     // get face surface and submesh
2837     Handle(Geom_Surface) surface;
2838     SMESHDS_SubMesh* faceSubMesh = 0;
2839     TopoDS_Face face;
2840     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2841     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2842     bool isUPeriodic = false, isVPeriodic = false;
2843     if ( *fId ) {
2844       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2845       surface = BRep_Tool::Surface( face );
2846       faceSubMesh = aMesh->MeshElements( *fId );
2847       fToler2 = BRep_Tool::Tolerance( face );
2848       fToler2 *= fToler2 * 10.;
2849       isUPeriodic = surface->IsUPeriodic();
2850       if ( isUPeriodic )
2851         vPeriod = surface->UPeriod();
2852       isVPeriodic = surface->IsVPeriodic();
2853       if ( isVPeriodic )
2854         uPeriod = surface->VPeriod();
2855       surface->Bounds( u1, u2, v1, v2 );
2856     }
2857     // ---------------------------------------------------------
2858     // for elements on a face, find movable and fixed nodes and
2859     // compute UV for them
2860     // ---------------------------------------------------------
2861     bool checkBoundaryNodes = false;
2862     bool isQuadratic = false;
2863     set<const SMDS_MeshNode*> setMovableNodes;
2864     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2865     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2866     list< const SMDS_MeshElement* > elemsOnFace;
2867
2868     Extrema_GenExtPS projector;
2869     GeomAdaptor_Surface surfAdaptor;
2870     if ( !surface.IsNull() ) {
2871       surfAdaptor.Load( surface );
2872       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2873     }
2874     int nbElemOnFace = 0;
2875     itElem = theElems.begin();
2876     // loop on not yet smoothed elements: look for elems on a face
2877     while ( itElem != theElems.end() ) {
2878       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2879         break; // all elements found
2880
2881       const SMDS_MeshElement* elem = *itElem;
2882       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2883            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2884         ++itElem;
2885         continue;
2886       }
2887       elemsOnFace.push_back( elem );
2888       theElems.erase( itElem++ );
2889       nbElemOnFace++;
2890
2891       if ( !isQuadratic )
2892         isQuadratic = elem->IsQuadratic();
2893
2894       // get movable nodes of elem
2895       const SMDS_MeshNode* node;
2896       SMDS_TypeOfPosition posType;
2897       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2898       int nn = 0, nbn =  elem->NbNodes();
2899       if(elem->IsQuadratic())
2900         nbn = nbn/2;
2901       while ( nn++ < nbn ) {
2902         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2903         const SMDS_PositionPtr& pos = node->GetPosition();
2904         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2905         if (posType != SMDS_TOP_EDGE &&
2906             posType != SMDS_TOP_VERTEX &&
2907             theFixedNodes.find( node ) == theFixedNodes.end())
2908         {
2909           // check if all faces around the node are on faceSubMesh
2910           // because a node on edge may be bound to face
2911           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2912           bool all = true;
2913           if ( faceSubMesh ) {
2914             while ( eIt->more() && all ) {
2915               const SMDS_MeshElement* e = eIt->next();
2916               all = faceSubMesh->Contains( e );
2917             }
2918           }
2919           if ( all )
2920             setMovableNodes.insert( node );
2921           else
2922             checkBoundaryNodes = true;
2923         }
2924         if ( posType == SMDS_TOP_3DSPACE )
2925           checkBoundaryNodes = true;
2926       }
2927
2928       if ( surface.IsNull() )
2929         continue;
2930
2931       // get nodes to check UV
2932       list< const SMDS_MeshNode* > uvCheckNodes;
2933       itN = elem->nodesIterator();
2934       nn = 0; nbn =  elem->NbNodes();
2935       if(elem->IsQuadratic())
2936         nbn = nbn/2;
2937       while ( nn++ < nbn ) {
2938         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2939         if ( uvMap.find( node ) == uvMap.end() )
2940           uvCheckNodes.push_back( node );
2941         // add nodes of elems sharing node
2942         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2943         //         while ( eIt->more() ) {
2944         //           const SMDS_MeshElement* e = eIt->next();
2945         //           if ( e != elem ) {
2946         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2947         //             while ( nIt->more() ) {
2948         //               const SMDS_MeshNode* n =
2949         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2950         //               if ( uvMap.find( n ) == uvMap.end() )
2951         //                 uvCheckNodes.push_back( n );
2952         //             }
2953         //           }
2954         //         }
2955       }
2956       // check UV on face
2957       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2958       for ( ; n != uvCheckNodes.end(); ++n ) {
2959         node = *n;
2960         gp_XY uv( 0, 0 );
2961         const SMDS_PositionPtr& pos = node->GetPosition();
2962         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2963         // get existing UV
2964         switch ( posType ) {
2965         case SMDS_TOP_FACE: {
2966           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2967           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2968           break;
2969         }
2970         case SMDS_TOP_EDGE: {
2971           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2972           Handle(Geom2d_Curve) pcurve;
2973           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2974             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2975           if ( !pcurve.IsNull() ) {
2976             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2977             uv = pcurve->Value( u ).XY();
2978           }
2979           break;
2980         }
2981         case SMDS_TOP_VERTEX: {
2982           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2983           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2984             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2985           break;
2986         }
2987         default:;
2988         }
2989         // check existing UV
2990         bool project = true;
2991         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2992         double dist1 = DBL_MAX, dist2 = 0;
2993         if ( posType != SMDS_TOP_3DSPACE ) {
2994           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2995           project = dist1 > fToler2;
2996         }
2997         if ( project ) { // compute new UV
2998           gp_XY newUV;
2999           if ( !getClosestUV( projector, pNode, newUV )) {
3000             MESSAGE("Node Projection Failed " << node);
3001           }
3002           else {
3003             if ( isUPeriodic )
3004               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3005             if ( isVPeriodic )
3006               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3007             // check new UV
3008             if ( posType != SMDS_TOP_3DSPACE )
3009               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3010             if ( dist2 < dist1 )
3011               uv = newUV;
3012           }
3013         }
3014         // store UV in the map
3015         listUV.push_back( uv );
3016         uvMap.insert( make_pair( node, &listUV.back() ));
3017       }
3018     } // loop on not yet smoothed elements
3019
3020     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3021       checkBoundaryNodes = true;
3022
3023     // fix nodes on mesh boundary
3024
3025     if ( checkBoundaryNodes ) {
3026       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3027       map< NLink, int >::iterator link_nb;
3028       // put all elements links to linkNbMap
3029       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3030       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3031         const SMDS_MeshElement* elem = (*elemIt);
3032         int nbn =  elem->NbNodes();
3033         if(elem->IsQuadratic())
3034           nbn = nbn/2;
3035         // loop on elem links: insert them in linkNbMap
3036         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3037         for ( int iN = 0; iN < nbn; ++iN ) {
3038           curNode = elem->GetNode( iN );
3039           NLink link;
3040           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3041           else                      link = make_pair( prevNode , curNode );
3042           prevNode = curNode;
3043           link_nb = linkNbMap.find( link );
3044           if ( link_nb == linkNbMap.end() )
3045             linkNbMap.insert( make_pair ( link, 1 ));
3046           else
3047             link_nb->second++;
3048         }
3049       }
3050       // remove nodes that are in links encountered only once from setMovableNodes
3051       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3052         if ( link_nb->second == 1 ) {
3053           setMovableNodes.erase( link_nb->first.first );
3054           setMovableNodes.erase( link_nb->first.second );
3055         }
3056       }
3057     }
3058
3059     // -----------------------------------------------------
3060     // for nodes on seam edge, compute one more UV ( uvMap2 );
3061     // find movable nodes linked to nodes on seam and which
3062     // are to be smoothed using the second UV ( uvMap2 )
3063     // -----------------------------------------------------
3064
3065     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3066     if ( !surface.IsNull() ) {
3067       TopExp_Explorer eExp( face, TopAbs_EDGE );
3068       for ( ; eExp.More(); eExp.Next() ) {
3069         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3070         if ( !BRep_Tool::IsClosed( edge, face ))
3071           continue;
3072         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3073         if ( !sm ) continue;
3074         // find out which parameter varies for a node on seam
3075         double f,l;
3076         gp_Pnt2d uv1, uv2;
3077         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3078         if ( pcurve.IsNull() ) continue;
3079         uv1 = pcurve->Value( f );
3080         edge.Reverse();
3081         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3082         if ( pcurve.IsNull() ) continue;
3083         uv2 = pcurve->Value( f );
3084         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3085         // assure uv1 < uv2
3086         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3087           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3088         }
3089         // get nodes on seam and its vertices
3090         list< const SMDS_MeshNode* > seamNodes;
3091         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3092         while ( nSeamIt->more() ) {
3093           const SMDS_MeshNode* node = nSeamIt->next();
3094           if ( !isQuadratic || !IsMedium( node ))
3095             seamNodes.push_back( node );
3096         }
3097         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3098         for ( ; vExp.More(); vExp.Next() ) {
3099           sm = aMesh->MeshElements( vExp.Current() );
3100           if ( sm ) {
3101             nSeamIt = sm->GetNodes();
3102             while ( nSeamIt->more() )
3103               seamNodes.push_back( nSeamIt->next() );
3104           }
3105         }
3106         // loop on nodes on seam
3107         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3108         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3109           const SMDS_MeshNode* nSeam = *noSeIt;
3110           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3111           if ( n_uv == uvMap.end() )
3112             continue;
3113           // set the first UV
3114           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3115           // set the second UV
3116           listUV.push_back( *n_uv->second );
3117           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3118           if ( uvMap2.empty() )
3119             uvMap2 = uvMap; // copy the uvMap contents
3120           uvMap2[ nSeam ] = &listUV.back();
3121
3122           // collect movable nodes linked to ones on seam in nodesNearSeam
3123           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3124           while ( eIt->more() ) {
3125             const SMDS_MeshElement* e = eIt->next();
3126             int nbUseMap1 = 0, nbUseMap2 = 0;
3127             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3128             int nn = 0, nbn =  e->NbNodes();
3129             if(e->IsQuadratic()) nbn = nbn/2;
3130             while ( nn++ < nbn )
3131             {
3132               const SMDS_MeshNode* n =
3133                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3134               if (n == nSeam ||
3135                   setMovableNodes.find( n ) == setMovableNodes.end() )
3136                 continue;
3137               // add only nodes being closer to uv2 than to uv1
3138               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3139                            0.5 * ( n->Y() + nSeam->Y() ),
3140                            0.5 * ( n->Z() + nSeam->Z() ));
3141               gp_XY uv;
3142               getClosestUV( projector, pMid, uv );
3143               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3144                 nodesNearSeam.insert( n );
3145                 nbUseMap2++;
3146               }
3147               else
3148                 nbUseMap1++;
3149             }
3150             // for centroidalSmooth all element nodes must
3151             // be on one side of a seam
3152             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3153               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3154               nn = 0;
3155               while ( nn++ < nbn ) {
3156                 const SMDS_MeshNode* n =
3157                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3158                 setMovableNodes.erase( n );
3159               }
3160             }
3161           }
3162         } // loop on nodes on seam
3163       } // loop on edge of a face
3164     } // if ( !face.IsNull() )
3165
3166     if ( setMovableNodes.empty() ) {
3167       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3168       continue; // goto next face
3169     }
3170
3171     // -------------
3172     // SMOOTHING //
3173     // -------------
3174
3175     int it = -1;
3176     double maxRatio = -1., maxDisplacement = -1.;
3177     set<const SMDS_MeshNode*>::iterator nodeToMove;
3178     for ( it = 0; it < theNbIterations; it++ ) {
3179       maxDisplacement = 0.;
3180       nodeToMove = setMovableNodes.begin();
3181       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3182         const SMDS_MeshNode* node = (*nodeToMove);
3183         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3184
3185         // smooth
3186         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3187         if ( theSmoothMethod == LAPLACIAN )
3188           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3189         else
3190           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3191
3192         // node displacement
3193         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3194         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3195         if ( aDispl > maxDisplacement )
3196           maxDisplacement = aDispl;
3197       }
3198       // no node movement => exit
3199       //if ( maxDisplacement < 1.e-16 ) {
3200       if ( maxDisplacement < disttol ) {
3201         MESSAGE("-- no node movement --");
3202         break;
3203       }
3204
3205       // check elements quality
3206       maxRatio  = 0;
3207       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3208       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3209         const SMDS_MeshElement* elem = (*elemIt);
3210         if ( !elem || elem->GetType() != SMDSAbs_Face )
3211           continue;
3212         SMESH::Controls::TSequenceOfXYZ aPoints;
3213         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3214           double aValue = aQualityFunc.GetValue( aPoints );
3215           if ( aValue > maxRatio )
3216             maxRatio = aValue;
3217         }
3218       }
3219       if ( maxRatio <= theTgtAspectRatio ) {
3220         MESSAGE("-- quality achived --");
3221         break;
3222       }
3223       if (it+1 == theNbIterations) {
3224         MESSAGE("-- Iteration limit exceeded --");
3225       }
3226     } // smoothing iterations
3227
3228     MESSAGE(" Face id: " << *fId <<
3229             " Nb iterstions: " << it <<
3230             " Displacement: " << maxDisplacement <<
3231             " Aspect Ratio " << maxRatio);
3232
3233     // ---------------------------------------
3234     // new nodes positions are computed,
3235     // record movement in DS and set new UV
3236     // ---------------------------------------
3237     nodeToMove = setMovableNodes.begin();
3238     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3239       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3240       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3241       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3242       if ( node_uv != uvMap.end() ) {
3243         gp_XY* uv = node_uv->second;
3244         node->SetPosition
3245           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3246       }
3247     }
3248
3249     // move medium nodes of quadratic elements
3250     if ( isQuadratic )
3251     {
3252       SMESH_MesherHelper helper( *GetMesh() );
3253       if ( !face.IsNull() )
3254         helper.SetSubShape( face );
3255       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3256       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3257         const SMDS_QuadraticFaceOfNodes* QF =
3258           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3259         if(QF) {
3260           vector<const SMDS_MeshNode*> Ns;
3261           Ns.reserve(QF->NbNodes()+1);
3262           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3263           while ( anIter->more() )
3264             Ns.push_back( anIter->next() );
3265           Ns.push_back( Ns[0] );
3266           double x, y, z;
3267           for(int i=0; i<QF->NbNodes(); i=i+2) {
3268             if ( !surface.IsNull() ) {
3269               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3270               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3271               gp_XY uv = ( uv1 + uv2 ) / 2.;
3272               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3273               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3274             }
3275             else {
3276               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3277               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3278               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3279             }
3280             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3281                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3282                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3283               // we have to move i+1 node
3284               aMesh->MoveNode( Ns[i+1], x, y, z );
3285             }
3286           }
3287         }
3288       }
3289     }
3290
3291   } // loop on face ids
3292
3293 }
3294
3295 //=======================================================================
3296 //function : isReverse
3297 //purpose  : Return true if normal of prevNodes is not co-directied with
3298 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3299 //           iNotSame is where prevNodes and nextNodes are different
3300 //=======================================================================
3301
3302 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3303                       vector<const SMDS_MeshNode*> nextNodes,
3304                       const int            nbNodes,
3305                       const int            iNotSame)
3306 {
3307   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3308   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3309
3310   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3311   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3312   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3313   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3314
3315   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3316   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3317   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3318   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3319
3320   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3321
3322   return (vA ^ vB) * vN < 0.0;
3323 }
3324
3325 //=======================================================================
3326 /*!
3327  * \brief Create elements by sweeping an element
3328  * \param elem - element to sweep
3329  * \param newNodesItVec - nodes generated from each node of the element
3330  * \param newElems - generated elements
3331  * \param nbSteps - number of sweeping steps
3332  * \param srcElements - to append elem for each generated element
3333  */
3334 //=======================================================================
3335
3336 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3337                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3338                                     list<const SMDS_MeshElement*>&        newElems,
3339                                     const int                             nbSteps,
3340                                     SMESH_SequenceOfElemPtr&              srcElements)
3341 {
3342   SMESHDS_Mesh* aMesh = GetMeshDS();
3343
3344   // Loop on elem nodes:
3345   // find new nodes and detect same nodes indices
3346   int nbNodes = elem->NbNodes();
3347   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3348   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3349   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3350   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3351
3352   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3353   vector<int> sames(nbNodes);
3354   vector<bool> issimple(nbNodes);
3355
3356   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3357     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3358     const SMDS_MeshNode*                 node         = nnIt->first;
3359     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3360     if ( listNewNodes.empty() ) {
3361       return;
3362     }
3363
3364     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3365
3366     itNN[ iNode ] = listNewNodes.begin();
3367     prevNod[ iNode ] = node;
3368     nextNod[ iNode ] = listNewNodes.front();
3369     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3370       if ( prevNod[ iNode ] != nextNod [ iNode ])
3371         iNotSameNode = iNode;
3372       else {
3373         iSameNode = iNode;
3374         //nbSame++;
3375         sames[nbSame++] = iNode;
3376       }
3377     }
3378   }
3379
3380   //cout<<"  nbSame = "<<nbSame<<endl;
3381   if ( nbSame == nbNodes || nbSame > 2) {
3382     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3383     //INFOS( " Too many same nodes of element " << elem->GetID() );
3384     return;
3385   }
3386
3387   //  if( elem->IsQuadratic() && nbSame>0 ) {
3388   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3389   //    return;
3390   //  }
3391
3392   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3393   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3394   if ( nbSame > 0 ) {
3395     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3396     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3397     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3398   }
3399
3400   //if(nbNodes==8)
3401   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3402   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3403   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3404   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3405
3406   // check element orientation
3407   int i0 = 0, i2 = 2;
3408   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3409     //MESSAGE("Reversed elem " << elem );
3410     i0 = 2;
3411     i2 = 0;
3412     if ( nbSame > 0 )
3413       std::swap( iBeforeSame, iAfterSame );
3414   }
3415
3416   // make new elements
3417   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3418     // get next nodes
3419     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3420       if(issimple[iNode]) {
3421         nextNod[ iNode ] = *itNN[ iNode ];
3422         itNN[ iNode ]++;
3423       }
3424       else {
3425         if( elem->GetType()==SMDSAbs_Node ) {
3426           // we have to use two nodes
3427           midlNod[ iNode ] = *itNN[ iNode ];
3428           itNN[ iNode ]++;
3429           nextNod[ iNode ] = *itNN[ iNode ];
3430           itNN[ iNode ]++;
3431         }
3432         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3433           // we have to use each second node
3434           //itNN[ iNode ]++;
3435           nextNod[ iNode ] = *itNN[ iNode ];
3436           itNN[ iNode ]++;
3437         }
3438         else {
3439           // we have to use two nodes
3440           midlNod[ iNode ] = *itNN[ iNode ];
3441           itNN[ iNode ]++;
3442           nextNod[ iNode ] = *itNN[ iNode ];
3443           itNN[ iNode ]++;
3444         }
3445       }
3446     }
3447     SMDS_MeshElement* aNewElem = 0;
3448     if(!elem->IsPoly()) {
3449       switch ( nbNodes ) {
3450       case 0:
3451         return;
3452       case 1: { // NODE
3453         if ( nbSame == 0 ) {
3454           if(issimple[0])
3455             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3456           else
3457             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3458         }
3459         break;
3460       }
3461       case 2: { // EDGE
3462         if ( nbSame == 0 )
3463           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3464                                     nextNod[ 1 ], nextNod[ 0 ] );
3465         else
3466           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3467                                     nextNod[ iNotSameNode ] );
3468         break;
3469       }
3470
3471       case 3: { // TRIANGLE or quadratic edge
3472         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3473
3474           if ( nbSame == 0 )       // --- pentahedron
3475             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3476                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3477
3478           else if ( nbSame == 1 )  // --- pyramid
3479             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3480                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3481                                          nextNod[ iSameNode ]);
3482
3483           else // 2 same nodes:      --- tetrahedron
3484             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3485                                          nextNod[ iNotSameNode ]);
3486         }
3487         else { // quadratic edge
3488           if(nbSame==0) {     // quadratic quadrangle
3489             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3490                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3491           }
3492           else if(nbSame==1) { // quadratic triangle
3493             if(sames[0]==2) {
3494               return; // medium node on axis
3495             }
3496             else if(sames[0]==0) {
3497               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3498                                         nextNod[2], midlNod[1], prevNod[2]);
3499             }
3500             else { // sames[0]==1
3501               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3502                                         midlNod[0], nextNod[2], prevNod[2]);
3503             }
3504           }
3505           else {
3506             return;
3507           }
3508         }
3509         break;
3510       }
3511       case 4: { // QUADRANGLE
3512
3513         if ( nbSame == 0 )       // --- hexahedron
3514           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3515                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3516
3517         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3518           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3519                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3520                                        nextNod[ iSameNode ]);
3521           newElems.push_back( aNewElem );
3522           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3523                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3524                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3525         }
3526         else if ( nbSame == 2 ) { // pentahedron
3527           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3528             // iBeforeSame is same too
3529             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3530                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3531                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3532           else
3533             // iAfterSame is same too
3534             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3535                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3536                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3537         }
3538         break;
3539       }
3540       case 6: { // quadratic triangle
3541         // create pentahedron with 15 nodes
3542         if(nbSame==0) {
3543           if(i0>0) { // reversed case
3544             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3545                                          nextNod[0], nextNod[2], nextNod[1],
3546                                          prevNod[5], prevNod[4], prevNod[3],
3547                                          nextNod[5], nextNod[4], nextNod[3],
3548                                          midlNod[0], midlNod[2], midlNod[1]);
3549           }
3550           else { // not reversed case
3551             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3552                                          nextNod[0], nextNod[1], nextNod[2],
3553                                          prevNod[3], prevNod[4], prevNod[5],
3554                                          nextNod[3], nextNod[4], nextNod[5],
3555                                          midlNod[0], midlNod[1], midlNod[2]);
3556           }
3557         }
3558         else if(nbSame==1) {
3559           // 2d order pyramid of 13 nodes
3560           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3561           //                                 int n12,int n23,int n34,int n41,
3562           //                                 int n15,int n25,int n35,int n45, int ID);
3563           int n5 = iSameNode;
3564           int n1,n4,n41,n15,n45;
3565           if(i0>0) { // reversed case
3566             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3567             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3568             n41 = n1 + 3;
3569             n15 = n5 + 3;
3570             n45 = n4 + 3;
3571           }
3572           else {
3573             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3574             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3575             n41 = n4 + 3;
3576             n15 = n1 + 3;
3577             n45 = n5 + 3;
3578           }
3579           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3580                                       nextNod[n4], prevNod[n4], prevNod[n5],
3581                                       midlNod[n1], nextNod[n41],
3582                                       midlNod[n4], prevNod[n41],
3583                                       prevNod[n15], nextNod[n15],
3584                                       nextNod[n45], prevNod[n45]);
3585         }
3586         else if(nbSame==2) {
3587           // 2d order tetrahedron of 10 nodes
3588           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3589           //                                 int n12,int n23,int n31,
3590           //                                 int n14,int n24,int n34, int ID);
3591           int n1 = iNotSameNode;
3592           int n2,n3,n12,n23,n31;
3593           if(i0>0) { // reversed case
3594             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3595             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3596             n12 = n2 + 3;
3597             n23 = n3 + 3;
3598             n31 = n1 + 3;
3599           }
3600           else {
3601             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3602             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3603             n12 = n1 + 3;
3604             n23 = n2 + 3;
3605             n31 = n3 + 3;
3606           }
3607           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3608                                        prevNod[n12], prevNod[n23], prevNod[n31],
3609                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3610         }
3611         break;
3612       }
3613       case 8: { // quadratic quadrangle
3614         if(nbSame==0) {
3615           // create hexahedron with 20 nodes
3616           if(i0>0) { // reversed case
3617             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3618                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3619                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3620                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3621                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3622           }
3623           else { // not reversed case
3624             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3625                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3626                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3627                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3628                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3629           }
3630         }
3631         else if(nbSame==1) { 
3632           // --- pyramid + pentahedron - can not be created since it is needed 
3633           // additional middle node ot the center of face
3634           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3635           return;
3636         }
3637         else if(nbSame==2) {
3638           // 2d order Pentahedron with 15 nodes
3639           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3640           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3641           //                                 int n14,int n25,int n36, int ID);
3642           int n1,n2,n4,n5;
3643           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3644             // iBeforeSame is same too
3645             n1 = iBeforeSame;
3646             n2 = iOpposSame;
3647             n4 = iSameNode;
3648             n5 = iAfterSame;
3649           }
3650           else {
3651             // iAfterSame is same too
3652             n1 = iSameNode;
3653             n2 = iBeforeSame;
3654             n4 = iAfterSame;
3655             n5 = iOpposSame;
3656           }
3657           int n12,n45,n14,n25;
3658           if(i0>0) { //reversed case
3659             n12 = n1 + 4;
3660             n45 = n5 + 4;
3661             n14 = n4 + 4;
3662             n25 = n2 + 4;
3663           }
3664           else {
3665             n12 = n2 + 4;
3666             n45 = n4 + 4;
3667             n14 = n1 + 4;
3668             n25 = n5 + 4;
3669           }
3670           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3671                                        prevNod[n4], prevNod[n5], nextNod[n5],
3672                                        prevNod[n12], midlNod[n2], nextNod[n12],
3673                                        prevNod[n45], midlNod[n5], nextNod[n45],
3674                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3675         }
3676         break;
3677       }
3678       default: {
3679         // realized for extrusion only
3680         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3681         //vector<int> quantities (nbNodes + 2);
3682
3683         //quantities[0] = nbNodes; // bottom of prism
3684         //for (int inode = 0; inode < nbNodes; inode++) {
3685         //  polyedre_nodes[inode] = prevNod[inode];
3686         //}
3687
3688         //quantities[1] = nbNodes; // top of prism
3689         //for (int inode = 0; inode < nbNodes; inode++) {
3690         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3691         //}
3692
3693         //for (int iface = 0; iface < nbNodes; iface++) {
3694         //  quantities[iface + 2] = 4;
3695         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3696         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3697         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3698         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3699         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3700         //}
3701         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3702         break;
3703       }
3704       }
3705     }
3706
3707     if(!aNewElem) {
3708       // realized for extrusion only
3709       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3710       vector<int> quantities (nbNodes + 2);
3711
3712       quantities[0] = nbNodes; // bottom of prism
3713       for (int inode = 0; inode < nbNodes; inode++) {
3714         polyedre_nodes[inode] = prevNod[inode];
3715       }
3716
3717       quantities[1] = nbNodes; // top of prism
3718       for (int inode = 0; inode < nbNodes; inode++) {
3719         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3720       }
3721
3722       for (int iface = 0; iface < nbNodes; iface++) {
3723         quantities[iface + 2] = 4;
3724         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3725         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3726         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3727         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3728         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3729       }
3730       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3731     }
3732
3733     if ( aNewElem ) {
3734       newElems.push_back( aNewElem );
3735       myLastCreatedElems.Append(aNewElem);
3736       srcElements.Append( elem );
3737     }
3738
3739     // set new prev nodes
3740     for ( iNode = 0; iNode < nbNodes; iNode++ )
3741       prevNod[ iNode ] = nextNod[ iNode ];
3742
3743   } // for steps
3744 }
3745
3746 //=======================================================================
3747 /*!
3748  * \brief Create 1D and 2D elements around swept elements
3749  * \param mapNewNodes - source nodes and ones generated from them
3750  * \param newElemsMap - source elements and ones generated from them
3751  * \param elemNewNodesMap - nodes generated from each node of each element
3752  * \param elemSet - all swept elements
3753  * \param nbSteps - number of sweeping steps
3754  * \param srcElements - to append elem for each generated element
3755  */
3756 //=======================================================================
3757
3758 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3759                                   TElemOfElemListMap &     newElemsMap,
3760                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3761                                   TIDSortedElemSet&        elemSet,
3762                                   const int                nbSteps,
3763                                   SMESH_SequenceOfElemPtr& srcElements)
3764 {
3765   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3766   SMESHDS_Mesh* aMesh = GetMeshDS();
3767
3768   // Find nodes belonging to only one initial element - sweep them to get edges.
3769
3770   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3771   for ( ; nList != mapNewNodes.end(); nList++ ) {
3772     const SMDS_MeshNode* node =
3773       static_cast<const SMDS_MeshNode*>( nList->first );
3774     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3775     int nbInitElems = 0;
3776     const SMDS_MeshElement* el = 0;
3777     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3778     while ( eIt->more() && nbInitElems < 2 ) {
3779       el = eIt->next();
3780       SMDSAbs_ElementType type = el->GetType();
3781       if ( type == SMDSAbs_Volume || type < highType ) continue;
3782       if ( type > highType ) {
3783         nbInitElems = 0;
3784         highType = type;
3785       }
3786       if ( elemSet.find(el) != elemSet.end() )
3787         nbInitElems++;
3788     }
3789     if ( nbInitElems < 2 ) {
3790       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3791       if(!NotCreateEdge) {
3792         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3793         list<const SMDS_MeshElement*> newEdges;
3794         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3795       }
3796     }
3797   }
3798
3799   // Make a ceiling for each element ie an equal element of last new nodes.
3800   // Find free links of faces - make edges and sweep them into faces.
3801
3802   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3803   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3804   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3805     const SMDS_MeshElement* elem = itElem->first;
3806     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3807
3808     if ( elem->GetType() == SMDSAbs_Edge ) {
3809       // create a ceiling edge
3810       if (!elem->IsQuadratic()) {
3811         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3812                                vecNewNodes[ 1 ]->second.back())) {
3813           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3814                                                    vecNewNodes[ 1 ]->second.back()));
3815           srcElements.Append( myLastCreatedElems.Last() );
3816         }
3817       }
3818       else {
3819         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3820                                vecNewNodes[ 1 ]->second.back(),
3821                                vecNewNodes[ 2 ]->second.back())) {
3822           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3823                                                    vecNewNodes[ 1 ]->second.back(),
3824                                                    vecNewNodes[ 2 ]->second.back()));
3825           srcElements.Append( myLastCreatedElems.Last() );
3826         }
3827       }
3828     }
3829     if ( elem->GetType() != SMDSAbs_Face )
3830       continue;
3831
3832     if(itElem->second.size()==0) continue;
3833
3834     bool hasFreeLinks = false;
3835
3836     TIDSortedElemSet avoidSet;
3837     avoidSet.insert( elem );
3838
3839     set<const SMDS_MeshNode*> aFaceLastNodes;
3840     int iNode, nbNodes = vecNewNodes.size();
3841     if(!elem->IsQuadratic()) {
3842       // loop on the face nodes
3843       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3844         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3845         // look for free links of the face
3846         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3847         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3848         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3849         // check if a link is free
3850         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3851           hasFreeLinks = true;
3852           // make an edge and a ceiling for a new edge
3853           if ( !aMesh->FindEdge( n1, n2 )) {
3854             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3855             srcElements.Append( myLastCreatedElems.Last() );
3856           }
3857           n1 = vecNewNodes[ iNode ]->second.back();
3858           n2 = vecNewNodes[ iNext ]->second.back();
3859           if ( !aMesh->FindEdge( n1, n2 )) {
3860             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3861             srcElements.Append( myLastCreatedElems.Last() );
3862           }
3863         }
3864       }
3865     }
3866     else { // elem is quadratic face
3867       int nbn = nbNodes/2;
3868       for ( iNode = 0; iNode < nbn; iNode++ ) {
3869         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3870         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3871         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3872         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3873         // check if a link is free
3874         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3875           hasFreeLinks = true;
3876           // make an edge and a ceiling for a new edge
3877           // find medium node
3878           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3879           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3880             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3881             srcElements.Append( myLastCreatedElems.Last() );
3882           }
3883           n1 = vecNewNodes[ iNode ]->second.back();
3884           n2 = vecNewNodes[ iNext ]->second.back();
3885           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3886           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3887             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3888             srcElements.Append( myLastCreatedElems.Last() );
3889           }
3890         }
3891       }
3892       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3893         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3894       }
3895     }
3896
3897     // sweep free links into faces
3898
3899     if ( hasFreeLinks )  {
3900       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3901       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3902
3903       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3904       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3905         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3906         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3907       }
3908       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3909         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3910         iVol = 0;
3911         while ( iVol++ < volNb ) v++;
3912         // find indices of free faces of a volume and their source edges
3913         list< int > freeInd;
3914         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3915         SMDS_VolumeTool vTool( *v );
3916         int iF, nbF = vTool.NbFaces();
3917         for ( iF = 0; iF < nbF; iF ++ ) {
3918           if (vTool.IsFreeFace( iF ) &&
3919               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3920               initNodeSet != faceNodeSet) // except an initial face
3921           {
3922             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3923               continue;
3924             freeInd.push_back( iF );
3925             // find source edge of a free face iF
3926             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3927             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3928             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3929                                    initNodeSet.begin(), initNodeSet.end(),
3930                                    commonNodes.begin());
3931             if ( (*v)->IsQuadratic() )
3932               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3933             else
3934               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3935 #ifdef _DEBUG_
3936             if ( !srcEdges.back() )
3937             {
3938               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3939                    << iF << " of volume #" << vTool.ID() << endl;
3940             }
3941 #endif
3942           }
3943         }
3944         if ( freeInd.empty() )
3945           continue;
3946
3947         // create faces for all steps;
3948         // if such a face has been already created by sweep of edge,
3949         // assure that its orientation is OK
3950         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3951           vTool.Set( *v );
3952           vTool.SetExternalNormal();
3953           list< int >::iterator ind = freeInd.begin();
3954           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3955           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3956           {
3957             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3958             int nbn = vTool.NbFaceNodes( *ind );
3959             switch ( nbn ) {
3960             case 3: { ///// triangle
3961               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3962               if ( !f )
3963                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3964               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3965                 aMesh->ChangeElementNodes( f, nodes, nbn );
3966               break;
3967             }
3968             case 4: { ///// quadrangle
3969               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3970               if ( !f )
3971                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3972               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3973                 aMesh->ChangeElementNodes( f, nodes, nbn );
3974               break;
3975             }
3976             default:
3977               if( (*v)->IsQuadratic() ) {
3978                 if(nbn==6) { /////// quadratic triangle
3979                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3980                                                              nodes[1], nodes[3], nodes[5] );
3981                   if ( !f ) {
3982                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3983                                                              nodes[1], nodes[3], nodes[5]));
3984                   }
3985                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3986                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3987                     tmpnodes[0] = nodes[0];
3988                     tmpnodes[1] = nodes[2];
3989                     tmpnodes[2] = nodes[4];
3990                     tmpnodes[3] = nodes[1];
3991                     tmpnodes[4] = nodes[3];
3992                     tmpnodes[5] = nodes[5];
3993                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3994                   }
3995                 }
3996                 else {       /////// quadratic quadrangle
3997                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3998                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3999                   if ( !f ) {
4000                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4001                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4002                   }
4003                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4004                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4005                     tmpnodes[0] = nodes[0];
4006                     tmpnodes[1] = nodes[2];
4007                     tmpnodes[2] = nodes[4];
4008                     tmpnodes[3] = nodes[6];
4009                     tmpnodes[4] = nodes[1];
4010                     tmpnodes[5] = nodes[3];
4011                     tmpnodes[6] = nodes[5];
4012                     tmpnodes[7] = nodes[7];
4013                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
4014                   }
4015                 }
4016               }
4017               else { //////// polygon
4018                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4019                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4020                 if ( !f )
4021                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4022                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4023                   aMesh->ChangeElementNodes( f, nodes, nbn );
4024               }
4025             }
4026             while ( srcElements.Length() < myLastCreatedElems.Length() )
4027               srcElements.Append( *srcEdge );
4028
4029           }  // loop on free faces
4030
4031           // go to the next volume
4032           iVol = 0;
4033           while ( iVol++ < nbVolumesByStep ) v++;
4034         }
4035       }
4036     } // sweep free links into faces
4037
4038     // Make a ceiling face with a normal external to a volume
4039
4040     SMDS_VolumeTool lastVol( itElem->second.back() );
4041
4042     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4043     if ( iF >= 0 ) {
4044       lastVol.SetExternalNormal();
4045       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4046       int nbn = lastVol.NbFaceNodes( iF );
4047       switch ( nbn ) {
4048       case 3:
4049         if (!hasFreeLinks ||
4050             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4051           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4052         break;
4053       case 4:
4054         if (!hasFreeLinks ||
4055             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4056           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4057         break;
4058       default:
4059         if(itElem->second.back()->IsQuadratic()) {
4060           if(nbn==6) {
4061             if (!hasFreeLinks ||
4062                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4063                                  nodes[1], nodes[3], nodes[5]) ) {
4064               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4065                                                        nodes[1], nodes[3], nodes[5]));
4066             }
4067           }
4068           else { // nbn==8
4069             if (!hasFreeLinks ||
4070                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4071                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4072               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4073                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4074           }
4075         }
4076         else {
4077           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4078           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4079             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4080         }
4081       } // switch
4082
4083       while ( srcElements.Length() < myLastCreatedElems.Length() )
4084         srcElements.Append( myLastCreatedElems.Last() );
4085     }
4086   } // loop on swept elements
4087 }
4088
4089 //=======================================================================
4090 //function : RotationSweep
4091 //purpose  :
4092 //=======================================================================
4093
4094 SMESH_MeshEditor::PGroupIDs
4095 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4096                                 const gp_Ax1&      theAxis,
4097                                 const double       theAngle,
4098                                 const int          theNbSteps,
4099                                 const double       theTol,
4100                                 const bool         theMakeGroups,
4101                                 const bool         theMakeWalls)
4102 {
4103   myLastCreatedElems.Clear();
4104   myLastCreatedNodes.Clear();
4105
4106   // source elements for each generated one
4107   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4108
4109   MESSAGE( "RotationSweep()");
4110   gp_Trsf aTrsf;
4111   aTrsf.SetRotation( theAxis, theAngle );
4112   gp_Trsf aTrsf2;
4113   aTrsf2.SetRotation( theAxis, theAngle/2. );
4114
4115   gp_Lin aLine( theAxis );
4116   double aSqTol = theTol * theTol;
4117
4118   SMESHDS_Mesh* aMesh = GetMeshDS();
4119
4120   TNodeOfNodeListMap mapNewNodes;
4121   TElemOfVecOfNnlmiMap mapElemNewNodes;
4122   TElemOfElemListMap newElemsMap;
4123
4124   // loop on theElems
4125   TIDSortedElemSet::iterator itElem;
4126   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4127     const SMDS_MeshElement* elem = *itElem;
4128     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4129       continue;
4130     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4131     newNodesItVec.reserve( elem->NbNodes() );
4132
4133     // loop on elem nodes
4134     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4135     while ( itN->more() ) {
4136       // check if a node has been already sweeped
4137       const SMDS_MeshNode* node = cast2Node( itN->next() );
4138
4139       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4140       double coord[3];
4141       aXYZ.Coord( coord[0], coord[1], coord[2] );
4142       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4143
4144       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4145       if ( nIt == mapNewNodes.end() ) {
4146         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4147         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4148
4149         // make new nodes
4150         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4151         //double coord[3];
4152         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4153         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4154         const SMDS_MeshNode * newNode = node;
4155         for ( int i = 0; i < theNbSteps; i++ ) {
4156           if ( !isOnAxis ) {
4157             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4158               // create two nodes
4159               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4160               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4161               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4162               myLastCreatedNodes.Append(newNode);
4163               srcNodes.Append( node );
4164               listNewNodes.push_back( newNode );
4165               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4166               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4167             }
4168             else {
4169               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4170             }
4171             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4172             myLastCreatedNodes.Append(newNode);
4173             srcNodes.Append( node );
4174             listNewNodes.push_back( newNode );
4175           }
4176           else {
4177             listNewNodes.push_back( newNode );
4178             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4179               listNewNodes.push_back( newNode );
4180             }
4181           }
4182         }
4183       }
4184       /*
4185         else {
4186         // if current elem is quadratic and current node is not medium
4187         // we have to check - may be it is needed to insert additional nodes
4188         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4189         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4190         if(listNewNodes.size()==theNbSteps) {
4191         listNewNodes.clear();
4192         // make new nodes
4193         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4194         //double coord[3];
4195         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4196         const SMDS_MeshNode * newNode = node;
4197         if ( !isOnAxis ) {
4198         for(int i = 0; i<theNbSteps; i++) {
4199         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4200         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4201         cout<<"    3 AddNode:  "<<newNode;
4202         myLastCreatedNodes.Append(newNode);
4203         listNewNodes.push_back( newNode );
4204         srcNodes.Append( node );
4205         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4206         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4207         cout<<"    4 AddNode:  "<<newNode;
4208         myLastCreatedNodes.Append(newNode);
4209         srcNodes.Append( node );
4210         listNewNodes.push_back( newNode );
4211         }
4212         }
4213         else {
4214         listNewNodes.push_back( newNode );
4215         }
4216         }
4217         }
4218         }
4219       */
4220       newNodesItVec.push_back( nIt );
4221     }
4222     // make new elements
4223     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4224   }
4225
4226   if ( theMakeWalls )
4227     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4228
4229   PGroupIDs newGroupIDs;
4230   if ( theMakeGroups )
4231     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4232
4233   return newGroupIDs;
4234 }
4235
4236
4237 //=======================================================================
4238 //function : CreateNode
4239 //purpose  :
4240 //=======================================================================
4241 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4242                                                   const double y,
4243                                                   const double z,
4244                                                   const double tolnode,
4245                                                   SMESH_SequenceOfNode& aNodes)
4246 {
4247   myLastCreatedElems.Clear();
4248   myLastCreatedNodes.Clear();
4249
4250   gp_Pnt P1(x,y,z);
4251   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4252
4253   // try to search in sequence of existing nodes
4254   // if aNodes.Length()>0 we 'nave to use given sequence
4255   // else - use all nodes of mesh
4256   if(aNodes.Length()>0) {
4257     int i;
4258     for(i=1; i<=aNodes.Length(); i++) {
4259       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4260       if(P1.Distance(P2)<tolnode)
4261         return aNodes.Value(i);
4262     }
4263   }
4264   else {
4265     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4266     while(itn->more()) {
4267       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4268       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4269       if(P1.Distance(P2)<tolnode)
4270         return aN;
4271     }
4272   }
4273
4274   // create new node and return it
4275   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4276   myLastCreatedNodes.Append(NewNode);
4277   return NewNode;
4278 }
4279
4280
4281 //=======================================================================
4282 //function : ExtrusionSweep
4283 //purpose  :
4284 //=======================================================================
4285
4286 SMESH_MeshEditor::PGroupIDs
4287 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4288                                   const gp_Vec&       theStep,
4289                                   const int           theNbSteps,
4290                                   TElemOfElemListMap& newElemsMap,
4291                                   const bool          theMakeGroups,
4292                                   const int           theFlags,
4293                                   const double        theTolerance)
4294 {
4295   ExtrusParam aParams;
4296   aParams.myDir = gp_Dir(theStep);
4297   aParams.myNodes.Clear();
4298   aParams.mySteps = new TColStd_HSequenceOfReal;
4299   int i;
4300   for(i=1; i<=theNbSteps; i++)
4301     aParams.mySteps->Append(theStep.Magnitude());
4302
4303   return
4304     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4305 }
4306
4307
4308 //=======================================================================
4309 //function : ExtrusionSweep
4310 //purpose  :
4311 //=======================================================================
4312
4313 SMESH_MeshEditor::PGroupIDs
4314 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4315                                   ExtrusParam&        theParams,
4316                                   TElemOfElemListMap& newElemsMap,
4317                                   const bool          theMakeGroups,
4318                                   const int           theFlags,
4319                                   const double        theTolerance)
4320 {
4321   myLastCreatedElems.Clear();
4322   myLastCreatedNodes.Clear();
4323
4324   // source elements for each generated one
4325   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4326
4327   SMESHDS_Mesh* aMesh = GetMeshDS();
4328
4329   int nbsteps = theParams.mySteps->Length();
4330
4331   TNodeOfNodeListMap mapNewNodes;
4332   //TNodeOfNodeVecMap mapNewNodes;
4333   TElemOfVecOfNnlmiMap mapElemNewNodes;
4334   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4335
4336   // loop on theElems
4337   TIDSortedElemSet::iterator itElem;
4338   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4339     // check element type
4340     const SMDS_MeshElement* elem = *itElem;
4341     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4342       continue;
4343
4344     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4345     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4346     newNodesItVec.reserve( elem->NbNodes() );
4347
4348     // loop on elem nodes
4349     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4350     while ( itN->more() )
4351     {
4352       // check if a node has been already sweeped
4353       const SMDS_MeshNode* node = cast2Node( itN->next() );
4354       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4355       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4356       if ( nIt == mapNewNodes.end() ) {
4357         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4358         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4359         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4360         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4361         //vecNewNodes.reserve(nbsteps);
4362
4363         // make new nodes
4364         double coord[] = { node->X(), node->Y(), node->Z() };
4365         //int nbsteps = theParams.mySteps->Length();
4366         for ( int i = 0; i < nbsteps; i++ ) {
4367           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4368             // create additional node
4369             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4370             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4371             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4372             if( theFlags & EXTRUSION_FLAG_SEW ) {
4373               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4374                                                          theTolerance, theParams.myNodes);
4375               listNewNodes.push_back( newNode );
4376             }
4377             else {
4378               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4379               myLastCreatedNodes.Append(newNode);
4380               srcNodes.Append( node );
4381               listNewNodes.push_back( newNode );
4382             }
4383           }
4384           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4385           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4386           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4387           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4388           if( theFlags & EXTRUSION_FLAG_SEW ) {
4389             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4390                                                        theTolerance, theParams.myNodes);
4391             listNewNodes.push_back( newNode );
4392             //vecNewNodes[i]=newNode;
4393           }
4394           else {
4395             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4396             myLastCreatedNodes.Append(newNode);
4397             srcNodes.Append( node );
4398             listNewNodes.push_back( newNode );
4399             //vecNewNodes[i]=newNode;
4400           }
4401         }
4402       }
4403       else {
4404         // if current elem is quadratic and current node is not medium
4405         // we have to check - may be it is needed to insert additional nodes
4406         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4407           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4408           if(listNewNodes.size()==nbsteps) {
4409             listNewNodes.clear();
4410             double coord[] = { node->X(), node->Y(), node->Z() };
4411             for ( int i = 0; i < nbsteps; i++ ) {
4412               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4413               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4414               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4415               if( theFlags & EXTRUSION_FLAG_SEW ) {
4416                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4417                                                            theTolerance, theParams.myNodes);
4418                 listNewNodes.push_back( newNode );
4419               }
4420               else {
4421                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4422                 myLastCreatedNodes.Append(newNode);
4423                 srcNodes.Append( node );
4424                 listNewNodes.push_back( newNode );
4425               }
4426               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4427               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4428               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4429               if( theFlags & EXTRUSION_FLAG_SEW ) {
4430                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4431                                                            theTolerance, theParams.myNodes);
4432                 listNewNodes.push_back( newNode );
4433               }
4434               else {
4435                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4436                 myLastCreatedNodes.Append(newNode);
4437                 srcNodes.Append( node );
4438                 listNewNodes.push_back( newNode );
4439               }
4440             }
4441           }
4442         }
4443       }
4444       newNodesItVec.push_back( nIt );
4445     }
4446     // make new elements
4447     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4448   }
4449
4450   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4451     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4452   }
4453   PGroupIDs newGroupIDs;
4454   if ( theMakeGroups )
4455     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4456
4457   return newGroupIDs;
4458 }
4459
4460 /*
4461 //=======================================================================
4462 //class    : SMESH_MeshEditor_PathPoint
4463 //purpose  : auxiliary class
4464 //=======================================================================
4465 class SMESH_MeshEditor_PathPoint {
4466 public:
4467 SMESH_MeshEditor_PathPoint() {
4468 myPnt.SetCoord(99., 99., 99.);
4469 myTgt.SetCoord(1.,0.,0.);
4470 myAngle=0.;
4471 myPrm=0.;
4472 }
4473 void SetPnt(const gp_Pnt& aP3D){
4474 myPnt=aP3D;
4475 }
4476 void SetTangent(const gp_Dir& aTgt){
4477 myTgt=aTgt;
4478 }
4479 void SetAngle(const double& aBeta){
4480 myAngle=aBeta;
4481 }
4482 void SetParameter(const double& aPrm){
4483 myPrm=aPrm;
4484 }
4485 const gp_Pnt& Pnt()const{
4486 return myPnt;
4487 }
4488 const gp_Dir& Tangent()const{
4489 return myTgt;
4490 }
4491 double Angle()const{
4492 return myAngle;
4493 }
4494 double Parameter()const{
4495 return myPrm;
4496 }
4497
4498 protected:
4499 gp_Pnt myPnt;
4500 gp_Dir myTgt;
4501 double myAngle;
4502 double myPrm;
4503 };
4504 */
4505
4506 //=======================================================================
4507 //function : ExtrusionAlongTrack
4508 //purpose  :
4509 //=======================================================================
4510 SMESH_MeshEditor::Extrusion_Error
4511 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4512                                        SMESH_subMesh*       theTrack,
4513                                        const SMDS_MeshNode* theN1,
4514                                        const bool           theHasAngles,
4515                                        list<double>&        theAngles,
4516                                        const bool           theLinearVariation,
4517                                        const bool           theHasRefPoint,
4518                                        const gp_Pnt&        theRefPoint,
4519                                        const bool           theMakeGroups)
4520 {
4521   myLastCreatedElems.Clear();
4522   myLastCreatedNodes.Clear();
4523
4524   int aNbE;
4525   std::list<double> aPrms;
4526   TIDSortedElemSet::iterator itElem;
4527
4528   gp_XYZ aGC;
4529   TopoDS_Edge aTrackEdge;
4530   TopoDS_Vertex aV1, aV2;
4531
4532   SMDS_ElemIteratorPtr aItE;
4533   SMDS_NodeIteratorPtr aItN;
4534   SMDSAbs_ElementType aTypeE;
4535
4536   TNodeOfNodeListMap mapNewNodes;
4537
4538   // 1. Check data
4539   aNbE = theElements.size();
4540   // nothing to do
4541   if ( !aNbE )
4542     return EXTR_NO_ELEMENTS;
4543
4544   // 1.1 Track Pattern
4545   ASSERT( theTrack );
4546
4547   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4548
4549   aItE = pSubMeshDS->GetElements();
4550   while ( aItE->more() ) {
4551     const SMDS_MeshElement* pE = aItE->next();
4552     aTypeE = pE->GetType();
4553     // Pattern must contain links only
4554     if ( aTypeE != SMDSAbs_Edge )
4555       return EXTR_PATH_NOT_EDGE;
4556   }
4557
4558   list<SMESH_MeshEditor_PathPoint> fullList;
4559
4560   const TopoDS_Shape& aS = theTrack->GetSubShape();
4561   // Sub shape for the Pattern must be an Edge or Wire
4562   if( aS.ShapeType() == TopAbs_EDGE ) {
4563     aTrackEdge = TopoDS::Edge( aS );
4564     // the Edge must not be degenerated
4565     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4566       return EXTR_BAD_PATH_SHAPE;
4567     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4568     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4569     const SMDS_MeshNode* aN1 = aItN->next();
4570     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4571     const SMDS_MeshNode* aN2 = aItN->next();
4572     // starting node must be aN1 or aN2
4573     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4574       return EXTR_BAD_STARTING_NODE;
4575     aItN = pSubMeshDS->GetNodes();
4576     while ( aItN->more() ) {
4577       const SMDS_MeshNode* pNode = aItN->next();
4578       const SMDS_EdgePosition* pEPos =
4579         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4580       double aT = pEPos->GetUParameter();
4581       aPrms.push_back( aT );
4582     }
4583     //Extrusion_Error err =
4584     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4585   }
4586   else if( aS.ShapeType() == TopAbs_WIRE ) {
4587     list< SMESH_subMesh* > LSM;
4588     TopTools_SequenceOfShape Edges;
4589     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4590     while(itSM->more()) {
4591       SMESH_subMesh* SM = itSM->next();
4592       LSM.push_back(SM);
4593       const TopoDS_Shape& aS = SM->GetSubShape();
4594       Edges.Append(aS);
4595     }
4596     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4597     int startNid = theN1->GetID();
4598     TColStd_MapOfInteger UsedNums;
4599     int NbEdges = Edges.Length();
4600     int i = 1;
4601     for(; i<=NbEdges; i++) {
4602       int k = 0;
4603       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4604       for(; itLSM!=LSM.end(); itLSM++) {
4605         k++;
4606         if(UsedNums.Contains(k)) continue;
4607         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4608         SMESH_subMesh* locTrack = *itLSM;
4609         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4610         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4611         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4612         const SMDS_MeshNode* aN1 = aItN->next();
4613         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4614         const SMDS_MeshNode* aN2 = aItN->next();
4615         // starting node must be aN1 or aN2
4616         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4617         // 2. Collect parameters on the track edge
4618         aPrms.clear();
4619         aItN = locMeshDS->GetNodes();
4620         while ( aItN->more() ) {
4621           const SMDS_MeshNode* pNode = aItN->next();
4622           const SMDS_EdgePosition* pEPos =
4623             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4624           double aT = pEPos->GetUParameter();
4625           aPrms.push_back( aT );
4626         }
4627         list<SMESH_MeshEditor_PathPoint> LPP;
4628         //Extrusion_Error err =
4629         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4630         LLPPs.push_back(LPP);
4631         UsedNums.Add(k);
4632         // update startN for search following egde
4633         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4634         else startNid = aN1->GetID();
4635         break;
4636       }
4637     }
4638     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4639     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4640     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4641     for(; itPP!=firstList.end(); itPP++) {
4642       fullList.push_back( *itPP );
4643     }
4644     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4645     fullList.pop_back();
4646     itLLPP++;
4647     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4648       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4649       itPP = currList.begin();
4650       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4651       gp_Dir D1 = PP1.Tangent();
4652       gp_Dir D2 = PP2.Tangent();
4653       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4654                            (D1.Z()+D2.Z())/2 ) );
4655       PP1.SetTangent(Dnew);
4656       fullList.push_back(PP1);
4657       itPP++;
4658       for(; itPP!=firstList.end(); itPP++) {
4659         fullList.push_back( *itPP );
4660       }
4661       PP1 = fullList.back();
4662       fullList.pop_back();
4663     }
4664     // if wire not closed
4665     fullList.push_back(PP1);
4666     // else ???
4667   }
4668   else {
4669     return EXTR_BAD_PATH_SHAPE;
4670   }
4671
4672   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4673                           theHasRefPoint, theRefPoint, theMakeGroups);
4674 }
4675
4676
4677 //=======================================================================
4678 //function : ExtrusionAlongTrack
4679 //purpose  :
4680 //=======================================================================
4681 SMESH_MeshEditor::Extrusion_Error
4682 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4683                                        SMESH_Mesh*          theTrack,
4684                                        const SMDS_MeshNode* theN1,
4685                                        const bool           theHasAngles,
4686                                        list<double>&        theAngles,
4687                                        const bool           theLinearVariation,
4688                                        const bool           theHasRefPoint,
4689                                        const gp_Pnt&        theRefPoint,
4690                                        const bool           theMakeGroups)
4691 {
4692   myLastCreatedElems.Clear();
4693   myLastCreatedNodes.Clear();
4694
4695   int aNbE;
4696   std::list<double> aPrms;
4697   TIDSortedElemSet::iterator itElem;
4698
4699   gp_XYZ aGC;
4700   TopoDS_Edge aTrackEdge;
4701   TopoDS_Vertex aV1, aV2;
4702
4703   SMDS_ElemIteratorPtr aItE;
4704   SMDS_NodeIteratorPtr aItN;
4705   SMDSAbs_ElementType aTypeE;
4706
4707   TNodeOfNodeListMap mapNewNodes;
4708
4709   // 1. Check data
4710   aNbE = theElements.size();
4711   // nothing to do
4712   if ( !aNbE )
4713     return EXTR_NO_ELEMENTS;
4714
4715   // 1.1 Track Pattern
4716   ASSERT( theTrack );
4717
4718   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4719
4720   aItE = pMeshDS->elementsIterator();
4721   while ( aItE->more() ) {
4722     const SMDS_MeshElement* pE = aItE->next();
4723     aTypeE = pE->GetType();
4724     // Pattern must contain links only
4725     if ( aTypeE != SMDSAbs_Edge )
4726       return EXTR_PATH_NOT_EDGE;
4727   }
4728
4729   list<SMESH_MeshEditor_PathPoint> fullList;
4730
4731   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4732   // Sub shape for the Pattern must be an Edge or Wire
4733   if( aS.ShapeType() == TopAbs_EDGE ) {
4734     aTrackEdge = TopoDS::Edge( aS );
4735     // the Edge must not be degenerated
4736     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4737       return EXTR_BAD_PATH_SHAPE;
4738     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4739     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4740     const SMDS_MeshNode* aN1 = aItN->next();
4741     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4742     const SMDS_MeshNode* aN2 = aItN->next();
4743     // starting node must be aN1 or aN2
4744     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4745       return EXTR_BAD_STARTING_NODE;
4746     aItN = pMeshDS->nodesIterator();
4747     while ( aItN->more() ) {
4748       const SMDS_MeshNode* pNode = aItN->next();
4749       if( pNode==aN1 || pNode==aN2 ) continue;
4750       const SMDS_EdgePosition* pEPos =
4751         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4752       double aT = pEPos->GetUParameter();
4753       aPrms.push_back( aT );
4754     }
4755     //Extrusion_Error err =
4756     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4757   }
4758   else if( aS.ShapeType() == TopAbs_WIRE ) {
4759     list< SMESH_subMesh* > LSM;
4760     TopTools_SequenceOfShape Edges;
4761     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4762     for(; eExp.More(); eExp.Next()) {
4763       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4764       if( BRep_Tool::Degenerated(E) ) continue;
4765       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4766       if(SM) {
4767         LSM.push_back(SM);
4768         Edges.Append(E);
4769       }
4770     }
4771     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4772     int startNid = theN1->GetID();
4773     TColStd_MapOfInteger UsedNums;
4774     int NbEdges = Edges.Length();
4775     int i = 1;
4776     for(; i<=NbEdges; i++) {
4777       int k = 0;
4778       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4779       for(; itLSM!=LSM.end(); itLSM++) {
4780         k++;
4781         if(UsedNums.Contains(k)) continue;
4782         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4783         SMESH_subMesh* locTrack = *itLSM;
4784         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4785         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4786         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4787         const SMDS_MeshNode* aN1 = aItN->next();
4788         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4789         const SMDS_MeshNode* aN2 = aItN->next();
4790         // starting node must be aN1 or aN2
4791         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4792         // 2. Collect parameters on the track edge
4793         aPrms.clear();
4794         aItN = locMeshDS->GetNodes();
4795         while ( aItN->more() ) {
4796           const SMDS_MeshNode* pNode = aItN->next();
4797           const SMDS_EdgePosition* pEPos =
4798             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4799           double aT = pEPos->GetUParameter();
4800           aPrms.push_back( aT );
4801         }
4802         list<SMESH_MeshEditor_PathPoint> LPP;
4803         //Extrusion_Error err =
4804         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4805         LLPPs.push_back(LPP);
4806         UsedNums.Add(k);
4807         // update startN for search following egde
4808         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4809         else startNid = aN1->GetID();
4810         break;
4811       }
4812     }
4813     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4814     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4815     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4816     for(; itPP!=firstList.end(); itPP++) {
4817       fullList.push_back( *itPP );
4818     }
4819     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4820     fullList.pop_back();
4821     itLLPP++;
4822     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4823       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4824       itPP = currList.begin();
4825       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4826       gp_Pnt P1 = PP1.Pnt();
4827       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4828       gp_Pnt P2 = PP2.Pnt();
4829       gp_Dir D1 = PP1.Tangent();
4830       gp_Dir D2 = PP2.Tangent();
4831       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4832                            (D1.Z()+D2.Z())/2 ) );
4833       PP1.SetTangent(Dnew);
4834       fullList.push_back(PP1);
4835       itPP++;
4836       for(; itPP!=currList.end(); itPP++) {
4837         fullList.push_back( *itPP );
4838       }
4839       PP1 = fullList.back();
4840       fullList.pop_back();
4841     }
4842     // if wire not closed
4843     fullList.push_back(PP1);
4844     // else ???
4845   }
4846   else {
4847     return EXTR_BAD_PATH_SHAPE;
4848   }
4849
4850   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4851                           theHasRefPoint, theRefPoint, theMakeGroups);
4852 }
4853
4854
4855 //=======================================================================
4856 //function : MakeEdgePathPoints
4857 //purpose  : auxilary for ExtrusionAlongTrack
4858 //=======================================================================
4859 SMESH_MeshEditor::Extrusion_Error
4860 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4861                                      const TopoDS_Edge& aTrackEdge,
4862                                      bool FirstIsStart,
4863                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4864 {
4865   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4866   aTolVec=1.e-7;
4867   aTolVec2=aTolVec*aTolVec;
4868   double aT1, aT2;
4869   TopoDS_Vertex aV1, aV2;
4870   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4871   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4872   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4873   // 2. Collect parameters on the track edge
4874   aPrms.push_front( aT1 );
4875   aPrms.push_back( aT2 );
4876   // sort parameters
4877   aPrms.sort();
4878   if( FirstIsStart ) {
4879     if ( aT1 > aT2 ) {
4880       aPrms.reverse();
4881     }
4882   }
4883   else {
4884     if ( aT2 > aT1 ) {
4885       aPrms.reverse();
4886     }
4887   }
4888   // 3. Path Points
4889   SMESH_MeshEditor_PathPoint aPP;
4890   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4891   std::list<double>::iterator aItD = aPrms.begin();
4892   for(; aItD != aPrms.end(); ++aItD) {
4893     double aT = *aItD;
4894     gp_Pnt aP3D;
4895     gp_Vec aVec;
4896     aC3D->D1( aT, aP3D, aVec );
4897     aL2 = aVec.SquareMagnitude();
4898     if ( aL2 < aTolVec2 )
4899       return EXTR_CANT_GET_TANGENT;
4900     gp_Dir aTgt( aVec );
4901     aPP.SetPnt( aP3D );
4902     aPP.SetTangent( aTgt );
4903     aPP.SetParameter( aT );
4904     LPP.push_back(aPP);
4905   }
4906   return EXTR_OK;
4907 }
4908
4909
4910 //=======================================================================
4911 //function : MakeExtrElements
4912 //purpose  : auxilary for ExtrusionAlongTrack
4913 //=======================================================================
4914 SMESH_MeshEditor::Extrusion_Error
4915 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4916                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4917                                    const bool theHasAngles,
4918                                    list<double>& theAngles,
4919                                    const bool theLinearVariation,
4920                                    const bool theHasRefPoint,
4921                                    const gp_Pnt& theRefPoint,
4922                                    const bool theMakeGroups)
4923 {
4924   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4925   int aNbTP = fullList.size();
4926   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4927   // Angles
4928   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4929     LinearAngleVariation(aNbTP-1, theAngles);
4930   }
4931   vector<double> aAngles( aNbTP );
4932   int j = 0;
4933   for(; j<aNbTP; ++j) {
4934     aAngles[j] = 0.;
4935   }
4936   if ( theHasAngles ) {
4937     double anAngle;;
4938     std::list<double>::iterator aItD = theAngles.begin();
4939     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4940       anAngle = *aItD;
4941       aAngles[j] = anAngle;
4942     }
4943   }
4944   // fill vector of path points with angles
4945   //aPPs.resize(fullList.size());
4946   j = -1;
4947   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4948   for(; itPP!=fullList.end(); itPP++) {
4949     j++;
4950     SMESH_MeshEditor_PathPoint PP = *itPP;
4951     PP.SetAngle(aAngles[j]);
4952     aPPs[j] = PP;
4953   }
4954
4955   TNodeOfNodeListMap mapNewNodes;
4956   TElemOfVecOfNnlmiMap mapElemNewNodes;
4957   TElemOfElemListMap newElemsMap;
4958   TIDSortedElemSet::iterator itElem;
4959   double aX, aY, aZ;
4960   int aNb;
4961   SMDSAbs_ElementType aTypeE;
4962   // source elements for each generated one
4963   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4964
4965   // 3. Center of rotation aV0
4966   gp_Pnt aV0 = theRefPoint;
4967   gp_XYZ aGC;
4968   if ( !theHasRefPoint ) {
4969     aNb = 0;
4970     aGC.SetCoord( 0.,0.,0. );
4971
4972     itElem = theElements.begin();
4973     for ( ; itElem != theElements.end(); itElem++ ) {
4974       const SMDS_MeshElement* elem = *itElem;
4975
4976       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4977       while ( itN->more() ) {
4978         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4979         aX = node->X();
4980         aY = node->Y();
4981         aZ = node->Z();
4982
4983         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4984           list<const SMDS_MeshNode*> aLNx;
4985           mapNewNodes[node] = aLNx;
4986           //
4987           gp_XYZ aXYZ( aX, aY, aZ );
4988           aGC += aXYZ;
4989           ++aNb;
4990         }
4991       }
4992     }
4993     aGC /= aNb;
4994     aV0.SetXYZ( aGC );
4995   } // if (!theHasRefPoint) {
4996   mapNewNodes.clear();
4997
4998   // 4. Processing the elements
4999   SMESHDS_Mesh* aMesh = GetMeshDS();
5000
5001   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5002     // check element type
5003     const SMDS_MeshElement* elem = *itElem;
5004     aTypeE = elem->GetType();
5005     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5006       continue;
5007
5008     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5009     newNodesItVec.reserve( elem->NbNodes() );
5010
5011     // loop on elem nodes
5012     int nodeIndex = -1;
5013     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5014     while ( itN->more() )
5015     {
5016       ++nodeIndex;
5017       // check if a node has been already processed
5018       const SMDS_MeshNode* node =
5019         static_cast<const SMDS_MeshNode*>( itN->next() );
5020       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5021       if ( nIt == mapNewNodes.end() ) {
5022         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5023         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5024
5025         // make new nodes
5026         aX = node->X();  aY = node->Y(); aZ = node->Z();
5027
5028         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5029         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5030         gp_Ax1 anAx1, anAxT1T0;
5031         gp_Dir aDT1x, aDT0x, aDT1T0;
5032
5033         aTolAng=1.e-4;
5034
5035         aV0x = aV0;
5036         aPN0.SetCoord(aX, aY, aZ);
5037
5038         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5039         aP0x = aPP0.Pnt();
5040         aDT0x= aPP0.Tangent();
5041         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5042
5043         for ( j = 1; j < aNbTP; ++j ) {
5044           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5045           aP1x = aPP1.Pnt();
5046           aDT1x = aPP1.Tangent();
5047           aAngle1x = aPP1.Angle();
5048
5049           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5050           // Translation
5051           gp_Vec aV01x( aP0x, aP1x );
5052           aTrsf.SetTranslation( aV01x );
5053
5054           // traslated point
5055           aV1x = aV0x.Transformed( aTrsf );
5056           aPN1 = aPN0.Transformed( aTrsf );
5057
5058           // rotation 1 [ T1,T0 ]
5059           aAngleT1T0=-aDT1x.Angle( aDT0x );
5060           if (fabs(aAngleT1T0) > aTolAng) {
5061             aDT1T0=aDT1x^aDT0x;
5062             anAxT1T0.SetLocation( aV1x );
5063             anAxT1T0.SetDirection( aDT1T0 );
5064             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5065
5066             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5067           }
5068
5069           // rotation 2
5070           if ( theHasAngles ) {
5071             anAx1.SetLocation( aV1x );
5072             anAx1.SetDirection( aDT1x );
5073             aTrsfRot.SetRotation( anAx1, aAngle1x );
5074
5075             aPN1 = aPN1.Transformed( aTrsfRot );
5076           }
5077
5078           // make new node
5079           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5080             // create additional node
5081             double x = ( aPN1.X() + aPN0.X() )/2.;
5082             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5083             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5084             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5085             myLastCreatedNodes.Append(newNode);
5086             srcNodes.Append( node );
5087             listNewNodes.push_back( newNode );
5088           }
5089           aX = aPN1.X();
5090           aY = aPN1.Y();
5091           aZ = aPN1.Z();
5092           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5093           myLastCreatedNodes.Append(newNode);
5094           srcNodes.Append( node );
5095           listNewNodes.push_back( newNode );
5096
5097           aPN0 = aPN1;
5098           aP0x = aP1x;
5099           aV0x = aV1x;
5100           aDT0x = aDT1x;
5101         }
5102       }
5103
5104       else {
5105         // if current elem is quadratic and current node is not medium
5106         // we have to check - may be it is needed to insert additional nodes
5107         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5108           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5109           if(listNewNodes.size()==aNbTP-1) {
5110             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5111             gp_XYZ P(node->X(), node->Y(), node->Z());
5112             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5113             int i;
5114             for(i=0; i<aNbTP-1; i++) {
5115               const SMDS_MeshNode* N = *it;
5116               double x = ( N->X() + P.X() )/2.;
5117               double y = ( N->Y() + P.Y() )/2.;
5118               double z = ( N->Z() + P.Z() )/2.;
5119               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5120               srcNodes.Append( node );
5121               myLastCreatedNodes.Append(newN);
5122               aNodes[2*i] = newN;
5123               aNodes[2*i+1] = N;
5124               P = gp_XYZ(N->X(),N->Y(),N->Z());
5125             }
5126             listNewNodes.clear();
5127             for(i=0; i<2*(aNbTP-1); i++) {
5128               listNewNodes.push_back(aNodes[i]);
5129             }
5130           }
5131         }
5132       }
5133
5134       newNodesItVec.push_back( nIt );
5135     }
5136     // make new elements
5137     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5138     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5139     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5140   }
5141
5142   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5143
5144   if ( theMakeGroups )
5145     generateGroups( srcNodes, srcElems, "extruded");
5146
5147   return EXTR_OK;
5148 }
5149
5150
5151 //=======================================================================
5152 //function : LinearAngleVariation
5153 //purpose  : auxilary for ExtrusionAlongTrack
5154 //=======================================================================
5155 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5156                                             list<double>& Angles)
5157 {
5158   int nbAngles = Angles.size();
5159   if( nbSteps > nbAngles ) {
5160     vector<double> theAngles(nbAngles);
5161     list<double>::iterator it = Angles.begin();
5162     int i = -1;
5163     for(; it!=Angles.end(); it++) {
5164       i++;
5165       theAngles[i] = (*it);
5166     }
5167     list<double> res;
5168     double rAn2St = double( nbAngles ) / double( nbSteps );
5169     double angPrev = 0, angle;
5170     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5171       double angCur = rAn2St * ( iSt+1 );
5172       double angCurFloor  = floor( angCur );
5173       double angPrevFloor = floor( angPrev );
5174       if ( angPrevFloor == angCurFloor )
5175         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5176       else {
5177         int iP = int( angPrevFloor );
5178         double angPrevCeil = ceil(angPrev);
5179         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5180
5181         int iC = int( angCurFloor );
5182         if ( iC < nbAngles )
5183           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5184
5185         iP = int( angPrevCeil );
5186         while ( iC-- > iP )
5187           angle += theAngles[ iC ];
5188       }
5189       res.push_back(angle);
5190       angPrev = angCur;
5191     }
5192     Angles.clear();
5193     it = res.begin();
5194     for(; it!=res.end(); it++)
5195       Angles.push_back( *it );
5196   }
5197 }
5198
5199
5200 //================================================================================
5201 /*!
5202  * \brief Move or copy theElements applying theTrsf to their nodes
5203  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5204  *  \param theTrsf - transformation to apply
5205  *  \param theCopy - if true, create translated copies of theElems
5206  *  \param theMakeGroups - if true and theCopy, create translated groups
5207  *  \param theTargetMesh - mesh to copy translated elements into
5208  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5209  */
5210 //================================================================================
5211
5212 SMESH_MeshEditor::PGroupIDs
5213 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5214                              const gp_Trsf&     theTrsf,
5215                              const bool         theCopy,
5216                              const bool         theMakeGroups,
5217                              SMESH_Mesh*        theTargetMesh)
5218 {
5219   myLastCreatedElems.Clear();
5220   myLastCreatedNodes.Clear();
5221
5222   bool needReverse = false;
5223   string groupPostfix;
5224   switch ( theTrsf.Form() ) {
5225   case gp_PntMirror:
5226   case gp_Ax1Mirror:
5227   case gp_Ax2Mirror:
5228     needReverse = true;
5229     groupPostfix = "mirrored";
5230     break;
5231   case gp_Rotation:
5232     groupPostfix = "rotated";
5233     break;
5234   case gp_Translation:
5235     groupPostfix = "translated";
5236     break;
5237   case gp_Scale:
5238   case gp_CompoundTrsf: // different scale by axis
5239     groupPostfix = "scaled";
5240     break;
5241   default:
5242     needReverse = false;
5243     groupPostfix = "transformed";
5244   }
5245
5246   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5247   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5248   SMESHDS_Mesh* aMesh    = GetMeshDS();
5249
5250
5251   // map old node to new one
5252   TNodeNodeMap nodeMap;
5253
5254   // elements sharing moved nodes; those of them which have all
5255   // nodes mirrored but are not in theElems are to be reversed
5256   TIDSortedElemSet inverseElemSet;
5257
5258   // source elements for each generated one
5259   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5260
5261   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5262   list<SMDS_MeshNode>          orphanCopy; // copies of orphan nodes
5263   vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5264
5265   if ( theElems.empty() ) // transform the whole mesh
5266   {
5267     // add all elements
5268     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5269     while ( eIt->more() ) theElems.insert( eIt->next() );
5270     // add orphan nodes
5271     SMDS_MeshElementIDFactory idFactory;
5272     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5273     while ( nIt->more() )
5274     {
5275       const SMDS_MeshNode* node = nIt->next();
5276       if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5277       {
5278         // node was not inserted into theElems because an element with the same ID
5279         // is already there. As a work around we insert a copy of node with
5280         // an ID = -<index in orphanNode>
5281         orphanCopy.push_back( *node ); // copy node
5282         SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5283         int uniqueID = -orphanNode.size();
5284         orphanNode.push_back( node );
5285         idFactory.BindID( uniqueID, nodeCopy );
5286         theElems.insert( nodeCopy );
5287       }
5288     }
5289   }
5290   // loop on theElems to transorm nodes
5291   TIDSortedElemSet::iterator itElem;
5292   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5293     const SMDS_MeshElement* elem = *itElem;
5294     if ( !elem )
5295       continue;
5296
5297     // loop on elem nodes
5298     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5299     while ( itN->more() ) {
5300
5301       const SMDS_MeshNode* node = cast2Node( itN->next() );
5302       if ( node->GetID() < 0 )
5303         node = orphanNode[ -node->GetID() ];
5304       // check if a node has been already transformed
5305       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5306         nodeMap.insert( make_pair ( node, node ));
5307       if ( !n2n_isnew.second )
5308         continue;
5309
5310       double coord[3];
5311       coord[0] = node->X();
5312       coord[1] = node->Y();
5313       coord[2] = node->Z();
5314       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5315       if ( theTargetMesh ) {
5316         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5317         n2n_isnew.first->second = newNode;
5318         myLastCreatedNodes.Append(newNode);
5319         srcNodes.Append( node );
5320       }
5321       else if ( theCopy ) {
5322         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5323         n2n_isnew.first->second = newNode;
5324         myLastCreatedNodes.Append(newNode);
5325         srcNodes.Append( node );
5326       }
5327       else {
5328         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5329         // node position on shape becomes invalid
5330         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5331           ( SMDS_SpacePosition::originSpacePosition() );
5332       }
5333
5334       // keep inverse elements
5335       if ( !theCopy && !theTargetMesh && needReverse ) {
5336         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5337         while ( invElemIt->more() ) {
5338           const SMDS_MeshElement* iel = invElemIt->next();
5339           inverseElemSet.insert( iel );
5340         }
5341       }
5342     }
5343   }
5344
5345   // either create new elements or reverse mirrored ones
5346   if ( !theCopy && !needReverse && !theTargetMesh )
5347     return PGroupIDs();
5348
5349   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5350   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5351     theElems.insert( *invElemIt );
5352
5353   // replicate or reverse elements
5354
5355   enum {
5356     REV_TETRA   = 0,  //  = nbNodes - 4
5357     REV_PYRAMID = 1,  //  = nbNodes - 4
5358     REV_PENTA   = 2,  //  = nbNodes - 4
5359     REV_FACE    = 3,
5360     REV_HEXA    = 4,  //  = nbNodes - 4
5361     FORWARD     = 5
5362   };
5363   int index[][8] = {
5364     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5365     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5366     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5367     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5368     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5369     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5370   };
5371
5372   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5373   {
5374     const SMDS_MeshElement* elem = *itElem;
5375     if ( !elem || elem->GetType() == SMDSAbs_Node )
5376       continue;
5377
5378     int nbNodes = elem->NbNodes();
5379     int elemType = elem->GetType();
5380
5381     if (elem->IsPoly()) {
5382       // Polygon or Polyhedral Volume
5383       switch ( elemType ) {
5384       case SMDSAbs_Face:
5385         {
5386           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5387           int iNode = 0;
5388           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5389           while (itN->more()) {
5390             const SMDS_MeshNode* node =
5391               static_cast<const SMDS_MeshNode*>(itN->next());
5392             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5393             if (nodeMapIt == nodeMap.end())
5394               break; // not all nodes transformed
5395             if (needReverse) {
5396               // reverse mirrored faces and volumes
5397               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5398             } else {
5399               poly_nodes[iNode] = (*nodeMapIt).second;
5400             }
5401             iNode++;
5402           }
5403           if ( iNode != nbNodes )
5404             continue; // not all nodes transformed
5405
5406           if ( theTargetMesh ) {
5407             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5408             srcElems.Append( elem );
5409           }
5410           else if ( theCopy ) {
5411             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5412             srcElems.Append( elem );
5413           }
5414           else {
5415             aMesh->ChangePolygonNodes(elem, poly_nodes);
5416           }
5417         }
5418         break;
5419       case SMDSAbs_Volume:
5420         {
5421           // ATTENTION: Reversing is not yet done!!!
5422           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5423             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5424           if (!aPolyedre) {
5425             MESSAGE("Warning: bad volumic element");
5426             continue;
5427           }
5428
5429           vector<const SMDS_MeshNode*> poly_nodes;
5430           vector<int> quantities;
5431
5432           bool allTransformed = true;
5433           int nbFaces = aPolyedre->NbFaces();
5434           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5435             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5436             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5437               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5438               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5439               if (nodeMapIt == nodeMap.end()) {
5440                 allTransformed = false; // not all nodes transformed
5441               } else {
5442                 poly_nodes.push_back((*nodeMapIt).second);
5443               }
5444             }
5445             quantities.push_back(nbFaceNodes);
5446           }
5447           if ( !allTransformed )
5448             continue; // not all nodes transformed
5449
5450           if ( theTargetMesh ) {
5451             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5452             srcElems.Append( elem );
5453           }
5454           else if ( theCopy ) {
5455             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5456             srcElems.Append( elem );
5457           }
5458           else {
5459             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5460           }
5461         }
5462         break;
5463       default:;
5464       }
5465       continue;
5466     }
5467
5468     // Regular elements
5469     int* i = index[ FORWARD ];
5470     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5471       if ( elemType == SMDSAbs_Face )
5472         i = index[ REV_FACE ];
5473       else
5474         i = index[ nbNodes - 4 ];
5475
5476     if(elem->IsQuadratic()) {
5477       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5478       i = anIds;
5479       if(needReverse) {
5480         if(nbNodes==3) { // quadratic edge
5481           static int anIds[] = {1,0,2};
5482           i = anIds;
5483         }
5484         else if(nbNodes==6) { // quadratic triangle
5485           static int anIds[] = {0,2,1,5,4,3};
5486           i = anIds;
5487         }
5488         else if(nbNodes==8) { // quadratic quadrangle
5489           static int anIds[] = {0,3,2,1,7,6,5,4};
5490           i = anIds;
5491         }
5492         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5493           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5494           i = anIds;
5495         }
5496         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5497           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5498           i = anIds;
5499         }
5500         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5501           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5502           i = anIds;
5503         }
5504         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5505           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5506           i = anIds;
5507         }
5508       }
5509     }
5510
5511     // find transformed nodes
5512     vector<const SMDS_MeshNode*> nodes(nbNodes);
5513     int iNode = 0;
5514     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5515     while ( itN->more() ) {
5516       const SMDS_MeshNode* node =
5517         static_cast<const SMDS_MeshNode*>( itN->next() );
5518       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5519       if ( nodeMapIt == nodeMap.end() )
5520         break; // not all nodes transformed
5521       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5522     }
5523     if ( iNode != nbNodes )
5524       continue; // not all nodes transformed
5525
5526     if ( theTargetMesh ) {
5527       if ( SMDS_MeshElement* copy =
5528            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5529         myLastCreatedElems.Append( copy );
5530         srcElems.Append( elem );
5531       }
5532     }
5533     else if ( theCopy ) {
5534       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5535         myLastCreatedElems.Append( copy );
5536         srcElems.Append( elem );
5537       }
5538     }
5539     else {
5540       // reverse element as it was reversed by transformation
5541       if ( nbNodes > 2 )
5542         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5543     }
5544   }
5545
5546   PGroupIDs newGroupIDs;
5547
5548   if ( theMakeGroups && theCopy ||
5549        theMakeGroups && theTargetMesh )
5550     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5551
5552   return newGroupIDs;
5553 }
5554
5555 //=======================================================================
5556 /*!
5557  * \brief Create groups of elements made during transformation
5558  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5559  * \param elemGens - elements making corresponding myLastCreatedElems
5560  * \param postfix - to append to names of new groups
5561  */
5562 //=======================================================================
5563
5564 SMESH_MeshEditor::PGroupIDs
5565 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5566                                  const SMESH_SequenceOfElemPtr& elemGens,
5567                                  const std::string&             postfix,
5568                                  SMESH_Mesh*                    targetMesh)
5569 {
5570   PGroupIDs newGroupIDs( new list<int> );
5571   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5572
5573   // Sort existing groups by types and collect their names
5574
5575   // to store an old group and a generated new one
5576   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5577   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5578   // group names
5579   set< string > groupNames;
5580   //
5581   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5582   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5583   while ( groupIt->more() ) {
5584     SMESH_Group * group = groupIt->next();
5585     if ( !group ) continue;
5586     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5587     if ( !groupDS || groupDS->IsEmpty() ) continue;
5588     groupNames.insert( group->GetName() );
5589     groupDS->SetStoreName( group->GetName() );
5590     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5591   }
5592
5593   // Groups creation
5594
5595   // loop on nodes and elements
5596   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5597   {
5598     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5599     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5600     if ( gens.Length() != elems.Length() )
5601       throw SALOME_Exception(LOCALIZED("invalid args"));
5602
5603     // loop on created elements
5604     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5605     {
5606       const SMDS_MeshElement* sourceElem = gens( iElem );
5607       if ( !sourceElem ) {
5608         MESSAGE("generateGroups(): NULL source element");
5609         continue;
5610       }
5611       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5612       if ( groupsOldNew.empty() ) {
5613         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5614           ++iElem; // skip all elements made by sourceElem
5615         continue;
5616       }
5617       // collect all elements made by sourceElem
5618       list< const SMDS_MeshElement* > resultElems;
5619       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5620         if ( resElem != sourceElem )
5621           resultElems.push_back( resElem );
5622       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5623         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5624           if ( resElem != sourceElem )
5625             resultElems.push_back( resElem );
5626       // do not generate element groups from node ones
5627       if ( sourceElem->GetType() == SMDSAbs_Node &&
5628            elems( iElem )->GetType() != SMDSAbs_Node )
5629         continue;
5630
5631       // add resultElems to groups made by ones the sourceElem belongs to
5632       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5633       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5634       {
5635         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5636         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5637         {
5638           SMDS_MeshGroup* & newGroup = gOldNew->second;
5639           if ( !newGroup )// create a new group
5640           {
5641             // make a name
5642             string name = oldGroup->GetStoreName();
5643             if ( !targetMesh ) {
5644               name += "_";
5645               name += postfix;
5646               int nb = 0;
5647               while ( !groupNames.insert( name ).second ) // name exists
5648               {
5649                 if ( nb == 0 ) {
5650                   name += "_1";
5651                 }
5652                 else {
5653                   TCollection_AsciiString nbStr(nb+1);
5654                   name.resize( name.rfind('_')+1 );
5655                   name += nbStr.ToCString();
5656                 }
5657                 ++nb;
5658               }
5659             }
5660             // make a group
5661             int id;
5662             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5663                                                  name.c_str(), id );
5664             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5665             newGroup = & groupDS->SMDSGroup();
5666             newGroupIDs->push_back( id );
5667           }
5668
5669           // fill in a new group
5670           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5671           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5672             newGroup->Add( *resElemIt );
5673         }
5674       }
5675     } // loop on created elements
5676   }// loop on nodes and elements
5677
5678   return newGroupIDs;
5679 }
5680
5681 //================================================================================
5682 /*!
5683  * \brief Return list of group of nodes close to each other within theTolerance
5684  *        Search among theNodes or in the whole mesh if theNodes is empty using
5685  *        an Octree algorithm
5686  */
5687 //================================================================================
5688
5689 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5690                                             const double         theTolerance,
5691                                             TListOfListOfNodes & theGroupsOfNodes)
5692 {
5693   myLastCreatedElems.Clear();
5694   myLastCreatedNodes.Clear();
5695
5696   if ( theNodes.empty() )
5697   { // get all nodes in the mesh
5698     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5699     while ( nIt->more() )
5700       theNodes.insert( theNodes.end(),nIt->next());
5701   }
5702
5703   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5704 }
5705
5706
5707 //=======================================================================
5708 /*!
5709  * \brief Implementation of search for the node closest to point
5710  */
5711 //=======================================================================
5712
5713 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5714 {
5715   //---------------------------------------------------------------------
5716   /*!
5717    * \brief Constructor
5718    */
5719   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5720   {
5721     myMesh = ( SMESHDS_Mesh* ) theMesh;
5722
5723     TIDSortedNodeSet nodes;
5724     if ( theMesh ) {
5725       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5726       while ( nIt->more() )
5727         nodes.insert( nodes.end(), nIt->next() );
5728     }
5729     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5730
5731     // get max size of a leaf box
5732     SMESH_OctreeNode* tree = myOctreeNode;
5733     while ( !tree->isLeaf() )
5734     {
5735       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5736       if ( cIt->more() )
5737         tree = cIt->next();
5738     }
5739     myHalfLeafSize = tree->maxSize() / 2.;
5740   }
5741
5742   //---------------------------------------------------------------------
5743   /*!
5744    * \brief Move node and update myOctreeNode accordingly
5745    */
5746   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5747   {
5748     myOctreeNode->UpdateByMoveNode( node, toPnt );
5749     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5750   }
5751
5752   //---------------------------------------------------------------------
5753   /*!
5754    * \brief Do it's job
5755    */
5756   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5757   {
5758     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5759     map<double, const SMDS_MeshNode*> dist2Nodes;
5760     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5761     if ( !dist2Nodes.empty() )
5762       return dist2Nodes.begin()->second;
5763     list<const SMDS_MeshNode*> nodes;
5764     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5765
5766     double minSqDist = DBL_MAX;
5767     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5768     {
5769       // sort leafs by their distance from thePnt
5770       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5771       TDistTreeMap treeMap;
5772       list< SMESH_OctreeNode* > treeList;
5773       list< SMESH_OctreeNode* >::iterator trIt;
5774       treeList.push_back( myOctreeNode );
5775
5776       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5777       bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5778       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5779       {
5780         SMESH_OctreeNode* tree = *trIt;
5781         if ( !tree->isLeaf() ) // put children to the queue
5782         {
5783           if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5784           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5785           while ( cIt->more() )
5786             treeList.push_back( cIt->next() );
5787         }
5788         else if ( tree->NbNodes() ) // put a tree to the treeMap
5789         {
5790           const Bnd_B3d& box = tree->getBox();
5791           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5792           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5793           if ( !it_in.second ) // not unique distance to box center
5794             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5795         }
5796       }
5797       // find distance after which there is no sense to check tree's
5798       double sqLimit = DBL_MAX;
5799       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5800       if ( treeMap.size() > 5 ) {
5801         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5802         const Bnd_B3d& box = closestTree->getBox();
5803         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5804         sqLimit = limit * limit;
5805       }
5806       // get all nodes from trees
5807       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5808         if ( sqDist_tree->first > sqLimit )
5809           break;
5810         SMESH_OctreeNode* tree = sqDist_tree->second;
5811         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5812       }
5813     }
5814     // find closest among nodes
5815     minSqDist = DBL_MAX;
5816     const SMDS_MeshNode* closestNode = 0;
5817     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5818     for ( ; nIt != nodes.end(); ++nIt ) {
5819       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5820       if ( minSqDist > sqDist ) {
5821         closestNode = *nIt;
5822         minSqDist = sqDist;
5823       }
5824     }
5825     return closestNode;
5826   }
5827
5828   //---------------------------------------------------------------------
5829   /*!
5830    * \brief Destructor
5831    */
5832   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5833
5834   //---------------------------------------------------------------------
5835   /*!
5836    * \brief Return the node tree
5837    */
5838   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5839
5840 private:
5841   SMESH_OctreeNode* myOctreeNode;
5842   SMESHDS_Mesh*     myMesh;
5843   double            myHalfLeafSize; // max size of a leaf box
5844 };
5845
5846 //=======================================================================
5847 /*!
5848  * \brief Return SMESH_NodeSearcher
5849  */
5850 //=======================================================================
5851
5852 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
5853 {
5854   return new SMESH_NodeSearcherImpl( GetMeshDS() );
5855 }
5856
5857 // ========================================================================
5858 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5859 {
5860   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5861   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5862   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
5863
5864   //=======================================================================
5865   /*!
5866    * \brief Octal tree of bounding boxes of elements
5867    */
5868   //=======================================================================
5869
5870   class ElementBndBoxTree : public SMESH_Octree
5871   {
5872   public:
5873
5874     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5875     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5876     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5877     ~ElementBndBoxTree();
5878
5879   protected:
5880     ElementBndBoxTree() {}
5881     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5882     void buildChildrenData();
5883     Bnd_B3d* buildRootBox();
5884   private:
5885     //!< Bounding box of element
5886     struct ElementBox : public Bnd_B3d
5887     {
5888       const SMDS_MeshElement* _element;
5889       int                     _refCount; // an ElementBox can be included in several tree branches
5890       ElementBox(const SMDS_MeshElement* elem);
5891     };
5892     vector< ElementBox* > _elements;
5893   };
5894
5895   //================================================================================
5896   /*!
5897    * \brief ElementBndBoxTree creation
5898    */
5899   //================================================================================
5900
5901   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5902     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5903   {
5904     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5905     _elements.reserve( nbElems );
5906
5907     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5908     while ( elemIt->more() )
5909       _elements.push_back( new ElementBox( elemIt->next() ));
5910
5911     if ( _elements.size() > MaxNbElemsInLeaf )
5912       compute();
5913     else
5914       myIsLeaf = true;
5915   }
5916
5917   //================================================================================
5918   /*!
5919    * \brief Destructor
5920    */
5921   //================================================================================
5922
5923   ElementBndBoxTree::~ElementBndBoxTree()
5924   {
5925     for ( int i = 0; i < _elements.size(); ++i )
5926       if ( --_elements[i]->_refCount <= 0 )
5927         delete _elements[i];
5928   }
5929
5930   //================================================================================
5931   /*!
5932    * \brief Return the maximal box
5933    */
5934   //================================================================================
5935
5936   Bnd_B3d* ElementBndBoxTree::buildRootBox()
5937   {
5938     Bnd_B3d* box = new Bnd_B3d;
5939     for ( int i = 0; i < _elements.size(); ++i )
5940       box->Add( *_elements[i] );
5941     return box;
5942   }
5943
5944   //================================================================================
5945   /*!
5946    * \brief Redistrubute element boxes among children
5947    */
5948   //================================================================================
5949
5950   void ElementBndBoxTree::buildChildrenData()
5951   {
5952     for ( int i = 0; i < _elements.size(); ++i )
5953     {
5954       for (int j = 0; j < 8; j++)
5955       {
5956         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5957         {
5958           _elements[i]->_refCount++;
5959           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5960         }
5961       }
5962       _elements[i]->_refCount--;
5963     }
5964     _elements.clear();
5965
5966     for (int j = 0; j < 8; j++)
5967     {
5968       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5969       if ( child->_elements.size() <= MaxNbElemsInLeaf )
5970         child->myIsLeaf = true;
5971
5972       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5973         child->_elements.resize( child->_elements.size() ); // compact
5974     }
5975   }
5976
5977   //================================================================================
5978   /*!
5979    * \brief Return elements which can include the point
5980    */
5981   //================================================================================
5982
5983   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
5984                                                 TIDSortedElemSet& foundElems)
5985   {
5986     if ( level() && getBox().IsOut( point.XYZ() ))
5987       return;
5988
5989     if ( isLeaf() )
5990     {
5991       for ( int i = 0; i < _elements.size(); ++i )
5992         if ( !_elements[i]->IsOut( point.XYZ() ))
5993           foundElems.insert( _elements[i]->_element );
5994     }
5995     else
5996     {
5997       for (int i = 0; i < 8; i++)
5998         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5999     }
6000   }
6001
6002   //================================================================================
6003   /*!
6004    * \brief Return elements which can be intersected by the line
6005    */
6006   //================================================================================
6007
6008   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6009                                                TIDSortedElemSet& foundElems)
6010   {
6011     if ( level() && getBox().IsOut( line ))
6012       return;
6013
6014     if ( isLeaf() )
6015     {
6016       for ( int i = 0; i < _elements.size(); ++i )
6017         if ( !_elements[i]->IsOut( line ))
6018           foundElems.insert( _elements[i]->_element );
6019     }
6020     else
6021     {
6022       for (int i = 0; i < 8; i++)
6023         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6024     }
6025   }
6026
6027   //================================================================================
6028   /*!
6029    * \brief Construct the element box
6030    */
6031   //================================================================================
6032
6033   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
6034   {
6035     _element  = elem;
6036     _refCount = 1;
6037     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6038     while ( nIt->more() )
6039       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6040     Enlarge( NodeRadius );
6041   }
6042
6043 } // namespace
6044
6045 //=======================================================================
6046 /*!
6047  * \brief Implementation of search for the elements by point and
6048  *        of classification of point in 2D mesh
6049  */
6050 //=======================================================================
6051
6052 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6053 {
6054   SMESHDS_Mesh*                _mesh;
6055   ElementBndBoxTree*           _ebbTree;
6056   SMESH_NodeSearcherImpl*      _nodeSearcher;
6057   SMDSAbs_ElementType          _elementType;
6058   double                       _tolerance;
6059   bool                         _outerFacesFound;
6060   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6061
6062   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6063     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6064   ~SMESH_ElementSearcherImpl()
6065   {
6066     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6067     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6068   }
6069   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6070                                   SMDSAbs_ElementType                type,
6071                                   vector< const SMDS_MeshElement* >& foundElements);
6072   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6073
6074   void GetElementsNearLine( const gp_Ax1&                      line,
6075                             SMDSAbs_ElementType                type,
6076                             vector< const SMDS_MeshElement* >& foundElems);
6077   double getTolerance();
6078   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6079                             const double tolerance, double & param);
6080   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6081   bool isOuterBoundary(const SMDS_MeshElement* face) const
6082   {
6083     return _outerFaces.empty() || _outerFaces.count(face);
6084   }
6085   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6086   {
6087     const SMDS_MeshElement* _face;
6088     gp_Vec                  _faceNorm;
6089     bool                    _coincides; //!< the line lays in face plane
6090     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6091       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6092   };
6093   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6094   {
6095     SMESH_TLink      _link;
6096     TIDSortedElemSet _faces;
6097     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6098       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6099   };
6100 };
6101
6102 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6103 {
6104   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6105              << ", _coincides="<<i._coincides << ")";
6106 }
6107
6108 //=======================================================================
6109 /*!
6110  * \brief define tolerance for search
6111  */
6112 //=======================================================================
6113
6114 double SMESH_ElementSearcherImpl::getTolerance()
6115 {
6116   if ( _tolerance < 0 )
6117   {
6118     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6119
6120     _tolerance = 0;
6121     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6122     {
6123       double boxSize = _nodeSearcher->getTree()->maxSize();
6124       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6125     }
6126     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6127     {
6128       double boxSize = _ebbTree->maxSize();
6129       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6130     }
6131     if ( _tolerance == 0 )
6132     {
6133       // define tolerance by size of a most complex element
6134       int complexType = SMDSAbs_Volume;
6135       while ( complexType > SMDSAbs_All &&
6136               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6137         --complexType;
6138       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6139
6140       double elemSize;
6141       if ( complexType == int( SMDSAbs_Node ))
6142       {
6143         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6144         elemSize = 1;
6145         if ( meshInfo.NbNodes() > 2 )
6146           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6147       }
6148       else
6149       {
6150         const SMDS_MeshElement* elem =
6151           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6152         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6153         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6154         while ( nodeIt->more() )
6155         {
6156           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6157           elemSize = max( dist, elemSize );
6158         }
6159       }
6160       _tolerance = 1e-6 * elemSize;
6161     }
6162   }
6163   return _tolerance;
6164 }
6165
6166 //================================================================================
6167 /*!
6168  * \brief Find intersection of the line and an edge of face and return parameter on line
6169  */
6170 //================================================================================
6171
6172 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6173                                                      const SMDS_MeshElement* face,
6174                                                      const double            tol,
6175                                                      double &                param)
6176 {
6177   int nbInts = 0;
6178   param = 0;
6179
6180   GeomAPI_ExtremaCurveCurve anExtCC;
6181   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6182   
6183   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6184   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6185   {
6186     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6187                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6188     anExtCC.Init( lineCurve, edge);
6189     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6190     {
6191       Quantity_Parameter pl, pe;
6192       anExtCC.LowerDistanceParameters( pl, pe );
6193       param += pl;
6194       if ( ++nbInts == 2 )
6195         break;
6196     }
6197   }
6198   if ( nbInts > 0 ) param /= nbInts;
6199   return nbInts > 0;
6200 }
6201 //================================================================================
6202 /*!
6203  * \brief Find all faces belonging to the outer boundary of mesh
6204  */
6205 //================================================================================
6206
6207 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6208 {
6209   if ( _outerFacesFound ) return;
6210
6211   // Collect all outer faces by passing from one outer face to another via their links
6212   // and BTW find out if there are internal faces at all.
6213
6214   // checked links and links where outer boundary meets internal one
6215   set< SMESH_TLink > visitedLinks, seamLinks;
6216
6217   // links to treat with already visited faces sharing them
6218   list < TFaceLink > startLinks;
6219
6220   // load startLinks with the first outerFace
6221   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6222   _outerFaces.insert( outerFace );
6223
6224   TIDSortedElemSet emptySet;
6225   while ( !startLinks.empty() )
6226   {
6227     const SMESH_TLink& link  = startLinks.front()._link;
6228     TIDSortedElemSet&  faces = startLinks.front()._faces;
6229
6230     outerFace = *faces.begin();
6231     // find other faces sharing the link
6232     const SMDS_MeshElement* f;
6233     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6234       faces.insert( f );
6235
6236     // select another outer face among the found 
6237     const SMDS_MeshElement* outerFace2 = 0;
6238     if ( faces.size() == 2 )
6239     {
6240       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6241     }
6242     else if ( faces.size() > 2 )
6243     {
6244       seamLinks.insert( link );
6245
6246       // link direction within the outerFace
6247       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6248                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6249       int i1 = outerFace->GetNodeIndex( link.node1() );
6250       int i2 = outerFace->GetNodeIndex( link.node2() );
6251       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6252       if ( rev ) n1n2.Reverse();
6253       // outerFace normal
6254       gp_XYZ ofNorm, fNorm;
6255       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6256       {
6257         // direction from the link inside outerFace
6258         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6259         // sort all other faces by angle with the dirInOF
6260         map< double, const SMDS_MeshElement* > angle2Face;
6261         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6262         for ( ; face != faces.end(); ++face )
6263         {
6264           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6265             continue;
6266           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6267           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6268           if ( angle < 0 ) angle += 2*PI;
6269           angle2Face.insert( make_pair( angle, *face ));
6270         }
6271         if ( !angle2Face.empty() )
6272           outerFace2 = angle2Face.begin()->second;
6273       }
6274     }
6275     // store the found outer face and add its links to continue seaching from
6276     if ( outerFace2 )
6277     {
6278       _outerFaces.insert( outerFace );
6279       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6280       for ( int i = 0; i < nbNodes; ++i )
6281       {
6282         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6283         if ( visitedLinks.insert( link2 ).second )
6284           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6285       }
6286     }
6287     startLinks.pop_front();
6288   }
6289   _outerFacesFound = true;
6290
6291   if ( !seamLinks.empty() )
6292   {
6293     // There are internal boundaries touching the outher one,
6294     // find all faces of internal boundaries in order to find
6295     // faces of boundaries of holes, if any.
6296     
6297   }
6298   else
6299   {
6300     _outerFaces.clear();
6301   }
6302 }
6303
6304 //=======================================================================
6305 /*!
6306  * \brief Find elements of given type where the given point is IN or ON.
6307  *        Returns nb of found elements and elements them-selves.
6308  *
6309  * 'ALL' type means elements of any type excluding nodes and 0D elements
6310  */
6311 //=======================================================================
6312
6313 int SMESH_ElementSearcherImpl::
6314 FindElementsByPoint(const gp_Pnt&                      point,
6315                     SMDSAbs_ElementType                type,
6316                     vector< const SMDS_MeshElement* >& foundElements)
6317 {
6318   foundElements.clear();
6319
6320   double tolerance = getTolerance();
6321
6322   // =================================================================================
6323   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6324   {
6325     if ( !_nodeSearcher )
6326       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6327
6328     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6329     if ( !closeNode ) return foundElements.size();
6330
6331     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6332       return foundElements.size(); // to far from any node
6333
6334     if ( type == SMDSAbs_Node )
6335     {
6336       foundElements.push_back( closeNode );
6337     }
6338     else
6339     {
6340       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6341       while ( elemIt->more() )
6342         foundElements.push_back( elemIt->next() );
6343     }
6344   }
6345   // =================================================================================
6346   else // elements more complex than 0D
6347   {
6348     if ( !_ebbTree || _elementType != type )
6349     {
6350       if ( _ebbTree ) delete _ebbTree;
6351       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6352     }
6353     TIDSortedElemSet suspectElems;
6354     _ebbTree->getElementsNearPoint( point, suspectElems );
6355     TIDSortedElemSet::iterator elem = suspectElems.begin();
6356     for ( ; elem != suspectElems.end(); ++elem )
6357       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6358         foundElements.push_back( *elem );
6359   }
6360   return foundElements.size();
6361 }
6362
6363 //================================================================================
6364 /*!
6365  * \brief Classify the given point in the closed 2D mesh
6366  */
6367 //================================================================================
6368
6369 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6370 {
6371   double tolerance = getTolerance();
6372   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6373   {
6374     if ( _ebbTree ) delete _ebbTree;
6375     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6376   }
6377   // Algo: analyse transition of a line starting at the point through mesh boundary;
6378   // try three lines parallel to axis of the coordinate system and perform rough
6379   // analysis. If solution is not clear perform thorough analysis.
6380
6381   const int nbAxes = 3;
6382   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6383   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6384   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6385   multimap< int, int > nbInt2Axis; // to find the simplest case
6386   for ( int axis = 0; axis < nbAxes; ++axis )
6387   {
6388     gp_Ax1 lineAxis( point, axisDir[axis]);
6389     gp_Lin line    ( lineAxis );
6390
6391     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6392     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6393
6394     // Intersect faces with the line
6395
6396     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6397     TIDSortedElemSet::iterator face = suspectFaces.begin();
6398     for ( ; face != suspectFaces.end(); ++face )
6399     {
6400       // get face plane
6401       gp_XYZ fNorm;
6402       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6403       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6404
6405       // perform intersection
6406       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6407       if ( !intersection.IsDone() )
6408         continue;
6409       if ( intersection.IsInQuadric() )
6410       {
6411         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6412       }
6413       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6414       {
6415         gp_Pnt intersectionPoint = intersection.Point(1);
6416         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6417           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6418       }
6419     }
6420     // Analyse intersections roughly
6421
6422     int nbInter = u2inters.size();
6423     if ( nbInter == 0 )
6424       return TopAbs_OUT; 
6425
6426     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6427     if ( nbInter == 1 ) // not closed mesh
6428       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6429
6430     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6431       return TopAbs_ON;
6432
6433     if ( (f<0) == (l<0) )
6434       return TopAbs_OUT;
6435
6436     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6437     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6438     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6439       return TopAbs_IN;
6440
6441     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6442
6443     if ( _outerFacesFound ) break; // pass to thorough analysis
6444
6445   } // three attempts - loop on CS axes
6446
6447   // Analyse intersections thoroughly.
6448   // We make two loops maximum, on the first one we only exclude touching intersections,
6449   // on the second, if situation is still unclear, we gather and use information on
6450   // position of faces (internal or outer). If faces position is already gathered,
6451   // we make the second loop right away.
6452
6453   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6454   {
6455     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6456     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6457     {
6458       int axis = nb_axis->second;
6459       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6460
6461       gp_Ax1 lineAxis( point, axisDir[axis]);
6462       gp_Lin line    ( lineAxis );
6463
6464       // add tangent intersections to u2inters
6465       double param;
6466       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6467       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6468         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6469           u2inters.insert(make_pair( param, *tgtInt ));
6470       tangentInters[ axis ].clear();
6471
6472       // Count intersections before and after the point excluding touching ones.
6473       // If hasPositionInfo we count intersections of outer boundary only
6474
6475       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6476       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6477       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6478       bool ok = ! u_int1->second._coincides;
6479       while ( ok && u_int1 != u2inters.end() )
6480       {
6481         double u = u_int1->first;
6482         bool touchingInt = false;
6483         if ( ++u_int2 != u2inters.end() )
6484         {
6485           // skip intersections at the same point (if the line passes through edge or node)
6486           int nbSamePnt = 0;
6487           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6488           {
6489             ++nbSamePnt;
6490             ++u_int2;
6491           }
6492
6493           // skip tangent intersections
6494           int nbTgt = 0;
6495           const SMDS_MeshElement* prevFace = u_int1->second._face;
6496           while ( ok && u_int2->second._coincides )
6497           {
6498             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6499               ok = false;
6500             else
6501             {
6502               nbTgt++;
6503               u_int2++;
6504               ok = ( u_int2 != u2inters.end() );
6505             }
6506           }
6507           if ( !ok ) break;
6508
6509           // skip intersections at the same point after tangent intersections
6510           if ( nbTgt > 0 )
6511           {
6512             double u2 = u_int2->first;
6513             ++u_int2;
6514             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6515             {
6516               ++nbSamePnt;
6517               ++u_int2;
6518             }
6519           }
6520           // decide if we skipped a touching intersection
6521           if ( nbSamePnt + nbTgt > 0 )
6522           {
6523             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6524             map< double, TInters >::iterator u_int = u_int1;
6525             for ( ; u_int != u_int2; ++u_int )
6526             {
6527               if ( u_int->second._coincides ) continue;
6528               double dot = u_int->second._faceNorm * line.Direction();
6529               if ( dot > maxDot ) maxDot = dot;
6530               if ( dot < minDot ) minDot = dot;
6531             }
6532             touchingInt = ( minDot*maxDot < 0 );
6533           }
6534         }
6535         if ( !touchingInt )
6536         {
6537           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6538           {
6539             if ( u < 0 )
6540               ++nbIntBeforePoint;
6541             else
6542               ++nbIntAfterPoint;
6543           }
6544           if ( u < f ) f = u;
6545           if ( u > l ) l = u;
6546         }
6547
6548         u_int1 = u_int2; // to next intersection
6549
6550       } // loop on intersections with one line
6551
6552       if ( ok )
6553       {
6554         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6555           return TopAbs_ON;
6556
6557         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6558           return TopAbs_OUT; 
6559
6560         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6561           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6562
6563         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6564           return TopAbs_IN;
6565
6566         if ( (f<0) == (l<0) )
6567           return TopAbs_OUT;
6568
6569         if ( hasPositionInfo )
6570           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6571       }
6572     } // loop on intersections of the tree lines - thorough analysis
6573
6574     if ( !hasPositionInfo )
6575     {
6576       // gather info on faces position - is face in the outer boundary or not
6577       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6578       findOuterBoundary( u2inters.begin()->second._face );
6579     }
6580
6581   } // two attempts - with and w/o faces position info in the mesh
6582
6583   return TopAbs_UNKNOWN;
6584 }
6585
6586 //=======================================================================
6587 /*!
6588  * \brief Return elements possibly intersecting the line
6589  */
6590 //=======================================================================
6591
6592 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6593                                                      SMDSAbs_ElementType                type,
6594                                                      vector< const SMDS_MeshElement* >& foundElems)
6595 {
6596   if ( !_ebbTree || _elementType != type )
6597   {
6598     if ( _ebbTree ) delete _ebbTree;
6599     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6600   }
6601   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6602   _ebbTree->getElementsNearLine( line, suspectFaces );
6603   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6604 }
6605
6606 //=======================================================================
6607 /*!
6608  * \brief Return SMESH_ElementSearcher
6609  */
6610 //=======================================================================
6611
6612 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6613 {
6614   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6615 }
6616
6617 //=======================================================================
6618 /*!
6619  * \brief Return true if the point is IN or ON of the element
6620  */
6621 //=======================================================================
6622
6623 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6624 {
6625   if ( element->GetType() == SMDSAbs_Volume)
6626   {
6627     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6628   }
6629
6630   // get ordered nodes
6631
6632   vector< gp_XYZ > xyz;
6633
6634   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6635   if ( element->IsQuadratic() )
6636     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6637       nodeIt = f->interlacedNodesElemIterator();
6638     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6639       nodeIt = e->interlacedNodesElemIterator();
6640
6641   while ( nodeIt->more() )
6642     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6643
6644   int i, nbNodes = element->NbNodes();
6645
6646   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6647   {
6648     // compute face normal
6649     gp_Vec faceNorm(0,0,0);
6650     xyz.push_back( xyz.front() );
6651     for ( i = 0; i < nbNodes; ++i )
6652     {
6653       gp_Vec edge1( xyz[i+1], xyz[i]);
6654       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6655       faceNorm += edge1 ^ edge2;
6656     }
6657     double normSize = faceNorm.Magnitude();
6658     if ( normSize <= tol )
6659     {
6660       // degenerated face: point is out if it is out of all face edges
6661       for ( i = 0; i < nbNodes; ++i )
6662       {
6663         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6664         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6665         SMDS_MeshEdge edge( &n1, &n2 );
6666         if ( !isOut( &edge, point, tol ))
6667           return false;
6668       }
6669       return true;
6670     }
6671     faceNorm /= normSize;
6672
6673     // check if the point lays on face plane
6674     gp_Vec n2p( xyz[0], point );
6675     if ( fabs( n2p * faceNorm ) > tol )
6676       return true; // not on face plane
6677
6678     // check if point is out of face boundary:
6679     // define it by closest transition of a ray point->infinity through face boundary
6680     // on the face plane.
6681     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6682     // to find intersections of the ray with the boundary.
6683     gp_Vec ray = n2p;
6684     gp_Vec plnNorm = ray ^ faceNorm;
6685     normSize = plnNorm.Magnitude();
6686     if ( normSize <= tol ) return false; // point coincides with the first node
6687     plnNorm /= normSize;
6688     // for each node of the face, compute its signed distance to the plane
6689     vector<double> dist( nbNodes + 1);
6690     for ( i = 0; i < nbNodes; ++i )
6691     {
6692       gp_Vec n2p( xyz[i], point );
6693       dist[i] = n2p * plnNorm;
6694     }
6695     dist.back() = dist.front();
6696     // find the closest intersection
6697     int    iClosest = -1;
6698     double rClosest, distClosest = 1e100;;
6699     gp_Pnt pClosest;
6700     for ( i = 0; i < nbNodes; ++i )
6701     {
6702       double r;
6703       if ( fabs( dist[i]) < tol )
6704         r = 0.;
6705       else if ( fabs( dist[i+1]) < tol )
6706         r = 1.;
6707       else if ( dist[i] * dist[i+1] < 0 )
6708         r = dist[i] / ( dist[i] - dist[i+1] );
6709       else
6710         continue; // no intersection
6711       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6712       gp_Vec p2int ( point, pInt);
6713       if ( p2int * ray > -tol ) // right half-space
6714       {
6715         double intDist = p2int.SquareMagnitude();
6716         if ( intDist < distClosest )
6717         {
6718           iClosest = i;
6719           rClosest = r;
6720           pClosest = pInt;
6721           distClosest = intDist;
6722         }
6723       }
6724     }
6725     if ( iClosest < 0 )
6726       return true; // no intesections - out
6727
6728     // analyse transition
6729     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6730     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6731     gp_Vec p2int ( point, pClosest );
6732     bool out = (edgeNorm * p2int) < -tol;
6733     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6734       return out;
6735
6736     // ray pass through a face node; analyze transition through an adjacent edge
6737     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6738     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6739     gp_Vec edgeAdjacent( p1, p2 );
6740     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6741     bool out2 = (edgeNorm2 * p2int) < -tol;
6742
6743     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6744     return covexCorner ? (out || out2) : (out && out2);
6745   }
6746   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6747   {
6748     // point is out of edge if it is NOT ON any straight part of edge
6749     // (we consider quadratic edge as being composed of two straight parts)
6750     for ( i = 1; i < nbNodes; ++i )
6751     {
6752       gp_Vec edge( xyz[i-1], xyz[i]);
6753       gp_Vec n1p ( xyz[i-1], point);
6754       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6755       if ( dist > tol )
6756         continue;
6757       gp_Vec n2p( xyz[i], point );
6758       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6759         continue;
6760       return false; // point is ON this part
6761     }
6762     return true;
6763   }
6764   // Node or 0D element -------------------------------------------------------------------------
6765   {
6766     gp_Vec n2p ( xyz[0], point );
6767     return n2p.Magnitude() <= tol;
6768   }
6769   return true;
6770 }
6771
6772 //=======================================================================
6773 //function : SimplifyFace
6774 //purpose  :
6775 //=======================================================================
6776 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6777                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6778                                     vector<int>&                        quantities) const
6779 {
6780   int nbNodes = faceNodes.size();
6781
6782   if (nbNodes < 3)
6783     return 0;
6784
6785   set<const SMDS_MeshNode*> nodeSet;
6786
6787   // get simple seq of nodes
6788   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6789   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6790   int iSimple = 0, nbUnique = 0;
6791
6792   simpleNodes[iSimple++] = faceNodes[0];
6793   nbUnique++;
6794   for (int iCur = 1; iCur < nbNodes; iCur++) {
6795     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6796       simpleNodes[iSimple++] = faceNodes[iCur];
6797       if (nodeSet.insert( faceNodes[iCur] ).second)
6798         nbUnique++;
6799     }
6800   }
6801   int nbSimple = iSimple;
6802   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6803     nbSimple--;
6804     iSimple--;
6805   }
6806
6807   if (nbUnique < 3)
6808     return 0;
6809
6810   // separate loops
6811   int nbNew = 0;
6812   bool foundLoop = (nbSimple > nbUnique);
6813   while (foundLoop) {
6814     foundLoop = false;
6815     set<const SMDS_MeshNode*> loopSet;
6816     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6817       const SMDS_MeshNode* n = simpleNodes[iSimple];
6818       if (!loopSet.insert( n ).second) {
6819         foundLoop = true;
6820
6821         // separate loop
6822         int iC = 0, curLast = iSimple;
6823         for (; iC < curLast; iC++) {
6824           if (simpleNodes[iC] == n) break;
6825         }
6826         int loopLen = curLast - iC;
6827         if (loopLen > 2) {
6828           // create sub-element
6829           nbNew++;
6830           quantities.push_back(loopLen);
6831           for (; iC < curLast; iC++) {
6832             poly_nodes.push_back(simpleNodes[iC]);
6833           }
6834         }
6835         // shift the rest nodes (place from the first loop position)
6836         for (iC = curLast + 1; iC < nbSimple; iC++) {
6837           simpleNodes[iC - loopLen] = simpleNodes[iC];
6838         }
6839         nbSimple -= loopLen;
6840         iSimple -= loopLen;
6841       }
6842     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6843   } // while (foundLoop)
6844
6845   if (iSimple > 2) {
6846     nbNew++;
6847     quantities.push_back(iSimple);
6848     for (int i = 0; i < iSimple; i++)
6849       poly_nodes.push_back(simpleNodes[i]);
6850   }
6851
6852   return nbNew;
6853 }
6854
6855 //=======================================================================
6856 //function : MergeNodes
6857 //purpose  : In each group, the cdr of nodes are substituted by the first one
6858 //           in all elements.
6859 //=======================================================================
6860
6861 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6862 {
6863   myLastCreatedElems.Clear();
6864   myLastCreatedNodes.Clear();
6865
6866   SMESHDS_Mesh* aMesh = GetMeshDS();
6867
6868   TNodeNodeMap nodeNodeMap; // node to replace - new node
6869   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6870   list< int > rmElemIds, rmNodeIds;
6871
6872   // Fill nodeNodeMap and elems
6873
6874   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6875   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6876     list<const SMDS_MeshNode*>& nodes = *grIt;
6877     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6878     const SMDS_MeshNode* nToKeep = *nIt;
6879     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6880       const SMDS_MeshNode* nToRemove = *nIt;
6881       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6882       if ( nToRemove != nToKeep ) {
6883         rmNodeIds.push_back( nToRemove->GetID() );
6884         AddToSameGroups( nToKeep, nToRemove, aMesh );
6885       }
6886
6887       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6888       while ( invElemIt->more() ) {
6889         const SMDS_MeshElement* elem = invElemIt->next();
6890         elems.insert(elem);
6891       }
6892     }
6893   }
6894   // Change element nodes or remove an element
6895
6896   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6897   for ( ; eIt != elems.end(); eIt++ ) {
6898     const SMDS_MeshElement* elem = *eIt;
6899     int nbNodes = elem->NbNodes();
6900     int aShapeId = FindShape( elem );
6901
6902     set<const SMDS_MeshNode*> nodeSet;
6903     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6904     int iUnique = 0, iCur = 0, nbRepl = 0;
6905     vector<int> iRepl( nbNodes );
6906
6907     // get new seq of nodes
6908     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6909     while ( itN->more() ) {
6910       const SMDS_MeshNode* n =
6911         static_cast<const SMDS_MeshNode*>( itN->next() );
6912
6913       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6914       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6915         n = (*nnIt).second;
6916         // BUG 0020185: begin
6917         {
6918           bool stopRecur = false;
6919           set<const SMDS_MeshNode*> nodesRecur;
6920           nodesRecur.insert(n);
6921           while (!stopRecur) {
6922             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6923             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6924               n = (*nnIt_i).second;
6925               if (!nodesRecur.insert(n).second) {
6926                 // error: recursive dependancy
6927                 stopRecur = true;
6928               }
6929             }
6930             else
6931               stopRecur = true;
6932           }
6933         }
6934         // BUG 0020185: end
6935         iRepl[ nbRepl++ ] = iCur;
6936       }
6937       curNodes[ iCur ] = n;
6938       bool isUnique = nodeSet.insert( n ).second;
6939       if ( isUnique )
6940         uniqueNodes[ iUnique++ ] = n;
6941       iCur++;
6942     }
6943
6944     // Analyse element topology after replacement
6945
6946     bool isOk = true;
6947     int nbUniqueNodes = nodeSet.size();
6948     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6949       // Polygons and Polyhedral volumes
6950       if (elem->IsPoly()) {
6951
6952         if (elem->GetType() == SMDSAbs_Face) {
6953           // Polygon
6954           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6955           int inode = 0;
6956           for (; inode < nbNodes; inode++) {
6957             face_nodes[inode] = curNodes[inode];
6958           }
6959
6960           vector<const SMDS_MeshNode *> polygons_nodes;
6961           vector<int> quantities;
6962           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6963
6964           if (nbNew > 0) {
6965             inode = 0;
6966             for (int iface = 0; iface < nbNew - 1; iface++) {
6967               int nbNodes = quantities[iface];
6968               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6969               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6970                 poly_nodes[ii] = polygons_nodes[inode];
6971               }
6972               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6973               myLastCreatedElems.Append(newElem);
6974               if (aShapeId)
6975                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6976             }
6977             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6978           }
6979           else {
6980             rmElemIds.push_back(elem->GetID());
6981           }
6982
6983         }
6984         else if (elem->GetType() == SMDSAbs_Volume) {
6985           // Polyhedral volume
6986           if (nbUniqueNodes < 4) {
6987             rmElemIds.push_back(elem->GetID());
6988           }
6989           else {
6990             // each face has to be analized in order to check volume validity
6991             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6992               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6993             if (aPolyedre) {
6994               int nbFaces = aPolyedre->NbFaces();
6995
6996               vector<const SMDS_MeshNode *> poly_nodes;
6997               vector<int> quantities;
6998
6999               for (int iface = 1; iface <= nbFaces; iface++) {
7000                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7001                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7002
7003                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7004                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7005                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7006                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7007                     faceNode = (*nnIt).second;
7008                   }
7009                   faceNodes[inode - 1] = faceNode;
7010                 }
7011
7012                 SimplifyFace(faceNodes, poly_nodes, quantities);
7013               }
7014
7015               if (quantities.size() > 3) {
7016                 // to be done: remove coincident faces
7017               }
7018
7019               if (quantities.size() > 3)
7020                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7021               else
7022                 rmElemIds.push_back(elem->GetID());
7023
7024             }
7025             else {
7026               rmElemIds.push_back(elem->GetID());
7027             }
7028           }
7029         }
7030         else {
7031         }
7032
7033         continue;
7034       }
7035
7036       // Regular elements
7037       switch ( nbNodes ) {
7038       case 2: ///////////////////////////////////// EDGE
7039         isOk = false; break;
7040       case 3: ///////////////////////////////////// TRIANGLE
7041         isOk = false; break;
7042       case 4:
7043         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7044           isOk = false;
7045         else { //////////////////////////////////// QUADRANGLE
7046           if ( nbUniqueNodes < 3 )
7047             isOk = false;
7048           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7049             isOk = false; // opposite nodes stick
7050         }
7051         break;
7052       case 6: ///////////////////////////////////// PENTAHEDRON
7053         if ( nbUniqueNodes == 4 ) {
7054           // ---------------------------------> tetrahedron
7055           if (nbRepl == 3 &&
7056               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7057             // all top nodes stick: reverse a bottom
7058             uniqueNodes[ 0 ] = curNodes [ 1 ];
7059             uniqueNodes[ 1 ] = curNodes [ 0 ];
7060           }
7061           else if (nbRepl == 3 &&
7062                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7063             // all bottom nodes stick: set a top before
7064             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7065             uniqueNodes[ 0 ] = curNodes [ 3 ];
7066             uniqueNodes[ 1 ] = curNodes [ 4 ];
7067             uniqueNodes[ 2 ] = curNodes [ 5 ];
7068           }
7069           else if (nbRepl == 4 &&
7070                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7071             // a lateral face turns into a line: reverse a bottom
7072             uniqueNodes[ 0 ] = curNodes [ 1 ];
7073             uniqueNodes[ 1 ] = curNodes [ 0 ];
7074           }
7075           else
7076             isOk = false;
7077         }
7078         else if ( nbUniqueNodes == 5 ) {
7079           // PENTAHEDRON --------------------> 2 tetrahedrons
7080           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7081             // a bottom node sticks with a linked top one
7082             // 1.
7083             SMDS_MeshElement* newElem =
7084               aMesh->AddVolume(curNodes[ 3 ],
7085                                curNodes[ 4 ],
7086                                curNodes[ 5 ],
7087                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7088             myLastCreatedElems.Append(newElem);
7089             if ( aShapeId )
7090               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7091             // 2. : reverse a bottom
7092             uniqueNodes[ 0 ] = curNodes [ 1 ];
7093             uniqueNodes[ 1 ] = curNodes [ 0 ];
7094             nbUniqueNodes = 4;
7095           }
7096           else
7097             isOk = false;
7098         }
7099         else
7100           isOk = false;
7101         break;
7102       case 8: {
7103         if(elem->IsQuadratic()) { // Quadratic quadrangle
7104           //   1    5    2
7105           //    +---+---+
7106           //    |       |
7107           //    |       |
7108           //   4+       +6
7109           //    |       |
7110           //    |       |
7111           //    +---+---+
7112           //   0    7    3
7113           isOk = false;
7114           if(nbRepl==3) {
7115             nbUniqueNodes = 6;
7116             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7117               uniqueNodes[0] = curNodes[0];
7118               uniqueNodes[1] = curNodes[2];
7119               uniqueNodes[2] = curNodes[3];
7120               uniqueNodes[3] = curNodes[5];
7121               uniqueNodes[4] = curNodes[6];
7122               uniqueNodes[5] = curNodes[7];
7123               isOk = true;
7124             }
7125             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7126               uniqueNodes[0] = curNodes[0];
7127               uniqueNodes[1] = curNodes[1];
7128               uniqueNodes[2] = curNodes[2];
7129               uniqueNodes[3] = curNodes[4];
7130               uniqueNodes[4] = curNodes[5];
7131               uniqueNodes[5] = curNodes[6];
7132               isOk = true;
7133             }
7134             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7135               uniqueNodes[0] = curNodes[1];
7136               uniqueNodes[1] = curNodes[2];
7137               uniqueNodes[2] = curNodes[3];
7138               uniqueNodes[3] = curNodes[5];
7139               uniqueNodes[4] = curNodes[6];
7140               uniqueNodes[5] = curNodes[0];
7141               isOk = true;
7142             }
7143             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7144               uniqueNodes[0] = curNodes[0];
7145               uniqueNodes[1] = curNodes[1];
7146               uniqueNodes[2] = curNodes[3];
7147               uniqueNodes[3] = curNodes[4];
7148               uniqueNodes[4] = curNodes[6];
7149               uniqueNodes[5] = curNodes[7];
7150               isOk = true;
7151             }
7152             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7153               uniqueNodes[0] = curNodes[0];
7154               uniqueNodes[1] = curNodes[2];
7155               uniqueNodes[2] = curNodes[3];
7156               uniqueNodes[3] = curNodes[1];
7157               uniqueNodes[4] = curNodes[6];
7158               uniqueNodes[5] = curNodes[7];
7159               isOk = true;
7160             }
7161             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7162               uniqueNodes[0] = curNodes[0];
7163               uniqueNodes[1] = curNodes[1];
7164               uniqueNodes[2] = curNodes[2];
7165               uniqueNodes[3] = curNodes[4];
7166               uniqueNodes[4] = curNodes[5];
7167               uniqueNodes[5] = curNodes[7];
7168               isOk = true;
7169             }
7170             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7171               uniqueNodes[0] = curNodes[0];
7172               uniqueNodes[1] = curNodes[1];
7173               uniqueNodes[2] = curNodes[3];
7174               uniqueNodes[3] = curNodes[4];
7175               uniqueNodes[4] = curNodes[2];
7176               uniqueNodes[5] = curNodes[7];
7177               isOk = true;
7178             }
7179             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7180               uniqueNodes[0] = curNodes[0];
7181               uniqueNodes[1] = curNodes[1];
7182               uniqueNodes[2] = curNodes[2];
7183               uniqueNodes[3] = curNodes[4];
7184               uniqueNodes[4] = curNodes[5];
7185               uniqueNodes[5] = curNodes[3];
7186               isOk = true;
7187             }
7188           }
7189           break;
7190         }
7191         //////////////////////////////////// HEXAHEDRON
7192         isOk = false;
7193         SMDS_VolumeTool hexa (elem);
7194         hexa.SetExternalNormal();
7195         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7196           //////////////////////// ---> tetrahedron
7197           for ( int iFace = 0; iFace < 6; iFace++ ) {
7198             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7199             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7200                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7201                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7202               // one face turns into a point ...
7203               int iOppFace = hexa.GetOppFaceIndex( iFace );
7204               ind = hexa.GetFaceNodesIndices( iOppFace );
7205               int nbStick = 0;
7206               iUnique = 2; // reverse a tetrahedron bottom
7207               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7208                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7209                   nbStick++;
7210                 else if ( iUnique >= 0 )
7211                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7212               }
7213               if ( nbStick == 1 ) {
7214                 // ... and the opposite one - into a triangle.
7215                 // set a top node
7216                 ind = hexa.GetFaceNodesIndices( iFace );
7217                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7218                 isOk = true;
7219               }
7220               break;
7221             }
7222           }
7223         }
7224         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7225           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7226           for ( int iFace = 0; iFace < 6; iFace++ ) {
7227             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7228             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7229                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7230                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7231               // one face turns into a point ...
7232               int iOppFace = hexa.GetOppFaceIndex( iFace );
7233               ind = hexa.GetFaceNodesIndices( iOppFace );
7234               int nbStick = 0;
7235               iUnique = 2;  // reverse a tetrahedron 1 bottom
7236               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7237                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7238                   nbStick++;
7239                 else if ( iUnique >= 0 )
7240                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7241               }
7242               if ( nbStick == 0 ) {
7243                 // ... and the opposite one is a quadrangle
7244                 // set a top node
7245                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7246                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7247                 nbUniqueNodes = 4;
7248                 // tetrahedron 2
7249                 SMDS_MeshElement* newElem =
7250                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7251                                    curNodes[ind[ 3 ]],
7252                                    curNodes[ind[ 2 ]],
7253                                    curNodes[indTop[ 0 ]]);
7254                 myLastCreatedElems.Append(newElem);
7255                 if ( aShapeId )
7256                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7257                 isOk = true;
7258               }
7259               break;
7260             }
7261           }
7262         }
7263         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7264           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7265           // find indices of quad and tri faces
7266           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7267           for ( iFace = 0; iFace < 6; iFace++ ) {
7268             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7269             nodeSet.clear();
7270             for ( iCur = 0; iCur < 4; iCur++ )
7271               nodeSet.insert( curNodes[ind[ iCur ]] );
7272             nbUniqueNodes = nodeSet.size();
7273             if ( nbUniqueNodes == 3 )
7274               iTriFace[ nbTri++ ] = iFace;
7275             else if ( nbUniqueNodes == 4 )
7276               iQuadFace[ nbQuad++ ] = iFace;
7277           }
7278           if (nbQuad == 2 && nbTri == 4 &&
7279               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7280             // 2 opposite quadrangles stuck with a diagonal;
7281             // sample groups of merged indices: (0-4)(2-6)
7282             // --------------------------------------------> 2 tetrahedrons
7283             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7284             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7285             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7286             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7287                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7288               // stuck with 0-2 diagonal
7289               i0  = ind1[ 3 ];
7290               i1d = ind1[ 0 ];
7291               i2  = ind1[ 1 ];
7292               i3d = ind1[ 2 ];
7293               i0t = ind2[ 1 ];
7294               i2t = ind2[ 3 ];
7295             }
7296             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7297                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7298               // stuck with 1-3 diagonal
7299               i0  = ind1[ 0 ];
7300               i1d = ind1[ 1 ];
7301               i2  = ind1[ 2 ];
7302               i3d = ind1[ 3 ];
7303               i0t = ind2[ 0 ];
7304               i2t = ind2[ 1 ];
7305             }
7306             else {
7307               ASSERT(0);
7308             }
7309             // tetrahedron 1
7310             uniqueNodes[ 0 ] = curNodes [ i0 ];
7311             uniqueNodes[ 1 ] = curNodes [ i1d ];
7312             uniqueNodes[ 2 ] = curNodes [ i3d ];
7313             uniqueNodes[ 3 ] = curNodes [ i0t ];
7314             nbUniqueNodes = 4;
7315             // tetrahedron 2
7316             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7317                                                          curNodes[ i2 ],
7318                                                          curNodes[ i3d ],
7319                                                          curNodes[ i2t ]);
7320             myLastCreatedElems.Append(newElem);
7321             if ( aShapeId )
7322               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7323             isOk = true;
7324           }
7325           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7326                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7327             // --------------------------------------------> prism
7328             // find 2 opposite triangles
7329             nbUniqueNodes = 6;
7330             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7331               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7332                 // find indices of kept and replaced nodes
7333                 // and fill unique nodes of 2 opposite triangles
7334                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7335                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7336                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7337                 // fill unique nodes
7338                 iUnique = 0;
7339                 isOk = true;
7340                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7341                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7342                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7343                   if ( n == nInit ) {
7344                     // iCur of a linked node of the opposite face (make normals co-directed):
7345                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7346                     // check that correspondent corners of triangles are linked
7347                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7348                       isOk = false;
7349                     else {
7350                       uniqueNodes[ iUnique ] = n;
7351                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7352                       iUnique++;
7353                     }
7354                   }
7355                 }
7356                 break;
7357               }
7358             }
7359           }
7360         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7361         break;
7362       } // HEXAHEDRON
7363
7364       default:
7365         isOk = false;
7366       } // switch ( nbNodes )
7367
7368     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7369
7370     if ( isOk ) {
7371       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7372         // Change nodes of polyedre
7373         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7374           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7375         if (aPolyedre) {
7376           int nbFaces = aPolyedre->NbFaces();
7377
7378           vector<const SMDS_MeshNode *> poly_nodes;
7379           vector<int> quantities (nbFaces);
7380
7381           for (int iface = 1; iface <= nbFaces; iface++) {
7382             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7383             quantities[iface - 1] = nbFaceNodes;
7384
7385             for (inode = 1; inode <= nbFaceNodes; inode++) {
7386               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7387
7388               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7389               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7390                 curNode = (*nnIt).second;
7391               }
7392               poly_nodes.push_back(curNode);
7393             }
7394           }
7395           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7396         }
7397       }
7398       else {
7399         // Change regular element or polygon
7400         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7401       }
7402     }
7403     else {
7404       // Remove invalid regular element or invalid polygon
7405       rmElemIds.push_back( elem->GetID() );
7406     }
7407
7408   } // loop on elements
7409
7410   // Remove equal nodes and bad elements
7411
7412   Remove( rmNodeIds, true );
7413   Remove( rmElemIds, false );
7414
7415 }
7416
7417
7418 // ========================================================
7419 // class   : SortableElement
7420 // purpose : allow sorting elements basing on their nodes
7421 // ========================================================
7422 class SortableElement : public set <const SMDS_MeshElement*>
7423 {
7424 public:
7425
7426   SortableElement( const SMDS_MeshElement* theElem )
7427   {
7428     myElem = theElem;
7429     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7430     while ( nodeIt->more() )
7431       this->insert( nodeIt->next() );
7432   }
7433
7434   const SMDS_MeshElement* Get() const
7435   { return myElem; }
7436
7437   void Set(const SMDS_MeshElement* e) const
7438   { myElem = e; }
7439
7440
7441 private:
7442   mutable const SMDS_MeshElement* myElem;
7443 };
7444
7445 //=======================================================================
7446 //function : FindEqualElements
7447 //purpose  : Return list of group of elements built on the same nodes.
7448 //           Search among theElements or in the whole mesh if theElements is empty
7449 //=======================================================================
7450 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7451                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7452 {
7453   myLastCreatedElems.Clear();
7454   myLastCreatedNodes.Clear();
7455
7456   typedef set<const SMDS_MeshElement*> TElemsSet;
7457   typedef map< SortableElement, int > TMapOfNodeSet;
7458   typedef list<int> TGroupOfElems;
7459
7460   TElemsSet elems;
7461   if ( theElements.empty() )
7462   { // get all elements in the mesh
7463     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7464     while ( eIt->more() )
7465       elems.insert( elems.end(), eIt->next());
7466   }
7467   else
7468     elems = theElements;
7469
7470   vector< TGroupOfElems > arrayOfGroups;
7471   TGroupOfElems groupOfElems;
7472   TMapOfNodeSet mapOfNodeSet;
7473
7474   TElemsSet::iterator elemIt = elems.begin();
7475   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7476     const SMDS_MeshElement* curElem = *elemIt;
7477     SortableElement SE(curElem);
7478     int ind = -1;
7479     // check uniqueness
7480     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7481     if( !(pp.second) ) {
7482       TMapOfNodeSet::iterator& itSE = pp.first;
7483       ind = (*itSE).second;
7484       arrayOfGroups[ind].push_back(curElem->GetID());
7485     }
7486     else {
7487       groupOfElems.clear();
7488       groupOfElems.push_back(curElem->GetID());
7489       arrayOfGroups.push_back(groupOfElems);
7490       i++;
7491     }
7492   }
7493
7494   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7495   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7496     groupOfElems = *groupIt;
7497     if ( groupOfElems.size() > 1 ) {
7498       groupOfElems.sort();
7499       theGroupsOfElementsID.push_back(groupOfElems);
7500     }
7501   }
7502 }
7503
7504 //=======================================================================
7505 //function : MergeElements
7506 //purpose  : In each given group, substitute all elements by the first one.
7507 //=======================================================================
7508
7509 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7510 {
7511   myLastCreatedElems.Clear();
7512   myLastCreatedNodes.Clear();
7513
7514   typedef list<int> TListOfIDs;
7515   TListOfIDs rmElemIds; // IDs of elems to remove
7516
7517   SMESHDS_Mesh* aMesh = GetMeshDS();
7518
7519   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7520   while ( groupsIt != theGroupsOfElementsID.end() ) {
7521     TListOfIDs& aGroupOfElemID = *groupsIt;
7522     aGroupOfElemID.sort();
7523     int elemIDToKeep = aGroupOfElemID.front();
7524     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7525     aGroupOfElemID.pop_front();
7526     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7527     while ( idIt != aGroupOfElemID.end() ) {
7528       int elemIDToRemove = *idIt;
7529       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7530       // add the kept element in groups of removed one (PAL15188)
7531       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7532       rmElemIds.push_back( elemIDToRemove );
7533       ++idIt;
7534     }
7535     ++groupsIt;
7536   }
7537
7538   Remove( rmElemIds, false );
7539 }
7540
7541 //=======================================================================
7542 //function : MergeEqualElements
7543 //purpose  : Remove all but one of elements built on the same nodes.
7544 //=======================================================================
7545
7546 void SMESH_MeshEditor::MergeEqualElements()
7547 {
7548   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7549                                                  to merge equal elements in the whole mesh */
7550   TListOfListOfElementsID aGroupsOfElementsID;
7551   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7552   MergeElements(aGroupsOfElementsID);
7553 }
7554
7555 //=======================================================================
7556 //function : FindFaceInSet
7557 //purpose  : Return a face having linked nodes n1 and n2 and which is
7558 //           - not in avoidSet,
7559 //           - in elemSet provided that !elemSet.empty()
7560 //           i1 and i2 optionally returns indices of n1 and n2
7561 //=======================================================================
7562
7563 const SMDS_MeshElement*
7564 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7565                                 const SMDS_MeshNode*    n2,
7566                                 const TIDSortedElemSet& elemSet,
7567                                 const TIDSortedElemSet& avoidSet,
7568                                 int*                    n1ind,
7569                                 int*                    n2ind)
7570
7571 {
7572   int i1, i2;
7573   const SMDS_MeshElement* face = 0;
7574
7575   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7576   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7577   {
7578     const SMDS_MeshElement* elem = invElemIt->next();
7579     if (avoidSet.count( elem ))
7580       continue;
7581     if ( !elemSet.empty() && !elemSet.count( elem ))
7582       continue;
7583     // index of n1
7584     i1 = elem->GetNodeIndex( n1 );
7585     // find a n2 linked to n1
7586     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7587     for ( int di = -1; di < 2 && !face; di += 2 )
7588     {
7589       i2 = (i1+di+nbN) % nbN;
7590       if ( elem->GetNode( i2 ) == n2 )
7591         face = elem;
7592     }
7593     if ( !face && elem->IsQuadratic())
7594     {
7595       // analysis for quadratic elements using all nodes
7596       const SMDS_QuadraticFaceOfNodes* F =
7597         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7598       // use special nodes iterator
7599       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7600       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7601       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7602       {
7603         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7604         if ( n1 == prevN && n2 == n )
7605         {
7606           face = elem;
7607         }
7608         else if ( n2 == prevN && n1 == n )
7609         {
7610           face = elem; swap( i1, i2 );
7611         }
7612         prevN = n;
7613       }
7614     }
7615   }
7616   if ( n1ind ) *n1ind = i1;
7617   if ( n2ind ) *n2ind = i2;
7618   return face;
7619 }
7620
7621 //=======================================================================
7622 //function : findAdjacentFace
7623 //purpose  :
7624 //=======================================================================
7625
7626 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7627                                                 const SMDS_MeshNode* n2,
7628                                                 const SMDS_MeshElement* elem)
7629 {
7630   TIDSortedElemSet elemSet, avoidSet;
7631   if ( elem )
7632     avoidSet.insert ( elem );
7633   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7634 }
7635
7636 //=======================================================================
7637 //function : FindFreeBorder
7638 //purpose  :
7639 //=======================================================================
7640
7641 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7642
7643 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7644                                        const SMDS_MeshNode*             theSecondNode,
7645                                        const SMDS_MeshNode*             theLastNode,
7646                                        list< const SMDS_MeshNode* > &   theNodes,
7647                                        list< const SMDS_MeshElement* >& theFaces)
7648 {
7649   if ( !theFirstNode || !theSecondNode )
7650     return false;
7651   // find border face between theFirstNode and theSecondNode
7652   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7653   if ( !curElem )
7654     return false;
7655
7656   theFaces.push_back( curElem );
7657   theNodes.push_back( theFirstNode );
7658   theNodes.push_back( theSecondNode );
7659
7660   //vector<const SMDS_MeshNode*> nodes;
7661   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7662   TIDSortedElemSet foundElems;
7663   bool needTheLast = ( theLastNode != 0 );
7664
7665   while ( nStart != theLastNode ) {
7666     if ( nStart == theFirstNode )
7667       return !needTheLast;
7668
7669     // find all free border faces sharing form nStart
7670
7671     list< const SMDS_MeshElement* > curElemList;
7672     list< const SMDS_MeshNode* > nStartList;
7673     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7674     while ( invElemIt->more() ) {
7675       const SMDS_MeshElement* e = invElemIt->next();
7676       if ( e == curElem || foundElems.insert( e ).second ) {
7677         // get nodes
7678         int iNode = 0, nbNodes = e->NbNodes();
7679         //const SMDS_MeshNode* nodes[nbNodes+1];
7680         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7681
7682         if(e->IsQuadratic()) {
7683           const SMDS_QuadraticFaceOfNodes* F =
7684             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7685           // use special nodes iterator
7686           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7687           while( anIter->more() ) {
7688             nodes[ iNode++ ] = anIter->next();
7689           }
7690         }
7691         else {
7692           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7693           while ( nIt->more() )
7694             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7695         }
7696         nodes[ iNode ] = nodes[ 0 ];
7697         // check 2 links
7698         for ( iNode = 0; iNode < nbNodes; iNode++ )
7699           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7700                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7701               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7702           {
7703             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7704             curElemList.push_back( e );
7705           }
7706       }
7707     }
7708     // analyse the found
7709
7710     int nbNewBorders = curElemList.size();
7711     if ( nbNewBorders == 0 ) {
7712       // no free border furthermore
7713       return !needTheLast;
7714     }
7715     else if ( nbNewBorders == 1 ) {
7716       // one more element found
7717       nIgnore = nStart;
7718       nStart = nStartList.front();
7719       curElem = curElemList.front();
7720       theFaces.push_back( curElem );
7721       theNodes.push_back( nStart );
7722     }
7723     else {
7724       // several continuations found
7725       list< const SMDS_MeshElement* >::iterator curElemIt;
7726       list< const SMDS_MeshNode* >::iterator nStartIt;
7727       // check if one of them reached the last node
7728       if ( needTheLast ) {
7729         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7730              curElemIt!= curElemList.end();
7731              curElemIt++, nStartIt++ )
7732           if ( *nStartIt == theLastNode ) {
7733             theFaces.push_back( *curElemIt );
7734             theNodes.push_back( *nStartIt );
7735             return true;
7736           }
7737       }
7738       // find the best free border by the continuations
7739       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7740       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7741       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7742            curElemIt!= curElemList.end();
7743            curElemIt++, nStartIt++ )
7744       {
7745         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7746         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7747         // find one more free border
7748         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7749           cNL->clear();
7750           cFL->clear();
7751         }
7752         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7753           // choice: clear a worse one
7754           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7755           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7756           contNodes[ iWorse ].clear();
7757           contFaces[ iWorse ].clear();
7758         }
7759       }
7760       if ( contNodes[0].empty() && contNodes[1].empty() )
7761         return false;
7762
7763       // append the best free border
7764       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7765       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7766       theNodes.pop_back(); // remove nIgnore
7767       theNodes.pop_back(); // remove nStart
7768       theFaces.pop_back(); // remove curElem
7769       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7770       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7771       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7772       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7773       return true;
7774
7775     } // several continuations found
7776   } // while ( nStart != theLastNode )
7777
7778   return true;
7779 }
7780
7781 //=======================================================================
7782 //function : CheckFreeBorderNodes
7783 //purpose  : Return true if the tree nodes are on a free border
7784 //=======================================================================
7785
7786 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7787                                             const SMDS_MeshNode* theNode2,
7788                                             const SMDS_MeshNode* theNode3)
7789 {
7790   list< const SMDS_MeshNode* > nodes;
7791   list< const SMDS_MeshElement* > faces;
7792   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7793 }
7794
7795 //=======================================================================
7796 //function : SewFreeBorder
7797 //purpose  :
7798 //=======================================================================
7799
7800 SMESH_MeshEditor::Sew_Error
7801 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7802                                  const SMDS_MeshNode* theBordSecondNode,
7803                                  const SMDS_MeshNode* theBordLastNode,
7804                                  const SMDS_MeshNode* theSideFirstNode,
7805                                  const SMDS_MeshNode* theSideSecondNode,
7806                                  const SMDS_MeshNode* theSideThirdNode,
7807                                  const bool           theSideIsFreeBorder,
7808                                  const bool           toCreatePolygons,
7809                                  const bool           toCreatePolyedrs)
7810 {
7811   myLastCreatedElems.Clear();
7812   myLastCreatedNodes.Clear();
7813
7814   MESSAGE("::SewFreeBorder()");
7815   Sew_Error aResult = SEW_OK;
7816
7817   // ====================================
7818   //    find side nodes and elements
7819   // ====================================
7820
7821   list< const SMDS_MeshNode* > nSide[ 2 ];
7822   list< const SMDS_MeshElement* > eSide[ 2 ];
7823   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7824   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7825
7826   // Free border 1
7827   // --------------
7828   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7829                       nSide[0], eSide[0])) {
7830     MESSAGE(" Free Border 1 not found " );
7831     aResult = SEW_BORDER1_NOT_FOUND;
7832   }
7833   if (theSideIsFreeBorder) {
7834     // Free border 2
7835     // --------------
7836     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7837                         nSide[1], eSide[1])) {
7838       MESSAGE(" Free Border 2 not found " );
7839       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7840     }
7841   }
7842   if ( aResult != SEW_OK )
7843     return aResult;
7844
7845   if (!theSideIsFreeBorder) {
7846     // Side 2
7847     // --------------
7848
7849     // -------------------------------------------------------------------------
7850     // Algo:
7851     // 1. If nodes to merge are not coincident, move nodes of the free border
7852     //    from the coord sys defined by the direction from the first to last
7853     //    nodes of the border to the correspondent sys of the side 2
7854     // 2. On the side 2, find the links most co-directed with the correspondent
7855     //    links of the free border
7856     // -------------------------------------------------------------------------
7857
7858     // 1. Since sewing may brake if there are volumes to split on the side 2,
7859     //    we wont move nodes but just compute new coordinates for them
7860     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7861     TNodeXYZMap nBordXYZ;
7862     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7863     list< const SMDS_MeshNode* >::iterator nBordIt;
7864
7865     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7866     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7867     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7868     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7869     double tol2 = 1.e-8;
7870     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7871     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7872       // Need node movement.
7873
7874       // find X and Z axes to create trsf
7875       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7876       gp_Vec X = Zs ^ Zb;
7877       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7878         // Zb || Zs
7879         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7880
7881       // coord systems
7882       gp_Ax3 toBordAx( Pb1, Zb, X );
7883       gp_Ax3 fromSideAx( Ps1, Zs, X );
7884       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7885       // set trsf
7886       gp_Trsf toBordSys, fromSide2Sys;
7887       toBordSys.SetTransformation( toBordAx );
7888       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7889       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7890
7891       // move
7892       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7893         const SMDS_MeshNode* n = *nBordIt;
7894         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7895         toBordSys.Transforms( xyz );
7896         fromSide2Sys.Transforms( xyz );
7897         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7898       }
7899     }
7900     else {
7901       // just insert nodes XYZ in the nBordXYZ map
7902       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7903         const SMDS_MeshNode* n = *nBordIt;
7904         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7905       }
7906     }
7907
7908     // 2. On the side 2, find the links most co-directed with the correspondent
7909     //    links of the free border
7910
7911     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7912     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7913     sideNodes.push_back( theSideFirstNode );
7914
7915     bool hasVolumes = false;
7916     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7917     set<long> foundSideLinkIDs, checkedLinkIDs;
7918     SMDS_VolumeTool volume;
7919     //const SMDS_MeshNode* faceNodes[ 4 ];
7920
7921     const SMDS_MeshNode*    sideNode;
7922     const SMDS_MeshElement* sideElem;
7923     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7924     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7925     nBordIt = bordNodes.begin();
7926     nBordIt++;
7927     // border node position and border link direction to compare with
7928     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7929     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7930     // choose next side node by link direction or by closeness to
7931     // the current border node:
7932     bool searchByDir = ( *nBordIt != theBordLastNode );
7933     do {
7934       // find the next node on the Side 2
7935       sideNode = 0;
7936       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7937       long linkID;
7938       checkedLinkIDs.clear();
7939       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7940
7941       // loop on inverse elements of current node (prevSideNode) on the Side 2
7942       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7943       while ( invElemIt->more() )
7944       {
7945         const SMDS_MeshElement* elem = invElemIt->next();
7946         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7947         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7948         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7949         bool isVolume = volume.Set( elem );
7950         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7951         if ( isVolume ) // --volume
7952           hasVolumes = true;
7953         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7954           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7955           if(elem->IsQuadratic()) {
7956             const SMDS_QuadraticFaceOfNodes* F =
7957               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7958             // use special nodes iterator
7959             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7960             while( anIter->more() ) {
7961               nodes[ iNode ] = anIter->next();
7962               if ( nodes[ iNode++ ] == prevSideNode )
7963                 iPrevNode = iNode - 1;
7964             }
7965           }
7966           else {
7967             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7968             while ( nIt->more() ) {
7969               nodes[ iNode ] = cast2Node( nIt->next() );
7970               if ( nodes[ iNode++ ] == prevSideNode )
7971                 iPrevNode = iNode - 1;
7972             }
7973           }
7974           // there are 2 links to check
7975           nbNodes = 2;
7976         }
7977         else // --edge
7978           continue;
7979         // loop on links, to be precise, on the second node of links
7980         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7981           const SMDS_MeshNode* n = nodes[ iNode ];
7982           if ( isVolume ) {
7983             if ( !volume.IsLinked( n, prevSideNode ))
7984               continue;
7985           }
7986           else {
7987             if ( iNode ) // a node before prevSideNode
7988               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7989             else         // a node after prevSideNode
7990               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7991           }
7992           // check if this link was already used
7993           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7994           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7995           if (!isJustChecked &&
7996               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7997           {
7998             // test a link geometrically
7999             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8000             bool linkIsBetter = false;
8001             double dot = 0.0, dist = 0.0;
8002             if ( searchByDir ) { // choose most co-directed link
8003               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8004               linkIsBetter = ( dot > maxDot );
8005             }
8006             else { // choose link with the node closest to bordPos
8007               dist = ( nextXYZ - bordPos ).SquareModulus();
8008               linkIsBetter = ( dist < minDist );
8009             }
8010             if ( linkIsBetter ) {
8011               maxDot = dot;
8012               minDist = dist;
8013               linkID = iLink;
8014               sideNode = n;
8015               sideElem = elem;
8016             }
8017           }
8018         }
8019       } // loop on inverse elements of prevSideNode
8020
8021       if ( !sideNode ) {
8022         MESSAGE(" Cant find path by links of the Side 2 ");
8023         return SEW_BAD_SIDE_NODES;
8024       }
8025       sideNodes.push_back( sideNode );
8026       sideElems.push_back( sideElem );
8027       foundSideLinkIDs.insert ( linkID );
8028       prevSideNode = sideNode;
8029
8030       if ( *nBordIt == theBordLastNode )
8031         searchByDir = false;
8032       else {
8033         // find the next border link to compare with
8034         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8035         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8036         // move to next border node if sideNode is before forward border node (bordPos)
8037         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8038           prevBordNode = *nBordIt;
8039           nBordIt++;
8040           bordPos = nBordXYZ[ *nBordIt ];
8041           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8042           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8043         }
8044       }
8045     }
8046     while ( sideNode != theSideSecondNode );
8047
8048     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8049       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8050       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8051     }
8052   } // end nodes search on the side 2
8053
8054   // ============================
8055   // sew the border to the side 2
8056   // ============================
8057
8058   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8059   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8060
8061   TListOfListOfNodes nodeGroupsToMerge;
8062   if ( nbNodes[0] == nbNodes[1] ||
8063        ( theSideIsFreeBorder && !theSideThirdNode)) {
8064
8065     // all nodes are to be merged
8066
8067     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8068          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8069          nIt[0]++, nIt[1]++ )
8070     {
8071       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8072       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8073       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8074     }
8075   }
8076   else {
8077
8078     // insert new nodes into the border and the side to get equal nb of segments
8079
8080     // get normalized parameters of nodes on the borders
8081     //double param[ 2 ][ maxNbNodes ];
8082     double* param[ 2 ];
8083     param[0] = new double [ maxNbNodes ];
8084     param[1] = new double [ maxNbNodes ];
8085     int iNode, iBord;
8086     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8087       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8088       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8089       const SMDS_MeshNode* nPrev = *nIt;
8090       double bordLength = 0;
8091       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8092         const SMDS_MeshNode* nCur = *nIt;
8093         gp_XYZ segment (nCur->X() - nPrev->X(),
8094                         nCur->Y() - nPrev->Y(),
8095                         nCur->Z() - nPrev->Z());
8096         double segmentLen = segment.Modulus();
8097         bordLength += segmentLen;
8098         param[ iBord ][ iNode ] = bordLength;
8099         nPrev = nCur;
8100       }
8101       // normalize within [0,1]
8102       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8103         param[ iBord ][ iNode ] /= bordLength;
8104       }
8105     }
8106
8107     // loop on border segments
8108     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8109     int i[ 2 ] = { 0, 0 };
8110     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8111     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8112
8113     TElemOfNodeListMap insertMap;
8114     TElemOfNodeListMap::iterator insertMapIt;
8115     // insertMap is
8116     // key:   elem to insert nodes into
8117     // value: 2 nodes to insert between + nodes to be inserted
8118     do {
8119       bool next[ 2 ] = { false, false };
8120
8121       // find min adjacent segment length after sewing
8122       double nextParam = 10., prevParam = 0;
8123       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8124         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8125           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8126         if ( i[ iBord ] > 0 )
8127           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8128       }
8129       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8130       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8131       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8132
8133       // choose to insert or to merge nodes
8134       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8135       if ( Abs( du ) <= minSegLen * 0.2 ) {
8136         // merge
8137         // ------
8138         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8139         const SMDS_MeshNode* n0 = *nIt[0];
8140         const SMDS_MeshNode* n1 = *nIt[1];
8141         nodeGroupsToMerge.back().push_back( n1 );
8142         nodeGroupsToMerge.back().push_back( n0 );
8143         // position of node of the border changes due to merge
8144         param[ 0 ][ i[0] ] += du;
8145         // move n1 for the sake of elem shape evaluation during insertion.
8146         // n1 will be removed by MergeNodes() anyway
8147         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8148         next[0] = next[1] = true;
8149       }
8150       else {
8151         // insert
8152         // ------
8153         int intoBord = ( du < 0 ) ? 0 : 1;
8154         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8155         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8156         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8157         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8158         if ( intoBord == 1 ) {
8159           // move node of the border to be on a link of elem of the side
8160           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8161           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8162           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8163           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8164           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8165         }
8166         insertMapIt = insertMap.find( elem );
8167         bool notFound = ( insertMapIt == insertMap.end() );
8168         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8169         if ( otherLink ) {
8170           // insert into another link of the same element:
8171           // 1. perform insertion into the other link of the elem
8172           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8173           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8174           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8175           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8176           // 2. perform insertion into the link of adjacent faces
8177           while (true) {
8178             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8179             if ( adjElem )
8180               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8181             else
8182               break;
8183           }
8184           if (toCreatePolyedrs) {
8185             // perform insertion into the links of adjacent volumes
8186             UpdateVolumes(n12, n22, nodeList);
8187           }
8188           // 3. find an element appeared on n1 and n2 after the insertion
8189           insertMap.erase( elem );
8190           elem = findAdjacentFace( n1, n2, 0 );
8191         }
8192         if ( notFound || otherLink ) {
8193           // add element and nodes of the side into the insertMap
8194           insertMapIt = insertMap.insert
8195             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8196           (*insertMapIt).second.push_back( n1 );
8197           (*insertMapIt).second.push_back( n2 );
8198         }
8199         // add node to be inserted into elem
8200         (*insertMapIt).second.push_back( nIns );
8201         next[ 1 - intoBord ] = true;
8202       }
8203
8204       // go to the next segment
8205       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8206         if ( next[ iBord ] ) {
8207           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8208             eIt[ iBord ]++;
8209           nPrev[ iBord ] = *nIt[ iBord ];
8210           nIt[ iBord ]++; i[ iBord ]++;
8211         }
8212       }
8213     }
8214     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8215
8216     // perform insertion of nodes into elements
8217
8218     for (insertMapIt = insertMap.begin();
8219          insertMapIt != insertMap.end();
8220          insertMapIt++ )
8221     {
8222       const SMDS_MeshElement* elem = (*insertMapIt).first;
8223       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8224       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8225       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8226
8227       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8228
8229       if ( !theSideIsFreeBorder ) {
8230         // look for and insert nodes into the faces adjacent to elem
8231         while (true) {
8232           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8233           if ( adjElem )
8234             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8235           else
8236             break;
8237         }
8238       }
8239       if (toCreatePolyedrs) {
8240         // perform insertion into the links of adjacent volumes
8241         UpdateVolumes(n1, n2, nodeList);
8242       }
8243     }
8244
8245     delete param[0];
8246     delete param[1];
8247   } // end: insert new nodes
8248
8249   MergeNodes ( nodeGroupsToMerge );
8250
8251   return aResult;
8252 }
8253
8254 //=======================================================================
8255 //function : InsertNodesIntoLink
8256 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8257 //           and theBetweenNode2 and split theElement
8258 //=======================================================================
8259
8260 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8261                                            const SMDS_MeshNode*        theBetweenNode1,
8262                                            const SMDS_MeshNode*        theBetweenNode2,
8263                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8264                                            const bool                  toCreatePoly)
8265 {
8266   if ( theFace->GetType() != SMDSAbs_Face ) return;
8267
8268   // find indices of 2 link nodes and of the rest nodes
8269   int iNode = 0, il1, il2, i3, i4;
8270   il1 = il2 = i3 = i4 = -1;
8271   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8272   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8273
8274   if(theFace->IsQuadratic()) {
8275     const SMDS_QuadraticFaceOfNodes* F =
8276       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8277     // use special nodes iterator
8278     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8279     while( anIter->more() ) {
8280       const SMDS_MeshNode* n = anIter->next();
8281       if ( n == theBetweenNode1 )
8282         il1 = iNode;
8283       else if ( n == theBetweenNode2 )
8284         il2 = iNode;
8285       else if ( i3 < 0 )
8286         i3 = iNode;
8287       else
8288         i4 = iNode;
8289       nodes[ iNode++ ] = n;
8290     }
8291   }
8292   else {
8293     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8294     while ( nodeIt->more() ) {
8295       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8296       if ( n == theBetweenNode1 )
8297         il1 = iNode;
8298       else if ( n == theBetweenNode2 )
8299         il2 = iNode;
8300       else if ( i3 < 0 )
8301         i3 = iNode;
8302       else
8303         i4 = iNode;
8304       nodes[ iNode++ ] = n;
8305     }
8306   }
8307   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8308     return ;
8309
8310   // arrange link nodes to go one after another regarding the face orientation
8311   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8312   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8313   if ( reverse ) {
8314     iNode = il1;
8315     il1 = il2;
8316     il2 = iNode;
8317     aNodesToInsert.reverse();
8318   }
8319   // check that not link nodes of a quadrangles are in good order
8320   int nbFaceNodes = theFace->NbNodes();
8321   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8322     iNode = i3;
8323     i3 = i4;
8324     i4 = iNode;
8325   }
8326
8327   if (toCreatePoly || theFace->IsPoly()) {
8328
8329     iNode = 0;
8330     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8331
8332     // add nodes of face up to first node of link
8333     bool isFLN = false;
8334
8335     if(theFace->IsQuadratic()) {
8336       const SMDS_QuadraticFaceOfNodes* F =
8337         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8338       // use special nodes iterator
8339       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8340       while( anIter->more()  && !isFLN ) {
8341         const SMDS_MeshNode* n = anIter->next();
8342         poly_nodes[iNode++] = n;
8343         if (n == nodes[il1]) {
8344           isFLN = true;
8345         }
8346       }
8347       // add nodes to insert
8348       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8349       for (; nIt != aNodesToInsert.end(); nIt++) {
8350         poly_nodes[iNode++] = *nIt;
8351       }
8352       // add nodes of face starting from last node of link
8353       while ( anIter->more() ) {
8354         poly_nodes[iNode++] = anIter->next();
8355       }
8356     }
8357     else {
8358       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8359       while ( nodeIt->more() && !isFLN ) {
8360         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8361         poly_nodes[iNode++] = n;
8362         if (n == nodes[il1]) {
8363           isFLN = true;
8364         }
8365       }
8366       // add nodes to insert
8367       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8368       for (; nIt != aNodesToInsert.end(); nIt++) {
8369         poly_nodes[iNode++] = *nIt;
8370       }
8371       // add nodes of face starting from last node of link
8372       while ( nodeIt->more() ) {
8373         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8374         poly_nodes[iNode++] = n;
8375       }
8376     }
8377
8378     // edit or replace the face
8379     SMESHDS_Mesh *aMesh = GetMeshDS();
8380
8381     if (theFace->IsPoly()) {
8382       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8383     }
8384     else {
8385       int aShapeId = FindShape( theFace );
8386
8387       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8388       myLastCreatedElems.Append(newElem);
8389       if ( aShapeId && newElem )
8390         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8391
8392       aMesh->RemoveElement(theFace);
8393     }
8394     return;
8395   }
8396
8397   if( !theFace->IsQuadratic() ) {
8398
8399     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8400     int nbLinkNodes = 2 + aNodesToInsert.size();
8401     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8402     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8403     linkNodes[ 0 ] = nodes[ il1 ];
8404     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8405     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8406     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8407       linkNodes[ iNode++ ] = *nIt;
8408     }
8409     // decide how to split a quadrangle: compare possible variants
8410     // and choose which of splits to be a quadrangle
8411     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8412     if ( nbFaceNodes == 3 ) {
8413       iBestQuad = nbSplits;
8414       i4 = i3;
8415     }
8416     else if ( nbFaceNodes == 4 ) {
8417       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8418       double aBestRate = DBL_MAX;
8419       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8420         i1 = 0; i2 = 1;
8421         double aBadRate = 0;
8422         // evaluate elements quality
8423         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8424           if ( iSplit == iQuad ) {
8425             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8426                                    linkNodes[ i2++ ],
8427                                    nodes[ i3 ],
8428                                    nodes[ i4 ]);
8429             aBadRate += getBadRate( &quad, aCrit );
8430           }
8431           else {
8432             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8433                                    linkNodes[ i2++ ],
8434                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8435             aBadRate += getBadRate( &tria, aCrit );
8436           }
8437         }
8438         // choice
8439         if ( aBadRate < aBestRate ) {
8440           iBestQuad = iQuad;
8441           aBestRate = aBadRate;
8442         }
8443       }
8444     }
8445
8446     // create new elements
8447     SMESHDS_Mesh *aMesh = GetMeshDS();
8448     int aShapeId = FindShape( theFace );
8449
8450     i1 = 0; i2 = 1;
8451     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8452       SMDS_MeshElement* newElem = 0;
8453       if ( iSplit == iBestQuad )
8454         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8455                                   linkNodes[ i2++ ],
8456                                   nodes[ i3 ],
8457                                   nodes[ i4 ]);
8458       else
8459         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8460                                   linkNodes[ i2++ ],
8461                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8462       myLastCreatedElems.Append(newElem);
8463       if ( aShapeId && newElem )
8464         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8465     }
8466
8467     // change nodes of theFace
8468     const SMDS_MeshNode* newNodes[ 4 ];
8469     newNodes[ 0 ] = linkNodes[ i1 ];
8470     newNodes[ 1 ] = linkNodes[ i2 ];
8471     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8472     newNodes[ 3 ] = nodes[ i4 ];
8473     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8474   } // end if(!theFace->IsQuadratic())
8475   else { // theFace is quadratic
8476     // we have to split theFace on simple triangles and one simple quadrangle
8477     int tmp = il1/2;
8478     int nbshift = tmp*2;
8479     // shift nodes in nodes[] by nbshift
8480     int i,j;
8481     for(i=0; i<nbshift; i++) {
8482       const SMDS_MeshNode* n = nodes[0];
8483       for(j=0; j<nbFaceNodes-1; j++) {
8484         nodes[j] = nodes[j+1];
8485       }
8486       nodes[nbFaceNodes-1] = n;
8487     }
8488     il1 = il1 - nbshift;
8489     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8490     //   n0      n1     n2    n0      n1     n2
8491     //     +-----+-----+        +-----+-----+
8492     //      \         /         |           |
8493     //       \       /          |           |
8494     //      n5+     +n3       n7+           +n3
8495     //         \   /            |           |
8496     //          \ /             |           |
8497     //           +              +-----+-----+
8498     //           n4           n6      n5     n4
8499
8500     // create new elements
8501     SMESHDS_Mesh *aMesh = GetMeshDS();
8502     int aShapeId = FindShape( theFace );
8503
8504     int n1,n2,n3;
8505     if(nbFaceNodes==6) { // quadratic triangle
8506       SMDS_MeshElement* newElem =
8507         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8508       myLastCreatedElems.Append(newElem);
8509       if ( aShapeId && newElem )
8510         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8511       if(theFace->IsMediumNode(nodes[il1])) {
8512         // create quadrangle
8513         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8514         myLastCreatedElems.Append(newElem);
8515         if ( aShapeId && newElem )
8516           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8517         n1 = 1;
8518         n2 = 2;
8519         n3 = 3;
8520       }
8521       else {
8522         // create quadrangle
8523         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8524         myLastCreatedElems.Append(newElem);
8525         if ( aShapeId && newElem )
8526           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8527         n1 = 0;
8528         n2 = 1;
8529         n3 = 5;
8530       }
8531     }
8532     else { // nbFaceNodes==8 - quadratic quadrangle
8533       SMDS_MeshElement* newElem =
8534         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8535       myLastCreatedElems.Append(newElem);
8536       if ( aShapeId && newElem )
8537         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8538       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8539       myLastCreatedElems.Append(newElem);
8540       if ( aShapeId && newElem )
8541         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8542       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8543       myLastCreatedElems.Append(newElem);
8544       if ( aShapeId && newElem )
8545         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8546       if(theFace->IsMediumNode(nodes[il1])) {
8547         // create quadrangle
8548         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8549         myLastCreatedElems.Append(newElem);
8550         if ( aShapeId && newElem )
8551           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8552         n1 = 1;
8553         n2 = 2;
8554         n3 = 3;
8555       }
8556       else {
8557         // create quadrangle
8558         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8559         myLastCreatedElems.Append(newElem);
8560         if ( aShapeId && newElem )
8561           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8562         n1 = 0;
8563         n2 = 1;
8564         n3 = 7;
8565       }
8566     }
8567     // create needed triangles using n1,n2,n3 and inserted nodes
8568     int nbn = 2 + aNodesToInsert.size();
8569     //const SMDS_MeshNode* aNodes[nbn];
8570     vector<const SMDS_MeshNode*> aNodes(nbn);
8571     aNodes[0] = nodes[n1];
8572     aNodes[nbn-1] = nodes[n2];
8573     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8574     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8575       aNodes[iNode++] = *nIt;
8576     }
8577     for(i=1; i<nbn; i++) {
8578       SMDS_MeshElement* newElem =
8579         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8580       myLastCreatedElems.Append(newElem);
8581       if ( aShapeId && newElem )
8582         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8583     }
8584     // remove old quadratic face
8585     aMesh->RemoveElement(theFace);
8586   }
8587 }
8588
8589 //=======================================================================
8590 //function : UpdateVolumes
8591 //purpose  :
8592 //=======================================================================
8593 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8594                                       const SMDS_MeshNode*        theBetweenNode2,
8595                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8596 {
8597   myLastCreatedElems.Clear();
8598   myLastCreatedNodes.Clear();
8599
8600   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8601   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8602     const SMDS_MeshElement* elem = invElemIt->next();
8603
8604     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8605     SMDS_VolumeTool aVolume (elem);
8606     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8607       continue;
8608
8609     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8610     int iface, nbFaces = aVolume.NbFaces();
8611     vector<const SMDS_MeshNode *> poly_nodes;
8612     vector<int> quantities (nbFaces);
8613
8614     for (iface = 0; iface < nbFaces; iface++) {
8615       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8616       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8617       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8618
8619       for (int inode = 0; inode < nbFaceNodes; inode++) {
8620         poly_nodes.push_back(faceNodes[inode]);
8621
8622         if (nbInserted == 0) {
8623           if (faceNodes[inode] == theBetweenNode1) {
8624             if (faceNodes[inode + 1] == theBetweenNode2) {
8625               nbInserted = theNodesToInsert.size();
8626
8627               // add nodes to insert
8628               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8629               for (; nIt != theNodesToInsert.end(); nIt++) {
8630                 poly_nodes.push_back(*nIt);
8631               }
8632             }
8633           }
8634           else if (faceNodes[inode] == theBetweenNode2) {
8635             if (faceNodes[inode + 1] == theBetweenNode1) {
8636               nbInserted = theNodesToInsert.size();
8637
8638               // add nodes to insert in reversed order
8639               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8640               nIt--;
8641               for (; nIt != theNodesToInsert.begin(); nIt--) {
8642                 poly_nodes.push_back(*nIt);
8643               }
8644               poly_nodes.push_back(*nIt);
8645             }
8646           }
8647           else {
8648           }
8649         }
8650       }
8651       quantities[iface] = nbFaceNodes + nbInserted;
8652     }
8653
8654     // Replace or update the volume
8655     SMESHDS_Mesh *aMesh = GetMeshDS();
8656
8657     if (elem->IsPoly()) {
8658       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8659
8660     }
8661     else {
8662       int aShapeId = FindShape( elem );
8663
8664       SMDS_MeshElement* newElem =
8665         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8666       myLastCreatedElems.Append(newElem);
8667       if (aShapeId && newElem)
8668         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8669
8670       aMesh->RemoveElement(elem);
8671     }
8672   }
8673 }
8674
8675 //=======================================================================
8676 /*!
8677  * \brief Convert elements contained in a submesh to quadratic
8678  * \retval int - nb of checked elements
8679  */
8680 //=======================================================================
8681
8682 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8683                                              SMESH_MesherHelper& theHelper,
8684                                              const bool          theForce3d)
8685 {
8686   int nbElem = 0;
8687   if( !theSm ) return nbElem;
8688
8689   vector<int> nbNodeInFaces;
8690   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8691   while(ElemItr->more())
8692   {
8693     nbElem++;
8694     const SMDS_MeshElement* elem = ElemItr->next();
8695     if( !elem || elem->IsQuadratic() ) continue;
8696
8697     int id = elem->GetID();
8698     int nbNodes = elem->NbNodes();
8699     SMDSAbs_ElementType aType = elem->GetType();
8700
8701     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
8702     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
8703       nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >( elem )->GetQuanities();
8704
8705     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8706
8707     const SMDS_MeshElement* NewElem = 0;
8708
8709     switch( aType )
8710     {
8711     case SMDSAbs_Edge :
8712       {
8713         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8714         break;
8715       }
8716     case SMDSAbs_Face :
8717       {
8718         switch(nbNodes)
8719         {
8720         case 3:
8721           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8722           break;
8723         case 4:
8724           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8725           break;
8726         default:
8727           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8728           continue;
8729         }
8730         break;
8731       }
8732     case SMDSAbs_Volume :
8733       {
8734         switch(nbNodes)
8735         {
8736         case 4:
8737           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8738           break;
8739         case 5:
8740           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8741           break;
8742         case 6:
8743           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8744           break;
8745         case 8:
8746           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8747                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8748           break;
8749         default:
8750           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8751         }
8752         break;
8753       }
8754     default :
8755       continue;
8756     }
8757     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8758     if( NewElem )
8759       theSm->AddElement( NewElem );
8760   }
8761   return nbElem;
8762 }
8763
8764 //=======================================================================
8765 //function : ConvertToQuadratic
8766 //purpose  :
8767 //=======================================================================
8768 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8769 {
8770   SMESHDS_Mesh* meshDS = GetMeshDS();
8771
8772   SMESH_MesherHelper aHelper(*myMesh);
8773   aHelper.SetIsQuadratic( true );
8774
8775   int nbCheckedElems = 0;
8776   if ( myMesh->HasShapeToMesh() )
8777   {
8778     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8779     {
8780       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8781       while ( smIt->more() ) {
8782         SMESH_subMesh* sm = smIt->next();
8783         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8784           aHelper.SetSubShape( sm->GetSubShape() );
8785           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8786         }
8787       }
8788     }
8789   }
8790   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8791   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8792   {
8793     SMESHDS_SubMesh *smDS = 0;
8794     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8795     while(aEdgeItr->more())
8796     {
8797       const SMDS_MeshEdge* edge = aEdgeItr->next();
8798       if(edge && !edge->IsQuadratic())
8799       {
8800         int id = edge->GetID();
8801         const SMDS_MeshNode* n1 = edge->GetNode(0);
8802         const SMDS_MeshNode* n2 = edge->GetNode(1);
8803
8804         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8805
8806         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8807         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8808       }
8809     }
8810     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8811     while(aFaceItr->more())
8812     {
8813       const SMDS_MeshFace* face = aFaceItr->next();
8814       if(!face || face->IsQuadratic() ) continue;
8815
8816       int id = face->GetID();
8817       int nbNodes = face->NbNodes();
8818       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8819
8820       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8821
8822       SMDS_MeshFace * NewFace = 0;
8823       switch(nbNodes)
8824       {
8825       case 3:
8826         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8827         break;
8828       case 4:
8829         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8830         break;
8831       default:
8832         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8833       }
8834       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8835     }
8836     vector<int> nbNodeInFaces;
8837     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8838     while(aVolumeItr->more())
8839     {
8840       const SMDS_MeshVolume* volume = aVolumeItr->next();
8841       if(!volume || volume->IsQuadratic() ) continue;
8842
8843       int id = volume->GetID();
8844       int nbNodes = volume->NbNodes();
8845       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8846       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
8847         nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >(volume)->GetQuanities();
8848
8849       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8850
8851       SMDS_MeshVolume * NewVolume = 0;
8852       switch(nbNodes)
8853       {
8854       case 4:
8855         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8856                                       nodes[3], id, theForce3d );
8857         break;
8858       case 5:
8859         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8860                                       nodes[3], nodes[4], id, theForce3d);
8861         break;
8862       case 6:
8863         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8864                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
8865         break;
8866       case 8:
8867         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8868                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8869         break;
8870       default:
8871         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8872       }
8873       ReplaceElemInGroups(volume, NewVolume, meshDS);
8874     }
8875   }
8876
8877   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
8878   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8879     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8880     aHelper.FixQuadraticElements();
8881   }
8882 }
8883
8884 //=======================================================================
8885 /*!
8886  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8887  * \retval int - nb of checked elements
8888  */
8889 //=======================================================================
8890
8891 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8892                                      SMDS_ElemIteratorPtr theItr,
8893                                      const int            theShapeID)
8894 {
8895   int nbElem = 0;
8896   SMESHDS_Mesh* meshDS = GetMeshDS();
8897   const bool notFromGroups = false;
8898
8899   while( theItr->more() )
8900   {
8901     const SMDS_MeshElement* elem = theItr->next();
8902     nbElem++;
8903     if( elem && elem->IsQuadratic())
8904     {
8905       int id = elem->GetID();
8906       int nbNodes = elem->NbNodes();
8907       vector<const SMDS_MeshNode *> nodes, mediumNodes;
8908       nodes.reserve( nbNodes );
8909       mediumNodes.reserve( nbNodes );
8910
8911       for(int i = 0; i < nbNodes; i++)
8912       {
8913         const SMDS_MeshNode* n = elem->GetNode(i);
8914
8915         if( elem->IsMediumNode( n ) )
8916           mediumNodes.push_back( n );
8917         else
8918           nodes.push_back( n );
8919       }
8920       if( nodes.empty() ) continue;
8921       SMDSAbs_ElementType aType = elem->GetType();
8922
8923       //remove old quadratic element
8924       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8925
8926       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
8927       ReplaceElemInGroups(elem, NewElem, meshDS);
8928       if( theSm && NewElem )
8929         theSm->AddElement( NewElem );
8930
8931       // remove medium nodes
8932       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8933       for ( ; nIt != mediumNodes.end(); ++nIt ) {
8934         const SMDS_MeshNode* n = *nIt;
8935         if ( n->NbInverseElements() == 0 ) {
8936           if ( n->GetPosition()->GetShapeId() != theShapeID )
8937             meshDS->RemoveFreeNode( n, meshDS->MeshElements
8938                                     ( n->GetPosition()->GetShapeId() ));
8939           else
8940             meshDS->RemoveFreeNode( n, theSm );
8941         }
8942       }
8943     }
8944   }
8945   return nbElem;
8946 }
8947
8948 //=======================================================================
8949 //function : ConvertFromQuadratic
8950 //purpose  :
8951 //=======================================================================
8952 bool  SMESH_MeshEditor::ConvertFromQuadratic()
8953 {
8954   int nbCheckedElems = 0;
8955   if ( myMesh->HasShapeToMesh() )
8956   {
8957     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8958     {
8959       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8960       while ( smIt->more() ) {
8961         SMESH_subMesh* sm = smIt->next();
8962         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8963           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8964       }
8965     }
8966   }
8967
8968   int totalNbElems =
8969     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8970   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8971   {
8972     SMESHDS_SubMesh *aSM = 0;
8973     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8974   }
8975
8976   return true;
8977 }
8978
8979 //=======================================================================
8980 //function : SewSideElements
8981 //purpose  :
8982 //=======================================================================
8983
8984 SMESH_MeshEditor::Sew_Error
8985 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
8986                                    TIDSortedElemSet&    theSide2,
8987                                    const SMDS_MeshNode* theFirstNode1,
8988                                    const SMDS_MeshNode* theFirstNode2,
8989                                    const SMDS_MeshNode* theSecondNode1,
8990                                    const SMDS_MeshNode* theSecondNode2)
8991 {
8992   myLastCreatedElems.Clear();
8993   myLastCreatedNodes.Clear();
8994
8995   MESSAGE ("::::SewSideElements()");
8996   if ( theSide1.size() != theSide2.size() )
8997     return SEW_DIFF_NB_OF_ELEMENTS;
8998
8999   Sew_Error aResult = SEW_OK;
9000   // Algo:
9001   // 1. Build set of faces representing each side
9002   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9003   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9004
9005   // =======================================================================
9006   // 1. Build set of faces representing each side:
9007   // =======================================================================
9008   // a. build set of nodes belonging to faces
9009   // b. complete set of faces: find missing fices whose nodes are in set of nodes
9010   // c. create temporary faces representing side of volumes if correspondent
9011   //    face does not exist
9012
9013   SMESHDS_Mesh* aMesh = GetMeshDS();
9014   SMDS_Mesh aTmpFacesMesh;
9015   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9016   set<const SMDS_MeshElement*> volSet1,  volSet2;
9017   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9018   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9019   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9020   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9021   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9022   int iSide, iFace, iNode;
9023
9024   for ( iSide = 0; iSide < 2; iSide++ ) {
9025     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9026     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9027     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9028     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9029     set<const SMDS_MeshElement*>::iterator vIt;
9030     TIDSortedElemSet::iterator eIt;
9031     set<const SMDS_MeshNode*>::iterator    nIt;
9032
9033     // check that given nodes belong to given elements
9034     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9035     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9036     int firstIndex = -1, secondIndex = -1;
9037     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9038       const SMDS_MeshElement* elem = *eIt;
9039       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9040       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9041       if ( firstIndex > -1 && secondIndex > -1 ) break;
9042     }
9043     if ( firstIndex < 0 || secondIndex < 0 ) {
9044       // we can simply return until temporary faces created
9045       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9046     }
9047
9048     // -----------------------------------------------------------
9049     // 1a. Collect nodes of existing faces
9050     //     and build set of face nodes in order to detect missing
9051     //     faces corresponing to sides of volumes
9052     // -----------------------------------------------------------
9053
9054     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9055
9056     // loop on the given element of a side
9057     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9058       //const SMDS_MeshElement* elem = *eIt;
9059       const SMDS_MeshElement* elem = *eIt;
9060       if ( elem->GetType() == SMDSAbs_Face ) {
9061         faceSet->insert( elem );
9062         set <const SMDS_MeshNode*> faceNodeSet;
9063         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9064         while ( nodeIt->more() ) {
9065           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9066           nodeSet->insert( n );
9067           faceNodeSet.insert( n );
9068         }
9069         setOfFaceNodeSet.insert( faceNodeSet );
9070       }
9071       else if ( elem->GetType() == SMDSAbs_Volume )
9072         volSet->insert( elem );
9073     }
9074     // ------------------------------------------------------------------------------
9075     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9076     // ------------------------------------------------------------------------------
9077
9078     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9079       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9080       while ( fIt->more() ) { // loop on faces sharing a node
9081         const SMDS_MeshElement* f = fIt->next();
9082         if ( faceSet->find( f ) == faceSet->end() ) {
9083           // check if all nodes are in nodeSet and
9084           // complete setOfFaceNodeSet if they are
9085           set <const SMDS_MeshNode*> faceNodeSet;
9086           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9087           bool allInSet = true;
9088           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9089             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9090             if ( nodeSet->find( n ) == nodeSet->end() )
9091               allInSet = false;
9092             else
9093               faceNodeSet.insert( n );
9094           }
9095           if ( allInSet ) {
9096             faceSet->insert( f );
9097             setOfFaceNodeSet.insert( faceNodeSet );
9098           }
9099         }
9100       }
9101     }
9102
9103     // -------------------------------------------------------------------------
9104     // 1c. Create temporary faces representing sides of volumes if correspondent
9105     //     face does not exist
9106     // -------------------------------------------------------------------------
9107
9108     if ( !volSet->empty() ) {
9109       //int nodeSetSize = nodeSet->size();
9110
9111       // loop on given volumes
9112       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9113         SMDS_VolumeTool vol (*vIt);
9114         // loop on volume faces: find free faces
9115         // --------------------------------------
9116         list<const SMDS_MeshElement* > freeFaceList;
9117         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9118           if ( !vol.IsFreeFace( iFace ))
9119             continue;
9120           // check if there is already a face with same nodes in a face set
9121           const SMDS_MeshElement* aFreeFace = 0;
9122           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9123           int nbNodes = vol.NbFaceNodes( iFace );
9124           set <const SMDS_MeshNode*> faceNodeSet;
9125           vol.GetFaceNodes( iFace, faceNodeSet );
9126           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9127           if ( isNewFace ) {
9128             // no such a face is given but it still can exist, check it
9129             if ( nbNodes == 3 ) {
9130               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9131             }
9132             else if ( nbNodes == 4 ) {
9133               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9134             }
9135             else {
9136               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9137               aFreeFace = aMesh->FindFace(poly_nodes);
9138             }
9139           }
9140           if ( !aFreeFace ) {
9141             // create a temporary face
9142             if ( nbNodes == 3 ) {
9143               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9144             }
9145             else if ( nbNodes == 4 ) {
9146               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9147             }
9148             else {
9149               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9150               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9151             }
9152           }
9153           if ( aFreeFace )
9154             freeFaceList.push_back( aFreeFace );
9155
9156         } // loop on faces of a volume
9157
9158         // choose one of several free faces
9159         // --------------------------------------
9160         if ( freeFaceList.size() > 1 ) {
9161           // choose a face having max nb of nodes shared by other elems of a side
9162           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9163           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9164           while ( fIt != freeFaceList.end() ) { // loop on free faces
9165             int nbSharedNodes = 0;
9166             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9167             while ( nodeIt->more() ) { // loop on free face nodes
9168               const SMDS_MeshNode* n =
9169                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9170               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9171               while ( invElemIt->more() ) {
9172                 const SMDS_MeshElement* e = invElemIt->next();
9173                 if ( faceSet->find( e ) != faceSet->end() )
9174                   nbSharedNodes++;
9175                 if ( elemSet->find( e ) != elemSet->end() )
9176                   nbSharedNodes++;
9177               }
9178             }
9179             if ( nbSharedNodes >= maxNbNodes ) {
9180               maxNbNodes = nbSharedNodes;
9181               fIt++;
9182             }
9183             else
9184               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9185           }
9186           if ( freeFaceList.size() > 1 )
9187           {
9188             // could not choose one face, use another way
9189             // choose a face most close to the bary center of the opposite side
9190             gp_XYZ aBC( 0., 0., 0. );
9191             set <const SMDS_MeshNode*> addedNodes;
9192             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9193             eIt = elemSet2->begin();
9194             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9195               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9196               while ( nodeIt->more() ) { // loop on free face nodes
9197                 const SMDS_MeshNode* n =
9198                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9199                 if ( addedNodes.insert( n ).second )
9200                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9201               }
9202             }
9203             aBC /= addedNodes.size();
9204             double minDist = DBL_MAX;
9205             fIt = freeFaceList.begin();
9206             while ( fIt != freeFaceList.end() ) { // loop on free faces
9207               double dist = 0;
9208               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9209               while ( nodeIt->more() ) { // loop on free face nodes
9210                 const SMDS_MeshNode* n =
9211                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9212                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9213                 dist += ( aBC - p ).SquareModulus();
9214               }
9215               if ( dist < minDist ) {
9216                 minDist = dist;
9217                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9218               }
9219               else
9220                 fIt = freeFaceList.erase( fIt++ );
9221             }
9222           }
9223         } // choose one of several free faces of a volume
9224
9225         if ( freeFaceList.size() == 1 ) {
9226           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9227           faceSet->insert( aFreeFace );
9228           // complete a node set with nodes of a found free face
9229           //           for ( iNode = 0; iNode < ; iNode++ )
9230           //             nodeSet->insert( fNodes[ iNode ] );
9231         }
9232
9233       } // loop on volumes of a side
9234
9235       //       // complete a set of faces if new nodes in a nodeSet appeared
9236       //       // ----------------------------------------------------------
9237       //       if ( nodeSetSize != nodeSet->size() ) {
9238       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9239       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9240       //           while ( fIt->more() ) { // loop on faces sharing a node
9241       //             const SMDS_MeshElement* f = fIt->next();
9242       //             if ( faceSet->find( f ) == faceSet->end() ) {
9243       //               // check if all nodes are in nodeSet and
9244       //               // complete setOfFaceNodeSet if they are
9245       //               set <const SMDS_MeshNode*> faceNodeSet;
9246       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9247       //               bool allInSet = true;
9248       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9249       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9250       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9251       //                   allInSet = false;
9252       //                 else
9253       //                   faceNodeSet.insert( n );
9254       //               }
9255       //               if ( allInSet ) {
9256       //                 faceSet->insert( f );
9257       //                 setOfFaceNodeSet.insert( faceNodeSet );
9258       //               }
9259       //             }
9260       //           }
9261       //         }
9262       //       }
9263     } // Create temporary faces, if there are volumes given
9264   } // loop on sides
9265
9266   if ( faceSet1.size() != faceSet2.size() ) {
9267     // delete temporary faces: they are in reverseElements of actual nodes
9268     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9269     while ( tmpFaceIt->more() )
9270       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9271     MESSAGE("Diff nb of faces");
9272     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9273   }
9274
9275   // ============================================================
9276   // 2. Find nodes to merge:
9277   //              bind a node to remove to a node to put instead
9278   // ============================================================
9279
9280   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9281   if ( theFirstNode1 != theFirstNode2 )
9282     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9283   if ( theSecondNode1 != theSecondNode2 )
9284     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9285
9286   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9287   set< long > linkIdSet; // links to process
9288   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9289
9290   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9291   list< NLink > linkList[2];
9292   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9293   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9294   // loop on links in linkList; find faces by links and append links
9295   // of the found faces to linkList
9296   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9297   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9298     NLink link[] = { *linkIt[0], *linkIt[1] };
9299     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9300     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9301       continue;
9302
9303     // by links, find faces in the face sets,
9304     // and find indices of link nodes in the found faces;
9305     // in a face set, there is only one or no face sharing a link
9306     // ---------------------------------------------------------------
9307
9308     const SMDS_MeshElement* face[] = { 0, 0 };
9309     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9310     vector<const SMDS_MeshNode*> fnodes1(9);
9311     vector<const SMDS_MeshNode*> fnodes2(9);
9312     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9313     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9314     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9315     int iLinkNode[2][2];
9316     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9317       const SMDS_MeshNode* n1 = link[iSide].first;
9318       const SMDS_MeshNode* n2 = link[iSide].second;
9319       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9320       set< const SMDS_MeshElement* > fMap;
9321       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9322         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9323         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9324         while ( fIt->more() ) { // loop on faces sharing a node
9325           const SMDS_MeshElement* f = fIt->next();
9326           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9327               ! fMap.insert( f ).second ) // f encounters twice
9328           {
9329             if ( face[ iSide ] ) {
9330               MESSAGE( "2 faces per link " );
9331               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9332               break;
9333             }
9334             face[ iSide ] = f;
9335             faceSet->erase( f );
9336             // get face nodes and find ones of a link
9337             iNode = 0;
9338             int nbl = -1;
9339             if(f->IsPoly()) {
9340               if(iSide==0) {
9341                 fnodes1.resize(f->NbNodes()+1);
9342                 notLinkNodes1.resize(f->NbNodes()-2);
9343               }
9344               else {
9345                 fnodes2.resize(f->NbNodes()+1);
9346                 notLinkNodes2.resize(f->NbNodes()-2);
9347               }
9348             }
9349             if(!f->IsQuadratic()) {
9350               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9351               while ( nIt->more() ) {
9352                 const SMDS_MeshNode* n =
9353                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9354                 if ( n == n1 ) {
9355                   iLinkNode[ iSide ][ 0 ] = iNode;
9356                 }
9357                 else if ( n == n2 ) {
9358                   iLinkNode[ iSide ][ 1 ] = iNode;
9359                 }
9360                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9361                 //  notLinkNodes[ iSide ][ 1 ] = n;
9362                 //else
9363                 //  notLinkNodes[ iSide ][ 0 ] = n;
9364                 else {
9365                   nbl++;
9366                   if(iSide==0)
9367                     notLinkNodes1[nbl] = n;
9368                   //notLinkNodes1.push_back(n);
9369                   else
9370                     notLinkNodes2[nbl] = n;
9371                   //notLinkNodes2.push_back(n);
9372                 }
9373                 //faceNodes[ iSide ][ iNode++ ] = n;
9374                 if(iSide==0) {
9375                   fnodes1[iNode++] = n;
9376                 }
9377                 else {
9378                   fnodes2[iNode++] = n;
9379                 }
9380               }
9381             }
9382             else { // f->IsQuadratic()
9383               const SMDS_QuadraticFaceOfNodes* F =
9384                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9385               // use special nodes iterator
9386               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9387               while ( anIter->more() ) {
9388                 const SMDS_MeshNode* n =
9389                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9390                 if ( n == n1 ) {
9391                   iLinkNode[ iSide ][ 0 ] = iNode;
9392                 }
9393                 else if ( n == n2 ) {
9394                   iLinkNode[ iSide ][ 1 ] = iNode;
9395                 }
9396                 else {
9397                   nbl++;
9398                   if(iSide==0) {
9399                     notLinkNodes1[nbl] = n;
9400                   }
9401                   else {
9402                     notLinkNodes2[nbl] = n;
9403                   }
9404                 }
9405                 if(iSide==0) {
9406                   fnodes1[iNode++] = n;
9407                 }
9408                 else {
9409                   fnodes2[iNode++] = n;
9410                 }
9411               }
9412             }
9413             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9414             if(iSide==0) {
9415               fnodes1[iNode] = fnodes1[0];
9416             }
9417             else {
9418               fnodes2[iNode] = fnodes1[0];
9419             }
9420           }
9421         }
9422       }
9423     }
9424
9425     // check similarity of elements of the sides
9426     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9427       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9428       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9429         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9430       }
9431       else {
9432         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9433       }
9434       break; // do not return because it s necessary to remove tmp faces
9435     }
9436
9437     // set nodes to merge
9438     // -------------------
9439
9440     if ( face[0] && face[1] )  {
9441       int nbNodes = face[0]->NbNodes();
9442       if ( nbNodes != face[1]->NbNodes() ) {
9443         MESSAGE("Diff nb of face nodes");
9444         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9445         break; // do not return because it s necessary to remove tmp faces
9446       }
9447       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9448       if ( nbNodes == 3 ) {
9449         //nReplaceMap.insert( TNodeNodeMap::value_type
9450         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9451         nReplaceMap.insert( TNodeNodeMap::value_type
9452                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9453       }
9454       else {
9455         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9456           // analyse link orientation in faces
9457           int i1 = iLinkNode[ iSide ][ 0 ];
9458           int i2 = iLinkNode[ iSide ][ 1 ];
9459           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9460           // if notLinkNodes are the first and the last ones, then
9461           // their order does not correspond to the link orientation
9462           if (( i1 == 1 && i2 == 2 ) ||
9463               ( i1 == 2 && i2 == 1 ))
9464             reverse[ iSide ] = !reverse[ iSide ];
9465         }
9466         if ( reverse[0] == reverse[1] ) {
9467           //nReplaceMap.insert( TNodeNodeMap::value_type
9468           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9469           //nReplaceMap.insert( TNodeNodeMap::value_type
9470           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9471           for(int nn=0; nn<nbNodes-2; nn++) {
9472             nReplaceMap.insert( TNodeNodeMap::value_type
9473                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9474           }
9475         }
9476         else {
9477           //nReplaceMap.insert( TNodeNodeMap::value_type
9478           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9479           //nReplaceMap.insert( TNodeNodeMap::value_type
9480           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9481           for(int nn=0; nn<nbNodes-2; nn++) {
9482             nReplaceMap.insert( TNodeNodeMap::value_type
9483                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9484           }
9485         }
9486       }
9487
9488       // add other links of the faces to linkList
9489       // -----------------------------------------
9490
9491       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9492       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9493         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9494         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9495         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9496         if ( !iter_isnew.second ) { // already in a set: no need to process
9497           linkIdSet.erase( iter_isnew.first );
9498         }
9499         else // new in set == encountered for the first time: add
9500         {
9501           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9502           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9503           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9504           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9505           linkList[0].push_back ( NLink( n1, n2 ));
9506           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9507         }
9508       }
9509     } // 2 faces found
9510   } // loop on link lists
9511
9512   if ( aResult == SEW_OK &&
9513        ( linkIt[0] != linkList[0].end() ||
9514          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9515     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9516              " " << (faceSetPtr[1]->empty()));
9517     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9518   }
9519
9520   // ====================================================================
9521   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9522   // ====================================================================
9523
9524   // delete temporary faces: they are in reverseElements of actual nodes
9525   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9526   while ( tmpFaceIt->more() )
9527     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9528
9529   if ( aResult != SEW_OK)
9530     return aResult;
9531
9532   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9533   // loop on nodes replacement map
9534   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9535   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9536     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9537       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9538       nodeIDsToRemove.push_back( nToRemove->GetID() );
9539       // loop on elements sharing nToRemove
9540       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9541       while ( invElemIt->more() ) {
9542         const SMDS_MeshElement* e = invElemIt->next();
9543         // get a new suite of nodes: make replacement
9544         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9545         vector< const SMDS_MeshNode*> nodes( nbNodes );
9546         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9547         while ( nIt->more() ) {
9548           const SMDS_MeshNode* n =
9549             static_cast<const SMDS_MeshNode*>( nIt->next() );
9550           nnIt = nReplaceMap.find( n );
9551           if ( nnIt != nReplaceMap.end() ) {
9552             nbReplaced++;
9553             n = (*nnIt).second;
9554           }
9555           nodes[ i++ ] = n;
9556         }
9557         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9558         //         elemIDsToRemove.push_back( e->GetID() );
9559         //       else
9560         if ( nbReplaced )
9561           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9562       }
9563     }
9564
9565   Remove( nodeIDsToRemove, true );
9566
9567   return aResult;
9568 }
9569
9570 //================================================================================
9571 /*!
9572  * \brief Find corresponding nodes in two sets of faces
9573  * \param theSide1 - first face set
9574  * \param theSide2 - second first face
9575  * \param theFirstNode1 - a boundary node of set 1
9576  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9577  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9578  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9579  * \param nReplaceMap - output map of corresponding nodes
9580  * \retval bool  - is a success or not
9581  */
9582 //================================================================================
9583
9584 #ifdef _DEBUG_
9585 //#define DEBUG_MATCHING_NODES
9586 #endif
9587
9588 SMESH_MeshEditor::Sew_Error
9589 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9590                                     set<const SMDS_MeshElement*>& theSide2,
9591                                     const SMDS_MeshNode*          theFirstNode1,
9592                                     const SMDS_MeshNode*          theFirstNode2,
9593                                     const SMDS_MeshNode*          theSecondNode1,
9594                                     const SMDS_MeshNode*          theSecondNode2,
9595                                     TNodeNodeMap &                nReplaceMap)
9596 {
9597   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9598
9599   nReplaceMap.clear();
9600   if ( theFirstNode1 != theFirstNode2 )
9601     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9602   if ( theSecondNode1 != theSecondNode2 )
9603     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9604
9605   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9606   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9607
9608   list< NLink > linkList[2];
9609   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9610   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9611
9612   // loop on links in linkList; find faces by links and append links
9613   // of the found faces to linkList
9614   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9615   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9616     NLink link[] = { *linkIt[0], *linkIt[1] };
9617     if ( linkSet.find( link[0] ) == linkSet.end() )
9618       continue;
9619
9620     // by links, find faces in the face sets,
9621     // and find indices of link nodes in the found faces;
9622     // in a face set, there is only one or no face sharing a link
9623     // ---------------------------------------------------------------
9624
9625     const SMDS_MeshElement* face[] = { 0, 0 };
9626     list<const SMDS_MeshNode*> notLinkNodes[2];
9627     //bool reverse[] = { false, false }; // order of notLinkNodes
9628     int nbNodes[2];
9629     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9630     {
9631       const SMDS_MeshNode* n1 = link[iSide].first;
9632       const SMDS_MeshNode* n2 = link[iSide].second;
9633       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9634       set< const SMDS_MeshElement* > facesOfNode1;
9635       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9636       {
9637         // during a loop of the first node, we find all faces around n1,
9638         // during a loop of the second node, we find one face sharing both n1 and n2
9639         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9640         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9641         while ( fIt->more() ) { // loop on faces sharing a node
9642           const SMDS_MeshElement* f = fIt->next();
9643           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9644               ! facesOfNode1.insert( f ).second ) // f encounters twice
9645           {
9646             if ( face[ iSide ] ) {
9647               MESSAGE( "2 faces per link " );
9648               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9649             }
9650             face[ iSide ] = f;
9651             faceSet->erase( f );
9652
9653             // get not link nodes
9654             int nbN = f->NbNodes();
9655             if ( f->IsQuadratic() )
9656               nbN /= 2;
9657             nbNodes[ iSide ] = nbN;
9658             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9659             int i1 = f->GetNodeIndex( n1 );
9660             int i2 = f->GetNodeIndex( n2 );
9661             int iEnd = nbN, iBeg = -1, iDelta = 1;
9662             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9663             if ( reverse ) {
9664               std::swap( iEnd, iBeg ); iDelta = -1;
9665             }
9666             int i = i2;
9667             while ( true ) {
9668               i += iDelta;
9669               if ( i == iEnd ) i = iBeg + iDelta;
9670               if ( i == i1 ) break;
9671               nodes.push_back ( f->GetNode( i ) );
9672             }
9673           }
9674         }
9675       }
9676     }
9677     // check similarity of elements of the sides
9678     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9679       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9680       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9681         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9682       }
9683       else {
9684         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9685       }
9686     }
9687
9688     // set nodes to merge
9689     // -------------------
9690
9691     if ( face[0] && face[1] )  {
9692       if ( nbNodes[0] != nbNodes[1] ) {
9693         MESSAGE("Diff nb of face nodes");
9694         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9695       }
9696 #ifdef DEBUG_MATCHING_NODES
9697       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9698                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9699                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9700 #endif
9701       int nbN = nbNodes[0];
9702       {
9703         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9704         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9705         for ( int i = 0 ; i < nbN - 2; ++i ) {
9706 #ifdef DEBUG_MATCHING_NODES
9707           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9708 #endif
9709           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9710         }
9711       }
9712
9713       // add other links of the face 1 to linkList
9714       // -----------------------------------------
9715
9716       const SMDS_MeshElement* f0 = face[0];
9717       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9718       for ( int i = 0; i < nbN; i++ )
9719       {
9720         const SMDS_MeshNode* n2 = f0->GetNode( i );
9721         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9722           linkSet.insert( SMESH_TLink( n1, n2 ));
9723         if ( !iter_isnew.second ) { // already in a set: no need to process
9724           linkSet.erase( iter_isnew.first );
9725         }
9726         else // new in set == encountered for the first time: add
9727         {
9728 #ifdef DEBUG_MATCHING_NODES
9729           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9730                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9731 #endif
9732           linkList[0].push_back ( NLink( n1, n2 ));
9733           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9734         }
9735         n1 = n2;
9736       }
9737     } // 2 faces found
9738   } // loop on link lists
9739
9740   return SEW_OK;
9741 }
9742
9743 //================================================================================
9744 /*!
9745   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9746   \param theElems - the list of elements (edges or faces) to be replicated
9747   The nodes for duplication could be found from these elements
9748   \param theNodesNot - list of nodes to NOT replicate
9749   \param theAffectedElems - the list of elements (cells and edges) to which the 
9750   replicated nodes should be associated to.
9751   \return TRUE if operation has been completed successfully, FALSE otherwise
9752 */
9753 //================================================================================
9754
9755 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9756                                     const TIDSortedElemSet& theNodesNot,
9757                                     const TIDSortedElemSet& theAffectedElems )
9758 {
9759   myLastCreatedElems.Clear();
9760   myLastCreatedNodes.Clear();
9761
9762   if ( theElems.size() == 0 )
9763     return false;
9764
9765   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9766   if ( !aMeshDS )
9767     return false;
9768
9769   bool res = false;
9770   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9771   // duplicate elements and nodes
9772   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9773   // replce nodes by duplications
9774   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9775   return res;
9776 }
9777
9778 //================================================================================
9779 /*!
9780   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9781   \param theMeshDS - mesh instance
9782   \param theElems - the elements replicated or modified (nodes should be changed)
9783   \param theNodesNot - nodes to NOT replicate
9784   \param theNodeNodeMap - relation of old node to new created node
9785   \param theIsDoubleElem - flag os to replicate element or modify
9786   \return TRUE if operation has been completed successfully, FALSE otherwise
9787 */
9788 //================================================================================
9789
9790 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9791                                     const TIDSortedElemSet& theElems,
9792                                     const TIDSortedElemSet& theNodesNot,
9793                                     std::map< const SMDS_MeshNode*,
9794                                     const SMDS_MeshNode* >& theNodeNodeMap,
9795                                     const bool theIsDoubleElem )
9796 {
9797   // iterate on through element and duplicate them (by nodes duplication)
9798   bool res = false;
9799   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9800   for ( ;  elemItr != theElems.end(); ++elemItr )
9801   {
9802     const SMDS_MeshElement* anElem = *elemItr;
9803     if (!anElem)
9804       continue;
9805
9806     bool isDuplicate = false;
9807     // duplicate nodes to duplicate element
9808     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9809     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9810     int ind = 0;
9811     while ( anIter->more() ) 
9812     { 
9813
9814       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9815       SMDS_MeshNode* aNewNode = aCurrNode;
9816       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9817         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9818       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9819       {
9820         // duplicate node
9821         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9822         theNodeNodeMap[ aCurrNode ] = aNewNode;
9823         myLastCreatedNodes.Append( aNewNode );
9824       }
9825       isDuplicate |= (aCurrNode != aNewNode);
9826       newNodes[ ind++ ] = aNewNode;
9827     }
9828     if ( !isDuplicate )
9829       continue;
9830
9831     if ( theIsDoubleElem )
9832       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
9833     else
9834       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9835
9836     res = true;
9837   }
9838   return res;
9839 }
9840
9841 //================================================================================
9842 /*!
9843   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9844   \param theNodes - identifiers of nodes to be doubled
9845   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
9846          nodes. If list of element identifiers is empty then nodes are doubled but 
9847          they not assigned to elements
9848   \return TRUE if operation has been completed successfully, FALSE otherwise
9849 */
9850 //================================================================================
9851
9852 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
9853                                     const std::list< int >& theListOfModifiedElems )
9854 {
9855   myLastCreatedElems.Clear();
9856   myLastCreatedNodes.Clear();
9857
9858   if ( theListOfNodes.size() == 0 )
9859     return false;
9860
9861   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9862   if ( !aMeshDS )
9863     return false;
9864
9865   // iterate through nodes and duplicate them
9866
9867   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9868
9869   std::list< int >::const_iterator aNodeIter;
9870   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9871   {
9872     int aCurr = *aNodeIter;
9873     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9874     if ( !aNode )
9875       continue;
9876
9877     // duplicate node
9878
9879     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9880     if ( aNewNode )
9881     {
9882       anOldNodeToNewNode[ aNode ] = aNewNode;
9883       myLastCreatedNodes.Append( aNewNode );
9884     }
9885   }
9886
9887   // Create map of new nodes for modified elements
9888
9889   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9890
9891   std::list< int >::const_iterator anElemIter;
9892   for ( anElemIter = theListOfModifiedElems.begin(); 
9893         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9894   {
9895     int aCurr = *anElemIter;
9896     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9897     if ( !anElem )
9898       continue;
9899
9900     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9901
9902     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9903     int ind = 0;
9904     while ( anIter->more() ) 
9905     { 
9906       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9907       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9908       {
9909         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9910         aNodeArr[ ind++ ] = aNewNode;
9911       }
9912       else
9913         aNodeArr[ ind++ ] = aCurrNode;
9914     }
9915     anElemToNodes[ anElem ] = aNodeArr;
9916   }
9917
9918   // Change nodes of elements  
9919
9920   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9921     anElemToNodesIter = anElemToNodes.begin();
9922   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9923   {
9924     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9925     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9926     if ( anElem )
9927       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9928   }
9929
9930   return true;
9931 }
9932
9933 namespace {
9934
9935   //================================================================================
9936   /*!
9937   \brief Check if element located inside shape
9938   \return TRUE if IN or ON shape, FALSE otherwise
9939   */
9940   //================================================================================
9941
9942   template<class Classifier>
9943   bool isInside(const SMDS_MeshElement* theElem,
9944                 Classifier&             theClassifier,
9945                 const double            theTol)
9946   {
9947     gp_XYZ centerXYZ (0, 0, 0);
9948     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9949     while (aNodeItr->more())
9950       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9951
9952     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9953     theClassifier.Perform(aPnt, theTol);
9954     TopAbs_State aState = theClassifier.State();
9955     return (aState == TopAbs_IN || aState == TopAbs_ON );
9956   }
9957
9958   //================================================================================
9959   /*!
9960    * \brief Classifier of the 3D point on the TopoDS_Face
9961    *        with interaface suitable for isInside()
9962    */
9963   //================================================================================
9964
9965   struct _FaceClassifier
9966   {
9967     Extrema_ExtPS       _extremum;
9968     BRepAdaptor_Surface _surface;
9969     TopAbs_State        _state;
9970
9971     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9972     {
9973       _extremum.Initialize( _surface,
9974                             _surface.FirstUParameter(), _surface.LastUParameter(),
9975                             _surface.FirstVParameter(), _surface.LastVParameter(),
9976                             _surface.Tolerance(), _surface.Tolerance() );
9977     }
9978     void Perform(const gp_Pnt& aPnt, double theTol)
9979     {
9980       _state = TopAbs_OUT;
9981       _extremum.Perform(aPnt);
9982       if ( _extremum.IsDone() )
9983         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9984           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9985     }
9986     TopAbs_State State() const
9987     {
9988       return _state;
9989     }
9990   };
9991 }
9992
9993 //================================================================================
9994 /*!
9995   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9996   \param theElems - group of of elements (edges or faces) to be replicated
9997   \param theNodesNot - group of nodes not to replicate
9998   \param theShape - shape to detect affected elements (element which geometric center
9999   located on or inside shape).
10000   The replicated nodes should be associated to affected elements.
10001   \return TRUE if operation has been completed successfully, FALSE otherwise
10002 */
10003 //================================================================================
10004
10005 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10006                                             const TIDSortedElemSet& theNodesNot,
10007                                             const TopoDS_Shape&     theShape )
10008 {
10009   if ( theShape.IsNull() )
10010     return false;
10011
10012   const double aTol = Precision::Confusion();
10013   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10014   auto_ptr<_FaceClassifier>              aFaceClassifier;
10015   if ( theShape.ShapeType() == TopAbs_SOLID )
10016   {
10017     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10018     bsc3d->PerformInfinitePoint(aTol);
10019   }
10020   else if (theShape.ShapeType() == TopAbs_FACE )
10021   {
10022     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10023   }
10024
10025   // iterates on indicated elements and get elements by back references from their nodes
10026   TIDSortedElemSet anAffected;
10027   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10028   for ( ;  elemItr != theElems.end(); ++elemItr )
10029   {
10030     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10031     if (!anElem)
10032       continue;
10033
10034     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10035     while ( nodeItr->more() )
10036     {
10037       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10038       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10039         continue;
10040       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10041       while ( backElemItr->more() )
10042       {
10043         const SMDS_MeshElement* curElem = backElemItr->next();
10044         if ( curElem && theElems.find(curElem) == theElems.end() &&
10045              ( bsc3d.get() ?
10046                isInside( curElem, *bsc3d, aTol ) :
10047                isInside( curElem, *aFaceClassifier, aTol )))
10048           anAffected.insert( curElem );
10049       }
10050     }
10051   }
10052   return DoubleNodes( theElems, theNodesNot, anAffected );
10053 }
10054
10055 //================================================================================
10056 /*!
10057  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10058  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10059  * \return TRUE if operation has been completed successfully, FALSE otherwise
10060  */
10061 //================================================================================
10062
10063 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10064 {
10065   // iterates on volume elements and detect all free faces on them
10066   SMESHDS_Mesh* aMesh = GetMeshDS();
10067   if (!aMesh)
10068     return false;
10069   //bool res = false;
10070   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10071   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10072   while(vIt->more())
10073   {
10074     const SMDS_MeshVolume* volume = vIt->next();
10075     SMDS_VolumeTool vTool( volume );
10076     vTool.SetExternalNormal();
10077     const bool isPoly = volume->IsPoly();
10078     const bool isQuad = volume->IsQuadratic();
10079     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10080     {
10081       if (!vTool.IsFreeFace(iface))
10082         continue;
10083       nbFree++;
10084       vector<const SMDS_MeshNode *> nodes;
10085       int nbFaceNodes = vTool.NbFaceNodes(iface);
10086       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10087       int inode = 0;
10088       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10089         nodes.push_back(faceNodes[inode]);
10090       if (isQuad)
10091         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10092           nodes.push_back(faceNodes[inode]);
10093
10094       // add new face based on volume nodes
10095       if (aMesh->FindFace( nodes ) ) {
10096         nbExisted++;
10097         continue; // face already exsist
10098       }
10099       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10100       nbCreated++;
10101     }
10102   }
10103   return ( nbFree==(nbExisted+nbCreated) );
10104 }