]> SALOME platform Git repositories - modules/smesh.git/blob - src/SMESH/SMESH_MeshEditor.cxx
Salome HOME
PR: debug memory leak (EDF 2662)
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2013  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 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #include "SMESH_MeshEditor.hxx"
28
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_SpacePosition.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_LinearEdge.hxx"
36 #include "SMDS_Downward.hxx"
37 #include "SMDS_SetIterator.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 <Basics_OCCTVersion.hxx>
50
51 #include "utilities.h"
52
53 #include <BRepAdaptor_Surface.hxx>
54 #include <BRepBuilderAPI_MakeEdge.hxx>
55 #include <BRepClass3d_SolidClassifier.hxx>
56 #include <BRep_Tool.hxx>
57 #include <ElCLib.hxx>
58 #include <Extrema_GenExtPS.hxx>
59 #include <Extrema_POnCurv.hxx>
60 #include <Extrema_POnSurf.hxx>
61 #include <GC_MakeSegment.hxx>
62 #include <Geom2d_Curve.hxx>
63 #include <GeomAPI_ExtremaCurveCurve.hxx>
64 #include <GeomAdaptor_Surface.hxx>
65 #include <Geom_Curve.hxx>
66 #include <Geom_Line.hxx>
67 #include <Geom_Surface.hxx>
68 #include <IntAna_IntConicQuad.hxx>
69 #include <IntAna_Quadric.hxx>
70 #include <Precision.hxx>
71 #include <TColStd_ListOfInteger.hxx>
72 #include <TopAbs_State.hxx>
73 #include <TopExp.hxx>
74 #include <TopExp_Explorer.hxx>
75 #include <TopTools_ListIteratorOfListOfShape.hxx>
76 #include <TopTools_ListOfShape.hxx>
77 #include <TopTools_SequenceOfShape.hxx>
78 #include <TopoDS.hxx>
79 #include <TopoDS_Face.hxx>
80 #include <TopoDS_Solid.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <cmath>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97 #include <algorithm>
98 #include <sstream>
99
100 #include <boost/tuple/tuple.hpp>
101
102 #include <Standard_Failure.hxx>
103 #include <Standard_ErrorHandler.hxx>
104
105 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
106
107 using namespace std;
108 using namespace SMESH::Controls;
109
110 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
111
112 //=======================================================================
113 //function : SMESH_MeshEditor
114 //purpose  :
115 //=======================================================================
116
117 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
118   :myMesh( theMesh ) // theMesh may be NULL
119 {
120 }
121
122 //================================================================================
123 /*!
124  * \brief Clears myLastCreatedNodes and myLastCreatedElems
125  */
126 //================================================================================
127
128 void SMESH_MeshEditor::CrearLastCreated()
129 {
130   myLastCreatedNodes.Clear();
131   myLastCreatedElems.Clear();
132 }
133
134
135 //=======================================================================
136 /*!
137  * \brief Add element
138  */
139 //=======================================================================
140
141 SMDS_MeshElement*
142 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
143                              const SMDSAbs_ElementType            type,
144                              const bool                           isPoly,
145                              const int                            ID,
146                              const double                         ballDiameter)
147 {
148   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
149   SMDS_MeshElement* e = 0;
150   int nbnode = node.size();
151   SMESHDS_Mesh* mesh = GetMeshDS();
152   switch ( type ) {
153   case SMDSAbs_Face:
154     if ( !isPoly ) {
155       if      (nbnode == 3) {
156         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
157         else           e = mesh->AddFace      (node[0], node[1], node[2] );
158       }
159       else if (nbnode == 4) {
160         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
161         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
162       }
163       else if (nbnode == 6) {
164         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
165                                                node[4], node[5], ID);
166         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
167                                                node[4], node[5] );
168       }
169       else if (nbnode == 8) {
170         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
171                                                node[4], node[5], node[6], node[7], ID);
172         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
173                                                node[4], node[5], node[6], node[7] );
174       }
175       else if (nbnode == 9) {
176         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
177                                                node[4], node[5], node[6], node[7], node[8], ID);
178         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
179                                                node[4], node[5], node[6], node[7], node[8] );
180       }
181     } else {
182       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
183       else           e = mesh->AddPolygonalFace      (node    );
184     }
185     break;
186
187   case SMDSAbs_Volume:
188     if ( !isPoly ) {
189       if      (nbnode == 4) {
190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
191         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
192       }
193       else if (nbnode == 5) {
194         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
195                                                  node[4], ID);
196         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
197                                                  node[4] );
198       }
199       else if (nbnode == 6) {
200         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201                                                  node[4], node[5], ID);
202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
203                                                  node[4], node[5] );
204       }
205       else if (nbnode == 8) {
206         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
207                                                  node[4], node[5], node[6], node[7], ID);
208         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
209                                                  node[4], node[5], node[6], node[7] );
210       }
211       else if (nbnode == 10) {
212         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
213                                                  node[4], node[5], node[6], node[7],
214                                                  node[8], node[9], 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] );
218       }
219       else if (nbnode == 12) {
220         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
221                                                  node[4], node[5], node[6], node[7],
222                                                  node[8], node[9], node[10], node[11], ID);
223         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
224                                                  node[4], node[5], node[6], node[7],
225                                                  node[8], node[9], node[10], node[11] );
226       }
227       else if (nbnode == 13) {
228         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
229                                                  node[4], node[5], node[6], node[7],
230                                                  node[8], node[9], node[10],node[11],
231                                                  node[12],ID);
232         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
233                                                  node[4], node[5], node[6], node[7],
234                                                  node[8], node[9], node[10],node[11],
235                                                  node[12] );
236       }
237       else if (nbnode == 15) {
238         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
239                                                  node[4], node[5], node[6], node[7],
240                                                  node[8], node[9], node[10],node[11],
241                                                  node[12],node[13],node[14],ID);
242         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
243                                                  node[4], node[5], node[6], node[7],
244                                                  node[8], node[9], node[10],node[11],
245                                                  node[12],node[13],node[14] );
246       }
247       else if (nbnode == 20) {
248         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
249                                                  node[4], node[5], node[6], node[7],
250                                                  node[8], node[9], node[10],node[11],
251                                                  node[12],node[13],node[14],node[15],
252                                                  node[16],node[17],node[18],node[19],ID);
253         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
254                                                  node[4], node[5], node[6], node[7],
255                                                  node[8], node[9], node[10],node[11],
256                                                  node[12],node[13],node[14],node[15],
257                                                  node[16],node[17],node[18],node[19] );
258       }
259       else if (nbnode == 27) {
260         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
261                                                  node[4], node[5], node[6], node[7],
262                                                  node[8], node[9], node[10],node[11],
263                                                  node[12],node[13],node[14],node[15],
264                                                  node[16],node[17],node[18],node[19],
265                                                  node[20],node[21],node[22],node[23],
266                                                  node[24],node[25],node[26], ID);
267         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
268                                                  node[4], node[5], node[6], node[7],
269                                                  node[8], node[9], node[10],node[11],
270                                                  node[12],node[13],node[14],node[15],
271                                                  node[16],node[17],node[18],node[19],
272                                                  node[20],node[21],node[22],node[23],
273                                                  node[24],node[25],node[26] );
274       }
275     }
276     break;
277
278   case SMDSAbs_Edge:
279     if ( nbnode == 2 ) {
280       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
281       else           e = mesh->AddEdge      (node[0], node[1] );
282     }
283     else if ( nbnode == 3 ) {
284       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
285       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
286     }
287     break;
288
289   case SMDSAbs_0DElement:
290     if ( nbnode == 1 ) {
291       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
292       else           e = mesh->Add0DElement      (node[0] );
293     }
294     break;
295
296   case SMDSAbs_Node:
297     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
298     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
299     break;
300
301   case SMDSAbs_Ball:
302     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
303     else           e = mesh->AddBall      (node[0], ballDiameter);
304     break;
305
306   default:;
307   }
308   if ( e ) myLastCreatedElems.Append( e );
309   return e;
310 }
311
312 //=======================================================================
313 /*!
314  * \brief Add element
315  */
316 //=======================================================================
317
318 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
319                                                const SMDSAbs_ElementType type,
320                                                const bool                isPoly,
321                                                const int                 ID)
322 {
323   vector<const SMDS_MeshNode*> nodes;
324   nodes.reserve( nodeIDs.size() );
325   vector<int>::const_iterator id = nodeIDs.begin();
326   while ( id != nodeIDs.end() ) {
327     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
328       nodes.push_back( node );
329     else
330       return 0;
331   }
332   return AddElement( nodes, type, isPoly, ID );
333 }
334
335 //=======================================================================
336 //function : Remove
337 //purpose  : Remove a node or an element.
338 //           Modify a compute state of sub-meshes which become empty
339 //=======================================================================
340
341 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
342                               const bool         isNodes )
343 {
344   myLastCreatedElems.Clear();
345   myLastCreatedNodes.Clear();
346
347   SMESHDS_Mesh* aMesh = GetMeshDS();
348   set< SMESH_subMesh *> smmap;
349
350   int removed = 0;
351   list<int>::const_iterator it = theIDs.begin();
352   for ( ; it != theIDs.end(); it++ ) {
353     const SMDS_MeshElement * elem;
354     if ( isNodes )
355       elem = aMesh->FindNode( *it );
356     else
357       elem = aMesh->FindElement( *it );
358     if ( !elem )
359       continue;
360
361     // Notify VERTEX sub-meshes about modification
362     if ( isNodes ) {
363       const SMDS_MeshNode* node = cast2Node( elem );
364       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
365         if ( int aShapeID = node->getshapeId() )
366           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
367             smmap.insert( sm );
368     }
369     // Find sub-meshes to notify about modification
370     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
371     //     while ( nodeIt->more() ) {
372     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
373     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
374     //       if ( aPosition.get() ) {
375     //         if ( int aShapeID = aPosition->GetShapeId() ) {
376     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
377     //             smmap.insert( sm );
378     //         }
379     //       }
380     //     }
381
382     // Do remove
383     if ( isNodes )
384       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
385     else
386       aMesh->RemoveElement( elem );
387     removed++;
388   }
389
390   // Notify sub-meshes about modification
391   if ( !smmap.empty() ) {
392     set< SMESH_subMesh *>::iterator smIt;
393     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
394       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
395   }
396
397   //   // Check if the whole mesh becomes empty
398   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
399   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
400
401   return removed;
402 }
403
404 //================================================================================
405 /*!
406  * \brief Create 0D elements on all nodes of the given object except those
407  *        nodes on which a 0D element already exists.
408  *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
409  *                    the all mesh is treated
410  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
411  */
412 //================================================================================
413
414 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
415                                                    TIDSortedElemSet&       all0DElems )
416 {
417   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator> TSetIterator;
418   SMDS_ElemIteratorPtr elemIt;
419   if ( elements.empty() )
420     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
421   else
422     elemIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
423
424   while ( elemIt->more() )
425   {
426     const SMDS_MeshElement* e = elemIt->next();
427     SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
428     while ( nodeIt->more() )
429     {
430       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
431       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
432       if ( it0D->more() )
433         all0DElems.insert( it0D->next() );
434       else {
435         myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
436         all0DElems.insert( myLastCreatedElems.Last() );
437       }
438     }
439   }
440 }
441
442 //=======================================================================
443 //function : FindShape
444 //purpose  : Return an index of the shape theElem is on
445 //           or zero if a shape not found
446 //=======================================================================
447
448 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
449 {
450   myLastCreatedElems.Clear();
451   myLastCreatedNodes.Clear();
452
453   SMESHDS_Mesh * aMesh = GetMeshDS();
454   if ( aMesh->ShapeToMesh().IsNull() )
455     return 0;
456
457   int aShapeID = theElem->getshapeId();
458   if ( aShapeID < 1 )
459     return 0;
460
461   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
462     if ( sm->Contains( theElem ))
463       return aShapeID;
464
465   if ( theElem->GetType() == SMDSAbs_Node ) {
466     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
467   }
468   else {
469     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
470   }
471
472   TopoDS_Shape aShape; // the shape a node of theElem is on
473   if ( theElem->GetType() != SMDSAbs_Node )
474   {
475     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
476     while ( nodeIt->more() ) {
477       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
478       if ((aShapeID = node->getshapeId()) > 0) {
479         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
480           if ( sm->Contains( theElem ))
481             return aShapeID;
482           if ( aShape.IsNull() )
483             aShape = aMesh->IndexToShape( aShapeID );
484         }
485       }
486     }
487   }
488
489   // None of nodes is on a proper shape,
490   // find the shape among ancestors of aShape on which a node is
491   if ( !aShape.IsNull() ) {
492     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
493     for ( ; ancIt.More(); ancIt.Next() ) {
494       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
495       if ( sm && sm->Contains( theElem ))
496         return aMesh->ShapeToIndex( ancIt.Value() );
497     }
498   }
499   else
500   {
501     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
502     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
503     for ( ; id_sm != id2sm.end(); ++id_sm )
504       if ( id_sm->second->Contains( theElem ))
505         return id_sm->first;
506   }
507
508   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
509   return 0;
510 }
511
512 //=======================================================================
513 //function : IsMedium
514 //purpose  :
515 //=======================================================================
516
517 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
518                                 const SMDSAbs_ElementType typeToCheck)
519 {
520   bool isMedium = false;
521   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
522   while (it->more() && !isMedium ) {
523     const SMDS_MeshElement* elem = it->next();
524     isMedium = elem->IsMediumNode(node);
525   }
526   return isMedium;
527 }
528
529 //=======================================================================
530 //function : ShiftNodesQuadTria
531 //purpose  : auxilary
532 //           Shift nodes in the array corresponded to quadratic triangle
533 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
534 //=======================================================================
535 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
536 {
537   const SMDS_MeshNode* nd1 = aNodes[0];
538   aNodes[0] = aNodes[1];
539   aNodes[1] = aNodes[2];
540   aNodes[2] = nd1;
541   const SMDS_MeshNode* nd2 = aNodes[3];
542   aNodes[3] = aNodes[4];
543   aNodes[4] = aNodes[5];
544   aNodes[5] = nd2;
545 }
546
547 //=======================================================================
548 //function : edgeConnectivity
549 //purpose  : auxilary
550 //           return number of the edges connected with the theNode.
551 //           if theEdges has connections with the other type of the
552 //           elements, return -1
553 //=======================================================================
554 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
555 {
556   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
557   int nb=0;
558   while(elemIt->more()) {
559     elemIt->next();
560     nb++;
561   }
562   return nb;
563 }
564
565
566 //=======================================================================
567 //function : GetNodesFromTwoTria
568 //purpose  : auxilary
569 //           Shift nodes in the array corresponded to quadratic triangle
570 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
571 //=======================================================================
572 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
573                                 const SMDS_MeshElement * theTria2,
574                                 const SMDS_MeshNode* N1[],
575                                 const SMDS_MeshNode* N2[])
576 {
577   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
578   int i=0;
579   while(i<6) {
580     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
581     i++;
582   }
583   if(it->more()) return false;
584   it = theTria2->nodesIterator();
585   i=0;
586   while(i<6) {
587     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
588     i++;
589   }
590   if(it->more()) return false;
591
592   int sames[3] = {-1,-1,-1};
593   int nbsames = 0;
594   int j;
595   for(i=0; i<3; i++) {
596     for(j=0; j<3; j++) {
597       if(N1[i]==N2[j]) {
598         sames[i] = j;
599         nbsames++;
600         break;
601       }
602     }
603   }
604   if(nbsames!=2) return false;
605   if(sames[0]>-1) {
606     ShiftNodesQuadTria(N1);
607     if(sames[1]>-1) {
608       ShiftNodesQuadTria(N1);
609     }
610   }
611   i = sames[0] + sames[1] + sames[2];
612   for(; i<2; i++) {
613     ShiftNodesQuadTria(N2);
614   }
615   // now we receive following N1 and N2 (using numeration as above image)
616   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
617   // i.e. first nodes from both arrays determ new diagonal
618   return true;
619 }
620
621 //=======================================================================
622 //function : InverseDiag
623 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
624 //           but having other common link.
625 //           Return False if args are improper
626 //=======================================================================
627
628 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
629                                     const SMDS_MeshElement * theTria2 )
630 {
631   MESSAGE("InverseDiag");
632   myLastCreatedElems.Clear();
633   myLastCreatedNodes.Clear();
634
635   if (!theTria1 || !theTria2)
636     return false;
637
638   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
639   if (!F1) return false;
640   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
641   if (!F2) return false;
642   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
643       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
644
645     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
646     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
647     //    |/ |                                         | \|
648     //  B +--+ 2                                     B +--+ 2
649
650     // put nodes in array and find out indices of the same ones
651     const SMDS_MeshNode* aNodes [6];
652     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
653     int i = 0;
654     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
655     while ( it->more() ) {
656       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
657
658       if ( i > 2 ) // theTria2
659         // find same node of theTria1
660         for ( int j = 0; j < 3; j++ )
661           if ( aNodes[ i ] == aNodes[ j ]) {
662             sameInd[ j ] = i;
663             sameInd[ i ] = j;
664             break;
665           }
666       // next
667       i++;
668       if ( i == 3 ) {
669         if ( it->more() )
670           return false; // theTria1 is not a triangle
671         it = theTria2->nodesIterator();
672       }
673       if ( i == 6 && it->more() )
674         return false; // theTria2 is not a triangle
675     }
676
677     // find indices of 1,2 and of A,B in theTria1
678     int iA = 0, iB = 0, i1 = 0, i2 = 0;
679     for ( i = 0; i < 6; i++ ) {
680       if ( sameInd [ i ] == 0 ) {
681         if ( i < 3 ) i1 = i;
682         else         i2 = i;
683       }
684       else if (i < 3) {
685         if ( iA ) iB = i;
686         else      iA = i;
687       }
688     }
689     // nodes 1 and 2 should not be the same
690     if ( aNodes[ i1 ] == aNodes[ i2 ] )
691       return false;
692
693     // theTria1: A->2
694     aNodes[ iA ] = aNodes[ i2 ];
695     // theTria2: B->1
696     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
697
698     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
699     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
700
701     return true;
702
703   } // end if(F1 && F2)
704
705   // check case of quadratic faces
706   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
707     return false;
708   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
709     return false;
710
711   //       5
712   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
713   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
714   //    |   / |
715   //  7 +  +  + 6
716   //    | /9  |
717   //    |/    |
718   //  4 +--+--+ 3
719   //       8
720
721   const SMDS_MeshNode* N1 [6];
722   const SMDS_MeshNode* N2 [6];
723   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
724     return false;
725   // now we receive following N1 and N2 (using numeration as above image)
726   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
727   // i.e. first nodes from both arrays determ new diagonal
728
729   const SMDS_MeshNode* N1new [6];
730   const SMDS_MeshNode* N2new [6];
731   N1new[0] = N1[0];
732   N1new[1] = N2[0];
733   N1new[2] = N2[1];
734   N1new[3] = N1[4];
735   N1new[4] = N2[3];
736   N1new[5] = N1[5];
737   N2new[0] = N1[0];
738   N2new[1] = N1[1];
739   N2new[2] = N2[0];
740   N2new[3] = N1[3];
741   N2new[4] = N2[5];
742   N2new[5] = N1[4];
743   // replaces nodes in faces
744   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
745   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
746
747   return true;
748 }
749
750 //=======================================================================
751 //function : findTriangles
752 //purpose  : find triangles sharing theNode1-theNode2 link
753 //=======================================================================
754
755 static bool findTriangles(const SMDS_MeshNode *    theNode1,
756                           const SMDS_MeshNode *    theNode2,
757                           const SMDS_MeshElement*& theTria1,
758                           const SMDS_MeshElement*& theTria2)
759 {
760   if ( !theNode1 || !theNode2 ) return false;
761
762   theTria1 = theTria2 = 0;
763
764   set< const SMDS_MeshElement* > emap;
765   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
766   while (it->more()) {
767     const SMDS_MeshElement* elem = it->next();
768     if ( elem->NbNodes() == 3 )
769       emap.insert( elem );
770   }
771   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
772   while (it->more()) {
773     const SMDS_MeshElement* elem = it->next();
774     if ( emap.find( elem ) != emap.end() ) {
775       if ( theTria1 ) {
776         // theTria1 must be element with minimum ID
777         if( theTria1->GetID() < elem->GetID() ) {
778           theTria2 = elem;
779         }
780         else {
781           theTria2 = theTria1;
782           theTria1 = elem;
783         }
784         break;
785       }
786       else {
787         theTria1 = elem;
788       }
789     }
790   }
791   return ( theTria1 && theTria2 );
792 }
793
794 //=======================================================================
795 //function : InverseDiag
796 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
797 //           with ones built on the same 4 nodes but having other common link.
798 //           Return false if proper faces not found
799 //=======================================================================
800
801 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
802                                     const SMDS_MeshNode * theNode2)
803 {
804   myLastCreatedElems.Clear();
805   myLastCreatedNodes.Clear();
806
807   MESSAGE( "::InverseDiag()" );
808
809   const SMDS_MeshElement *tr1, *tr2;
810   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
811     return false;
812
813   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
814   if (!F1) return false;
815   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
816   if (!F2) return false;
817   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
818       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
819
820     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
821     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
822     //    |/ |                                    | \|
823     //  B +--+ 2                                B +--+ 2
824
825     // put nodes in array
826     // and find indices of 1,2 and of A in tr1 and of B in tr2
827     int i, iA1 = 0, i1 = 0;
828     const SMDS_MeshNode* aNodes1 [3];
829     SMDS_ElemIteratorPtr it;
830     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
831       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
832       if ( aNodes1[ i ] == theNode1 )
833         iA1 = i; // node A in tr1
834       else if ( aNodes1[ i ] != theNode2 )
835         i1 = i;  // node 1
836     }
837     int iB2 = 0, i2 = 0;
838     const SMDS_MeshNode* aNodes2 [3];
839     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
840       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
841       if ( aNodes2[ i ] == theNode2 )
842         iB2 = i; // node B in tr2
843       else if ( aNodes2[ i ] != theNode1 )
844         i2 = i;  // node 2
845     }
846
847     // nodes 1 and 2 should not be the same
848     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
849       return false;
850
851     // tr1: A->2
852     aNodes1[ iA1 ] = aNodes2[ i2 ];
853     // tr2: B->1
854     aNodes2[ iB2 ] = aNodes1[ i1 ];
855
856     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
857     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
858
859     return true;
860   }
861
862   // check case of quadratic faces
863   return InverseDiag(tr1,tr2);
864 }
865
866 //=======================================================================
867 //function : getQuadrangleNodes
868 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
869 //           fusion of triangles tr1 and tr2 having shared link on
870 //           theNode1 and theNode2
871 //=======================================================================
872
873 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
874                         const SMDS_MeshNode *    theNode1,
875                         const SMDS_MeshNode *    theNode2,
876                         const SMDS_MeshElement * tr1,
877                         const SMDS_MeshElement * tr2 )
878 {
879   if( tr1->NbNodes() != tr2->NbNodes() )
880     return false;
881   // find the 4-th node to insert into tr1
882   const SMDS_MeshNode* n4 = 0;
883   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
884   int i=0;
885   while ( !n4 && i<3 ) {
886     const SMDS_MeshNode * n = cast2Node( it->next() );
887     i++;
888     bool isDiag = ( n == theNode1 || n == theNode2 );
889     if ( !isDiag )
890       n4 = n;
891   }
892   // Make an array of nodes to be in a quadrangle
893   int iNode = 0, iFirstDiag = -1;
894   it = tr1->nodesIterator();
895   i=0;
896   while ( i<3 ) {
897     const SMDS_MeshNode * n = cast2Node( it->next() );
898     i++;
899     bool isDiag = ( n == theNode1 || n == theNode2 );
900     if ( isDiag ) {
901       if ( iFirstDiag < 0 )
902         iFirstDiag = iNode;
903       else if ( iNode - iFirstDiag == 1 )
904         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
905     }
906     else if ( n == n4 ) {
907       return false; // tr1 and tr2 should not have all the same nodes
908     }
909     theQuadNodes[ iNode++ ] = n;
910   }
911   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
912     theQuadNodes[ iNode ] = n4;
913
914   return true;
915 }
916
917 //=======================================================================
918 //function : DeleteDiag
919 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
920 //           with a quadrangle built on the same 4 nodes.
921 //           Return false if proper faces not found
922 //=======================================================================
923
924 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
925                                    const SMDS_MeshNode * theNode2)
926 {
927   myLastCreatedElems.Clear();
928   myLastCreatedNodes.Clear();
929
930   MESSAGE( "::DeleteDiag()" );
931
932   const SMDS_MeshElement *tr1, *tr2;
933   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
934     return false;
935
936   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
937   if (!F1) return false;
938   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
939   if (!F2) return false;
940   SMESHDS_Mesh * aMesh = GetMeshDS();
941
942   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
943       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
944
945     const SMDS_MeshNode* aNodes [ 4 ];
946     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
947       return false;
948
949     const SMDS_MeshElement* newElem = 0;
950     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
951     myLastCreatedElems.Append(newElem);
952     AddToSameGroups( newElem, tr1, aMesh );
953     int aShapeId = tr1->getshapeId();
954     if ( aShapeId )
955       {
956         aMesh->SetMeshElementOnShape( newElem, aShapeId );
957       }
958     aMesh->RemoveElement( tr1 );
959     aMesh->RemoveElement( tr2 );
960
961     return true;
962   }
963
964   // check case of quadratic faces
965   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
966     return false;
967   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
968     return false;
969
970   //       5
971   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
972   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
973   //    |   / |
974   //  7 +  +  + 6
975   //    | /9  |
976   //    |/    |
977   //  4 +--+--+ 3
978   //       8
979
980   const SMDS_MeshNode* N1 [6];
981   const SMDS_MeshNode* N2 [6];
982   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
983     return false;
984   // now we receive following N1 and N2 (using numeration as above image)
985   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
986   // i.e. first nodes from both arrays determ new diagonal
987
988   const SMDS_MeshNode* aNodes[8];
989   aNodes[0] = N1[0];
990   aNodes[1] = N1[1];
991   aNodes[2] = N2[0];
992   aNodes[3] = N2[1];
993   aNodes[4] = N1[3];
994   aNodes[5] = N2[5];
995   aNodes[6] = N2[3];
996   aNodes[7] = N1[5];
997
998   const SMDS_MeshElement* newElem = 0;
999   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1000                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1001   myLastCreatedElems.Append(newElem);
1002   AddToSameGroups( newElem, tr1, aMesh );
1003   int aShapeId = tr1->getshapeId();
1004   if ( aShapeId )
1005     {
1006       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1007     }
1008   aMesh->RemoveElement( tr1 );
1009   aMesh->RemoveElement( tr2 );
1010
1011   // remove middle node (9)
1012   GetMeshDS()->RemoveNode( N1[4] );
1013
1014   return true;
1015 }
1016
1017 //=======================================================================
1018 //function : Reorient
1019 //purpose  : Reverse theElement orientation
1020 //=======================================================================
1021
1022 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1023 {
1024   MESSAGE("Reorient");
1025   myLastCreatedElems.Clear();
1026   myLastCreatedNodes.Clear();
1027
1028   if (!theElem)
1029     return false;
1030   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1031   if ( !it || !it->more() )
1032     return false;
1033
1034   switch ( theElem->GetType() ) {
1035
1036   case SMDSAbs_Edge:
1037   case SMDSAbs_Face: {
1038     if(!theElem->IsQuadratic()) {
1039       int i = theElem->NbNodes();
1040       vector<const SMDS_MeshNode*> aNodes( i );
1041       while ( it->more() )
1042         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
1043       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
1044     }
1045     else {
1046       // quadratic elements
1047       if(theElem->GetType()==SMDSAbs_Edge) {
1048         vector<const SMDS_MeshNode*> aNodes(3);
1049         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
1050         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
1051         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
1052         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
1053       }
1054       else {
1055         int nbn = theElem->NbNodes();
1056         vector<const SMDS_MeshNode*> aNodes(nbn);
1057         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
1058         int i=1;
1059         for(; i<nbn/2; i++) {
1060           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1061         }
1062         for(i=0; i<nbn/2; i++) {
1063           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1064         }
1065         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1066       }
1067     }
1068   }
1069   case SMDSAbs_Volume: {
1070     if (theElem->IsPoly()) {
1071       // TODO reorient vtk polyhedron
1072       MESSAGE("reorient vtk polyhedron ?");
1073       const SMDS_VtkVolume* aPolyedre =
1074         dynamic_cast<const SMDS_VtkVolume*>( theElem );
1075       if (!aPolyedre) {
1076         MESSAGE("Warning: bad volumic element");
1077         return false;
1078       }
1079
1080       int nbFaces = aPolyedre->NbFaces();
1081       vector<const SMDS_MeshNode *> poly_nodes;
1082       vector<int> quantities (nbFaces);
1083
1084       // reverse each face of the polyedre
1085       for (int iface = 1; iface <= nbFaces; iface++) {
1086         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1087         quantities[iface - 1] = nbFaceNodes;
1088
1089         for (inode = nbFaceNodes; inode >= 1; inode--) {
1090           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1091           poly_nodes.push_back(curNode);
1092         }
1093       }
1094
1095       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1096
1097     }
1098     else {
1099       SMDS_VolumeTool vTool;
1100       if ( !vTool.Set( theElem ))
1101         return false;
1102       vTool.Inverse();
1103       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1104       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1105     }
1106   }
1107   default:;
1108   }
1109
1110   return false;
1111 }
1112
1113 //================================================================================
1114 /*!
1115  * \brief Reorient faces.
1116  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1117  * \param theDirection - desired direction of normal of \a theFace
1118  * \param theFace - one of \a theFaces that sould be oriented according to
1119  *        \a theDirection and whose orientation defines orientation of other faces
1120  * \return number of reoriented faces.
1121  */
1122 //================================================================================
1123
1124 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1125                                   const gp_Dir&            theDirection,
1126                                   const SMDS_MeshElement * theFace)
1127 {
1128   int nbReori = 0;
1129   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1130
1131   if ( theFaces.empty() )
1132   {
1133     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1134     while ( fIt->more() )
1135       theFaces.insert( theFaces.end(), fIt->next() );
1136   }
1137
1138   // orient theFace according to theDirection
1139   gp_XYZ normal;
1140   SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false );
1141   if ( normal * theDirection.XYZ() < 0 )
1142     nbReori += Reorient( theFace );
1143
1144   // Orient other faces
1145
1146   set< const SMDS_MeshElement* > startFaces, visitedFaces;
1147   TIDSortedElemSet avoidSet;
1148   set< SMESH_TLink > checkedLinks;
1149   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1150
1151   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1152     theFaces.erase( theFace );
1153   startFaces.insert( theFace );
1154
1155   int nodeInd1, nodeInd2;
1156   const SMDS_MeshElement*           otherFace;
1157   vector< const SMDS_MeshElement* > facesNearLink;
1158   vector< std::pair< int, int > >   nodeIndsOfFace;
1159
1160   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1161   while ( !startFaces.empty() )
1162   {
1163     startFace = startFaces.begin();
1164     theFace = *startFace;
1165     startFaces.erase( startFace );
1166     if ( !visitedFaces.insert( theFace ).second )
1167       continue;
1168
1169     avoidSet.clear();
1170     avoidSet.insert(theFace);
1171
1172     NLink link( theFace->GetNode( 0 ), 0 );
1173
1174     const int nbNodes = theFace->NbCornerNodes();
1175     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1176     {
1177       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1178       linkIt_isNew = checkedLinks.insert( link );
1179       if ( !linkIt_isNew.second )
1180       {
1181         // link has already been checked and won't be encountered more
1182         // if the group (theFaces) is manifold
1183         //checkedLinks.erase( linkIt_isNew.first );
1184       }
1185       else
1186       {
1187         facesNearLink.clear();
1188         nodeIndsOfFace.clear();
1189         while (( otherFace = FindFaceInSet( link.first, link.second,
1190                                             theFaces, avoidSet, &nodeInd1, &nodeInd2 )))
1191           if ( otherFace != theFace)
1192           {
1193             facesNearLink.push_back( otherFace );
1194             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1195             avoidSet.insert( otherFace );
1196           }
1197         if ( facesNearLink.size() > 1 )
1198         {
1199           // NON-MANIFOLD mesh shell !
1200           // select a face most co-directed with theFace,
1201           // other faces won't be visited this time
1202           gp_XYZ NF, NOF;
1203           SMESH_Algo::FaceNormal( theFace, NF, /*normalized=*/false );
1204           double proj, maxProj = -1;
1205           for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1206             SMESH_Algo::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1207             if (( proj = Abs( NF * NOF )) > maxProj ) {
1208               maxProj = proj;
1209               otherFace = facesNearLink[i];
1210               nodeInd1  = nodeIndsOfFace[i].first;
1211               nodeInd2  = nodeIndsOfFace[i].second;
1212             }
1213           }
1214           // not to visit rejected faces
1215           for ( size_t i = 0; i < facesNearLink.size(); ++i )
1216             if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1217               visitedFaces.insert( facesNearLink[i] );
1218         }
1219         else if ( facesNearLink.size() == 1 )
1220         {
1221           otherFace = facesNearLink[0];
1222           nodeInd1  = nodeIndsOfFace.back().first;
1223           nodeInd2  = nodeIndsOfFace.back().second;
1224         }
1225         if ( otherFace && otherFace != theFace)
1226         {
1227           // link must be reverse in otherFace if orientation ot otherFace
1228           // is same as that of theFace
1229           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1230           {
1231             nbReori += Reorient( otherFace );
1232           }
1233           startFaces.insert( otherFace );
1234         }
1235       }
1236       std::swap( link.first, link.second ); // reverse the link
1237     }
1238   }
1239   return nbReori;
1240 }
1241
1242 //=======================================================================
1243 //function : getBadRate
1244 //purpose  :
1245 //=======================================================================
1246
1247 static double getBadRate (const SMDS_MeshElement*               theElem,
1248                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1249 {
1250   SMESH::Controls::TSequenceOfXYZ P;
1251   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1252     return 1e100;
1253   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1254   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1255 }
1256
1257 //=======================================================================
1258 //function : QuadToTri
1259 //purpose  : Cut quadrangles into triangles.
1260 //           theCrit is used to select a diagonal to cut
1261 //=======================================================================
1262
1263 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1264                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1265 {
1266   myLastCreatedElems.Clear();
1267   myLastCreatedNodes.Clear();
1268
1269   MESSAGE( "::QuadToTri()" );
1270
1271   if ( !theCrit.get() )
1272     return false;
1273
1274   SMESHDS_Mesh * aMesh = GetMeshDS();
1275
1276   Handle(Geom_Surface) surface;
1277   SMESH_MesherHelper   helper( *GetMesh() );
1278
1279   TIDSortedElemSet::iterator itElem;
1280   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1281     const SMDS_MeshElement* elem = *itElem;
1282     if ( !elem || elem->GetType() != SMDSAbs_Face )
1283       continue;
1284     if ( elem->NbCornerNodes() != 4 )
1285       continue;
1286
1287     // retrieve element nodes
1288     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1289
1290     // compare two sets of possible triangles
1291     double aBadRate1, aBadRate2; // to what extent a set is bad
1292     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1293     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1294     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1295
1296     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1297     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1298     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1299
1300     int aShapeId = FindShape( elem );
1301     const SMDS_MeshElement* newElem1 = 0;
1302     const SMDS_MeshElement* newElem2 = 0;
1303
1304     if( !elem->IsQuadratic() ) {
1305
1306       // split liner quadrangle
1307       // for MaxElementLength2D functor we return minimum diagonal for splitting,
1308       // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1309       if ( aBadRate1 <= aBadRate2 ) {
1310         // tr1 + tr2 is better
1311         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1312         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1313       }
1314       else {
1315         // tr3 + tr4 is better
1316         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1317         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1318       }
1319     }
1320     else {
1321
1322       // split quadratic quadrangle
1323
1324       // get surface elem is on
1325       if ( aShapeId != helper.GetSubShapeID() ) {
1326         surface.Nullify();
1327         TopoDS_Shape shape;
1328         if ( aShapeId > 0 )
1329           shape = aMesh->IndexToShape( aShapeId );
1330         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1331           TopoDS_Face face = TopoDS::Face( shape );
1332           surface = BRep_Tool::Surface( face );
1333           if ( !surface.IsNull() )
1334             helper.SetSubShape( shape );
1335         }
1336       }
1337       // find middle point for (0,1,2,3)
1338       // and create a node in this point;
1339       const SMDS_MeshNode* newN = 0;
1340       if ( aNodes.size() == 9 )
1341       {
1342         // SMDSEntity_BiQuad_Quadrangle
1343         newN = aNodes.back();
1344       }
1345       else
1346       {
1347         gp_XYZ p( 0,0,0 );
1348         if ( surface.IsNull() )
1349         {
1350           for ( int i = 0; i < 4; i++ )
1351             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1352           p /= 4;
1353         }
1354         else
1355         {
1356           const SMDS_MeshNode* inFaceNode = 0;
1357           if ( helper.GetNodeUVneedInFaceNode() )
1358             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1359               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1360                 inFaceNode = aNodes[ i ];
1361
1362           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1363           gp_XY uv( 0,0 );
1364           for ( int i = 0; i < 4; i++ )
1365             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1366           uv /= 4.;
1367           p = surface->Value( uv.X(), uv.Y() ).XYZ();
1368         }
1369         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1370         myLastCreatedNodes.Append(newN);
1371       }
1372       // create a new element
1373       if ( aBadRate1 <= aBadRate2 ) {
1374         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1375                                   aNodes[6], aNodes[7], newN );
1376         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1377                                   newN,      aNodes[4], aNodes[5] );
1378       }
1379       else {
1380         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1381                                   aNodes[7], aNodes[4], newN );
1382         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1383                                   newN,      aNodes[5], aNodes[6] );
1384       }
1385     } // quadratic case
1386
1387     // care of a new element
1388
1389     myLastCreatedElems.Append(newElem1);
1390     myLastCreatedElems.Append(newElem2);
1391     AddToSameGroups( newElem1, elem, aMesh );
1392     AddToSameGroups( newElem2, elem, aMesh );
1393
1394     // put a new triangle on the same shape
1395     if ( aShapeId )
1396       {
1397         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1398         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1399       }
1400     aMesh->RemoveElement( elem );
1401   }
1402   return true;
1403 }
1404
1405 //=======================================================================
1406 //function : BestSplit
1407 //purpose  : Find better diagonal for cutting.
1408 //=======================================================================
1409
1410 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1411                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1412 {
1413   myLastCreatedElems.Clear();
1414   myLastCreatedNodes.Clear();
1415
1416   if (!theCrit.get())
1417     return -1;
1418
1419   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1420     return -1;
1421
1422   if( theQuad->NbNodes()==4 ||
1423       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1424
1425     // retrieve element nodes
1426     const SMDS_MeshNode* aNodes [4];
1427     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1428     int i = 0;
1429     //while (itN->more())
1430     while (i<4) {
1431       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1432     }
1433     // compare two sets of possible triangles
1434     double aBadRate1, aBadRate2; // to what extent a set is bad
1435     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1436     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1437     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1438
1439     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1440     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1441     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1442     // for MaxElementLength2D functor we return minimum diagonal for splitting,
1443     // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1444     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1445       return 1; // diagonal 1-3
1446
1447     return 2; // diagonal 2-4
1448   }
1449   return -1;
1450 }
1451
1452 namespace
1453 {
1454   // Methods of splitting volumes into tetra
1455
1456   const int theHexTo5_1[5*4+1] =
1457     {
1458       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1459     };
1460   const int theHexTo5_2[5*4+1] =
1461     {
1462       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1463     };
1464   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1465
1466   const int theHexTo6_1[6*4+1] =
1467     {
1468       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
1469     };
1470   const int theHexTo6_2[6*4+1] =
1471     {
1472       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
1473     };
1474   const int theHexTo6_3[6*4+1] =
1475     {
1476       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
1477     };
1478   const int theHexTo6_4[6*4+1] =
1479     {
1480       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
1481     };
1482   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1483
1484   const int thePyraTo2_1[2*4+1] =
1485     {
1486       0, 1, 2, 4,    0, 2, 3, 4,   -1
1487     };
1488   const int thePyraTo2_2[2*4+1] =
1489     {
1490       1, 2, 3, 4,    1, 3, 0, 4,   -1
1491     };
1492   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1493
1494   const int thePentaTo3_1[3*4+1] =
1495     {
1496       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1497     };
1498   const int thePentaTo3_2[3*4+1] =
1499     {
1500       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1501     };
1502   const int thePentaTo3_3[3*4+1] =
1503     {
1504       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1505     };
1506   const int thePentaTo3_4[3*4+1] =
1507     {
1508       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1509     };
1510   const int thePentaTo3_5[3*4+1] =
1511     {
1512       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1513     };
1514   const int thePentaTo3_6[3*4+1] =
1515     {
1516       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1517     };
1518   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1519                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1520
1521   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1522   {
1523     int _n1, _n2, _n3;
1524     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1525     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1526     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1527   };
1528   struct TSplitMethod
1529   {
1530     int        _nbTetra;
1531     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1532     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1533     bool       _ownConn;      //!< to delete _connectivity in destructor
1534     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1535
1536     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1537       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1538     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1539     bool hasFacet( const TTriangleFacet& facet ) const
1540     {
1541       const int* tetConn = _connectivity;
1542       for ( ; tetConn[0] >= 0; tetConn += 4 )
1543         if (( facet.contains( tetConn[0] ) +
1544               facet.contains( tetConn[1] ) +
1545               facet.contains( tetConn[2] ) +
1546               facet.contains( tetConn[3] )) == 3 )
1547           return true;
1548       return false;
1549     }
1550   };
1551
1552   //=======================================================================
1553   /*!
1554    * \brief return TSplitMethod for the given element
1555    */
1556   //=======================================================================
1557
1558   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1559   {
1560     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1561
1562     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1563     // an edge and a face barycenter; tertaherdons are based on triangles and
1564     // a volume barycenter
1565     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1566
1567     // Find out how adjacent volumes are split
1568
1569     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1570     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1571     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1572     {
1573       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1574       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1575       if ( nbNodes < 4 ) continue;
1576
1577       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1578       const int* nInd = vol.GetFaceNodesIndices( iF );
1579       if ( nbNodes == 4 )
1580       {
1581         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1582         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1583         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1584         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1585       }
1586       else
1587       {
1588         int iCom = 0; // common node of triangle faces to split into
1589         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1590         {
1591           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1592                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1593                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1594           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1595                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1596                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1597           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1598           {
1599             triaSplits.push_back( t012 );
1600             triaSplits.push_back( t023 );
1601             break;
1602           }
1603         }
1604       }
1605       if ( !triaSplits.empty() )
1606         hasAdjacentSplits = true;
1607     }
1608
1609     // Among variants of split method select one compliant with adjacent volumes
1610
1611     TSplitMethod method;
1612     if ( !vol.Element()->IsPoly() && !is24TetMode )
1613     {
1614       int nbVariants = 2, nbTet = 0;
1615       const int** connVariants = 0;
1616       switch ( vol.Element()->GetEntityType() )
1617       {
1618       case SMDSEntity_Hexa:
1619       case SMDSEntity_Quad_Hexa:
1620       case SMDSEntity_TriQuad_Hexa:
1621         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1622           connVariants = theHexTo5, nbTet = 5;
1623         else
1624           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1625         break;
1626       case SMDSEntity_Pyramid:
1627       case SMDSEntity_Quad_Pyramid:
1628         connVariants = thePyraTo2;  nbTet = 2;
1629         break;
1630       case SMDSEntity_Penta:
1631       case SMDSEntity_Quad_Penta:
1632         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1633         break;
1634       default:
1635         nbVariants = 0;
1636       }
1637       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1638       {
1639         // check method compliancy with adjacent tetras,
1640         // all found splits must be among facets of tetras described by this method
1641         method = TSplitMethod( nbTet, connVariants[variant] );
1642         if ( hasAdjacentSplits && method._nbTetra > 0 )
1643         {
1644           bool facetCreated = true;
1645           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1646           {
1647             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1648             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1649               facetCreated = method.hasFacet( *facet );
1650           }
1651           if ( !facetCreated )
1652             method = TSplitMethod(0); // incompatible method
1653         }
1654       }
1655     }
1656     if ( method._nbTetra < 1 )
1657     {
1658       // No standard method is applicable, use a generic solution:
1659       // each facet of a volume is split into triangles and
1660       // each of triangles and a volume barycenter form a tetrahedron.
1661
1662       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1663
1664       int* connectivity = new int[ maxTetConnSize + 1 ];
1665       method._connectivity = connectivity;
1666       method._ownConn = true;
1667       method._baryNode = !isHex27; // to create central node or not
1668
1669       int connSize = 0;
1670       int baryCenInd = vol.NbNodes() - int( isHex27 );
1671       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1672       {
1673         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1674         const int*   nInd = vol.GetFaceNodesIndices( iF );
1675         // find common node of triangle facets of tetra to create
1676         int iCommon = 0; // index in linear numeration
1677         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1678         if ( !triaSplits.empty() )
1679         {
1680           // by found facets
1681           const TTriangleFacet* facet = &triaSplits.front();
1682           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1683             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1684                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1685               break;
1686         }
1687         else if ( nbNodes > 3 && !is24TetMode )
1688         {
1689           // find the best method of splitting into triangles by aspect ratio
1690           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1691           map< double, int > badness2iCommon;
1692           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1693           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1694           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1695           {
1696             double badness = 0;
1697             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1698             {
1699               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1700                                       nodes[ iQ*((iLast-1)%nbNodes)],
1701                                       nodes[ iQ*((iLast  )%nbNodes)]);
1702               badness += getBadRate( &tria, aspectRatio );
1703             }
1704             badness2iCommon.insert( make_pair( badness, iCommon ));
1705           }
1706           // use iCommon with lowest badness
1707           iCommon = badness2iCommon.begin()->second;
1708         }
1709         if ( iCommon >= nbNodes )
1710           iCommon = 0; // something wrong
1711
1712         // fill connectivity of tetrahedra based on a current face
1713         int nbTet = nbNodes - 2;
1714         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1715         {
1716           int faceBaryCenInd;
1717           if ( isHex27 )
1718           {
1719             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1720             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1721           }
1722           else
1723           {
1724             method._faceBaryNode[ iF ] = 0;
1725             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1726           }
1727           nbTet = nbNodes;
1728           for ( int i = 0; i < nbTet; ++i )
1729           {
1730             int i1 = i, i2 = (i+1) % nbNodes;
1731             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1732             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1733             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1734             connectivity[ connSize++ ] = faceBaryCenInd;
1735             connectivity[ connSize++ ] = baryCenInd;
1736           }
1737         }
1738         else
1739         {
1740           for ( int i = 0; i < nbTet; ++i )
1741           {
1742             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1743             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1744             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1745             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1746             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1747             connectivity[ connSize++ ] = baryCenInd;
1748           }
1749         }
1750         method._nbTetra += nbTet;
1751
1752       } // loop on volume faces
1753
1754       connectivity[ connSize++ ] = -1;
1755
1756     } // end of generic solution
1757
1758     return method;
1759   }
1760   //================================================================================
1761   /*!
1762    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1763    */
1764   //================================================================================
1765
1766   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1767   {
1768     // find the tetrahedron including the three nodes of facet
1769     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1770     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1771     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1772     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1773     while ( volIt1->more() )
1774     {
1775       const SMDS_MeshElement* v = volIt1->next();
1776       SMDSAbs_EntityType type = v->GetEntityType();
1777       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1778         continue;
1779       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1780         continue; // medium node not allowed
1781       const int ind2 = v->GetNodeIndex( n2 );
1782       if ( ind2 < 0 || 3 < ind2 )
1783         continue;
1784       const int ind3 = v->GetNodeIndex( n3 );
1785       if ( ind3 < 0 || 3 < ind3 )
1786         continue;
1787       return true;
1788     }
1789     return false;
1790   }
1791
1792   //=======================================================================
1793   /*!
1794    * \brief A key of a face of volume
1795    */
1796   //=======================================================================
1797
1798   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1799   {
1800     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1801     {
1802       TIDSortedNodeSet sortedNodes;
1803       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1804       int nbNodes = vol.NbFaceNodes( iF );
1805       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1806       for ( int i = 0; i < nbNodes; i += iQ )
1807         sortedNodes.insert( fNodes[i] );
1808       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1809       first.first   = (*(n++))->GetID();
1810       first.second  = (*(n++))->GetID();
1811       second.first  = (*(n++))->GetID();
1812       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1813     }
1814   };
1815 } // namespace
1816
1817 //=======================================================================
1818 //function : SplitVolumesIntoTetra
1819 //purpose  : Split volume elements into tetrahedra.
1820 //=======================================================================
1821
1822 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1823                                               const int                theMethodFlags)
1824 {
1825   // std-like iterator on coordinates of nodes of mesh element
1826   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1827   NXyzIterator xyzEnd;
1828
1829   SMDS_VolumeTool    volTool;
1830   SMESH_MesherHelper helper( *GetMesh());
1831
1832   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1833   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1834
1835   SMESH_SequenceOfElemPtr newNodes, newElems;
1836
1837   // map face of volume to it's baricenrtic node
1838   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1839   double bc[3];
1840
1841   TIDSortedElemSet::const_iterator elem = theElems.begin();
1842   for ( ; elem != theElems.end(); ++elem )
1843   {
1844     if ( (*elem)->GetType() != SMDSAbs_Volume )
1845       continue;
1846     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1847     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1848       continue;
1849
1850     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1851
1852     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1853     if ( splitMethod._nbTetra < 1 ) continue;
1854
1855     // find submesh to add new tetras to
1856     if ( !subMesh || !subMesh->Contains( *elem ))
1857     {
1858       int shapeID = FindShape( *elem );
1859       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1860       subMesh = GetMeshDS()->MeshElements( shapeID );
1861     }
1862     int iQ;
1863     if ( (*elem)->IsQuadratic() )
1864     {
1865       iQ = 2;
1866       // add quadratic links to the helper
1867       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1868       {
1869         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1870         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1871         for ( int iN = 0; iN < nbN; iN += iQ )
1872           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1873       }
1874       helper.SetIsQuadratic( true );
1875     }
1876     else
1877     {
1878       iQ = 1;
1879       helper.SetIsQuadratic( false );
1880     }
1881     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1882     helper.SetElementsOnShape( true );
1883     if ( splitMethod._baryNode )
1884     {
1885       // make a node at barycenter
1886       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1887       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1888       nodes.push_back( gcNode );
1889       newNodes.Append( gcNode );
1890     }
1891     if ( !splitMethod._faceBaryNode.empty() )
1892     {
1893       // make or find baricentric nodes of faces
1894       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1895       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1896       {
1897         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1898           volFace2BaryNode.insert
1899           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1900         if ( !f_n->second )
1901         {
1902           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1903           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1904         }
1905         nodes.push_back( iF_n->second = f_n->second );
1906       }
1907     }
1908
1909     // make tetras
1910     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1911     const int* tetConn = splitMethod._connectivity;
1912     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1913       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1914                                                        nodes[ tetConn[1] ],
1915                                                        nodes[ tetConn[2] ],
1916                                                        nodes[ tetConn[3] ]));
1917
1918     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1919
1920     // Split faces on sides of the split volume
1921
1922     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1923     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1924     {
1925       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1926       if ( nbNodes < 4 ) continue;
1927
1928       // find an existing face
1929       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1930                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1931       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1932                                                                        /*noMedium=*/false))
1933       {
1934         // make triangles
1935         helper.SetElementsOnShape( false );
1936         vector< const SMDS_MeshElement* > triangles;
1937
1938         // find submesh to add new triangles in
1939         if ( !fSubMesh || !fSubMesh->Contains( face ))
1940         {
1941           int shapeID = FindShape( face );
1942           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1943         }
1944         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1945         if ( iF_n != splitMethod._faceBaryNode.end() )
1946         {
1947           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1948           {
1949             const SMDS_MeshNode* n1 = fNodes[iN];
1950             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1951             const SMDS_MeshNode *n3 = iF_n->second;
1952             if ( !volTool.IsFaceExternal( iF ))
1953               swap( n2, n3 );
1954             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1955
1956             if ( fSubMesh && n3->getshapeId() < 1 )
1957               fSubMesh->AddNode( n3 );
1958           }
1959         }
1960         else
1961         {
1962           // among possible triangles create ones discribed by split method
1963           const int* nInd = volTool.GetFaceNodesIndices( iF );
1964           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1965           int iCom = 0; // common node of triangle faces to split into
1966           list< TTriangleFacet > facets;
1967           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1968           {
1969             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1970                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1971                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1972             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1973                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1974                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1975             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1976             {
1977               facets.push_back( t012 );
1978               facets.push_back( t023 );
1979               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1980                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1981                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1982                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1983               break;
1984             }
1985           }
1986           list< TTriangleFacet >::iterator facet = facets.begin();
1987           for ( ; facet != facets.end(); ++facet )
1988           {
1989             if ( !volTool.IsFaceExternal( iF ))
1990               swap( facet->_n2, facet->_n3 );
1991             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1992                                                  volNodes[ facet->_n2 ],
1993                                                  volNodes[ facet->_n3 ]));
1994           }
1995         }
1996         for ( int i = 0; i < triangles.size(); ++i )
1997         {
1998           if ( !triangles[i] ) continue;
1999           if ( fSubMesh )
2000             fSubMesh->AddElement( triangles[i]);
2001           newElems.Append( triangles[i] );
2002         }
2003         ReplaceElemInGroups( face, triangles, GetMeshDS() );
2004         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
2005       }
2006
2007     } // loop on volume faces to split them into triangles
2008
2009     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
2010
2011     if ( geomType == SMDSEntity_TriQuad_Hexa )
2012     {
2013       // remove medium nodes that could become free
2014       for ( int i = 20; i < volTool.NbNodes(); ++i )
2015         if ( volNodes[i]->NbInverseElements() == 0 )
2016           GetMeshDS()->RemoveNode( volNodes[i] );
2017     }
2018   } // loop on volumes to split
2019
2020   myLastCreatedNodes = newNodes;
2021   myLastCreatedElems = newElems;
2022 }
2023
2024 //=======================================================================
2025 //function : AddToSameGroups
2026 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
2027 //=======================================================================
2028
2029 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
2030                                         const SMDS_MeshElement* elemInGroups,
2031                                         SMESHDS_Mesh *          aMesh)
2032 {
2033   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2034   if (!groups.empty()) {
2035     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2036     for ( ; grIt != groups.end(); grIt++ ) {
2037       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2038       if ( group && group->Contains( elemInGroups ))
2039         group->SMDSGroup().Add( elemToAdd );
2040     }
2041   }
2042 }
2043
2044
2045 //=======================================================================
2046 //function : RemoveElemFromGroups
2047 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
2048 //=======================================================================
2049 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
2050                                              SMESHDS_Mesh *          aMesh)
2051 {
2052   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2053   if (!groups.empty())
2054   {
2055     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2056     for (; GrIt != groups.end(); GrIt++)
2057     {
2058       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2059       if (!grp || grp->IsEmpty()) continue;
2060       grp->SMDSGroup().Remove(removeelem);
2061     }
2062   }
2063 }
2064
2065 //================================================================================
2066 /*!
2067  * \brief Replace elemToRm by elemToAdd in the all groups
2068  */
2069 //================================================================================
2070
2071 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2072                                             const SMDS_MeshElement* elemToAdd,
2073                                             SMESHDS_Mesh *          aMesh)
2074 {
2075   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2076   if (!groups.empty()) {
2077     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2078     for ( ; grIt != groups.end(); grIt++ ) {
2079       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2080       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2081         group->SMDSGroup().Add( elemToAdd );
2082     }
2083   }
2084 }
2085
2086 //================================================================================
2087 /*!
2088  * \brief Replace elemToRm by elemToAdd in the all groups
2089  */
2090 //================================================================================
2091
2092 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2093                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2094                                             SMESHDS_Mesh *                         aMesh)
2095 {
2096   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2097   if (!groups.empty())
2098   {
2099     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2100     for ( ; grIt != groups.end(); grIt++ ) {
2101       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2102       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2103         for ( int i = 0; i < elemToAdd.size(); ++i )
2104           group->SMDSGroup().Add( elemToAdd[ i ] );
2105     }
2106   }
2107 }
2108
2109 //=======================================================================
2110 //function : QuadToTri
2111 //purpose  : Cut quadrangles into triangles.
2112 //           theCrit is used to select a diagonal to cut
2113 //=======================================================================
2114
2115 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2116                                   const bool         the13Diag)
2117 {
2118   myLastCreatedElems.Clear();
2119   myLastCreatedNodes.Clear();
2120
2121   MESSAGE( "::QuadToTri()" );
2122
2123   SMESHDS_Mesh * aMesh = GetMeshDS();
2124
2125   Handle(Geom_Surface) surface;
2126   SMESH_MesherHelper   helper( *GetMesh() );
2127
2128   TIDSortedElemSet::iterator itElem;
2129   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2130     const SMDS_MeshElement* elem = *itElem;
2131     if ( !elem || elem->GetType() != SMDSAbs_Face )
2132       continue;
2133     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2134     if(!isquad) continue;
2135
2136     if(elem->NbNodes()==4) {
2137       // retrieve element nodes
2138       const SMDS_MeshNode* aNodes [4];
2139       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2140       int i = 0;
2141       while ( itN->more() )
2142         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2143
2144       int aShapeId = FindShape( elem );
2145       const SMDS_MeshElement* newElem1 = 0;
2146       const SMDS_MeshElement* newElem2 = 0;
2147       if ( the13Diag ) {
2148         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2149         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2150       }
2151       else {
2152         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2153         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2154       }
2155       myLastCreatedElems.Append(newElem1);
2156       myLastCreatedElems.Append(newElem2);
2157       // put a new triangle on the same shape and add to the same groups
2158       if ( aShapeId )
2159         {
2160           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2161           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2162         }
2163       AddToSameGroups( newElem1, elem, aMesh );
2164       AddToSameGroups( newElem2, elem, aMesh );
2165       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2166       aMesh->RemoveElement( elem );
2167     }
2168
2169     // Quadratic quadrangle
2170
2171     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2172
2173       // get surface elem is on
2174       int aShapeId = FindShape( elem );
2175       if ( aShapeId != helper.GetSubShapeID() ) {
2176         surface.Nullify();
2177         TopoDS_Shape shape;
2178         if ( aShapeId > 0 )
2179           shape = aMesh->IndexToShape( aShapeId );
2180         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2181           TopoDS_Face face = TopoDS::Face( shape );
2182           surface = BRep_Tool::Surface( face );
2183           if ( !surface.IsNull() )
2184             helper.SetSubShape( shape );
2185         }
2186       }
2187
2188       const SMDS_MeshNode* aNodes [8];
2189       const SMDS_MeshNode* inFaceNode = 0;
2190       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2191       int i = 0;
2192       while ( itN->more() ) {
2193         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2194         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2195              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2196         {
2197           inFaceNode = aNodes[ i-1 ];
2198         }
2199       }
2200
2201       // find middle point for (0,1,2,3)
2202       // and create a node in this point;
2203       gp_XYZ p( 0,0,0 );
2204       if ( surface.IsNull() ) {
2205         for(i=0; i<4; i++)
2206           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2207         p /= 4;
2208       }
2209       else {
2210         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2211         gp_XY uv( 0,0 );
2212         for(i=0; i<4; i++)
2213           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2214         uv /= 4.;
2215         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2216       }
2217       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2218       myLastCreatedNodes.Append(newN);
2219
2220       // create a new element
2221       const SMDS_MeshElement* newElem1 = 0;
2222       const SMDS_MeshElement* newElem2 = 0;
2223       if ( the13Diag ) {
2224         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2225                                   aNodes[6], aNodes[7], newN );
2226         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2227                                   newN,      aNodes[4], aNodes[5] );
2228       }
2229       else {
2230         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2231                                   aNodes[7], aNodes[4], newN );
2232         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2233                                   newN,      aNodes[5], aNodes[6] );
2234       }
2235       myLastCreatedElems.Append(newElem1);
2236       myLastCreatedElems.Append(newElem2);
2237       // put a new triangle on the same shape and add to the same groups
2238       if ( aShapeId )
2239         {
2240           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2241           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2242         }
2243       AddToSameGroups( newElem1, elem, aMesh );
2244       AddToSameGroups( newElem2, elem, aMesh );
2245       aMesh->RemoveElement( elem );
2246     }
2247   }
2248
2249   return true;
2250 }
2251
2252 //=======================================================================
2253 //function : getAngle
2254 //purpose  :
2255 //=======================================================================
2256
2257 double getAngle(const SMDS_MeshElement * tr1,
2258                 const SMDS_MeshElement * tr2,
2259                 const SMDS_MeshNode *    n1,
2260                 const SMDS_MeshNode *    n2)
2261 {
2262   double angle = 2. * M_PI; // bad angle
2263
2264   // get normals
2265   SMESH::Controls::TSequenceOfXYZ P1, P2;
2266   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2267        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2268     return angle;
2269   gp_Vec N1,N2;
2270   if(!tr1->IsQuadratic())
2271     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2272   else
2273     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2274   if ( N1.SquareMagnitude() <= gp::Resolution() )
2275     return angle;
2276   if(!tr2->IsQuadratic())
2277     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2278   else
2279     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2280   if ( N2.SquareMagnitude() <= gp::Resolution() )
2281     return angle;
2282
2283   // find the first diagonal node n1 in the triangles:
2284   // take in account a diagonal link orientation
2285   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2286   for ( int t = 0; t < 2; t++ ) {
2287     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2288     int i = 0, iDiag = -1;
2289     while ( it->more()) {
2290       const SMDS_MeshElement *n = it->next();
2291       if ( n == n1 || n == n2 ) {
2292         if ( iDiag < 0)
2293           iDiag = i;
2294         else {
2295           if ( i - iDiag == 1 )
2296             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2297           else
2298             nFirst[ t ] = n;
2299           break;
2300         }
2301       }
2302       i++;
2303     }
2304   }
2305   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2306     N2.Reverse();
2307
2308   angle = N1.Angle( N2 );
2309   //SCRUTE( angle );
2310   return angle;
2311 }
2312
2313 // =================================================
2314 // class generating a unique ID for a pair of nodes
2315 // and able to return nodes by that ID
2316 // =================================================
2317 class LinkID_Gen {
2318 public:
2319
2320   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2321     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2322   {}
2323
2324   long GetLinkID (const SMDS_MeshNode * n1,
2325                   const SMDS_MeshNode * n2) const
2326   {
2327     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2328   }
2329
2330   bool GetNodes (const long             theLinkID,
2331                  const SMDS_MeshNode* & theNode1,
2332                  const SMDS_MeshNode* & theNode2) const
2333   {
2334     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2335     if ( !theNode1 ) return false;
2336     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2337     if ( !theNode2 ) return false;
2338     return true;
2339   }
2340
2341 private:
2342   LinkID_Gen();
2343   const SMESHDS_Mesh* myMesh;
2344   long                myMaxID;
2345 };
2346
2347
2348 //=======================================================================
2349 //function : TriToQuad
2350 //purpose  : Fuse neighbour triangles into quadrangles.
2351 //           theCrit is used to select a neighbour to fuse with.
2352 //           theMaxAngle is a max angle between element normals at which
2353 //           fusion is still performed.
2354 //=======================================================================
2355
2356 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2357                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2358                                   const double                         theMaxAngle)
2359 {
2360   myLastCreatedElems.Clear();
2361   myLastCreatedNodes.Clear();
2362
2363   MESSAGE( "::TriToQuad()" );
2364
2365   if ( !theCrit.get() )
2366     return false;
2367
2368   SMESHDS_Mesh * aMesh = GetMeshDS();
2369
2370   // Prepare data for algo: build
2371   // 1. map of elements with their linkIDs
2372   // 2. map of linkIDs with their elements
2373
2374   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2375   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2376   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2377   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2378
2379   TIDSortedElemSet::iterator itElem;
2380   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2381     const SMDS_MeshElement* elem = *itElem;
2382     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2383     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2384     if(!IsTria) continue;
2385
2386     // retrieve element nodes
2387     const SMDS_MeshNode* aNodes [4];
2388     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2389     int i = 0;
2390     while ( i<3 )
2391       aNodes[ i++ ] = cast2Node( itN->next() );
2392     aNodes[ 3 ] = aNodes[ 0 ];
2393
2394     // fill maps
2395     for ( i = 0; i < 3; i++ ) {
2396       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2397       // check if elements sharing a link can be fused
2398       itLE = mapLi_listEl.find( link );
2399       if ( itLE != mapLi_listEl.end() ) {
2400         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2401           continue;
2402         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2403         //if ( FindShape( elem ) != FindShape( elem2 ))
2404         //  continue; // do not fuse triangles laying on different shapes
2405         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2406           continue; // avoid making badly shaped quads
2407         (*itLE).second.push_back( elem );
2408       }
2409       else {
2410         mapLi_listEl[ link ].push_back( elem );
2411       }
2412       mapEl_setLi [ elem ].insert( link );
2413     }
2414   }
2415   // Clean the maps from the links shared by a sole element, ie
2416   // links to which only one element is bound in mapLi_listEl
2417
2418   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2419     int nbElems = (*itLE).second.size();
2420     if ( nbElems < 2  ) {
2421       const SMDS_MeshElement* elem = (*itLE).second.front();
2422       SMESH_TLink link = (*itLE).first;
2423       mapEl_setLi[ elem ].erase( link );
2424       if ( mapEl_setLi[ elem ].empty() )
2425         mapEl_setLi.erase( elem );
2426     }
2427   }
2428
2429   // Algo: fuse triangles into quadrangles
2430
2431   while ( ! mapEl_setLi.empty() ) {
2432     // Look for the start element:
2433     // the element having the least nb of shared links
2434     const SMDS_MeshElement* startElem = 0;
2435     int minNbLinks = 4;
2436     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2437       int nbLinks = (*itEL).second.size();
2438       if ( nbLinks < minNbLinks ) {
2439         startElem = (*itEL).first;
2440         minNbLinks = nbLinks;
2441         if ( minNbLinks == 1 )
2442           break;
2443       }
2444     }
2445
2446     // search elements to fuse starting from startElem or links of elements
2447     // fused earlyer - startLinks
2448     list< SMESH_TLink > startLinks;
2449     while ( startElem || !startLinks.empty() ) {
2450       while ( !startElem && !startLinks.empty() ) {
2451         // Get an element to start, by a link
2452         SMESH_TLink linkId = startLinks.front();
2453         startLinks.pop_front();
2454         itLE = mapLi_listEl.find( linkId );
2455         if ( itLE != mapLi_listEl.end() ) {
2456           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2457           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2458           for ( ; itE != listElem.end() ; itE++ )
2459             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2460               startElem = (*itE);
2461           mapLi_listEl.erase( itLE );
2462         }
2463       }
2464
2465       if ( startElem ) {
2466         // Get candidates to be fused
2467         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2468         const SMESH_TLink *link12, *link13;
2469         startElem = 0;
2470         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2471         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2472         ASSERT( !setLi.empty() );
2473         set< SMESH_TLink >::iterator itLi;
2474         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2475         {
2476           const SMESH_TLink & link = (*itLi);
2477           itLE = mapLi_listEl.find( link );
2478           if ( itLE == mapLi_listEl.end() )
2479             continue;
2480
2481           const SMDS_MeshElement* elem = (*itLE).second.front();
2482           if ( elem == tr1 )
2483             elem = (*itLE).second.back();
2484           mapLi_listEl.erase( itLE );
2485           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2486             continue;
2487           if ( tr2 ) {
2488             tr3 = elem;
2489             link13 = &link;
2490           }
2491           else {
2492             tr2 = elem;
2493             link12 = &link;
2494           }
2495
2496           // add other links of elem to list of links to re-start from
2497           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2498           set< SMESH_TLink >::iterator it;
2499           for ( it = links.begin(); it != links.end(); it++ ) {
2500             const SMESH_TLink& link2 = (*it);
2501             if ( link2 != link )
2502               startLinks.push_back( link2 );
2503           }
2504         }
2505
2506         // Get nodes of possible quadrangles
2507         const SMDS_MeshNode *n12 [4], *n13 [4];
2508         bool Ok12 = false, Ok13 = false;
2509         const SMDS_MeshNode *linkNode1, *linkNode2;
2510         if(tr2) {
2511           linkNode1 = link12->first;
2512           linkNode2 = link12->second;
2513           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2514             Ok12 = true;
2515         }
2516         if(tr3) {
2517           linkNode1 = link13->first;
2518           linkNode2 = link13->second;
2519           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2520             Ok13 = true;
2521         }
2522
2523         // Choose a pair to fuse
2524         if ( Ok12 && Ok13 ) {
2525           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2526           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2527           double aBadRate12 = getBadRate( &quad12, theCrit );
2528           double aBadRate13 = getBadRate( &quad13, theCrit );
2529           if (  aBadRate13 < aBadRate12 )
2530             Ok12 = false;
2531           else
2532             Ok13 = false;
2533         }
2534
2535         // Make quadrangles
2536         // and remove fused elems and removed links from the maps
2537         mapEl_setLi.erase( tr1 );
2538         if ( Ok12 ) {
2539           mapEl_setLi.erase( tr2 );
2540           mapLi_listEl.erase( *link12 );
2541           if(tr1->NbNodes()==3) {
2542             const SMDS_MeshElement* newElem = 0;
2543             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2544             myLastCreatedElems.Append(newElem);
2545             AddToSameGroups( newElem, tr1, aMesh );
2546             int aShapeId = tr1->getshapeId();
2547             if ( aShapeId )
2548               {
2549                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2550               }
2551             aMesh->RemoveElement( tr1 );
2552             aMesh->RemoveElement( tr2 );
2553           }
2554           else {
2555             const SMDS_MeshNode* N1 [6];
2556             const SMDS_MeshNode* N2 [6];
2557             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2558             // now we receive following N1 and N2 (using numeration as above image)
2559             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2560             // i.e. first nodes from both arrays determ new diagonal
2561             const SMDS_MeshNode* aNodes[8];
2562             aNodes[0] = N1[0];
2563             aNodes[1] = N1[1];
2564             aNodes[2] = N2[0];
2565             aNodes[3] = N2[1];
2566             aNodes[4] = N1[3];
2567             aNodes[5] = N2[5];
2568             aNodes[6] = N2[3];
2569             aNodes[7] = N1[5];
2570             const SMDS_MeshElement* newElem = 0;
2571             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2572                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2573             myLastCreatedElems.Append(newElem);
2574             AddToSameGroups( newElem, tr1, aMesh );
2575             int aShapeId = tr1->getshapeId();
2576             if ( aShapeId )
2577               {
2578                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2579               }
2580             aMesh->RemoveElement( tr1 );
2581             aMesh->RemoveElement( tr2 );
2582             // remove middle node (9)
2583             GetMeshDS()->RemoveNode( N1[4] );
2584           }
2585         }
2586         else if ( Ok13 ) {
2587           mapEl_setLi.erase( tr3 );
2588           mapLi_listEl.erase( *link13 );
2589           if(tr1->NbNodes()==3) {
2590             const SMDS_MeshElement* newElem = 0;
2591             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2592             myLastCreatedElems.Append(newElem);
2593             AddToSameGroups( newElem, tr1, aMesh );
2594             int aShapeId = tr1->getshapeId();
2595             if ( aShapeId )
2596               {
2597                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2598               }
2599             aMesh->RemoveElement( tr1 );
2600             aMesh->RemoveElement( tr3 );
2601           }
2602           else {
2603             const SMDS_MeshNode* N1 [6];
2604             const SMDS_MeshNode* N2 [6];
2605             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2606             // now we receive following N1 and N2 (using numeration as above image)
2607             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2608             // i.e. first nodes from both arrays determ new diagonal
2609             const SMDS_MeshNode* aNodes[8];
2610             aNodes[0] = N1[0];
2611             aNodes[1] = N1[1];
2612             aNodes[2] = N2[0];
2613             aNodes[3] = N2[1];
2614             aNodes[4] = N1[3];
2615             aNodes[5] = N2[5];
2616             aNodes[6] = N2[3];
2617             aNodes[7] = N1[5];
2618             const SMDS_MeshElement* newElem = 0;
2619             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2620                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2621             myLastCreatedElems.Append(newElem);
2622             AddToSameGroups( newElem, tr1, aMesh );
2623             int aShapeId = tr1->getshapeId();
2624             if ( aShapeId )
2625               {
2626                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2627               }
2628             aMesh->RemoveElement( tr1 );
2629             aMesh->RemoveElement( tr3 );
2630             // remove middle node (9)
2631             GetMeshDS()->RemoveNode( N1[4] );
2632           }
2633         }
2634
2635         // Next element to fuse: the rejected one
2636         if ( tr3 )
2637           startElem = Ok12 ? tr3 : tr2;
2638
2639       } // if ( startElem )
2640     } // while ( startElem || !startLinks.empty() )
2641   } // while ( ! mapEl_setLi.empty() )
2642
2643   return true;
2644 }
2645
2646
2647 /*#define DUMPSO(txt) \
2648 //  cout << txt << endl;
2649 //=============================================================================
2650 //
2651 //
2652 //
2653 //=============================================================================
2654 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2655 {
2656 if ( i1 == i2 )
2657 return;
2658 int tmp = idNodes[ i1 ];
2659 idNodes[ i1 ] = idNodes[ i2 ];
2660 idNodes[ i2 ] = tmp;
2661 gp_Pnt Ptmp = P[ i1 ];
2662 P[ i1 ] = P[ i2 ];
2663 P[ i2 ] = Ptmp;
2664 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2665 }
2666
2667 //=======================================================================
2668 //function : SortQuadNodes
2669 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2670 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2671 //           1 or 2 else 0.
2672 //=======================================================================
2673
2674 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2675 int               idNodes[] )
2676 {
2677   gp_Pnt P[4];
2678   int i;
2679   for ( i = 0; i < 4; i++ ) {
2680     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2681     if ( !n ) return 0;
2682     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2683   }
2684
2685   gp_Vec V1(P[0], P[1]);
2686   gp_Vec V2(P[0], P[2]);
2687   gp_Vec V3(P[0], P[3]);
2688
2689   gp_Vec Cross1 = V1 ^ V2;
2690   gp_Vec Cross2 = V2 ^ V3;
2691
2692   i = 0;
2693   if (Cross1.Dot(Cross2) < 0)
2694   {
2695     Cross1 = V2 ^ V1;
2696     Cross2 = V1 ^ V3;
2697
2698     if (Cross1.Dot(Cross2) < 0)
2699       i = 2;
2700     else
2701       i = 1;
2702     swap ( i, i + 1, idNodes, P );
2703
2704     //     for ( int ii = 0; ii < 4; ii++ ) {
2705     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2706     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2707     //     }
2708   }
2709   return i;
2710 }
2711
2712 //=======================================================================
2713 //function : SortHexaNodes
2714 //purpose  : Set 8 nodes of a hexahedron in a good order.
2715 //           Return success status
2716 //=======================================================================
2717
2718 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2719                                       int               idNodes[] )
2720 {
2721   gp_Pnt P[8];
2722   int i;
2723   DUMPSO( "INPUT: ========================================");
2724   for ( i = 0; i < 8; i++ ) {
2725     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2726     if ( !n ) return false;
2727     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2728     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2729   }
2730   DUMPSO( "========================================");
2731
2732
2733   set<int> faceNodes;  // ids of bottom face nodes, to be found
2734   set<int> checkedId1; // ids of tried 2-nd nodes
2735   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2736   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2737   int iMin, iLoop1 = 0;
2738
2739   // Loop to try the 2-nd nodes
2740
2741   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2742   {
2743     // Find not checked 2-nd node
2744     for ( i = 1; i < 8; i++ )
2745       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2746         int id1 = idNodes[i];
2747         swap ( 1, i, idNodes, P );
2748         checkedId1.insert ( id1 );
2749         break;
2750       }
2751
2752     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2753     // ie that all but meybe one (id3 which is on the same face) nodes
2754     // lay on the same side from the triangle plane.
2755
2756     bool manyInPlane = false; // more than 4 nodes lay in plane
2757     int iLoop2 = 0;
2758     while ( ++iLoop2 < 6 ) {
2759
2760       // get 1-2-3 plane coeffs
2761       Standard_Real A, B, C, D;
2762       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2763       if ( N.SquareMagnitude() > gp::Resolution() )
2764       {
2765         gp_Pln pln ( P[0], N );
2766         pln.Coefficients( A, B, C, D );
2767
2768         // find the node (iMin) closest to pln
2769         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2770         set<int> idInPln;
2771         for ( i = 3; i < 8; i++ ) {
2772           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2773           if ( fabs( dist[i] ) < minDist ) {
2774             minDist = fabs( dist[i] );
2775             iMin = i;
2776           }
2777           if ( fabs( dist[i] ) <= tol )
2778             idInPln.insert( idNodes[i] );
2779         }
2780
2781         // there should not be more than 4 nodes in bottom plane
2782         if ( idInPln.size() > 1 )
2783         {
2784           DUMPSO( "### idInPln.size() = " << idInPln.size());
2785           // idInPlane does not contain the first 3 nodes
2786           if ( manyInPlane || idInPln.size() == 5)
2787             return false; // all nodes in one plane
2788           manyInPlane = true;
2789
2790           // set the 1-st node to be not in plane
2791           for ( i = 3; i < 8; i++ ) {
2792             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2793               DUMPSO( "### Reset 0-th node");
2794               swap( 0, i, idNodes, P );
2795               break;
2796             }
2797           }
2798
2799           // reset to re-check second nodes
2800           leastDist = DBL_MAX;
2801           faceNodes.clear();
2802           checkedId1.clear();
2803           iLoop1 = 0;
2804           break; // from iLoop2;
2805         }
2806
2807         // check that the other 4 nodes are on the same side
2808         bool sameSide = true;
2809         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2810         for ( i = 3; sameSide && i < 8; i++ ) {
2811           if ( i != iMin )
2812             sameSide = ( isNeg == dist[i] <= 0.);
2813         }
2814
2815         // keep best solution
2816         if ( sameSide && minDist < leastDist ) {
2817           leastDist = minDist;
2818           faceNodes.clear();
2819           faceNodes.insert( idNodes[ 1 ] );
2820           faceNodes.insert( idNodes[ 2 ] );
2821           faceNodes.insert( idNodes[ iMin ] );
2822           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2823                   << " leastDist = " << leastDist);
2824           if ( leastDist <= DBL_MIN )
2825             break;
2826         }
2827       }
2828
2829       // set next 3-d node to check
2830       int iNext = 2 + iLoop2;
2831       if ( iNext < 8 ) {
2832         DUMPSO( "Try 2-nd");
2833         swap ( 2, iNext, idNodes, P );
2834       }
2835     } // while ( iLoop2 < 6 )
2836   } // iLoop1
2837
2838   if ( faceNodes.empty() ) return false;
2839
2840   // Put the faceNodes in proper places
2841   for ( i = 4; i < 8; i++ ) {
2842     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2843       // find a place to put
2844       int iTo = 1;
2845       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2846         iTo++;
2847       DUMPSO( "Set faceNodes");
2848       swap ( iTo, i, idNodes, P );
2849     }
2850   }
2851
2852
2853   // Set nodes of the found bottom face in good order
2854   DUMPSO( " Found bottom face: ");
2855   i = SortQuadNodes( theMesh, idNodes );
2856   if ( i ) {
2857     gp_Pnt Ptmp = P[ i ];
2858     P[ i ] = P[ i+1 ];
2859     P[ i+1 ] = Ptmp;
2860   }
2861   //   else
2862   //     for ( int ii = 0; ii < 4; ii++ ) {
2863   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2864   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2865   //    }
2866
2867   // Gravity center of the top and bottom faces
2868   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2869   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2870
2871   // Get direction from the bottom to the top face
2872   gp_Vec upDir ( aGCb, aGCt );
2873   Standard_Real upDirSize = upDir.Magnitude();
2874   if ( upDirSize <= gp::Resolution() ) return false;
2875   upDir / upDirSize;
2876
2877   // Assure that the bottom face normal points up
2878   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2879   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2880   if ( Nb.Dot( upDir ) < 0 ) {
2881     DUMPSO( "Reverse bottom face");
2882     swap( 1, 3, idNodes, P );
2883   }
2884
2885   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2886   Standard_Real minDist = DBL_MAX;
2887   for ( i = 4; i < 8; i++ ) {
2888     // projection of P[i] to the plane defined by P[0] and upDir
2889     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2890     Standard_Real sqDist = P[0].SquareDistance( Pp );
2891     if ( sqDist < minDist ) {
2892       minDist = sqDist;
2893       iMin = i;
2894     }
2895   }
2896   DUMPSO( "Set 4-th");
2897   swap ( 4, iMin, idNodes, P );
2898
2899   // Set nodes of the top face in good order
2900   DUMPSO( "Sort top face");
2901   i = SortQuadNodes( theMesh, &idNodes[4] );
2902   if ( i ) {
2903     i += 4;
2904     gp_Pnt Ptmp = P[ i ];
2905     P[ i ] = P[ i+1 ];
2906     P[ i+1 ] = Ptmp;
2907   }
2908
2909   // Assure that direction of the top face normal is from the bottom face
2910   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2911   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2912   if ( Nt.Dot( upDir ) < 0 ) {
2913     DUMPSO( "Reverse top face");
2914     swap( 5, 7, idNodes, P );
2915   }
2916
2917   //   DUMPSO( "OUTPUT: ========================================");
2918   //   for ( i = 0; i < 8; i++ ) {
2919   //     float *p = ugrid->GetPoint(idNodes[i]);
2920   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2921   //   }
2922
2923   return true;
2924 }*/
2925
2926 //================================================================================
2927 /*!
2928  * \brief Return nodes linked to the given one
2929  * \param theNode - the node
2930  * \param linkedNodes - the found nodes
2931  * \param type - the type of elements to check
2932  *
2933  * Medium nodes are ignored
2934  */
2935 //================================================================================
2936
2937 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2938                                        TIDSortedElemSet &   linkedNodes,
2939                                        SMDSAbs_ElementType  type )
2940 {
2941   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2942   while ( elemIt->more() )
2943   {
2944     const SMDS_MeshElement* elem = elemIt->next();
2945     if(elem->GetType() == SMDSAbs_0DElement)
2946       continue;
2947
2948     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2949     if ( elem->GetType() == SMDSAbs_Volume )
2950     {
2951       SMDS_VolumeTool vol( elem );
2952       while ( nodeIt->more() ) {
2953         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2954         if ( theNode != n && vol.IsLinked( theNode, n ))
2955           linkedNodes.insert( n );
2956       }
2957     }
2958     else
2959     {
2960       for ( int i = 0; nodeIt->more(); ++i ) {
2961         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2962         if ( n == theNode ) {
2963           int iBefore = i - 1;
2964           int iAfter  = i + 1;
2965           if ( elem->IsQuadratic() ) {
2966             int nb = elem->NbNodes() / 2;
2967             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2968             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2969           }
2970           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2971           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2972         }
2973       }
2974     }
2975   }
2976 }
2977
2978 //=======================================================================
2979 //function : laplacianSmooth
2980 //purpose  : pulls theNode toward the center of surrounding nodes directly
2981 //           connected to that node along an element edge
2982 //=======================================================================
2983
2984 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2985                      const Handle(Geom_Surface)&          theSurface,
2986                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2987 {
2988   // find surrounding nodes
2989
2990   TIDSortedElemSet nodeSet;
2991   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2992
2993   // compute new coodrs
2994
2995   double coord[] = { 0., 0., 0. };
2996   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2997   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2998     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2999     if ( theSurface.IsNull() ) { // smooth in 3D
3000       coord[0] += node->X();
3001       coord[1] += node->Y();
3002       coord[2] += node->Z();
3003     }
3004     else { // smooth in 2D
3005       ASSERT( theUVMap.find( node ) != theUVMap.end() );
3006       gp_XY* uv = theUVMap[ node ];
3007       coord[0] += uv->X();
3008       coord[1] += uv->Y();
3009     }
3010   }
3011   int nbNodes = nodeSet.size();
3012   if ( !nbNodes )
3013     return;
3014   coord[0] /= nbNodes;
3015   coord[1] /= nbNodes;
3016
3017   if ( !theSurface.IsNull() ) {
3018     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
3019     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
3020     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
3021     coord[0] = p3d.X();
3022     coord[1] = p3d.Y();
3023     coord[2] = p3d.Z();
3024   }
3025   else
3026     coord[2] /= nbNodes;
3027
3028   // move node
3029
3030   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
3031 }
3032
3033 //=======================================================================
3034 //function : centroidalSmooth
3035 //purpose  : pulls theNode toward the element-area-weighted centroid of the
3036 //           surrounding elements
3037 //=======================================================================
3038
3039 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
3040                       const Handle(Geom_Surface)&          theSurface,
3041                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3042 {
3043   gp_XYZ aNewXYZ(0.,0.,0.);
3044   SMESH::Controls::Area anAreaFunc;
3045   double totalArea = 0.;
3046   int nbElems = 0;
3047
3048   // compute new XYZ
3049
3050   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3051   while ( elemIt->more() )
3052   {
3053     const SMDS_MeshElement* elem = elemIt->next();
3054     nbElems++;
3055
3056     gp_XYZ elemCenter(0.,0.,0.);
3057     SMESH::Controls::TSequenceOfXYZ aNodePoints;
3058     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3059     int nn = elem->NbNodes();
3060     if(elem->IsQuadratic()) nn = nn/2;
3061     int i=0;
3062     //while ( itN->more() ) {
3063     while ( i<nn ) {
3064       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3065       i++;
3066       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3067       aNodePoints.push_back( aP );
3068       if ( !theSurface.IsNull() ) { // smooth in 2D
3069         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3070         gp_XY* uv = theUVMap[ aNode ];
3071         aP.SetCoord( uv->X(), uv->Y(), 0. );
3072       }
3073       elemCenter += aP;
3074     }
3075     double elemArea = anAreaFunc.GetValue( aNodePoints );
3076     totalArea += elemArea;
3077     elemCenter /= nn;
3078     aNewXYZ += elemCenter * elemArea;
3079   }
3080   aNewXYZ /= totalArea;
3081   if ( !theSurface.IsNull() ) {
3082     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3083     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3084   }
3085
3086   // move node
3087
3088   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3089 }
3090
3091 //=======================================================================
3092 //function : getClosestUV
3093 //purpose  : return UV of closest projection
3094 //=======================================================================
3095
3096 static bool getClosestUV (Extrema_GenExtPS& projector,
3097                           const gp_Pnt&     point,
3098                           gp_XY &           result)
3099 {
3100   projector.Perform( point );
3101   if ( projector.IsDone() ) {
3102     double u, v, minVal = DBL_MAX;
3103     for ( int i = projector.NbExt(); i > 0; i-- )
3104 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3105       if ( projector.SquareDistance( i ) < minVal ) {
3106         minVal = projector.SquareDistance( i );
3107 #else
3108       if ( projector.Value( i ) < minVal ) {
3109         minVal = projector.Value( i );
3110 #endif
3111         projector.Point( i ).Parameter( u, v );
3112       }
3113     result.SetCoord( u, v );
3114     return true;
3115   }
3116   return false;
3117 }
3118
3119 //=======================================================================
3120 //function : Smooth
3121 //purpose  : Smooth theElements during theNbIterations or until a worst
3122 //           element has aspect ratio <= theTgtAspectRatio.
3123 //           Aspect Ratio varies in range [1.0, inf].
3124 //           If theElements is empty, the whole mesh is smoothed.
3125 //           theFixedNodes contains additionally fixed nodes. Nodes built
3126 //           on edges and boundary nodes are always fixed.
3127 //=======================================================================
3128
3129 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3130                                set<const SMDS_MeshNode*> & theFixedNodes,
3131                                const SmoothMethod          theSmoothMethod,
3132                                const int                   theNbIterations,
3133                                double                      theTgtAspectRatio,
3134                                const bool                  the2D)
3135 {
3136   myLastCreatedElems.Clear();
3137   myLastCreatedNodes.Clear();
3138
3139   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3140
3141   if ( theTgtAspectRatio < 1.0 )
3142     theTgtAspectRatio = 1.0;
3143
3144   const double disttol = 1.e-16;
3145
3146   SMESH::Controls::AspectRatio aQualityFunc;
3147
3148   SMESHDS_Mesh* aMesh = GetMeshDS();
3149
3150   if ( theElems.empty() ) {
3151     // add all faces to theElems
3152     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3153     while ( fIt->more() ) {
3154       const SMDS_MeshElement* face = fIt->next();
3155       theElems.insert( theElems.end(), face );
3156     }
3157   }
3158   // get all face ids theElems are on
3159   set< int > faceIdSet;
3160   TIDSortedElemSet::iterator itElem;
3161   if ( the2D )
3162     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3163       int fId = FindShape( *itElem );
3164       // check that corresponding submesh exists and a shape is face
3165       if (fId &&
3166           faceIdSet.find( fId ) == faceIdSet.end() &&
3167           aMesh->MeshElements( fId )) {
3168         TopoDS_Shape F = aMesh->IndexToShape( fId );
3169         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3170           faceIdSet.insert( fId );
3171       }
3172     }
3173   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3174
3175   // ===============================================
3176   // smooth elements on each TopoDS_Face separately
3177   // ===============================================
3178
3179   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3180   for ( ; fId != faceIdSet.rend(); ++fId ) {
3181     // get face surface and submesh
3182     Handle(Geom_Surface) surface;
3183     SMESHDS_SubMesh* faceSubMesh = 0;
3184     TopoDS_Face face;
3185     double fToler2 = 0, f,l;
3186     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3187     bool isUPeriodic = false, isVPeriodic = false;
3188     if ( *fId ) {
3189       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3190       surface = BRep_Tool::Surface( face );
3191       faceSubMesh = aMesh->MeshElements( *fId );
3192       fToler2 = BRep_Tool::Tolerance( face );
3193       fToler2 *= fToler2 * 10.;
3194       isUPeriodic = surface->IsUPeriodic();
3195       if ( isUPeriodic )
3196         surface->UPeriod();
3197       isVPeriodic = surface->IsVPeriodic();
3198       if ( isVPeriodic )
3199         surface->VPeriod();
3200       surface->Bounds( u1, u2, v1, v2 );
3201     }
3202     // ---------------------------------------------------------
3203     // for elements on a face, find movable and fixed nodes and
3204     // compute UV for them
3205     // ---------------------------------------------------------
3206     bool checkBoundaryNodes = false;
3207     bool isQuadratic = false;
3208     set<const SMDS_MeshNode*> setMovableNodes;
3209     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3210     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3211     list< const SMDS_MeshElement* > elemsOnFace;
3212
3213     Extrema_GenExtPS projector;
3214     GeomAdaptor_Surface surfAdaptor;
3215     if ( !surface.IsNull() ) {
3216       surfAdaptor.Load( surface );
3217       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3218     }
3219     int nbElemOnFace = 0;
3220     itElem = theElems.begin();
3221     // loop on not yet smoothed elements: look for elems on a face
3222     while ( itElem != theElems.end() ) {
3223       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3224         break; // all elements found
3225
3226       const SMDS_MeshElement* elem = *itElem;
3227       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3228            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3229         ++itElem;
3230         continue;
3231       }
3232       elemsOnFace.push_back( elem );
3233       theElems.erase( itElem++ );
3234       nbElemOnFace++;
3235
3236       if ( !isQuadratic )
3237         isQuadratic = elem->IsQuadratic();
3238
3239       // get movable nodes of elem
3240       const SMDS_MeshNode* node;
3241       SMDS_TypeOfPosition posType;
3242       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3243       int nn = 0, nbn =  elem->NbNodes();
3244       if(elem->IsQuadratic())
3245         nbn = nbn/2;
3246       while ( nn++ < nbn ) {
3247         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3248         const SMDS_PositionPtr& pos = node->GetPosition();
3249         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3250         if (posType != SMDS_TOP_EDGE &&
3251             posType != SMDS_TOP_VERTEX &&
3252             theFixedNodes.find( node ) == theFixedNodes.end())
3253         {
3254           // check if all faces around the node are on faceSubMesh
3255           // because a node on edge may be bound to face
3256           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3257           bool all = true;
3258           if ( faceSubMesh ) {
3259             while ( eIt->more() && all ) {
3260               const SMDS_MeshElement* e = eIt->next();
3261               all = faceSubMesh->Contains( e );
3262             }
3263           }
3264           if ( all )
3265             setMovableNodes.insert( node );
3266           else
3267             checkBoundaryNodes = true;
3268         }
3269         if ( posType == SMDS_TOP_3DSPACE )
3270           checkBoundaryNodes = true;
3271       }
3272
3273       if ( surface.IsNull() )
3274         continue;
3275
3276       // get nodes to check UV
3277       list< const SMDS_MeshNode* > uvCheckNodes;
3278       itN = elem->nodesIterator();
3279       nn = 0; nbn =  elem->NbNodes();
3280       if(elem->IsQuadratic())
3281         nbn = nbn/2;
3282       while ( nn++ < nbn ) {
3283         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3284         if ( uvMap.find( node ) == uvMap.end() )
3285           uvCheckNodes.push_back( node );
3286         // add nodes of elems sharing node
3287         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3288         //         while ( eIt->more() ) {
3289         //           const SMDS_MeshElement* e = eIt->next();
3290         //           if ( e != elem ) {
3291         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3292         //             while ( nIt->more() ) {
3293         //               const SMDS_MeshNode* n =
3294         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3295         //               if ( uvMap.find( n ) == uvMap.end() )
3296         //                 uvCheckNodes.push_back( n );
3297         //             }
3298         //           }
3299         //         }
3300       }
3301       // check UV on face
3302       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3303       for ( ; n != uvCheckNodes.end(); ++n ) {
3304         node = *n;
3305         gp_XY uv( 0, 0 );
3306         const SMDS_PositionPtr& pos = node->GetPosition();
3307         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3308         // get existing UV
3309         switch ( posType ) {
3310         case SMDS_TOP_FACE: {
3311           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3312           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3313           break;
3314         }
3315         case SMDS_TOP_EDGE: {
3316           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3317           Handle(Geom2d_Curve) pcurve;
3318           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3319             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3320           if ( !pcurve.IsNull() ) {
3321             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3322             uv = pcurve->Value( u ).XY();
3323           }
3324           break;
3325         }
3326         case SMDS_TOP_VERTEX: {
3327           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3328           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3329             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3330           break;
3331         }
3332         default:;
3333         }
3334         // check existing UV
3335         bool project = true;
3336         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3337         double dist1 = DBL_MAX, dist2 = 0;
3338         if ( posType != SMDS_TOP_3DSPACE ) {
3339           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3340           project = dist1 > fToler2;
3341         }
3342         if ( project ) { // compute new UV
3343           gp_XY newUV;
3344           if ( !getClosestUV( projector, pNode, newUV )) {
3345             MESSAGE("Node Projection Failed " << node);
3346           }
3347           else {
3348             if ( isUPeriodic )
3349               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3350             if ( isVPeriodic )
3351               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3352             // check new UV
3353             if ( posType != SMDS_TOP_3DSPACE )
3354               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3355             if ( dist2 < dist1 )
3356               uv = newUV;
3357           }
3358         }
3359         // store UV in the map
3360         listUV.push_back( uv );
3361         uvMap.insert( make_pair( node, &listUV.back() ));
3362       }
3363     } // loop on not yet smoothed elements
3364
3365     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3366       checkBoundaryNodes = true;
3367
3368     // fix nodes on mesh boundary
3369
3370     if ( checkBoundaryNodes ) {
3371       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3372       map< SMESH_TLink, int >::iterator link_nb;
3373       // put all elements links to linkNbMap
3374       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3375       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3376         const SMDS_MeshElement* elem = (*elemIt);
3377         int nbn =  elem->NbCornerNodes();
3378         // loop on elem links: insert them in linkNbMap
3379         for ( int iN = 0; iN < nbn; ++iN ) {
3380           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3381           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3382           SMESH_TLink link( n1, n2 );
3383           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3384           link_nb->second++;
3385         }
3386       }
3387       // remove nodes that are in links encountered only once from setMovableNodes
3388       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3389         if ( link_nb->second == 1 ) {
3390           setMovableNodes.erase( link_nb->first.node1() );
3391           setMovableNodes.erase( link_nb->first.node2() );
3392         }
3393       }
3394     }
3395
3396     // -----------------------------------------------------
3397     // for nodes on seam edge, compute one more UV ( uvMap2 );
3398     // find movable nodes linked to nodes on seam and which
3399     // are to be smoothed using the second UV ( uvMap2 )
3400     // -----------------------------------------------------
3401
3402     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3403     if ( !surface.IsNull() ) {
3404       TopExp_Explorer eExp( face, TopAbs_EDGE );
3405       for ( ; eExp.More(); eExp.Next() ) {
3406         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3407         if ( !BRep_Tool::IsClosed( edge, face ))
3408           continue;
3409         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3410         if ( !sm ) continue;
3411         // find out which parameter varies for a node on seam
3412         double f,l;
3413         gp_Pnt2d uv1, uv2;
3414         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3415         if ( pcurve.IsNull() ) continue;
3416         uv1 = pcurve->Value( f );
3417         edge.Reverse();
3418         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3419         if ( pcurve.IsNull() ) continue;
3420         uv2 = pcurve->Value( f );
3421         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3422         // assure uv1 < uv2
3423         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3424           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3425         }
3426         // get nodes on seam and its vertices
3427         list< const SMDS_MeshNode* > seamNodes;
3428         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3429         while ( nSeamIt->more() ) {
3430           const SMDS_MeshNode* node = nSeamIt->next();
3431           if ( !isQuadratic || !IsMedium( node ))
3432             seamNodes.push_back( node );
3433         }
3434         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3435         for ( ; vExp.More(); vExp.Next() ) {
3436           sm = aMesh->MeshElements( vExp.Current() );
3437           if ( sm ) {
3438             nSeamIt = sm->GetNodes();
3439             while ( nSeamIt->more() )
3440               seamNodes.push_back( nSeamIt->next() );
3441           }
3442         }
3443         // loop on nodes on seam
3444         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3445         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3446           const SMDS_MeshNode* nSeam = *noSeIt;
3447           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3448           if ( n_uv == uvMap.end() )
3449             continue;
3450           // set the first UV
3451           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3452           // set the second UV
3453           listUV.push_back( *n_uv->second );
3454           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3455           if ( uvMap2.empty() )
3456             uvMap2 = uvMap; // copy the uvMap contents
3457           uvMap2[ nSeam ] = &listUV.back();
3458
3459           // collect movable nodes linked to ones on seam in nodesNearSeam
3460           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3461           while ( eIt->more() ) {
3462             const SMDS_MeshElement* e = eIt->next();
3463             int nbUseMap1 = 0, nbUseMap2 = 0;
3464             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3465             int nn = 0, nbn =  e->NbNodes();
3466             if(e->IsQuadratic()) nbn = nbn/2;
3467             while ( nn++ < nbn )
3468             {
3469               const SMDS_MeshNode* n =
3470                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3471               if (n == nSeam ||
3472                   setMovableNodes.find( n ) == setMovableNodes.end() )
3473                 continue;
3474               // add only nodes being closer to uv2 than to uv1
3475               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3476                            0.5 * ( n->Y() + nSeam->Y() ),
3477                            0.5 * ( n->Z() + nSeam->Z() ));
3478               gp_XY uv;
3479               getClosestUV( projector, pMid, uv );
3480               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3481                 nodesNearSeam.insert( n );
3482                 nbUseMap2++;
3483               }
3484               else
3485                 nbUseMap1++;
3486             }
3487             // for centroidalSmooth all element nodes must
3488             // be on one side of a seam
3489             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3490               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3491               nn = 0;
3492               while ( nn++ < nbn ) {
3493                 const SMDS_MeshNode* n =
3494                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3495                 setMovableNodes.erase( n );
3496               }
3497             }
3498           }
3499         } // loop on nodes on seam
3500       } // loop on edge of a face
3501     } // if ( !face.IsNull() )
3502
3503     if ( setMovableNodes.empty() ) {
3504       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3505       continue; // goto next face
3506     }
3507
3508     // -------------
3509     // SMOOTHING //
3510     // -------------
3511
3512     int it = -1;
3513     double maxRatio = -1., maxDisplacement = -1.;
3514     set<const SMDS_MeshNode*>::iterator nodeToMove;
3515     for ( it = 0; it < theNbIterations; it++ ) {
3516       maxDisplacement = 0.;
3517       nodeToMove = setMovableNodes.begin();
3518       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3519         const SMDS_MeshNode* node = (*nodeToMove);
3520         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3521
3522         // smooth
3523         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3524         if ( theSmoothMethod == LAPLACIAN )
3525           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3526         else
3527           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3528
3529         // node displacement
3530         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3531         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3532         if ( aDispl > maxDisplacement )
3533           maxDisplacement = aDispl;
3534       }
3535       // no node movement => exit
3536       //if ( maxDisplacement < 1.e-16 ) {
3537       if ( maxDisplacement < disttol ) {
3538         MESSAGE("-- no node movement --");
3539         break;
3540       }
3541
3542       // check elements quality
3543       maxRatio  = 0;
3544       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3545       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3546         const SMDS_MeshElement* elem = (*elemIt);
3547         if ( !elem || elem->GetType() != SMDSAbs_Face )
3548           continue;
3549         SMESH::Controls::TSequenceOfXYZ aPoints;
3550         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3551           double aValue = aQualityFunc.GetValue( aPoints );
3552           if ( aValue > maxRatio )
3553             maxRatio = aValue;
3554         }
3555       }
3556       if ( maxRatio <= theTgtAspectRatio ) {
3557         MESSAGE("-- quality achived --");
3558         break;
3559       }
3560       if (it+1 == theNbIterations) {
3561         MESSAGE("-- Iteration limit exceeded --");
3562       }
3563     } // smoothing iterations
3564
3565     MESSAGE(" Face id: " << *fId <<
3566             " Nb iterstions: " << it <<
3567             " Displacement: " << maxDisplacement <<
3568             " Aspect Ratio " << maxRatio);
3569
3570     // ---------------------------------------
3571     // new nodes positions are computed,
3572     // record movement in DS and set new UV
3573     // ---------------------------------------
3574     nodeToMove = setMovableNodes.begin();
3575     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3576       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3577       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3578       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3579       if ( node_uv != uvMap.end() ) {
3580         gp_XY* uv = node_uv->second;
3581         node->SetPosition
3582           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3583       }
3584     }
3585
3586     // move medium nodes of quadratic elements
3587     if ( isQuadratic )
3588     {
3589       SMESH_MesherHelper helper( *GetMesh() );
3590       if ( !face.IsNull() )
3591         helper.SetSubShape( face );
3592       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3593       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3594         const SMDS_VtkFace* QF =
3595           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3596         if(QF && QF->IsQuadratic()) {
3597           vector<const SMDS_MeshNode*> Ns;
3598           Ns.reserve(QF->NbNodes()+1);
3599           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3600           while ( anIter->more() )
3601             Ns.push_back( cast2Node(anIter->next()) );
3602           Ns.push_back( Ns[0] );
3603           double x, y, z;
3604           for(int i=0; i<QF->NbNodes(); i=i+2) {
3605             if ( !surface.IsNull() ) {
3606               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3607               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3608               gp_XY uv = ( uv1 + uv2 ) / 2.;
3609               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3610               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3611             }
3612             else {
3613               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3614               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3615               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3616             }
3617             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3618                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3619                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3620               // we have to move i+1 node
3621               aMesh->MoveNode( Ns[i+1], x, y, z );
3622             }
3623           }
3624         }
3625       }
3626     }
3627
3628   } // loop on face ids
3629
3630 }
3631
3632 //=======================================================================
3633 //function : isReverse
3634 //purpose  : Return true if normal of prevNodes is not co-directied with
3635 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3636 //           iNotSame is where prevNodes and nextNodes are different.
3637 //           If result is true then future volume orientation is OK
3638 //=======================================================================
3639
3640 static bool isReverse(const SMDS_MeshElement*             face,
3641                       const vector<const SMDS_MeshNode*>& prevNodes,
3642                       const vector<const SMDS_MeshNode*>& nextNodes,
3643                       const int                           iNotSame)
3644 {
3645
3646   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3647   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3648   gp_XYZ extrDir( pN - pP ), faceNorm;
3649   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3650
3651   return faceNorm * extrDir < 0.0;
3652 }
3653
3654 //=======================================================================
3655 /*!
3656  * \brief Create elements by sweeping an element
3657  * \param elem - element to sweep
3658  * \param newNodesItVec - nodes generated from each node of the element
3659  * \param newElems - generated elements
3660  * \param nbSteps - number of sweeping steps
3661  * \param srcElements - to append elem for each generated element
3662  */
3663 //=======================================================================
3664
3665 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3666                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3667                                     list<const SMDS_MeshElement*>&        newElems,
3668                                     const int                             nbSteps,
3669                                     SMESH_SequenceOfElemPtr&              srcElements)
3670 {
3671   //MESSAGE("sweepElement " << nbSteps);
3672   SMESHDS_Mesh* aMesh = GetMeshDS();
3673
3674   const int           nbNodes = elem->NbNodes();
3675   const int         nbCorners = elem->NbCornerNodes();
3676   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
3677                                                           polyhedron creation !!! */
3678   // Loop on elem nodes:
3679   // find new nodes and detect same nodes indices
3680   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3681   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3682   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3683   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3684
3685   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3686   vector<int> sames(nbNodes);
3687   vector<bool> isSingleNode(nbNodes);
3688
3689   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3690     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3691     const SMDS_MeshNode*                         node = nnIt->first;
3692     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3693     if ( listNewNodes.empty() )
3694       return;
3695
3696     itNN   [ iNode ] = listNewNodes.begin();
3697     prevNod[ iNode ] = node;
3698     nextNod[ iNode ] = listNewNodes.front();
3699
3700     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3701                                                              corner node of linear */
3702     if ( prevNod[ iNode ] != nextNod [ iNode ])
3703       nbDouble += !isSingleNode[iNode];
3704
3705     if( iNode < nbCorners ) { // check corners only
3706       if ( prevNod[ iNode ] == nextNod [ iNode ])
3707         sames[nbSame++] = iNode;
3708       else
3709         iNotSameNode = iNode;
3710     }
3711   }
3712
3713   if ( nbSame == nbNodes || nbSame > 2) {
3714     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3715     return;
3716   }
3717
3718   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3719   {
3720     // fix nodes order to have bottom normal external
3721     if ( baseType == SMDSEntity_Polygon )
3722     {
3723       std::reverse( itNN.begin(), itNN.end() );
3724       std::reverse( prevNod.begin(), prevNod.end() );
3725       std::reverse( midlNod.begin(), midlNod.end() );
3726       std::reverse( nextNod.begin(), nextNod.end() );
3727       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3728     }
3729     else
3730     {
3731       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3732       SMDS_MeshCell::applyInterlace( ind, itNN );
3733       SMDS_MeshCell::applyInterlace( ind, prevNod );
3734       SMDS_MeshCell::applyInterlace( ind, nextNod );
3735       SMDS_MeshCell::applyInterlace( ind, midlNod );
3736       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3737       if ( nbSame > 0 )
3738       {
3739         sames[nbSame] = iNotSameNode;
3740         for ( int j = 0; j <= nbSame; ++j )
3741           for ( size_t i = 0; i < ind.size(); ++i )
3742             if ( ind[i] == sames[j] )
3743             {
3744               sames[j] = i;
3745               break;
3746             }
3747         iNotSameNode = sames[nbSame];
3748       }
3749     }
3750   }
3751
3752   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3753   if ( nbSame > 0 ) {
3754     iSameNode    = sames[ nbSame-1 ];
3755     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3756     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3757     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3758   }
3759
3760   // make new elements
3761   for (int iStep = 0; iStep < nbSteps; iStep++ )
3762   {
3763     // get next nodes
3764     for ( iNode = 0; iNode < nbNodes; iNode++ )
3765     {
3766       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3767       nextNod[ iNode ] = *itNN[ iNode ]++;
3768     }
3769
3770     SMDS_MeshElement* aNewElem = 0;
3771     /*if(!elem->IsPoly())*/ {
3772       switch ( baseType ) {
3773       case SMDSEntity_0D:
3774       case SMDSEntity_Node: { // sweep NODE
3775         if ( nbSame == 0 ) {
3776           if ( isSingleNode[0] )
3777             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3778           else
3779             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3780         }
3781         else
3782           return;
3783         break;
3784       }
3785       case SMDSEntity_Edge: { // sweep EDGE
3786         if ( nbDouble == 0 )
3787         {
3788           if ( nbSame == 0 ) // ---> quadrangle
3789             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3790                                       nextNod[ 1 ], nextNod[ 0 ] );
3791           else               // ---> triangle
3792             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3793                                       nextNod[ iNotSameNode ] );
3794         }
3795         else                 // ---> polygon
3796         {
3797           vector<const SMDS_MeshNode*> poly_nodes;
3798           poly_nodes.push_back( prevNod[0] );
3799           poly_nodes.push_back( prevNod[1] );
3800           if ( prevNod[1] != nextNod[1] )
3801           {
3802             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3803             poly_nodes.push_back( nextNod[1] );
3804           }
3805           if ( prevNod[0] != nextNod[0] )
3806           {
3807             poly_nodes.push_back( nextNod[0] );
3808             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3809           }
3810           switch ( poly_nodes.size() ) {
3811           case 3:
3812             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3813             break;
3814           case 4:
3815             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3816                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3817             break;
3818           default:
3819             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3820           }
3821         }
3822         break;
3823       }
3824       case SMDSEntity_Triangle: // TRIANGLE --->
3825         {
3826           if ( nbDouble > 0 ) break;
3827           if ( nbSame == 0 )       // ---> pentahedron
3828             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3829                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3830
3831           else if ( nbSame == 1 )  // ---> pyramid
3832             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3833                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3834                                          nextNod[ iSameNode ]);
3835
3836           else // 2 same nodes:       ---> tetrahedron
3837             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3838                                          nextNod[ iNotSameNode ]);
3839           break;
3840         }
3841       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3842         {
3843           if ( nbSame == 2 )
3844             return;
3845           if ( nbDouble+nbSame == 2 )
3846           {
3847             if(nbSame==0) {      // ---> quadratic quadrangle
3848               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3849                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3850             }
3851             else { //(nbSame==1) // ---> quadratic triangle
3852               if(sames[0]==2) {
3853                 return; // medium node on axis
3854               }
3855               else if(sames[0]==0)
3856                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3857                                           nextNod[2], midlNod[1], prevNod[2]);
3858               else // sames[0]==1
3859                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3860                                           midlNod[0], nextNod[2], prevNod[2]);
3861             }
3862           }
3863           else if ( nbDouble == 3 )
3864           {
3865             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3866               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3867                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3868             }
3869           }
3870           else
3871             return;
3872           break;
3873         }
3874       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3875         if ( nbDouble > 0 ) break;
3876
3877         if ( nbSame == 0 )       // ---> hexahedron
3878           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3879                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3880
3881         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3882           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3883                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3884                                        nextNod[ iSameNode ]);
3885           newElems.push_back( aNewElem );
3886           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3887                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3888                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3889         }
3890         else if ( nbSame == 2 ) { // ---> pentahedron
3891           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3892             // iBeforeSame is same too
3893             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3894                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3895                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3896           else
3897             // iAfterSame is same too
3898             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3899                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3900                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3901         }
3902         break;
3903       }
3904       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3905         if ( nbDouble+nbSame != 3 ) break;
3906         if(nbSame==0) {
3907           // --->  pentahedron with 15 nodes
3908           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3909                                        nextNod[0], nextNod[1], nextNod[2],
3910                                        prevNod[3], prevNod[4], prevNod[5],
3911                                        nextNod[3], nextNod[4], nextNod[5],
3912                                        midlNod[0], midlNod[1], midlNod[2]);
3913         }
3914         else if(nbSame==1) {
3915           // --->  2d order pyramid of 13 nodes
3916           int apex = iSameNode;
3917           int i0 = ( apex + 1 ) % nbCorners;
3918           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3919           int i0a = apex + 3;
3920           int i1a = i1 + 3;
3921           int i01 = i0 + 3;
3922           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3923                                       nextNod[i0], nextNod[i1], prevNod[apex],
3924                                       prevNod[i01], midlNod[i0],
3925                                       nextNod[i01], midlNod[i1],
3926                                       prevNod[i1a], prevNod[i0a],
3927                                       nextNod[i0a], nextNod[i1a]);
3928         }
3929         else if(nbSame==2) {
3930           // --->  2d order tetrahedron of 10 nodes
3931           int n1 = iNotSameNode;
3932           int n2 = ( n1 + 1             ) % nbCorners;
3933           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3934           int n12 = n1 + 3;
3935           int n23 = n2 + 3;
3936           int n31 = n3 + 3;
3937           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3938                                        prevNod[n12], prevNod[n23], prevNod[n31],
3939                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3940         }
3941         break;
3942       }
3943       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3944         if( nbSame == 0 ) {
3945           if ( nbDouble != 4 ) break;
3946           // --->  hexahedron with 20 nodes
3947           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3948                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3949                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3950                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3951                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3952         }
3953         else if(nbSame==1) {
3954           // ---> pyramid + pentahedron - can not be created since it is needed
3955           // additional middle node at the center of face
3956           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3957           return;
3958         }
3959         else if( nbSame == 2 ) {
3960           if ( nbDouble != 2 ) break;
3961           // --->  2d order Pentahedron with 15 nodes
3962           int n1,n2,n4,n5;
3963           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3964             // iBeforeSame is same too
3965             n1 = iBeforeSame;
3966             n2 = iOpposSame;
3967             n4 = iSameNode;
3968             n5 = iAfterSame;
3969           }
3970           else {
3971             // iAfterSame is same too
3972             n1 = iSameNode;
3973             n2 = iBeforeSame;
3974             n4 = iAfterSame;
3975             n5 = iOpposSame;
3976           }
3977           int n12 = n2 + 4;
3978           int n45 = n4 + 4;
3979           int n14 = n1 + 4;
3980           int n25 = n5 + 4;
3981           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3982                                        prevNod[n4], prevNod[n5], nextNod[n5],
3983                                        prevNod[n12], midlNod[n2], nextNod[n12],
3984                                        prevNod[n45], midlNod[n5], nextNod[n45],
3985                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3986         }
3987         break;
3988       }
3989       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3990
3991         if( nbSame == 0 && nbDouble == 9 ) {
3992           // --->  tri-quadratic hexahedron with 27 nodes
3993           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3994                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3995                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3996                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3997                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3998                                        prevNod[8], // bottom center
3999                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
4000                                        nextNod[8], // top center
4001                                        midlNod[8]);// elem center
4002         }
4003         else
4004         {
4005           return;
4006         }
4007         break;
4008       }
4009       case SMDSEntity_Polygon: { // sweep POLYGON
4010
4011         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
4012           // --->  hexagonal prism
4013           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4014                                        prevNod[3], prevNod[4], prevNod[5],
4015                                        nextNod[0], nextNod[1], nextNod[2],
4016                                        nextNod[3], nextNod[4], nextNod[5]);
4017         }
4018         break;
4019       }
4020       case SMDSEntity_Ball:
4021         return;
4022
4023       default:
4024         break;
4025       }
4026     }
4027
4028     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
4029     {
4030       if ( baseType != SMDSEntity_Polygon )
4031       {
4032         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
4033         SMDS_MeshCell::applyInterlace( ind, prevNod );
4034         SMDS_MeshCell::applyInterlace( ind, nextNod );
4035         SMDS_MeshCell::applyInterlace( ind, midlNod );
4036         SMDS_MeshCell::applyInterlace( ind, itNN );
4037         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4038         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
4039       }
4040       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
4041       vector<int> quantities (nbNodes + 2);
4042       polyedre_nodes.clear();
4043       quantities.clear();
4044
4045       // bottom of prism
4046       for (int inode = 0; inode < nbNodes; inode++)
4047         polyedre_nodes.push_back( prevNod[inode] );
4048       quantities.push_back( nbNodes );
4049
4050       // top of prism
4051       polyedre_nodes.push_back( nextNod[0] );
4052       for (int inode = nbNodes; inode-1; --inode )
4053         polyedre_nodes.push_back( nextNod[inode-1] );
4054       quantities.push_back( nbNodes );
4055
4056       // side faces
4057       for (int iface = 0; iface < nbNodes; iface++)
4058       {
4059         const int prevNbNodes = polyedre_nodes.size();
4060         int inextface = (iface+1) % nbNodes;
4061         polyedre_nodes.push_back( prevNod[inextface] );
4062         polyedre_nodes.push_back( prevNod[iface] );
4063         if ( prevNod[iface] != nextNod[iface] )
4064         {
4065           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
4066           polyedre_nodes.push_back( nextNod[iface] );
4067         }
4068         if ( prevNod[inextface] != nextNod[inextface] )
4069         {
4070           polyedre_nodes.push_back( nextNod[inextface] );
4071           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
4072         }
4073         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4074         if ( nbFaceNodes > 2 )
4075           quantities.push_back( nbFaceNodes );
4076         else // degenerated face
4077           polyedre_nodes.resize( prevNbNodes );
4078       }
4079       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4080     }
4081
4082     if ( aNewElem ) {
4083       newElems.push_back( aNewElem );
4084       myLastCreatedElems.Append(aNewElem);
4085       srcElements.Append( elem );
4086     }
4087
4088     // set new prev nodes
4089     for ( iNode = 0; iNode < nbNodes; iNode++ )
4090       prevNod[ iNode ] = nextNod[ iNode ];
4091
4092   } // for steps
4093 }
4094
4095 //=======================================================================
4096 /*!
4097  * \brief Create 1D and 2D elements around swept elements
4098  * \param mapNewNodes - source nodes and ones generated from them
4099  * \param newElemsMap - source elements and ones generated from them
4100  * \param elemNewNodesMap - nodes generated from each node of each element
4101  * \param elemSet - all swept elements
4102  * \param nbSteps - number of sweeping steps
4103  * \param srcElements - to append elem for each generated element
4104  */
4105 //=======================================================================
4106
4107 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4108                                   TElemOfElemListMap &     newElemsMap,
4109                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4110                                   TIDSortedElemSet&        elemSet,
4111                                   const int                nbSteps,
4112                                   SMESH_SequenceOfElemPtr& srcElements)
4113 {
4114   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4115   SMESHDS_Mesh* aMesh = GetMeshDS();
4116
4117   // Find nodes belonging to only one initial element - sweep them to get edges.
4118
4119   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4120   for ( ; nList != mapNewNodes.end(); nList++ )
4121   {
4122     const SMDS_MeshNode* node =
4123       static_cast<const SMDS_MeshNode*>( nList->first );
4124     if ( newElemsMap.count( node ))
4125       continue; // node was extruded into edge
4126     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4127     int nbInitElems = 0;
4128     const SMDS_MeshElement* el = 0;
4129     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4130     while ( eIt->more() && nbInitElems < 2 ) {
4131       el = eIt->next();
4132       SMDSAbs_ElementType type = el->GetType();
4133       if ( type == SMDSAbs_Volume || type < highType ) continue;
4134       if ( type > highType ) {
4135         nbInitElems = 0;
4136         highType = type;
4137       }
4138       nbInitElems += elemSet.count(el);
4139     }
4140     if ( nbInitElems < 2 ) {
4141       bool NotCreateEdge = el && el->IsMediumNode(node);
4142       if(!NotCreateEdge) {
4143         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4144         list<const SMDS_MeshElement*> newEdges;
4145         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4146       }
4147     }
4148   }
4149
4150   // Make a ceiling for each element ie an equal element of last new nodes.
4151   // Find free links of faces - make edges and sweep them into faces.
4152
4153   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
4154   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4155   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4156   {
4157     const SMDS_MeshElement* elem = itElem->first;
4158     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4159
4160     if(itElem->second.size()==0) continue;
4161
4162     const bool isQuadratic = elem->IsQuadratic();
4163
4164     if ( elem->GetType() == SMDSAbs_Edge ) {
4165       // create a ceiling edge
4166       if ( !isQuadratic ) {
4167         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4168                                vecNewNodes[ 1 ]->second.back())) {
4169           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4170                                                    vecNewNodes[ 1 ]->second.back()));
4171           srcElements.Append( elem );
4172         }
4173       }
4174       else {
4175         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4176                                vecNewNodes[ 1 ]->second.back(),
4177                                vecNewNodes[ 2 ]->second.back())) {
4178           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4179                                                    vecNewNodes[ 1 ]->second.back(),
4180                                                    vecNewNodes[ 2 ]->second.back()));
4181           srcElements.Append( elem );
4182         }
4183       }
4184     }
4185     if ( elem->GetType() != SMDSAbs_Face )
4186       continue;
4187
4188     bool hasFreeLinks = false;
4189
4190     TIDSortedElemSet avoidSet;
4191     avoidSet.insert( elem );
4192
4193     set<const SMDS_MeshNode*> aFaceLastNodes;
4194     int iNode, nbNodes = vecNewNodes.size();
4195     if ( !isQuadratic ) {
4196       // loop on the face nodes
4197       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4198         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4199         // look for free links of the face
4200         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4201         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4202         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4203         // check if a link n1-n2 is free
4204         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4205           hasFreeLinks = true;
4206           // make a new edge and a ceiling for a new edge
4207           const SMDS_MeshElement* edge;
4208           if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
4209             myLastCreatedElems.Append( edge = aMesh->AddEdge( n1, n2 )); // free link edge
4210             srcElements.Append( myLastCreatedElems.Last() );
4211           }
4212           n1 = vecNewNodes[ iNode ]->second.back();
4213           n2 = vecNewNodes[ iNext ]->second.back();
4214           if ( !aMesh->FindEdge( n1, n2 )) {
4215             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // new edge ceiling
4216             srcElements.Append( edge );
4217           }
4218         }
4219       }
4220     }
4221     else { // elem is quadratic face
4222       int nbn = nbNodes/2;
4223       for ( iNode = 0; iNode < nbn; iNode++ ) {
4224         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4225         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4226         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4227         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4228         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4229         // check if a link is free
4230         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4231              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4232              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4233           hasFreeLinks = true;
4234           // make an edge and a ceiling for a new edge
4235           // find medium node
4236           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4237             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4238             srcElements.Append( elem );
4239           }
4240           n1 = vecNewNodes[ iNode ]->second.back();
4241           n2 = vecNewNodes[ iNext ]->second.back();
4242           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4243           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4244             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4245             srcElements.Append( elem );
4246           }
4247         }
4248       }
4249       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4250         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4251       }
4252     }
4253
4254     // sweep free links into faces
4255
4256     if ( hasFreeLinks )  {
4257       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4258       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4259
4260       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4261       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4262         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4263         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4264       }
4265       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4266         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4267         std::advance( v, volNb );
4268         // find indices of free faces of a volume and their source edges
4269         list< int > freeInd;
4270         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4271         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4272         int iF, nbF = vTool.NbFaces();
4273         for ( iF = 0; iF < nbF; iF ++ ) {
4274           if (vTool.IsFreeFace( iF ) &&
4275               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4276               initNodeSet != faceNodeSet) // except an initial face
4277           {
4278             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4279               continue;
4280             freeInd.push_back( iF );
4281             // find source edge of a free face iF
4282             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4283             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4284             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4285                                    initNodeSet.begin(), initNodeSet.end(),
4286                                    commonNodes.begin());
4287             if ( (*v)->IsQuadratic() )
4288               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4289             else
4290               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4291 #ifdef _DEBUG_
4292             if ( !srcEdges.back() )
4293             {
4294               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4295                    << iF << " of volume #" << vTool.ID() << endl;
4296             }
4297 #endif
4298           }
4299         }
4300         if ( freeInd.empty() )
4301           continue;
4302
4303         // create faces for all steps;
4304         // if such a face has been already created by sweep of edge,
4305         // assure that its orientation is OK
4306         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4307           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4308           vTool.SetExternalNormal();
4309           const int nextShift = vTool.IsForward() ? +1 : -1;
4310           list< int >::iterator ind = freeInd.begin();
4311           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4312           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4313           {
4314             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4315             int nbn = vTool.NbFaceNodes( *ind );
4316             const SMDS_MeshElement * f = 0;
4317             if ( nbn == 3 )              ///// triangle
4318             {
4319               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4320               if ( !f ||
4321                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4322               {
4323                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4324                                                      nodes[ 1 ],
4325                                                      nodes[ 1 + nextShift ] };
4326                 if ( f )
4327                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4328                 else
4329                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4330                                                             newOrder[ 2 ] ));
4331               }
4332             }
4333             else if ( nbn == 4 )       ///// quadrangle
4334             {
4335               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4336               if ( !f ||
4337                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4338               {
4339                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4340                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4341                 if ( f )
4342                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4343                 else
4344                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4345                                                             newOrder[ 2 ], newOrder[ 3 ]));
4346               }
4347             }
4348             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4349             {
4350               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4351               if ( !f ||
4352                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4353               {
4354                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4355                                                      nodes[2],
4356                                                      nodes[2 + 2*nextShift],
4357                                                      nodes[3 - 2*nextShift],
4358                                                      nodes[3],
4359                                                      nodes[3 + 2*nextShift]};
4360                 if ( f )
4361                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4362                 else
4363                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4364                                                             newOrder[ 1 ],
4365                                                             newOrder[ 2 ],
4366                                                             newOrder[ 3 ],
4367                                                             newOrder[ 4 ],
4368                                                             newOrder[ 5 ] ));
4369               }
4370             }
4371             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4372             {
4373               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4374                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4375               if ( !f ||
4376                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4377               {
4378                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4379                                                      nodes[4 - 2*nextShift],
4380                                                      nodes[4],
4381                                                      nodes[4 + 2*nextShift],
4382                                                      nodes[1],
4383                                                      nodes[5 - 2*nextShift],
4384                                                      nodes[5],
4385                                                      nodes[5 + 2*nextShift] };
4386                 if ( f )
4387                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4388                 else
4389                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4390                                                            newOrder[ 2 ], newOrder[ 3 ],
4391                                                            newOrder[ 4 ], newOrder[ 5 ],
4392                                                            newOrder[ 6 ], newOrder[ 7 ]));
4393               }
4394             }
4395             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4396             {
4397               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4398                                       SMDSAbs_Face, /*noMedium=*/false);
4399               if ( !f ||
4400                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4401               {
4402                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4403                                                      nodes[4 - 2*nextShift],
4404                                                      nodes[4],
4405                                                      nodes[4 + 2*nextShift],
4406                                                      nodes[1],
4407                                                      nodes[5 - 2*nextShift],
4408                                                      nodes[5],
4409                                                      nodes[5 + 2*nextShift],
4410                                                      nodes[8] };
4411                 if ( f )
4412                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4413                 else
4414                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4415                                                            newOrder[ 2 ], newOrder[ 3 ],
4416                                                            newOrder[ 4 ], newOrder[ 5 ],
4417                                                            newOrder[ 6 ], newOrder[ 7 ],
4418                                                            newOrder[ 8 ]));
4419               }
4420             }
4421             else  //////// polygon
4422             {
4423               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4424               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4425               if ( !f ||
4426                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4427               {
4428                 if ( !vTool.IsForward() )
4429                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4430                 if ( f )
4431                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4432                 else
4433                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4434               }
4435             }
4436
4437             while ( srcElements.Length() < myLastCreatedElems.Length() )
4438               srcElements.Append( *srcEdge );
4439
4440           }  // loop on free faces
4441
4442           // go to the next volume
4443           iVol = 0;
4444           while ( iVol++ < nbVolumesByStep ) v++;
4445
4446         } // loop on steps
4447       } // loop on volumes of one step
4448     } // sweep free links into faces
4449
4450     // Make a ceiling face with a normal external to a volume
4451
4452     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4453
4454     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4455     if ( iF >= 0 ) {
4456       lastVol.SetExternalNormal();
4457       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4458       int nbn = lastVol.NbFaceNodes( iF );
4459       if ( nbn == 3 ) {
4460         if (!hasFreeLinks ||
4461             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4462           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4463       }
4464       else if ( nbn == 4 )
4465       {
4466         if (!hasFreeLinks ||
4467             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4468           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4469       }
4470       else if ( nbn == 6 && isQuadratic )
4471       {
4472         if (!hasFreeLinks ||
4473             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4474           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4475                                                    nodes[1], nodes[3], nodes[5]));
4476       }
4477       else if ( nbn == 8 && isQuadratic )
4478       {
4479         if (!hasFreeLinks ||
4480             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4481                              nodes[1], nodes[3], nodes[5], nodes[7]) )
4482           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4483                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
4484       }
4485       else if ( nbn == 9 && isQuadratic )
4486       {
4487         if (!hasFreeLinks ||
4488             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4489                                 SMDSAbs_Face, /*noMedium=*/false) )
4490           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4491                                                    nodes[1], nodes[3], nodes[5], nodes[7],
4492                                                    nodes[8]));
4493       }
4494       else {
4495         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4496         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4497           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4498       }
4499
4500       while ( srcElements.Length() < myLastCreatedElems.Length() )
4501         srcElements.Append( elem );
4502     }
4503   } // loop on swept elements
4504 }
4505
4506 //=======================================================================
4507 //function : RotationSweep
4508 //purpose  :
4509 //=======================================================================
4510
4511 SMESH_MeshEditor::PGroupIDs
4512 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4513                                 const gp_Ax1&      theAxis,
4514                                 const double       theAngle,
4515                                 const int          theNbSteps,
4516                                 const double       theTol,
4517                                 const bool         theMakeGroups,
4518                                 const bool         theMakeWalls)
4519 {
4520   myLastCreatedElems.Clear();
4521   myLastCreatedNodes.Clear();
4522
4523   // source elements for each generated one
4524   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4525
4526   MESSAGE( "RotationSweep()");
4527   gp_Trsf aTrsf;
4528   aTrsf.SetRotation( theAxis, theAngle );
4529   gp_Trsf aTrsf2;
4530   aTrsf2.SetRotation( theAxis, theAngle/2. );
4531
4532   gp_Lin aLine( theAxis );
4533   double aSqTol = theTol * theTol;
4534
4535   SMESHDS_Mesh* aMesh = GetMeshDS();
4536
4537   TNodeOfNodeListMap mapNewNodes;
4538   TElemOfVecOfNnlmiMap mapElemNewNodes;
4539   TElemOfElemListMap newElemsMap;
4540
4541   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4542                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4543                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4544   // loop on theElems
4545   TIDSortedElemSet::iterator itElem;
4546   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4547     const SMDS_MeshElement* elem = *itElem;
4548     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4549       continue;
4550     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4551     newNodesItVec.reserve( elem->NbNodes() );
4552
4553     // loop on elem nodes
4554     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4555     while ( itN->more() )
4556     {
4557       // check if a node has been already sweeped
4558       const SMDS_MeshNode* node = cast2Node( itN->next() );
4559
4560       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4561       double coord[3];
4562       aXYZ.Coord( coord[0], coord[1], coord[2] );
4563       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4564
4565       TNodeOfNodeListMapItr nIt =
4566         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4567       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4568       if ( listNewNodes.empty() )
4569       {
4570         // check if we are to create medium nodes between corner ones
4571         bool needMediumNodes = false;
4572         if ( isQuadraticMesh )
4573         {
4574           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4575           while (it->more() && !needMediumNodes )
4576           {
4577             const SMDS_MeshElement* invElem = it->next();
4578             if ( invElem != elem && !theElems.count( invElem )) continue;
4579             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4580             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4581               needMediumNodes = true;
4582           }
4583         }
4584
4585         // make new nodes
4586         const SMDS_MeshNode * newNode = node;
4587         for ( int i = 0; i < theNbSteps; i++ ) {
4588           if ( !isOnAxis ) {
4589             if ( needMediumNodes )  // create a medium node
4590             {
4591               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4592               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4593               myLastCreatedNodes.Append(newNode);
4594               srcNodes.Append( node );
4595               listNewNodes.push_back( newNode );
4596               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4597             }
4598             else {
4599               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4600             }
4601             // create a corner node
4602             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4603             myLastCreatedNodes.Append(newNode);
4604             srcNodes.Append( node );
4605             listNewNodes.push_back( newNode );
4606           }
4607           else {
4608             listNewNodes.push_back( newNode );
4609             // if ( needMediumNodes )
4610             //   listNewNodes.push_back( newNode );
4611           }
4612         }
4613       }
4614       newNodesItVec.push_back( nIt );
4615     }
4616     // make new elements
4617     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4618   }
4619
4620   if ( theMakeWalls )
4621     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4622
4623   PGroupIDs newGroupIDs;
4624   if ( theMakeGroups )
4625     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4626
4627   return newGroupIDs;
4628 }
4629
4630
4631 //=======================================================================
4632 //function : CreateNode
4633 //purpose  :
4634 //=======================================================================
4635 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4636                                                   const double y,
4637                                                   const double z,
4638                                                   const double tolnode,
4639                                                   SMESH_SequenceOfNode& aNodes)
4640 {
4641   // myLastCreatedElems.Clear();
4642   // myLastCreatedNodes.Clear();
4643
4644   gp_Pnt P1(x,y,z);
4645   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4646
4647   // try to search in sequence of existing nodes
4648   // if aNodes.Length()>0 we 'nave to use given sequence
4649   // else - use all nodes of mesh
4650   if(aNodes.Length()>0) {
4651     int i;
4652     for(i=1; i<=aNodes.Length(); i++) {
4653       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4654       if(P1.Distance(P2)<tolnode)
4655         return aNodes.Value(i);
4656     }
4657   }
4658   else {
4659     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4660     while(itn->more()) {
4661       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4662       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4663       if(P1.Distance(P2)<tolnode)
4664         return aN;
4665     }
4666   }
4667
4668   // create new node and return it
4669   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4670   //myLastCreatedNodes.Append(NewNode);
4671   return NewNode;
4672 }
4673
4674
4675 //=======================================================================
4676 //function : ExtrusionSweep
4677 //purpose  :
4678 //=======================================================================
4679
4680 SMESH_MeshEditor::PGroupIDs
4681 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4682                                   const gp_Vec&       theStep,
4683                                   const int           theNbSteps,
4684                                   TElemOfElemListMap& newElemsMap,
4685                                   const bool          theMakeGroups,
4686                                   const int           theFlags,
4687                                   const double        theTolerance)
4688 {
4689   ExtrusParam aParams;
4690   aParams.myDir = gp_Dir(theStep);
4691   aParams.myNodes.Clear();
4692   aParams.mySteps = new TColStd_HSequenceOfReal;
4693   int i;
4694   for(i=1; i<=theNbSteps; i++)
4695     aParams.mySteps->Append(theStep.Magnitude());
4696
4697   return
4698     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4699 }
4700
4701
4702 //=======================================================================
4703 //function : ExtrusionSweep
4704 //purpose  :
4705 //=======================================================================
4706
4707 SMESH_MeshEditor::PGroupIDs
4708 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4709                                   ExtrusParam&        theParams,
4710                                   TElemOfElemListMap& newElemsMap,
4711                                   const bool          theMakeGroups,
4712                                   const int           theFlags,
4713                                   const double        theTolerance)
4714 {
4715   myLastCreatedElems.Clear();
4716   myLastCreatedNodes.Clear();
4717
4718   // source elements for each generated one
4719   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4720
4721   SMESHDS_Mesh* aMesh = GetMeshDS();
4722
4723   int nbsteps = theParams.mySteps->Length();
4724
4725   TNodeOfNodeListMap mapNewNodes;
4726   //TNodeOfNodeVecMap mapNewNodes;
4727   TElemOfVecOfNnlmiMap mapElemNewNodes;
4728   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4729
4730   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4731                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4732                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4733   // loop on theElems
4734   TIDSortedElemSet::iterator itElem;
4735   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4736     // check element type
4737     const SMDS_MeshElement* elem = *itElem;
4738     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4739       continue;
4740
4741     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4742     newNodesItVec.reserve( elem->NbNodes() );
4743
4744     // loop on elem nodes
4745     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4746     while ( itN->more() )
4747     {
4748       // check if a node has been already sweeped
4749       const SMDS_MeshNode* node = cast2Node( itN->next() );
4750       TNodeOfNodeListMap::iterator nIt =
4751         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4752       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4753       if ( listNewNodes.empty() )
4754       {
4755         // make new nodes
4756
4757         // check if we are to create medium nodes between corner ones
4758         bool needMediumNodes = false;
4759         if ( isQuadraticMesh )
4760         {
4761           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4762           while (it->more() && !needMediumNodes )
4763           {
4764             const SMDS_MeshElement* invElem = it->next();
4765             if ( invElem != elem && !theElems.count( invElem )) continue;
4766             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4767             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4768               needMediumNodes = true;
4769           }
4770         }
4771
4772         double coord[] = { node->X(), node->Y(), node->Z() };
4773         for ( int i = 0; i < nbsteps; i++ )
4774         {
4775           if ( needMediumNodes ) // create a medium node
4776           {
4777             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4778             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4779             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4780             if( theFlags & EXTRUSION_FLAG_SEW ) {
4781               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4782                                                          theTolerance, theParams.myNodes);
4783               listNewNodes.push_back( newNode );
4784             }
4785             else {
4786               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4787               myLastCreatedNodes.Append(newNode);
4788               srcNodes.Append( node );
4789               listNewNodes.push_back( newNode );
4790             }
4791           }
4792           // create a corner node
4793           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4794           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4795           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4796           if( theFlags & EXTRUSION_FLAG_SEW ) {
4797             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4798                                                        theTolerance, theParams.myNodes);
4799             listNewNodes.push_back( newNode );
4800           }
4801           else {
4802             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4803             myLastCreatedNodes.Append(newNode);
4804             srcNodes.Append( node );
4805             listNewNodes.push_back( newNode );
4806           }
4807         }
4808       }
4809       newNodesItVec.push_back( nIt );
4810     }
4811     // make new elements
4812     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4813   }
4814
4815   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4816     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4817   }
4818   PGroupIDs newGroupIDs;
4819   if ( theMakeGroups )
4820     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4821
4822   return newGroupIDs;
4823 }
4824
4825 //=======================================================================
4826 //function : ExtrusionAlongTrack
4827 //purpose  :
4828 //=======================================================================
4829 SMESH_MeshEditor::Extrusion_Error
4830 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4831                                        SMESH_subMesh*       theTrack,
4832                                        const SMDS_MeshNode* theN1,
4833                                        const bool           theHasAngles,
4834                                        list<double>&        theAngles,
4835                                        const bool           theLinearVariation,
4836                                        const bool           theHasRefPoint,
4837                                        const gp_Pnt&        theRefPoint,
4838                                        const bool           theMakeGroups)
4839 {
4840   MESSAGE("ExtrusionAlongTrack");
4841   myLastCreatedElems.Clear();
4842   myLastCreatedNodes.Clear();
4843
4844   int aNbE;
4845   std::list<double> aPrms;
4846   TIDSortedElemSet::iterator itElem;
4847
4848   gp_XYZ aGC;
4849   TopoDS_Edge aTrackEdge;
4850   TopoDS_Vertex aV1, aV2;
4851
4852   SMDS_ElemIteratorPtr aItE;
4853   SMDS_NodeIteratorPtr aItN;
4854   SMDSAbs_ElementType aTypeE;
4855
4856   TNodeOfNodeListMap mapNewNodes;
4857
4858   // 1. Check data
4859   aNbE = theElements.size();
4860   // nothing to do
4861   if ( !aNbE )
4862     return EXTR_NO_ELEMENTS;
4863
4864   // 1.1 Track Pattern
4865   ASSERT( theTrack );
4866
4867   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4868
4869   aItE = pSubMeshDS->GetElements();
4870   while ( aItE->more() ) {
4871     const SMDS_MeshElement* pE = aItE->next();
4872     aTypeE = pE->GetType();
4873     // Pattern must contain links only
4874     if ( aTypeE != SMDSAbs_Edge )
4875       return EXTR_PATH_NOT_EDGE;
4876   }
4877
4878   list<SMESH_MeshEditor_PathPoint> fullList;
4879
4880   const TopoDS_Shape& aS = theTrack->GetSubShape();
4881   // Sub-shape for the Pattern must be an Edge or Wire
4882   if( aS.ShapeType() == TopAbs_EDGE ) {
4883     aTrackEdge = TopoDS::Edge( aS );
4884     // the Edge must not be degenerated
4885     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4886       return EXTR_BAD_PATH_SHAPE;
4887     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4888     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4889     const SMDS_MeshNode* aN1 = aItN->next();
4890     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4891     const SMDS_MeshNode* aN2 = aItN->next();
4892     // starting node must be aN1 or aN2
4893     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4894       return EXTR_BAD_STARTING_NODE;
4895     aItN = pSubMeshDS->GetNodes();
4896     while ( aItN->more() ) {
4897       const SMDS_MeshNode* pNode = aItN->next();
4898       const SMDS_EdgePosition* pEPos =
4899         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4900       double aT = pEPos->GetUParameter();
4901       aPrms.push_back( aT );
4902     }
4903     //Extrusion_Error err =
4904     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4905   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4906     list< SMESH_subMesh* > LSM;
4907     TopTools_SequenceOfShape Edges;
4908     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4909     while(itSM->more()) {
4910       SMESH_subMesh* SM = itSM->next();
4911       LSM.push_back(SM);
4912       const TopoDS_Shape& aS = SM->GetSubShape();
4913       Edges.Append(aS);
4914     }
4915     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4916     int startNid = theN1->GetID();
4917     TColStd_MapOfInteger UsedNums;
4918
4919     int NbEdges = Edges.Length();
4920     int i = 1;
4921     for(; i<=NbEdges; i++) {
4922       int k = 0;
4923       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4924       for(; itLSM!=LSM.end(); itLSM++) {
4925         k++;
4926         if(UsedNums.Contains(k)) continue;
4927         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4928         SMESH_subMesh* locTrack = *itLSM;
4929         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4930         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4931         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4932         const SMDS_MeshNode* aN1 = aItN->next();
4933         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4934         const SMDS_MeshNode* aN2 = aItN->next();
4935         // starting node must be aN1 or aN2
4936         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4937         // 2. Collect parameters on the track edge
4938         aPrms.clear();
4939         aItN = locMeshDS->GetNodes();
4940         while ( aItN->more() ) {
4941           const SMDS_MeshNode* pNode = aItN->next();
4942           const SMDS_EdgePosition* pEPos =
4943             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4944           double aT = pEPos->GetUParameter();
4945           aPrms.push_back( aT );
4946         }
4947         list<SMESH_MeshEditor_PathPoint> LPP;
4948         //Extrusion_Error err =
4949         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4950         LLPPs.push_back(LPP);
4951         UsedNums.Add(k);
4952         // update startN for search following egde
4953         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4954         else startNid = aN1->GetID();
4955         break;
4956       }
4957     }
4958     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4959     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4960     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4961     for(; itPP!=firstList.end(); itPP++) {
4962       fullList.push_back( *itPP );
4963     }
4964     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4965     fullList.pop_back();
4966     itLLPP++;
4967     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4968       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4969       itPP = currList.begin();
4970       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4971       gp_Dir D1 = PP1.Tangent();
4972       gp_Dir D2 = PP2.Tangent();
4973       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4974                            (D1.Z()+D2.Z())/2 ) );
4975       PP1.SetTangent(Dnew);
4976       fullList.push_back(PP1);
4977       itPP++;
4978       for(; itPP!=firstList.end(); itPP++) {
4979         fullList.push_back( *itPP );
4980       }
4981       PP1 = fullList.back();
4982       fullList.pop_back();
4983     }
4984     // if wire not closed
4985     fullList.push_back(PP1);
4986     // else ???
4987   }
4988   else {
4989     return EXTR_BAD_PATH_SHAPE;
4990   }
4991
4992   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4993                           theHasRefPoint, theRefPoint, theMakeGroups);
4994 }
4995
4996
4997 //=======================================================================
4998 //function : ExtrusionAlongTrack
4999 //purpose  :
5000 //=======================================================================
5001 SMESH_MeshEditor::Extrusion_Error
5002 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
5003                                        SMESH_Mesh*          theTrack,
5004                                        const SMDS_MeshNode* theN1,
5005                                        const bool           theHasAngles,
5006                                        list<double>&        theAngles,
5007                                        const bool           theLinearVariation,
5008                                        const bool           theHasRefPoint,
5009                                        const gp_Pnt&        theRefPoint,
5010                                        const bool           theMakeGroups)
5011 {
5012   myLastCreatedElems.Clear();
5013   myLastCreatedNodes.Clear();
5014
5015   int aNbE;
5016   std::list<double> aPrms;
5017   TIDSortedElemSet::iterator itElem;
5018
5019   gp_XYZ aGC;
5020   TopoDS_Edge aTrackEdge;
5021   TopoDS_Vertex aV1, aV2;
5022
5023   SMDS_ElemIteratorPtr aItE;
5024   SMDS_NodeIteratorPtr aItN;
5025   SMDSAbs_ElementType aTypeE;
5026
5027   TNodeOfNodeListMap mapNewNodes;
5028
5029   // 1. Check data
5030   aNbE = theElements.size();
5031   // nothing to do
5032   if ( !aNbE )
5033     return EXTR_NO_ELEMENTS;
5034
5035   // 1.1 Track Pattern
5036   ASSERT( theTrack );
5037
5038   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
5039
5040   aItE = pMeshDS->elementsIterator();
5041   while ( aItE->more() ) {
5042     const SMDS_MeshElement* pE = aItE->next();
5043     aTypeE = pE->GetType();
5044     // Pattern must contain links only
5045     if ( aTypeE != SMDSAbs_Edge )
5046       return EXTR_PATH_NOT_EDGE;
5047   }
5048
5049   list<SMESH_MeshEditor_PathPoint> fullList;
5050
5051   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
5052
5053   if( aS == SMESH_Mesh::PseudoShape() ) {
5054     //Mesh without shape
5055     const SMDS_MeshNode* currentNode = NULL;
5056     const SMDS_MeshNode* prevNode = theN1;
5057     std::vector<const SMDS_MeshNode*> aNodesList;
5058     aNodesList.push_back(theN1);
5059     int nbEdges = 0, conn=0;
5060     const SMDS_MeshElement* prevElem = NULL;
5061     const SMDS_MeshElement* currentElem = NULL;
5062     int totalNbEdges = theTrack->NbEdges();
5063     SMDS_ElemIteratorPtr nIt;
5064
5065     //check start node
5066     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
5067       return EXTR_BAD_STARTING_NODE;
5068     }
5069
5070     conn = nbEdgeConnectivity(theN1);
5071     if(conn > 2)
5072       return EXTR_PATH_NOT_EDGE;
5073
5074     aItE = theN1->GetInverseElementIterator();
5075     prevElem = aItE->next();
5076     currentElem = prevElem;
5077     //Get all nodes
5078     if(totalNbEdges == 1 ) {
5079       nIt = currentElem->nodesIterator();
5080       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5081       if(currentNode == prevNode)
5082         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5083       aNodesList.push_back(currentNode);
5084     } else {
5085       nIt = currentElem->nodesIterator();
5086       while( nIt->more() ) {
5087         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5088         if(currentNode == prevNode)
5089           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5090         aNodesList.push_back(currentNode);
5091
5092         //case of the closed mesh
5093         if(currentNode == theN1) {
5094           nbEdges++;
5095           break;
5096         }
5097
5098         conn = nbEdgeConnectivity(currentNode);
5099         if(conn > 2) {
5100           return EXTR_PATH_NOT_EDGE;
5101         }else if( conn == 1 && nbEdges > 0 ) {
5102           //End of the path
5103           nbEdges++;
5104           break;
5105         }else {
5106           prevNode = currentNode;
5107           aItE = currentNode->GetInverseElementIterator();
5108           currentElem = aItE->next();
5109           if( currentElem  == prevElem)
5110             currentElem = aItE->next();
5111           nIt = currentElem->nodesIterator();
5112           prevElem = currentElem;
5113           nbEdges++;
5114         }
5115       }
5116     }
5117
5118     if(nbEdges != totalNbEdges)
5119       return EXTR_PATH_NOT_EDGE;
5120
5121     TopTools_SequenceOfShape Edges;
5122     double x1,x2,y1,y2,z1,z2;
5123     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5124     int startNid = theN1->GetID();
5125     for(int i = 1; i < aNodesList.size(); i++) {
5126       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5127       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5128       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5129       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5130       list<SMESH_MeshEditor_PathPoint> LPP;
5131       aPrms.clear();
5132       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5133       LLPPs.push_back(LPP);
5134       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5135       else startNid = aNodesList[i-1]->GetID();
5136
5137     }
5138
5139     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5140     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5141     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5142     for(; itPP!=firstList.end(); itPP++) {
5143       fullList.push_back( *itPP );
5144     }
5145
5146     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5147     SMESH_MeshEditor_PathPoint PP2;
5148     fullList.pop_back();
5149     itLLPP++;
5150     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5151       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5152       itPP = currList.begin();
5153       PP2 = currList.front();
5154       gp_Dir D1 = PP1.Tangent();
5155       gp_Dir D2 = PP2.Tangent();
5156       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5157                            (D1.Z()+D2.Z())/2 ) );
5158       PP1.SetTangent(Dnew);
5159       fullList.push_back(PP1);
5160       itPP++;
5161       for(; itPP!=currList.end(); itPP++) {
5162         fullList.push_back( *itPP );
5163       }
5164       PP1 = fullList.back();
5165       fullList.pop_back();
5166     }
5167     fullList.push_back(PP1);
5168
5169   } // Sub-shape for the Pattern must be an Edge or Wire
5170   else if( aS.ShapeType() == TopAbs_EDGE ) {
5171     aTrackEdge = TopoDS::Edge( aS );
5172     // the Edge must not be degenerated
5173     if ( BRep_Tool::Degenerated( aTrackEdge ) )
5174       return EXTR_BAD_PATH_SHAPE;
5175     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5176     const SMDS_MeshNode* aN1 = 0;
5177     const SMDS_MeshNode* aN2 = 0;
5178     if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
5179       aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5180       aN1 = aItN->next();
5181     }
5182     if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
5183       aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5184       aN2 = aItN->next();
5185     }
5186     // starting node must be aN1 or aN2
5187     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5188       return EXTR_BAD_STARTING_NODE;
5189     aItN = pMeshDS->nodesIterator();
5190     while ( aItN->more() ) {
5191       const SMDS_MeshNode* pNode = aItN->next();
5192       if( pNode==aN1 || pNode==aN2 ) continue;
5193       const SMDS_EdgePosition* pEPos =
5194         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5195       double aT = pEPos->GetUParameter();
5196       aPrms.push_back( aT );
5197     }
5198     //Extrusion_Error err =
5199     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5200   }
5201   else if( aS.ShapeType() == TopAbs_WIRE ) {
5202     list< SMESH_subMesh* > LSM;
5203     TopTools_SequenceOfShape Edges;
5204     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5205     for(; eExp.More(); eExp.Next()) {
5206       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5207       if( BRep_Tool::Degenerated(E) ) continue;
5208       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5209       if(SM) {
5210         LSM.push_back(SM);
5211         Edges.Append(E);
5212       }
5213     }
5214     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5215     TopoDS_Vertex aVprev;
5216     TColStd_MapOfInteger UsedNums;
5217     int NbEdges = Edges.Length();
5218     int i = 1;
5219     for(; i<=NbEdges; i++) {
5220       int k = 0;
5221       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5222       for(; itLSM!=LSM.end(); itLSM++) {
5223         k++;
5224         if(UsedNums.Contains(k)) continue;
5225         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5226         SMESH_subMesh* locTrack = *itLSM;
5227         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5228         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5229         bool aN1isOK = false, aN2isOK = false;
5230         if ( aVprev.IsNull() ) {
5231           // if previous vertex is not yet defined, it means that we in the beginning of wire
5232           // and we have to find initial vertex corresponding to starting node theN1
5233           const SMDS_MeshNode* aN1 = 0;
5234           const SMDS_MeshNode* aN2 = 0;
5235
5236           if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
5237             aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5238             aN1 = aItN->next();
5239           }
5240           if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
5241             aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5242             aN2 = aItN->next();
5243           }
5244           // starting node must be aN1 or aN2
5245           aN1isOK = ( aN1 && aN1 == theN1 );
5246           aN2isOK = ( aN2 && aN2 == theN1 );
5247         }
5248         else {
5249           // we have specified ending vertex of the previous edge on the previous iteration
5250           // and we have just to check that it corresponds to any vertex in current segment
5251           aN1isOK = aVprev.IsSame( aV1 );
5252           aN2isOK = aVprev.IsSame( aV2 );
5253         }
5254         if ( !aN1isOK && !aN2isOK ) continue;
5255         // 2. Collect parameters on the track edge
5256         aPrms.clear();
5257         aItN = locMeshDS->GetNodes();
5258         while ( aItN->more() ) {
5259           const SMDS_MeshNode*     pNode = aItN->next();
5260           const SMDS_EdgePosition* pEPos =
5261             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5262           double aT = pEPos->GetUParameter();
5263           aPrms.push_back( aT );
5264         }
5265         list<SMESH_MeshEditor_PathPoint> LPP;
5266         //Extrusion_Error err =
5267         MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
5268         LLPPs.push_back(LPP);
5269         UsedNums.Add(k);
5270         // update startN for search following egde
5271         if ( aN1isOK ) aVprev = aV2;
5272         else           aVprev = aV1;
5273         break;
5274       }
5275     }
5276     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5277     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5278     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5279     for(; itPP!=firstList.end(); itPP++) {
5280       fullList.push_back( *itPP );
5281     }
5282     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5283     fullList.pop_back();
5284     itLLPP++;
5285     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5286       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5287       itPP = currList.begin();
5288       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5289       gp_Dir D1 = PP1.Tangent();
5290       gp_Dir D2 = PP2.Tangent();
5291       gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
5292       PP1.SetTangent(Dnew);
5293       fullList.push_back(PP1);
5294       itPP++;
5295       for(; itPP!=currList.end(); itPP++) {
5296         fullList.push_back( *itPP );
5297       }
5298       PP1 = fullList.back();
5299       fullList.pop_back();
5300     }
5301     // if wire not closed
5302     fullList.push_back(PP1);
5303     // else ???
5304   }
5305   else {
5306     return EXTR_BAD_PATH_SHAPE;
5307   }
5308
5309   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5310                           theHasRefPoint, theRefPoint, theMakeGroups);
5311 }
5312
5313
5314 //=======================================================================
5315 //function : MakeEdgePathPoints
5316 //purpose  : auxilary for ExtrusionAlongTrack
5317 //=======================================================================
5318 SMESH_MeshEditor::Extrusion_Error
5319 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5320                                      const TopoDS_Edge& aTrackEdge,
5321                                      bool FirstIsStart,
5322                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5323 {
5324   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5325   aTolVec=1.e-7;
5326   aTolVec2=aTolVec*aTolVec;
5327   double aT1, aT2;
5328   TopoDS_Vertex aV1, aV2;
5329   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5330   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5331   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5332   // 2. Collect parameters on the track edge
5333   aPrms.push_front( aT1 );
5334   aPrms.push_back( aT2 );
5335   // sort parameters
5336   aPrms.sort();
5337   if( FirstIsStart ) {
5338     if ( aT1 > aT2 ) {
5339       aPrms.reverse();
5340     }
5341   }
5342   else {
5343     if ( aT2 > aT1 ) {
5344       aPrms.reverse();
5345     }
5346   }
5347   // 3. Path Points
5348   SMESH_MeshEditor_PathPoint aPP;
5349   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5350   std::list<double>::iterator aItD = aPrms.begin();
5351   for(; aItD != aPrms.end(); ++aItD) {
5352     double aT = *aItD;
5353     gp_Pnt aP3D;
5354     gp_Vec aVec;
5355     aC3D->D1( aT, aP3D, aVec );
5356     aL2 = aVec.SquareMagnitude();
5357     if ( aL2 < aTolVec2 )
5358       return EXTR_CANT_GET_TANGENT;
5359     gp_Dir aTgt( aVec );
5360     aPP.SetPnt( aP3D );
5361     aPP.SetTangent( aTgt );
5362     aPP.SetParameter( aT );
5363     LPP.push_back(aPP);
5364   }
5365   return EXTR_OK;
5366 }
5367
5368
5369 //=======================================================================
5370 //function : MakeExtrElements
5371 //purpose  : auxilary for ExtrusionAlongTrack
5372 //=======================================================================
5373 SMESH_MeshEditor::Extrusion_Error
5374 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5375                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5376                                    const bool theHasAngles,
5377                                    list<double>& theAngles,
5378                                    const bool theLinearVariation,
5379                                    const bool theHasRefPoint,
5380                                    const gp_Pnt& theRefPoint,
5381                                    const bool theMakeGroups)
5382 {
5383   MESSAGE("MakeExtrElements");
5384   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5385   int aNbTP = fullList.size();
5386   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5387   // Angles
5388   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5389     LinearAngleVariation(aNbTP-1, theAngles);
5390   }
5391   vector<double> aAngles( aNbTP );
5392   int j = 0;
5393   for(; j<aNbTP; ++j) {
5394     aAngles[j] = 0.;
5395   }
5396   if ( theHasAngles ) {
5397     double anAngle;;
5398     std::list<double>::iterator aItD = theAngles.begin();
5399     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5400       anAngle = *aItD;
5401       aAngles[j] = anAngle;
5402     }
5403   }
5404   // fill vector of path points with angles
5405   //aPPs.resize(fullList.size());
5406   j = -1;
5407   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5408   for(; itPP!=fullList.end(); itPP++) {
5409     j++;
5410     SMESH_MeshEditor_PathPoint PP = *itPP;
5411     PP.SetAngle(aAngles[j]);
5412     aPPs[j] = PP;
5413   }
5414
5415   TNodeOfNodeListMap mapNewNodes;
5416   TElemOfVecOfNnlmiMap mapElemNewNodes;
5417   TElemOfElemListMap newElemsMap;
5418   TIDSortedElemSet::iterator itElem;
5419   double aX, aY, aZ;
5420   int aNb;
5421   SMDSAbs_ElementType aTypeE;
5422   // source elements for each generated one
5423   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5424
5425   // 3. Center of rotation aV0
5426   gp_Pnt aV0 = theRefPoint;
5427   gp_XYZ aGC;
5428   if ( !theHasRefPoint ) {
5429     aNb = 0;
5430     aGC.SetCoord( 0.,0.,0. );
5431
5432     itElem = theElements.begin();
5433     for ( ; itElem != theElements.end(); itElem++ ) {
5434       const SMDS_MeshElement* elem = *itElem;
5435
5436       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5437       while ( itN->more() ) {
5438         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5439         aX = node->X();
5440         aY = node->Y();
5441         aZ = node->Z();
5442
5443         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5444           list<const SMDS_MeshNode*> aLNx;
5445           mapNewNodes[node] = aLNx;
5446           //
5447           gp_XYZ aXYZ( aX, aY, aZ );
5448           aGC += aXYZ;
5449           ++aNb;
5450         }
5451       }
5452     }
5453     aGC /= aNb;
5454     aV0.SetXYZ( aGC );
5455   } // if (!theHasRefPoint) {
5456   mapNewNodes.clear();
5457
5458   // 4. Processing the elements
5459   SMESHDS_Mesh* aMesh = GetMeshDS();
5460
5461   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5462     // check element type
5463     const SMDS_MeshElement* elem = *itElem;
5464     aTypeE = elem->GetType();
5465     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5466       continue;
5467
5468     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5469     newNodesItVec.reserve( elem->NbNodes() );
5470
5471     // loop on elem nodes
5472     int nodeIndex = -1;
5473     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5474     while ( itN->more() )
5475     {
5476       ++nodeIndex;
5477       // check if a node has been already processed
5478       const SMDS_MeshNode* node =
5479         static_cast<const SMDS_MeshNode*>( itN->next() );
5480       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5481       if ( nIt == mapNewNodes.end() ) {
5482         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5483         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5484
5485         // make new nodes
5486         aX = node->X();  aY = node->Y(); aZ = node->Z();
5487
5488         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5489         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5490         gp_Ax1 anAx1, anAxT1T0;
5491         gp_Dir aDT1x, aDT0x, aDT1T0;
5492
5493         aTolAng=1.e-4;
5494
5495         aV0x = aV0;
5496         aPN0.SetCoord(aX, aY, aZ);
5497
5498         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5499         aP0x = aPP0.Pnt();
5500         aDT0x= aPP0.Tangent();
5501         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5502
5503         for ( j = 1; j < aNbTP; ++j ) {
5504           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5505           aP1x = aPP1.Pnt();
5506           aDT1x = aPP1.Tangent();
5507           aAngle1x = aPP1.Angle();
5508
5509           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5510           // Translation
5511           gp_Vec aV01x( aP0x, aP1x );
5512           aTrsf.SetTranslation( aV01x );
5513
5514           // traslated point
5515           aV1x = aV0x.Transformed( aTrsf );
5516           aPN1 = aPN0.Transformed( aTrsf );
5517
5518           // rotation 1 [ T1,T0 ]
5519           aAngleT1T0=-aDT1x.Angle( aDT0x );
5520           if (fabs(aAngleT1T0) > aTolAng) {
5521             aDT1T0=aDT1x^aDT0x;
5522             anAxT1T0.SetLocation( aV1x );
5523             anAxT1T0.SetDirection( aDT1T0 );
5524             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5525
5526             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5527           }
5528
5529           // rotation 2
5530           if ( theHasAngles ) {
5531             anAx1.SetLocation( aV1x );
5532             anAx1.SetDirection( aDT1x );
5533             aTrsfRot.SetRotation( anAx1, aAngle1x );
5534
5535             aPN1 = aPN1.Transformed( aTrsfRot );
5536           }
5537
5538           // make new node
5539           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5540           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5541             // create additional node
5542             double x = ( aPN1.X() + aPN0.X() )/2.;
5543             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5544             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5545             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5546             myLastCreatedNodes.Append(newNode);
5547             srcNodes.Append( node );
5548             listNewNodes.push_back( newNode );
5549           }
5550           aX = aPN1.X();
5551           aY = aPN1.Y();
5552           aZ = aPN1.Z();
5553           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5554           myLastCreatedNodes.Append(newNode);
5555           srcNodes.Append( node );
5556           listNewNodes.push_back( newNode );
5557
5558           aPN0 = aPN1;
5559           aP0x = aP1x;
5560           aV0x = aV1x;
5561           aDT0x = aDT1x;
5562         }
5563       }
5564
5565       else {
5566         // if current elem is quadratic and current node is not medium
5567         // we have to check - may be it is needed to insert additional nodes
5568         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5569           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5570           if(listNewNodes.size()==aNbTP-1) {
5571             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5572             gp_XYZ P(node->X(), node->Y(), node->Z());
5573             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5574             int i;
5575             for(i=0; i<aNbTP-1; i++) {
5576               const SMDS_MeshNode* N = *it;
5577               double x = ( N->X() + P.X() )/2.;
5578               double y = ( N->Y() + P.Y() )/2.;
5579               double z = ( N->Z() + P.Z() )/2.;
5580               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5581               srcNodes.Append( node );
5582               myLastCreatedNodes.Append(newN);
5583               aNodes[2*i] = newN;
5584               aNodes[2*i+1] = N;
5585               P = gp_XYZ(N->X(),N->Y(),N->Z());
5586             }
5587             listNewNodes.clear();
5588             for(i=0; i<2*(aNbTP-1); i++) {
5589               listNewNodes.push_back(aNodes[i]);
5590             }
5591           }
5592         }
5593       }
5594
5595       newNodesItVec.push_back( nIt );
5596     }
5597     // make new elements
5598     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5599     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5600     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5601   }
5602
5603   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5604
5605   if ( theMakeGroups )
5606     generateGroups( srcNodes, srcElems, "extruded");
5607
5608   return EXTR_OK;
5609 }
5610
5611
5612 //=======================================================================
5613 //function : LinearAngleVariation
5614 //purpose  : auxilary for ExtrusionAlongTrack
5615 //=======================================================================
5616 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5617                                             list<double>& Angles)
5618 {
5619   int nbAngles = Angles.size();
5620   if( nbSteps > nbAngles ) {
5621     vector<double> theAngles(nbAngles);
5622     list<double>::iterator it = Angles.begin();
5623     int i = -1;
5624     for(; it!=Angles.end(); it++) {
5625       i++;
5626       theAngles[i] = (*it);
5627     }
5628     list<double> res;
5629     double rAn2St = double( nbAngles ) / double( nbSteps );
5630     double angPrev = 0, angle;
5631     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5632       double angCur = rAn2St * ( iSt+1 );
5633       double angCurFloor  = floor( angCur );
5634       double angPrevFloor = floor( angPrev );
5635       if ( angPrevFloor == angCurFloor )
5636         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5637       else {
5638         int iP = int( angPrevFloor );
5639         double angPrevCeil = ceil(angPrev);
5640         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5641
5642         int iC = int( angCurFloor );
5643         if ( iC < nbAngles )
5644           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5645
5646         iP = int( angPrevCeil );
5647         while ( iC-- > iP )
5648           angle += theAngles[ iC ];
5649       }
5650       res.push_back(angle);
5651       angPrev = angCur;
5652     }
5653     Angles.clear();
5654     it = res.begin();
5655     for(; it!=res.end(); it++)
5656       Angles.push_back( *it );
5657   }
5658 }
5659
5660
5661 //================================================================================
5662 /*!
5663  * \brief Move or copy theElements applying theTrsf to their nodes
5664  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5665  *  \param theTrsf - transformation to apply
5666  *  \param theCopy - if true, create translated copies of theElems
5667  *  \param theMakeGroups - if true and theCopy, create translated groups
5668  *  \param theTargetMesh - mesh to copy translated elements into
5669  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5670  */
5671 //================================================================================
5672
5673 SMESH_MeshEditor::PGroupIDs
5674 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5675                              const gp_Trsf&     theTrsf,
5676                              const bool         theCopy,
5677                              const bool         theMakeGroups,
5678                              SMESH_Mesh*        theTargetMesh)
5679 {
5680   myLastCreatedElems.Clear();
5681   myLastCreatedNodes.Clear();
5682
5683   bool needReverse = false;
5684   string groupPostfix;
5685   switch ( theTrsf.Form() ) {
5686   case gp_PntMirror:
5687     MESSAGE("gp_PntMirror");
5688     needReverse = true;
5689     groupPostfix = "mirrored";
5690     break;
5691   case gp_Ax1Mirror:
5692     MESSAGE("gp_Ax1Mirror");
5693     groupPostfix = "mirrored";
5694     break;
5695   case gp_Ax2Mirror:
5696     MESSAGE("gp_Ax2Mirror");
5697     needReverse = true;
5698     groupPostfix = "mirrored";
5699     break;
5700   case gp_Rotation:
5701     MESSAGE("gp_Rotation");
5702     groupPostfix = "rotated";
5703     break;
5704   case gp_Translation:
5705     MESSAGE("gp_Translation");
5706     groupPostfix = "translated";
5707     break;
5708   case gp_Scale:
5709     MESSAGE("gp_Scale");
5710     groupPostfix = "scaled";
5711     break;
5712   case gp_CompoundTrsf: // different scale by axis
5713     MESSAGE("gp_CompoundTrsf");
5714     groupPostfix = "scaled";
5715     break;
5716   default:
5717     MESSAGE("default");
5718     needReverse = false;
5719     groupPostfix = "transformed";
5720   }
5721
5722   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5723   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5724   SMESHDS_Mesh* aMesh    = GetMeshDS();
5725
5726
5727   // map old node to new one
5728   TNodeNodeMap nodeMap;
5729
5730   // elements sharing moved nodes; those of them which have all
5731   // nodes mirrored but are not in theElems are to be reversed
5732   TIDSortedElemSet inverseElemSet;
5733
5734   // source elements for each generated one
5735   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5736
5737   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5738   TIDSortedElemSet orphanNode;
5739
5740   if ( theElems.empty() ) // transform the whole mesh
5741   {
5742     // add all elements
5743     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5744     while ( eIt->more() ) theElems.insert( eIt->next() );
5745     // add orphan nodes
5746     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5747     while ( nIt->more() )
5748     {
5749       const SMDS_MeshNode* node = nIt->next();
5750       if ( node->NbInverseElements() == 0)
5751         orphanNode.insert( node );
5752     }
5753   }
5754
5755   // loop on elements to transform nodes : first orphan nodes then elems
5756   TIDSortedElemSet::iterator itElem;
5757   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5758   for (int i=0; i<2; i++)
5759   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5760     const SMDS_MeshElement* elem = *itElem;
5761     if ( !elem )
5762       continue;
5763
5764     // loop on elem nodes
5765     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5766     while ( itN->more() ) {
5767
5768       const SMDS_MeshNode* node = cast2Node( itN->next() );
5769       // check if a node has been already transformed
5770       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5771         nodeMap.insert( make_pair ( node, node ));
5772       if ( !n2n_isnew.second )
5773         continue;
5774
5775       double coord[3];
5776       coord[0] = node->X();
5777       coord[1] = node->Y();
5778       coord[2] = node->Z();
5779       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5780       if ( theTargetMesh ) {
5781         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5782         n2n_isnew.first->second = newNode;
5783         myLastCreatedNodes.Append(newNode);
5784         srcNodes.Append( node );
5785       }
5786       else if ( theCopy ) {
5787         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5788         n2n_isnew.first->second = newNode;
5789         myLastCreatedNodes.Append(newNode);
5790         srcNodes.Append( node );
5791       }
5792       else {
5793         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5794         // node position on shape becomes invalid
5795         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5796           ( SMDS_SpacePosition::originSpacePosition() );
5797       }
5798
5799       // keep inverse elements
5800       if ( !theCopy && !theTargetMesh && needReverse ) {
5801         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5802         while ( invElemIt->more() ) {
5803           const SMDS_MeshElement* iel = invElemIt->next();
5804           inverseElemSet.insert( iel );
5805         }
5806       }
5807     }
5808   }
5809
5810   // either create new elements or reverse mirrored ones
5811   if ( !theCopy && !needReverse && !theTargetMesh )
5812     return PGroupIDs();
5813
5814   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5815   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5816     theElems.insert( *invElemIt );
5817
5818   // Replicate or reverse elements
5819
5820   std::vector<int> iForw;
5821   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5822   {
5823     const SMDS_MeshElement* elem = *itElem;
5824     if ( !elem ) continue;
5825
5826     SMDSAbs_GeometryType geomType = elem->GetGeomType();
5827     int                  nbNodes  = elem->NbNodes();
5828     if ( geomType == SMDSGeom_NONE ) continue; // node
5829
5830     switch ( geomType ) {
5831
5832     case SMDSGeom_POLYGON:  // ---------------------- polygon
5833       {
5834         vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5835         int iNode = 0;
5836         SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5837         while (itN->more()) {
5838           const SMDS_MeshNode* node =
5839             static_cast<const SMDS_MeshNode*>(itN->next());
5840           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5841           if (nodeMapIt == nodeMap.end())
5842             break; // not all nodes transformed
5843           if (needReverse) {
5844             // reverse mirrored faces and volumes
5845             poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5846           } else {
5847             poly_nodes[iNode] = (*nodeMapIt).second;
5848           }
5849           iNode++;
5850         }
5851         if ( iNode != nbNodes )
5852           continue; // not all nodes transformed
5853
5854         if ( theTargetMesh ) {
5855           myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5856           srcElems.Append( elem );
5857         }
5858         else if ( theCopy ) {
5859           myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5860           srcElems.Append( elem );
5861         }
5862         else {
5863           aMesh->ChangePolygonNodes(elem, poly_nodes);
5864         }
5865       }
5866       break;
5867
5868     case SMDSGeom_POLYHEDRA:  // ------------------ polyhedral volume
5869       {
5870         const SMDS_VtkVolume* aPolyedre =
5871           dynamic_cast<const SMDS_VtkVolume*>( elem );
5872         if (!aPolyedre) {
5873           MESSAGE("Warning: bad volumic element");
5874           continue;
5875         }
5876
5877         vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5878         vector<int> quantities; quantities.reserve( nbNodes );
5879
5880         bool allTransformed = true;
5881         int nbFaces = aPolyedre->NbFaces();
5882         for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5883           int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5884           for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5885             const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5886             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5887             if (nodeMapIt == nodeMap.end()) {
5888               allTransformed = false; // not all nodes transformed
5889             } else {
5890               poly_nodes.push_back((*nodeMapIt).second);
5891             }
5892             if ( needReverse && allTransformed )
5893               std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5894           }
5895           quantities.push_back(nbFaceNodes);
5896         }
5897         if ( !allTransformed )
5898           continue; // not all nodes transformed
5899
5900         if ( theTargetMesh ) {
5901           myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5902           srcElems.Append( elem );
5903         }
5904         else if ( theCopy ) {
5905           myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5906           srcElems.Append( elem );
5907         }
5908         else {
5909           aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5910         }
5911       }
5912       break;
5913
5914     case SMDSGeom_BALL: // -------------------- Ball
5915       {
5916         if ( !theCopy && !theTargetMesh ) continue;
5917
5918         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
5919         if (nodeMapIt == nodeMap.end())
5920           continue; // not all nodes transformed
5921
5922         double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
5923         if ( theTargetMesh ) {
5924           myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
5925           srcElems.Append( elem );
5926         }
5927         else {
5928           myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
5929           srcElems.Append( elem );
5930         }
5931       }
5932       break;
5933
5934     default: // ----------------------- Regular elements
5935
5936       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5937       const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5938       const std::vector<int>& i = needReverse ? iRev : iForw;
5939
5940       // find transformed nodes
5941       vector<const SMDS_MeshNode*> nodes(nbNodes);
5942       int iNode = 0;
5943       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5944       while ( itN->more() ) {
5945         const SMDS_MeshNode* node =
5946           static_cast<const SMDS_MeshNode*>( itN->next() );
5947         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5948         if ( nodeMapIt == nodeMap.end() )
5949           break; // not all nodes transformed
5950         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5951       }
5952       if ( iNode != nbNodes )
5953         continue; // not all nodes transformed
5954
5955       if ( theTargetMesh ) {
5956         if ( SMDS_MeshElement* copy =
5957              targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5958           myLastCreatedElems.Append( copy );
5959           srcElems.Append( elem );
5960         }
5961       }
5962       else if ( theCopy ) {
5963         if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5964           srcElems.Append( elem );
5965       }
5966       else {
5967         // reverse element as it was reversed by transformation
5968         if ( nbNodes > 2 )
5969           aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5970       }
5971     } // switch ( geomType )
5972
5973   } // loop on elements
5974
5975   PGroupIDs newGroupIDs;
5976
5977   if ( ( theMakeGroups && theCopy ) ||
5978        ( theMakeGroups && theTargetMesh ) )
5979     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5980
5981   return newGroupIDs;
5982 }
5983
5984 //=======================================================================
5985 /*!
5986  * \brief Create groups of elements made during transformation
5987  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5988  * \param elemGens - elements making corresponding myLastCreatedElems
5989  * \param postfix - to append to names of new groups
5990  */
5991 //=======================================================================
5992
5993 SMESH_MeshEditor::PGroupIDs
5994 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5995                                  const SMESH_SequenceOfElemPtr& elemGens,
5996                                  const std::string&             postfix,
5997                                  SMESH_Mesh*                    targetMesh)
5998 {
5999   PGroupIDs newGroupIDs( new list<int> );
6000   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6001
6002   // Sort existing groups by types and collect their names
6003
6004   // to store an old group and a generated new ones
6005   using boost::tuple;
6006   using boost::make_tuple;
6007   typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
6008   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6009   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
6010   // group names
6011   set< string > groupNames;
6012
6013   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6014   if ( !groupIt->more() ) return newGroupIDs;
6015
6016   int newGroupID = mesh->GetGroupIds().back()+1;
6017   while ( groupIt->more() )
6018   {
6019     SMESH_Group * group = groupIt->next();
6020     if ( !group ) continue;
6021     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6022     if ( !groupDS || groupDS->IsEmpty() ) continue;
6023     groupNames.insert    ( group->GetName() );
6024     groupDS->SetStoreName( group->GetName() );
6025     const SMDSAbs_ElementType type = groupDS->GetType();
6026     SMESHDS_Group* newGroup    = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6027     SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6028     groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
6029     orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
6030   }
6031
6032   // Loop on nodes and elements to add them in new groups
6033
6034   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6035   {
6036     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6037     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6038     if ( gens.Length() != elems.Length() )
6039       throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
6040
6041     // loop on created elements
6042     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6043     {
6044       const SMDS_MeshElement* sourceElem = gens( iElem );
6045       if ( !sourceElem ) {
6046         MESSAGE("generateGroups(): NULL source element");
6047         continue;
6048       }
6049       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6050       if ( groupsOldNew.empty() ) { // no groups of this type at all
6051         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6052           ++iElem; // skip all elements made by sourceElem
6053         continue;
6054       }
6055       // collect all elements made by the iElem-th sourceElem
6056       list< const SMDS_MeshElement* > resultElems;
6057       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6058         if ( resElem != sourceElem )
6059           resultElems.push_back( resElem );
6060       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6061         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6062           if ( resElem != sourceElem )
6063             resultElems.push_back( resElem );
6064
6065       // there must be a top element
6066       const SMDS_MeshElement* topElem = 0;
6067       if ( isNodes )
6068       {
6069         topElem = resultElems.back();
6070         resultElems.pop_back();
6071       }
6072       else
6073       {
6074         list< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
6075         for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
6076           if ( (*resElemIt)->GetType() == sourceElem->GetType() )
6077           {
6078             topElem = *resElemIt;
6079             resultElems.erase( --(resElemIt.base()) ); // erase *resElemIt
6080             break;
6081           }
6082       }
6083
6084       // add resultElems to groups originted from ones the sourceElem belongs to
6085       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6086       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6087       {
6088         SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
6089         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6090         {
6091           // fill in a new group
6092           SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
6093           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6094           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6095             newGroup.Add( *resElemIt );
6096
6097           // fill a "top" group
6098           if ( topElem )
6099           {
6100             SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
6101             newTopGroup.Add( topElem );
6102           }
6103         }
6104       }
6105     } // loop on created elements
6106   }// loop on nodes and elements
6107
6108   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6109
6110   list<int> topGrouIds;
6111   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6112   {
6113     SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
6114     SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
6115                                       orderedOldNewGroups[i]->get<2>() };
6116     const int nbNewGroups = !newGroups[0]->IsEmpty() + !newGroups[1]->IsEmpty();
6117     for ( int is2nd = 0; is2nd < 2; ++is2nd )
6118     {
6119       SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
6120       if ( newGroupDS->IsEmpty() )
6121       {
6122         mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6123       }
6124       else
6125       {
6126         // set group type
6127         newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6128
6129         // make a name
6130         const bool isTop = ( nbNewGroups == 2 &&
6131                              newGroupDS->GetType() == oldGroupDS->GetType() &&
6132                              is2nd );
6133
6134         string name = oldGroupDS->GetStoreName();
6135         if ( !targetMesh ) {
6136           string suffix = ( isTop ? "top": postfix.c_str() );
6137           name += "_";
6138           name += suffix;
6139           int nb = 1;
6140           while ( !groupNames.insert( name ).second ) // name exists
6141             name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
6142         }
6143         else if ( isTop ) {
6144           name += "_top";
6145         }
6146         newGroupDS->SetStoreName( name.c_str() );
6147
6148         // make a SMESH_Groups
6149         mesh->AddGroup( newGroupDS );
6150         if ( isTop )
6151           topGrouIds.push_back( newGroupDS->GetID() );
6152         else
6153           newGroupIDs->push_back( newGroupDS->GetID() );
6154       }
6155     }
6156   }
6157   newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
6158
6159   return newGroupIDs;
6160 }
6161
6162 //================================================================================
6163 /*!
6164  * \brief Return list of group of nodes close to each other within theTolerance
6165  *        Search among theNodes or in the whole mesh if theNodes is empty using
6166  *        an Octree algorithm
6167  */
6168 //================================================================================
6169
6170 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6171                                             const double         theTolerance,
6172                                             TListOfListOfNodes & theGroupsOfNodes)
6173 {
6174   myLastCreatedElems.Clear();
6175   myLastCreatedNodes.Clear();
6176
6177   if ( theNodes.empty() )
6178   { // get all nodes in the mesh
6179     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6180     while ( nIt->more() )
6181       theNodes.insert( theNodes.end(),nIt->next());
6182   }
6183
6184   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6185 }
6186
6187
6188 //=======================================================================
6189 /*!
6190  * \brief Implementation of search for the node closest to point
6191  */
6192 //=======================================================================
6193
6194 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6195 {
6196   //---------------------------------------------------------------------
6197   /*!
6198    * \brief Constructor
6199    */
6200   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6201   {
6202     myMesh = ( SMESHDS_Mesh* ) theMesh;
6203
6204     TIDSortedNodeSet nodes;
6205     if ( theMesh ) {
6206       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6207       while ( nIt->more() )
6208         nodes.insert( nodes.end(), nIt->next() );
6209     }
6210     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6211
6212     // get max size of a leaf box
6213     SMESH_OctreeNode* tree = myOctreeNode;
6214     while ( !tree->isLeaf() )
6215     {
6216       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6217       if ( cIt->more() )
6218         tree = cIt->next();
6219     }
6220     myHalfLeafSize = tree->maxSize() / 2.;
6221   }
6222
6223   //---------------------------------------------------------------------
6224   /*!
6225    * \brief Move node and update myOctreeNode accordingly
6226    */
6227   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6228   {
6229     myOctreeNode->UpdateByMoveNode( node, toPnt );
6230     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6231   }
6232
6233   //---------------------------------------------------------------------
6234   /*!
6235    * \brief Do it's job
6236    */
6237   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6238   {
6239     map<double, const SMDS_MeshNode*> dist2Nodes;
6240     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6241     if ( !dist2Nodes.empty() )
6242       return dist2Nodes.begin()->second;
6243     list<const SMDS_MeshNode*> nodes;
6244     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6245
6246     double minSqDist = DBL_MAX;
6247     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6248     {
6249       // sort leafs by their distance from thePnt
6250       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6251       TDistTreeMap treeMap;
6252       list< SMESH_OctreeNode* > treeList;
6253       list< SMESH_OctreeNode* >::iterator trIt;
6254       treeList.push_back( myOctreeNode );
6255
6256       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6257       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6258       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6259       {
6260         SMESH_OctreeNode* tree = *trIt;
6261         if ( !tree->isLeaf() ) // put children to the queue
6262         {
6263           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6264           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6265           while ( cIt->more() )
6266             treeList.push_back( cIt->next() );
6267         }
6268         else if ( tree->NbNodes() ) // put a tree to the treeMap
6269         {
6270           const Bnd_B3d& box = *tree->getBox();
6271           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6272           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6273           if ( !it_in.second ) // not unique distance to box center
6274             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6275         }
6276       }
6277       // find distance after which there is no sense to check tree's
6278       double sqLimit = DBL_MAX;
6279       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6280       if ( treeMap.size() > 5 ) {
6281         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6282         const Bnd_B3d& box = *closestTree->getBox();
6283         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6284         sqLimit = limit * limit;
6285       }
6286       // get all nodes from trees
6287       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6288         if ( sqDist_tree->first > sqLimit )
6289           break;
6290         SMESH_OctreeNode* tree = sqDist_tree->second;
6291         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6292       }
6293     }
6294     // find closest among nodes
6295     minSqDist = DBL_MAX;
6296     const SMDS_MeshNode* closestNode = 0;
6297     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6298     for ( ; nIt != nodes.end(); ++nIt ) {
6299       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6300       if ( minSqDist > sqDist ) {
6301         closestNode = *nIt;
6302         minSqDist = sqDist;
6303       }
6304     }
6305     return closestNode;
6306   }
6307
6308   //---------------------------------------------------------------------
6309   /*!
6310    * \brief Destructor
6311    */
6312   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6313
6314   //---------------------------------------------------------------------
6315   /*!
6316    * \brief Return the node tree
6317    */
6318   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6319
6320 private:
6321   SMESH_OctreeNode* myOctreeNode;
6322   SMESHDS_Mesh*     myMesh;
6323   double            myHalfLeafSize; // max size of a leaf box
6324 };
6325
6326 //=======================================================================
6327 /*!
6328  * \brief Return SMESH_NodeSearcher
6329  */
6330 //=======================================================================
6331
6332 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6333 {
6334   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6335 }
6336
6337 // ========================================================================
6338 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6339 {
6340   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6341   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6342   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6343
6344   //=======================================================================
6345   /*!
6346    * \brief Octal tree of bounding boxes of elements
6347    */
6348   //=======================================================================
6349
6350   class ElementBndBoxTree : public SMESH_Octree
6351   {
6352   public:
6353
6354     ElementBndBoxTree(const SMDS_Mesh&     mesh,
6355                       SMDSAbs_ElementType  elemType,
6356                       SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
6357                       double               tolerance = NodeRadius );
6358     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
6359     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6360     void getElementsInSphere ( const gp_XYZ& center,
6361                                const double  radius, TIDSortedElemSet& foundElems);
6362     size_t getSize() { return std::max( _size, _elements.size() ); }
6363     virtual ~ElementBndBoxTree();
6364
6365   protected:
6366     ElementBndBoxTree():_size(0) {}
6367     SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
6368     void          buildChildrenData();
6369     Bnd_B3d*      buildRootBox();
6370   private:
6371     //!< Bounding box of element
6372     struct ElementBox : public Bnd_B3d
6373     {
6374       const SMDS_MeshElement* _element;
6375       int                     _refCount; // an ElementBox can be included in several tree branches
6376       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6377     };
6378     vector< ElementBox* > _elements;
6379     size_t                _size;
6380   };
6381
6382   //================================================================================
6383   /*!
6384    * \brief ElementBndBoxTree creation
6385    */
6386   //================================================================================
6387
6388   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6389     :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ))
6390   {
6391     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6392     _elements.reserve( nbElems );
6393
6394     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6395     while ( elemIt->more() )
6396       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6397
6398     compute();
6399   }
6400
6401   //================================================================================
6402   /*!
6403    * \brief Destructor
6404    */
6405   //================================================================================
6406
6407   ElementBndBoxTree::~ElementBndBoxTree()
6408   {
6409     for ( int i = 0; i < _elements.size(); ++i )
6410       if ( --_elements[i]->_refCount <= 0 )
6411         delete _elements[i];
6412   }
6413
6414   //================================================================================
6415   /*!
6416    * \brief Return the maximal box
6417    */
6418   //================================================================================
6419
6420   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6421   {
6422     Bnd_B3d* box = new Bnd_B3d;
6423     for ( int i = 0; i < _elements.size(); ++i )
6424       box->Add( *_elements[i] );
6425     return box;
6426   }
6427
6428   //================================================================================
6429   /*!
6430    * \brief Redistrubute element boxes among children
6431    */
6432   //================================================================================
6433
6434   void ElementBndBoxTree::buildChildrenData()
6435   {
6436     for ( int i = 0; i < _elements.size(); ++i )
6437     {
6438       for (int j = 0; j < 8; j++)
6439       {
6440         if ( !_elements[i]->IsOut( *myChildren[j]->getBox() ))
6441         {
6442           _elements[i]->_refCount++;
6443           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6444         }
6445       }
6446       _elements[i]->_refCount--;
6447     }
6448     _size = _elements.size();
6449     SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
6450
6451     for (int j = 0; j < 8; j++)
6452     {
6453       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6454       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6455         child->myIsLeaf = true;
6456
6457       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6458         SMESHUtils::CompactVector( child->_elements );
6459     }
6460   }
6461
6462   //================================================================================
6463   /*!
6464    * \brief Return elements which can include the point
6465    */
6466   //================================================================================
6467
6468   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6469                                                 TIDSortedElemSet& foundElems)
6470   {
6471     if ( getBox()->IsOut( point.XYZ() ))
6472       return;
6473
6474     if ( isLeaf() )
6475     {
6476       for ( int i = 0; i < _elements.size(); ++i )
6477         if ( !_elements[i]->IsOut( point.XYZ() ))
6478           foundElems.insert( _elements[i]->_element );
6479     }
6480     else
6481     {
6482       for (int i = 0; i < 8; i++)
6483         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6484     }
6485   }
6486
6487   //================================================================================
6488   /*!
6489    * \brief Return elements which can be intersected by the line
6490    */
6491   //================================================================================
6492
6493   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6494                                                TIDSortedElemSet& foundElems)
6495   {
6496     if ( getBox()->IsOut( line ))
6497       return;
6498
6499     if ( isLeaf() )
6500     {
6501       for ( int i = 0; i < _elements.size(); ++i )
6502         if ( !_elements[i]->IsOut( line ))
6503           foundElems.insert( _elements[i]->_element );
6504     }
6505     else
6506     {
6507       for (int i = 0; i < 8; i++)
6508         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6509     }
6510   }
6511
6512   //================================================================================
6513   /*!
6514    * \brief Return elements from leaves intersecting the sphere
6515    */
6516   //================================================================================
6517
6518   void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&     center,
6519                                                 const double      radius,
6520                                                 TIDSortedElemSet& foundElems)
6521   {
6522     if ( getBox()->IsOut( center, radius ))
6523       return;
6524
6525     if ( isLeaf() )
6526     {
6527       for ( int i = 0; i < _elements.size(); ++i )
6528         if ( !_elements[i]->IsOut( center, radius ))
6529           foundElems.insert( _elements[i]->_element );
6530     }
6531     else
6532     {
6533       for (int i = 0; i < 8; i++)
6534         ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
6535     }
6536   }
6537
6538   //================================================================================
6539   /*!
6540    * \brief Construct the element box
6541    */
6542   //================================================================================
6543
6544   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6545   {
6546     _element  = elem;
6547     _refCount = 1;
6548     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6549     while ( nIt->more() )
6550       Add( SMESH_TNodeXYZ( nIt->next() ));
6551     Enlarge( tolerance );
6552   }
6553
6554 } // namespace
6555
6556 //=======================================================================
6557 /*!
6558  * \brief Implementation of search for the elements by point and
6559  *        of classification of point in 2D mesh
6560  */
6561 //=======================================================================
6562 SMESH_ElementSearcher::~SMESH_ElementSearcher()
6563 {
6564 }
6565
6566 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6567 {
6568   SMESHDS_Mesh*                _mesh;
6569   SMDS_ElemIteratorPtr         _meshPartIt;
6570   ElementBndBoxTree*           _ebbTree;
6571   SMESH_NodeSearcherImpl*      _nodeSearcher;
6572   SMDSAbs_ElementType          _elementType;
6573   double                       _tolerance;
6574   bool                         _outerFacesFound;
6575   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6576
6577   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6578     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {MESSAGE("-----------> SMESH_ElementSearcherImpl constructor");}
6579   virtual ~SMESH_ElementSearcherImpl()
6580   {
6581     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6582     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6583   }
6584   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6585                                   SMDSAbs_ElementType                type,
6586                                   vector< const SMDS_MeshElement* >& foundElements);
6587   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6588   virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt&       point,
6589                                                  SMDSAbs_ElementType type );
6590
6591   void GetElementsNearLine( const gp_Ax1&                      line,
6592                             SMDSAbs_ElementType                type,
6593                             vector< const SMDS_MeshElement* >& foundElems);
6594   double getTolerance();
6595   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6596                             const double tolerance, double & param);
6597   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6598   bool isOuterBoundary(const SMDS_MeshElement* face) const
6599   {
6600     return _outerFaces.empty() || _outerFaces.count(face);
6601   }
6602   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6603   {
6604     const SMDS_MeshElement* _face;
6605     gp_Vec                  _faceNorm;
6606     bool                    _coincides; //!< the line lays in face plane
6607     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6608       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6609   };
6610   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6611   {
6612     SMESH_TLink      _link;
6613     TIDSortedElemSet _faces;
6614     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6615       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6616   };
6617 };
6618
6619 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6620 {
6621   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6622              << ", _coincides="<<i._coincides << ")";
6623 }
6624
6625 //=======================================================================
6626 /*!
6627  * \brief define tolerance for search
6628  */
6629 //=======================================================================
6630
6631 double SMESH_ElementSearcherImpl::getTolerance()
6632 {
6633   if ( _tolerance < 0 )
6634   {
6635     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6636
6637     _tolerance = 0;
6638     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6639     {
6640       double boxSize = _nodeSearcher->getTree()->maxSize();
6641       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6642     }
6643     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6644     {
6645       double boxSize = _ebbTree->maxSize();
6646       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6647     }
6648     if ( _tolerance == 0 )
6649     {
6650       // define tolerance by size of a most complex element
6651       int complexType = SMDSAbs_Volume;
6652       while ( complexType > SMDSAbs_All &&
6653               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6654         --complexType;
6655       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6656       double elemSize;
6657       if ( complexType == int( SMDSAbs_Node ))
6658       {
6659         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6660         elemSize = 1;
6661         if ( meshInfo.NbNodes() > 2 )
6662           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6663       }
6664       else
6665       {
6666         SMDS_ElemIteratorPtr elemIt =
6667             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6668         const SMDS_MeshElement* elem = elemIt->next();
6669         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6670         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6671         elemSize = 0;
6672         while ( nodeIt->more() )
6673         {
6674           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6675           elemSize = max( dist, elemSize );
6676         }
6677       }
6678       _tolerance = 1e-4 * elemSize;
6679     }
6680   }
6681   return _tolerance;
6682 }
6683
6684 //================================================================================
6685 /*!
6686  * \brief Find intersection of the line and an edge of face and return parameter on line
6687  */
6688 //================================================================================
6689
6690 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6691                                                      const SMDS_MeshElement* face,
6692                                                      const double            tol,
6693                                                      double &                param)
6694 {
6695   int nbInts = 0;
6696   param = 0;
6697
6698   GeomAPI_ExtremaCurveCurve anExtCC;
6699   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6700
6701   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6702   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6703   {
6704     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6705                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6706     anExtCC.Init( lineCurve, edge);
6707     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6708     {
6709       Quantity_Parameter pl, pe;
6710       anExtCC.LowerDistanceParameters( pl, pe );
6711       param += pl;
6712       if ( ++nbInts == 2 )
6713         break;
6714     }
6715   }
6716   if ( nbInts > 0 ) param /= nbInts;
6717   return nbInts > 0;
6718 }
6719 //================================================================================
6720 /*!
6721  * \brief Find all faces belonging to the outer boundary of mesh
6722  */
6723 //================================================================================
6724
6725 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6726 {
6727   if ( _outerFacesFound ) return;
6728
6729   // Collect all outer faces by passing from one outer face to another via their links
6730   // and BTW find out if there are internal faces at all.
6731
6732   // checked links and links where outer boundary meets internal one
6733   set< SMESH_TLink > visitedLinks, seamLinks;
6734
6735   // links to treat with already visited faces sharing them
6736   list < TFaceLink > startLinks;
6737
6738   // load startLinks with the first outerFace
6739   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6740   _outerFaces.insert( outerFace );
6741
6742   TIDSortedElemSet emptySet;
6743   while ( !startLinks.empty() )
6744   {
6745     const SMESH_TLink& link  = startLinks.front()._link;
6746     TIDSortedElemSet&  faces = startLinks.front()._faces;
6747
6748     outerFace = *faces.begin();
6749     // find other faces sharing the link
6750     const SMDS_MeshElement* f;
6751     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6752       faces.insert( f );
6753
6754     // select another outer face among the found
6755     const SMDS_MeshElement* outerFace2 = 0;
6756     if ( faces.size() == 2 )
6757     {
6758       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6759     }
6760     else if ( faces.size() > 2 )
6761     {
6762       seamLinks.insert( link );
6763
6764       // link direction within the outerFace
6765       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6766                    SMESH_TNodeXYZ( link.node2()));
6767       int i1 = outerFace->GetNodeIndex( link.node1() );
6768       int i2 = outerFace->GetNodeIndex( link.node2() );
6769       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6770       if ( rev ) n1n2.Reverse();
6771       // outerFace normal
6772       gp_XYZ ofNorm, fNorm;
6773       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6774       {
6775         // direction from the link inside outerFace
6776         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6777         // sort all other faces by angle with the dirInOF
6778         map< double, const SMDS_MeshElement* > angle2Face;
6779         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6780         for ( ; face != faces.end(); ++face )
6781         {
6782           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6783             continue;
6784           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6785           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6786           if ( angle < 0 ) angle += 2. * M_PI;
6787           angle2Face.insert( make_pair( angle, *face ));
6788         }
6789         if ( !angle2Face.empty() )
6790           outerFace2 = angle2Face.begin()->second;
6791       }
6792     }
6793     // store the found outer face and add its links to continue seaching from
6794     if ( outerFace2 )
6795     {
6796       _outerFaces.insert( outerFace );
6797       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6798       for ( int i = 0; i < nbNodes; ++i )
6799       {
6800         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6801         if ( visitedLinks.insert( link2 ).second )
6802           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6803       }
6804     }
6805     startLinks.pop_front();
6806   }
6807   _outerFacesFound = true;
6808
6809   if ( !seamLinks.empty() )
6810   {
6811     // There are internal boundaries touching the outher one,
6812     // find all faces of internal boundaries in order to find
6813     // faces of boundaries of holes, if any.
6814
6815   }
6816   else
6817   {
6818     _outerFaces.clear();
6819   }
6820 }
6821
6822 //=======================================================================
6823 /*!
6824  * \brief Find elements of given type where the given point is IN or ON.
6825  *        Returns nb of found elements and elements them-selves.
6826  *
6827  * 'ALL' type means elements of any type excluding nodes, balls and 0D elements
6828  */
6829 //=======================================================================
6830
6831 int SMESH_ElementSearcherImpl::
6832 FindElementsByPoint(const gp_Pnt&                      point,
6833                     SMDSAbs_ElementType                type,
6834                     vector< const SMDS_MeshElement* >& foundElements)
6835 {
6836   foundElements.clear();
6837
6838   double tolerance = getTolerance();
6839
6840   // =================================================================================
6841   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball)
6842   {
6843     if ( !_nodeSearcher )
6844       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6845
6846     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6847     if ( !closeNode ) return foundElements.size();
6848
6849     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6850       return foundElements.size(); // to far from any node
6851
6852     if ( type == SMDSAbs_Node )
6853     {
6854       foundElements.push_back( closeNode );
6855     }
6856     else
6857     {
6858       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type );
6859       while ( elemIt->more() )
6860         foundElements.push_back( elemIt->next() );
6861     }
6862   }
6863   // =================================================================================
6864   else // elements more complex than 0D
6865   {
6866     if ( !_ebbTree || _elementType != type )
6867     {
6868       if ( _ebbTree ) delete _ebbTree;
6869       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6870     }
6871     TIDSortedElemSet suspectElems;
6872     _ebbTree->getElementsNearPoint( point, suspectElems );
6873     TIDSortedElemSet::iterator elem = suspectElems.begin();
6874     for ( ; elem != suspectElems.end(); ++elem )
6875       if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance ))
6876         foundElements.push_back( *elem );
6877   }
6878   return foundElements.size();
6879 }
6880
6881 //=======================================================================
6882 /*!
6883  * \brief Find an element of given type most close to the given point
6884  *
6885  * WARNING: Only face search is implemeneted so far
6886  */
6887 //=======================================================================
6888
6889 const SMDS_MeshElement*
6890 SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
6891                                           SMDSAbs_ElementType type )
6892 {
6893   const SMDS_MeshElement* closestElem = 0;
6894
6895   if ( type == SMDSAbs_Face )
6896   {
6897     if ( !_ebbTree || _elementType != type )
6898     {
6899       if ( _ebbTree ) delete _ebbTree;
6900       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
6901     }
6902     TIDSortedElemSet suspectElems;
6903     _ebbTree->getElementsNearPoint( point, suspectElems );
6904
6905     if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
6906     {
6907       gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() +
6908                                  _ebbTree->getBox()->CornerMax() );
6909       double radius;
6910       if ( _ebbTree->getBox()->IsOut( point.XYZ() ))
6911         radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
6912       else
6913         radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
6914       while ( suspectElems.empty() )
6915       {
6916         _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
6917         radius *= 1.1;
6918       }
6919     }
6920     double minDist = std::numeric_limits<double>::max();
6921     multimap< double, const SMDS_MeshElement* > dist2face;
6922     TIDSortedElemSet::iterator elem = suspectElems.begin();
6923     for ( ; elem != suspectElems.end(); ++elem )
6924     {
6925       double dist = SMESH_MeshEditor::GetDistance( dynamic_cast<const SMDS_MeshFace*>(*elem),
6926                                                    point );
6927       if ( dist < minDist + 1e-10)
6928       {
6929         minDist = dist;
6930         dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
6931       }
6932     }
6933     if ( !dist2face.empty() )
6934     {
6935       multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
6936       closestElem = d2f->second;
6937       // if there are several elements at the same distance, select one
6938       // with GC closest to the point
6939       typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
6940       double minDistToGC = 0;
6941       for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f )
6942       {
6943         if ( minDistToGC == 0 )
6944         {
6945           gp_XYZ gc(0,0,0);
6946           gc = accumulate( TXyzIterator(closestElem->nodesIterator()),
6947                            TXyzIterator(), gc ) / closestElem->NbNodes();
6948           minDistToGC = point.SquareDistance( gc );
6949         }
6950         gp_XYZ gc(0,0,0);
6951         gc = accumulate( TXyzIterator( d2f->second->nodesIterator()),
6952                          TXyzIterator(), gc ) / d2f->second->NbNodes();
6953         double d = point.SquareDistance( gc );
6954         if ( d < minDistToGC )
6955         {
6956           minDistToGC = d;
6957           closestElem = d2f->second;
6958         }
6959       }
6960       // cout << "FindClosestTo( " <<point.X()<<", "<<point.Y()<<", "<<point.Z()<<" ) FACE "
6961       //      <<closestElem->GetID() << " DIST " << minDist << endl;
6962     }
6963   }
6964   else
6965   {
6966     // NOT IMPLEMENTED SO FAR
6967   }
6968   return closestElem;
6969 }
6970
6971
6972 //================================================================================
6973 /*!
6974  * \brief Classify the given point in the closed 2D mesh
6975  */
6976 //================================================================================
6977
6978 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6979 {
6980   double tolerance = getTolerance();
6981   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6982   {
6983     if ( _ebbTree ) delete _ebbTree;
6984     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6985   }
6986   // Algo: analyse transition of a line starting at the point through mesh boundary;
6987   // try three lines parallel to axis of the coordinate system and perform rough
6988   // analysis. If solution is not clear perform thorough analysis.
6989
6990   const int nbAxes = 3;
6991   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6992   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6993   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6994   multimap< int, int > nbInt2Axis; // to find the simplest case
6995   for ( int axis = 0; axis < nbAxes; ++axis )
6996   {
6997     gp_Ax1 lineAxis( point, axisDir[axis]);
6998     gp_Lin line    ( lineAxis );
6999
7000     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
7001     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
7002
7003     // Intersect faces with the line
7004
7005     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
7006     TIDSortedElemSet::iterator face = suspectFaces.begin();
7007     for ( ; face != suspectFaces.end(); ++face )
7008     {
7009       // get face plane
7010       gp_XYZ fNorm;
7011       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
7012       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
7013
7014       // perform intersection
7015       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
7016       if ( !intersection.IsDone() )
7017         continue;
7018       if ( intersection.IsInQuadric() )
7019       {
7020         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
7021       }
7022       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
7023       {
7024         gp_Pnt intersectionPoint = intersection.Point(1);
7025         if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance ))
7026           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
7027       }
7028     }
7029     // Analyse intersections roughly
7030
7031     int nbInter = u2inters.size();
7032     if ( nbInter == 0 )
7033       return TopAbs_OUT;
7034
7035     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
7036     if ( nbInter == 1 ) // not closed mesh
7037       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7038
7039     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
7040       return TopAbs_ON;
7041
7042     if ( (f<0) == (l<0) )
7043       return TopAbs_OUT;
7044
7045     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
7046     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
7047     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7048       return TopAbs_IN;
7049
7050     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
7051
7052     if ( _outerFacesFound ) break; // pass to thorough analysis
7053
7054   } // three attempts - loop on CS axes
7055
7056   // Analyse intersections thoroughly.
7057   // We make two loops maximum, on the first one we only exclude touching intersections,
7058   // on the second, if situation is still unclear, we gather and use information on
7059   // position of faces (internal or outer). If faces position is already gathered,
7060   // we make the second loop right away.
7061
7062   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
7063   {
7064     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
7065     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
7066     {
7067       int axis = nb_axis->second;
7068       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
7069
7070       gp_Ax1 lineAxis( point, axisDir[axis]);
7071       gp_Lin line    ( lineAxis );
7072
7073       // add tangent intersections to u2inters
7074       double param;
7075       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
7076       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
7077         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
7078           u2inters.insert(make_pair( param, *tgtInt ));
7079       tangentInters[ axis ].clear();
7080
7081       // Count intersections before and after the point excluding touching ones.
7082       // If hasPositionInfo we count intersections of outer boundary only
7083
7084       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
7085       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
7086       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
7087       bool ok = ! u_int1->second._coincides;
7088       while ( ok && u_int1 != u2inters.end() )
7089       {
7090         double u = u_int1->first;
7091         bool touchingInt = false;
7092         if ( ++u_int2 != u2inters.end() )
7093         {
7094           // skip intersections at the same point (if the line passes through edge or node)
7095           int nbSamePnt = 0;
7096           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
7097           {
7098             ++nbSamePnt;
7099             ++u_int2;
7100           }
7101
7102           // skip tangent intersections
7103           int nbTgt = 0;
7104           const SMDS_MeshElement* prevFace = u_int1->second._face;
7105           while ( ok && u_int2->second._coincides )
7106           {
7107             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
7108               ok = false;
7109             else
7110             {
7111               nbTgt++;
7112               u_int2++;
7113               ok = ( u_int2 != u2inters.end() );
7114             }
7115           }
7116           if ( !ok ) break;
7117
7118           // skip intersections at the same point after tangent intersections
7119           if ( nbTgt > 0 )
7120           {
7121             double u2 = u_int2->first;
7122             ++u_int2;
7123             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
7124             {
7125               ++nbSamePnt;
7126               ++u_int2;
7127             }
7128           }
7129           // decide if we skipped a touching intersection
7130           if ( nbSamePnt + nbTgt > 0 )
7131           {
7132             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
7133             map< double, TInters >::iterator u_int = u_int1;
7134             for ( ; u_int != u_int2; ++u_int )
7135             {
7136               if ( u_int->second._coincides ) continue;
7137               double dot = u_int->second._faceNorm * line.Direction();
7138               if ( dot > maxDot ) maxDot = dot;
7139               if ( dot < minDot ) minDot = dot;
7140             }
7141             touchingInt = ( minDot*maxDot < 0 );
7142           }
7143         }
7144         if ( !touchingInt )
7145         {
7146           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
7147           {
7148             if ( u < 0 )
7149               ++nbIntBeforePoint;
7150             else
7151               ++nbIntAfterPoint;
7152           }
7153           if ( u < f ) f = u;
7154           if ( u > l ) l = u;
7155         }
7156
7157         u_int1 = u_int2; // to next intersection
7158
7159       } // loop on intersections with one line
7160
7161       if ( ok )
7162       {
7163         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
7164           return TopAbs_ON;
7165
7166         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
7167           return TopAbs_OUT;
7168
7169         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
7170           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7171
7172         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7173           return TopAbs_IN;
7174
7175         if ( (f<0) == (l<0) )
7176           return TopAbs_OUT;
7177
7178         if ( hasPositionInfo )
7179           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7180       }
7181     } // loop on intersections of the tree lines - thorough analysis
7182
7183     if ( !hasPositionInfo )
7184     {
7185       // gather info on faces position - is face in the outer boundary or not
7186       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7187       findOuterBoundary( u2inters.begin()->second._face );
7188     }
7189
7190   } // two attempts - with and w/o faces position info in the mesh
7191
7192   return TopAbs_UNKNOWN;
7193 }
7194
7195 //=======================================================================
7196 /*!
7197  * \brief Return elements possibly intersecting the line
7198  */
7199 //=======================================================================
7200
7201 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7202                                                      SMDSAbs_ElementType                type,
7203                                                      vector< const SMDS_MeshElement* >& foundElems)
7204 {
7205   if ( !_ebbTree || _elementType != type )
7206   {
7207     if ( _ebbTree ) delete _ebbTree;
7208     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7209   }
7210   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7211   _ebbTree->getElementsNearLine( line, suspectFaces );
7212   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7213 }
7214
7215 //=======================================================================
7216 /*!
7217  * \brief Return SMESH_ElementSearcher
7218  */
7219 //=======================================================================
7220
7221 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7222 {
7223   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7224 }
7225
7226 //=======================================================================
7227 /*!
7228  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
7229  */
7230 //=======================================================================
7231
7232 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7233 {
7234   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7235 }
7236
7237 //=======================================================================
7238 /*!
7239  * \brief Return true if the point is IN or ON of the element
7240  */
7241 //=======================================================================
7242
7243 bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7244 {
7245   if ( element->GetType() == SMDSAbs_Volume)
7246   {
7247     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7248   }
7249
7250   // get ordered nodes
7251
7252   vector< gp_XYZ > xyz;
7253   vector<const SMDS_MeshNode*> nodeList;
7254
7255   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7256   if ( element->IsQuadratic() ) {
7257     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7258       nodeIt = f->interlacedNodesElemIterator();
7259     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7260       nodeIt = e->interlacedNodesElemIterator();
7261   }
7262   while ( nodeIt->more() )
7263     {
7264       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7265       xyz.push_back( SMESH_TNodeXYZ(node) );
7266       nodeList.push_back(node);
7267     }
7268
7269   int i, nbNodes = element->NbNodes();
7270
7271   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7272   {
7273     // compute face normal
7274     gp_Vec faceNorm(0,0,0);
7275     xyz.push_back( xyz.front() );
7276     nodeList.push_back( nodeList.front() );
7277     for ( i = 0; i < nbNodes; ++i )
7278     {
7279       gp_Vec edge1( xyz[i+1], xyz[i]);
7280       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7281       faceNorm += edge1 ^ edge2;
7282     }
7283     double normSize = faceNorm.Magnitude();
7284     if ( normSize <= tol )
7285     {
7286       // degenerated face: point is out if it is out of all face edges
7287       for ( i = 0; i < nbNodes; ++i )
7288       {
7289         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7290         if ( !IsOut( &edge, point, tol ))
7291           return false;
7292       }
7293       return true;
7294     }
7295     faceNorm /= normSize;
7296
7297     // check if the point lays on face plane
7298     gp_Vec n2p( xyz[0], point );
7299     if ( fabs( n2p * faceNorm ) > tol )
7300       return true; // not on face plane
7301
7302     // check if point is out of face boundary:
7303     // define it by closest transition of a ray point->infinity through face boundary
7304     // on the face plane.
7305     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7306     // to find intersections of the ray with the boundary.
7307     gp_Vec ray = n2p;
7308     gp_Vec plnNorm = ray ^ faceNorm;
7309     normSize = plnNorm.Magnitude();
7310     if ( normSize <= tol ) return false; // point coincides with the first node
7311     plnNorm /= normSize;
7312     // for each node of the face, compute its signed distance to the plane
7313     vector<double> dist( nbNodes + 1);
7314     for ( i = 0; i < nbNodes; ++i )
7315     {
7316       gp_Vec n2p( xyz[i], point );
7317       dist[i] = n2p * plnNorm;
7318     }
7319     dist.back() = dist.front();
7320     // find the closest intersection
7321     int    iClosest = -1;
7322     double rClosest, distClosest = 1e100;;
7323     gp_Pnt pClosest;
7324     for ( i = 0; i < nbNodes; ++i )
7325     {
7326       double r;
7327       if ( fabs( dist[i]) < tol )
7328         r = 0.;
7329       else if ( fabs( dist[i+1]) < tol )
7330         r = 1.;
7331       else if ( dist[i] * dist[i+1] < 0 )
7332         r = dist[i] / ( dist[i] - dist[i+1] );
7333       else
7334         continue; // no intersection
7335       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7336       gp_Vec p2int ( point, pInt);
7337       if ( p2int * ray > -tol ) // right half-space
7338       {
7339         double intDist = p2int.SquareMagnitude();
7340         if ( intDist < distClosest )
7341         {
7342           iClosest = i;
7343           rClosest = r;
7344           pClosest = pInt;
7345           distClosest = intDist;
7346         }
7347       }
7348     }
7349     if ( iClosest < 0 )
7350       return true; // no intesections - out
7351
7352     // analyse transition
7353     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7354     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7355     gp_Vec p2int ( point, pClosest );
7356     bool out = (edgeNorm * p2int) < -tol;
7357     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7358       return out;
7359
7360     // ray pass through a face node; analyze transition through an adjacent edge
7361     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7362     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7363     gp_Vec edgeAdjacent( p1, p2 );
7364     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7365     bool out2 = (edgeNorm2 * p2int) < -tol;
7366
7367     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7368     return covexCorner ? (out || out2) : (out && out2);
7369   }
7370   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7371   {
7372     // point is out of edge if it is NOT ON any straight part of edge
7373     // (we consider quadratic edge as being composed of two straight parts)
7374     for ( i = 1; i < nbNodes; ++i )
7375     {
7376       gp_Vec edge( xyz[i-1], xyz[i]);
7377       gp_Vec n1p ( xyz[i-1], point);
7378       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7379       if ( dist > tol )
7380         continue;
7381       gp_Vec n2p( xyz[i], point );
7382       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7383         continue;
7384       return false; // point is ON this part
7385     }
7386     return true;
7387   }
7388   // Node or 0D element -------------------------------------------------------------------------
7389   {
7390     gp_Vec n2p ( xyz[0], point );
7391     return n2p.Magnitude() <= tol;
7392   }
7393   return true;
7394 }
7395
7396 //=======================================================================
7397
7398 namespace
7399 {
7400   // Position of a point relative to a segment
7401   //            .           .
7402   //            .  LEFT     .
7403   //            .           .
7404   //  VERTEX 1  o----ON----->  VERTEX 2
7405   //            .           .
7406   //            .  RIGHT    .
7407   //            .           .
7408   enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
7409                       POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
7410   struct PointPos
7411   {
7412     PositionName _name;
7413     int          _index; // index of vertex or segment
7414
7415     PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {}
7416     bool operator < (const PointPos& other ) const
7417     {
7418       if ( _name == other._name )
7419         return  ( _index < 0 || other._index < 0 ) ? false : _index < other._index;
7420       return _name < other._name;
7421     }
7422   };
7423
7424   //================================================================================
7425   /*!
7426    * \brief Return of a point relative to a segment
7427    *  \param point2D      - the point to analyze position of
7428    *  \param xyVec        - end points of segments
7429    *  \param index0       - 0-based index of the first point of segment
7430    *  \param posToFindOut - flags of positions to detect
7431    *  \retval PointPos - point position
7432    */
7433   //================================================================================
7434
7435   PointPos getPointPosition( const gp_XY& point2D,
7436                              const gp_XY* segEnds,
7437                              const int    index0 = 0,
7438                              const int    posToFindOut = POS_ALL)
7439   {
7440     const gp_XY& p1 = segEnds[ index0   ];
7441     const gp_XY& p2 = segEnds[ index0+1 ];
7442     const gp_XY grad = p2 - p1;
7443
7444     if ( posToFindOut & POS_VERTEX )
7445     {
7446       // check if the point2D is at "vertex 1" zone
7447       gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(),
7448                                   p1.Y() + grad.X() ) };
7449       if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT )
7450         return PointPos( POS_VERTEX, index0 );
7451
7452       // check if the point2D is at "vertex 2" zone
7453       gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(),
7454                                   p2.Y() + grad.X() ) };
7455       if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT )
7456         return PointPos( POS_VERTEX, index0 + 1);
7457     }
7458     double edgeEquation =
7459       ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X();
7460     return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 );
7461   }
7462 }
7463
7464 //=======================================================================
7465 /*!
7466  * \brief Return minimal distance from a point to a face
7467  *
7468  * Currently we ignore non-planarity and 2nd order of face
7469  */
7470 //=======================================================================
7471
7472 double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face,
7473                                       const gp_Pnt&        point )
7474 {
7475   double badDistance = -1;
7476   if ( !face ) return badDistance;
7477
7478   // coordinates of nodes (medium nodes, if any, ignored)
7479   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
7480   vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
7481   xyz.resize( face->NbCornerNodes()+1 );
7482
7483   // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
7484   // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
7485   gp_Trsf trsf;
7486   gp_Vec OZ ( xyz[0], xyz[1] );
7487   gp_Vec OX ( xyz[0], xyz[2] );
7488   if ( OZ.Magnitude() < std::numeric_limits<double>::min() )
7489   {
7490     if ( xyz.size() < 4 ) return badDistance;
7491     OZ = gp_Vec ( xyz[0], xyz[2] );
7492     OX = gp_Vec ( xyz[0], xyz[3] );
7493   }
7494   gp_Ax3 tgtCS;
7495   try {
7496     tgtCS = gp_Ax3( xyz[0], OZ, OX );
7497   }
7498   catch ( Standard_Failure ) {
7499     return badDistance;
7500   }
7501   trsf.SetTransformation( tgtCS );
7502
7503   // move all the nodes to 2D
7504   vector<gp_XY> xy( xyz.size() );
7505   for ( size_t i = 0;i < xyz.size()-1; ++i )
7506   {
7507     gp_XYZ p3d = xyz[i];
7508     trsf.Transforms( p3d );
7509     xy[i].SetCoord( p3d.X(), p3d.Z() );
7510   }
7511   xyz.back() = xyz.front();
7512   xy.back() = xy.front();
7513
7514   // // move the point in 2D
7515   gp_XYZ tmpPnt = point.XYZ();
7516   trsf.Transforms( tmpPnt );
7517   gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
7518
7519   // loop on segments of the face to analyze point position ralative to the face
7520   set< PointPos > pntPosSet;
7521   for ( size_t i = 1; i < xy.size(); ++i )
7522   {
7523     PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
7524     pntPosSet.insert( pos );
7525   }
7526
7527   // compute distance
7528   PointPos pos = *pntPosSet.begin();
7529   // cout << "Face " << face->GetID() << " DIST: ";
7530   switch ( pos._name )
7531   {
7532   case POS_LEFT: {
7533     // point is most close to a segment
7534     gp_Vec p0p1( point, xyz[ pos._index ] );
7535     gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
7536     p1p2.Normalize();
7537     double projDist = p0p1 * p1p2; // distance projected to the segment
7538     gp_Vec projVec = p1p2 * projDist;
7539     gp_Vec distVec = p0p1 - projVec;
7540     // cout << distVec.Magnitude()  << ", SEG " << face->GetNode(pos._index)->GetID()
7541     //      << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
7542     return distVec.Magnitude();
7543   }
7544   case POS_RIGHT: {
7545     // point is inside the face
7546     double distToFacePlane = tmpPnt.Y();
7547     // cout << distToFacePlane << ", INSIDE " << endl;
7548     return Abs( distToFacePlane );
7549   }
7550   case POS_VERTEX: {
7551     // point is most close to a node
7552     gp_Vec distVec( point, xyz[ pos._index ]);
7553     // cout << distVec.Magnitude()  << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
7554     return distVec.Magnitude();
7555   }
7556   }
7557   return badDistance;
7558 }
7559
7560 //=======================================================================
7561 //function : SimplifyFace
7562 //purpose  :
7563 //=======================================================================
7564 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7565                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7566                                     vector<int>&                        quantities) const
7567 {
7568   int nbNodes = faceNodes.size();
7569
7570   if (nbNodes < 3)
7571     return 0;
7572
7573   set<const SMDS_MeshNode*> nodeSet;
7574
7575   // get simple seq of nodes
7576   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7577   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7578   int iSimple = 0, nbUnique = 0;
7579
7580   simpleNodes[iSimple++] = faceNodes[0];
7581   nbUnique++;
7582   for (int iCur = 1; iCur < nbNodes; iCur++) {
7583     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7584       simpleNodes[iSimple++] = faceNodes[iCur];
7585       if (nodeSet.insert( faceNodes[iCur] ).second)
7586         nbUnique++;
7587     }
7588   }
7589   int nbSimple = iSimple;
7590   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7591     nbSimple--;
7592     iSimple--;
7593   }
7594
7595   if (nbUnique < 3)
7596     return 0;
7597
7598   // separate loops
7599   int nbNew = 0;
7600   bool foundLoop = (nbSimple > nbUnique);
7601   while (foundLoop) {
7602     foundLoop = false;
7603     set<const SMDS_MeshNode*> loopSet;
7604     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7605       const SMDS_MeshNode* n = simpleNodes[iSimple];
7606       if (!loopSet.insert( n ).second) {
7607         foundLoop = true;
7608
7609         // separate loop
7610         int iC = 0, curLast = iSimple;
7611         for (; iC < curLast; iC++) {
7612           if (simpleNodes[iC] == n) break;
7613         }
7614         int loopLen = curLast - iC;
7615         if (loopLen > 2) {
7616           // create sub-element
7617           nbNew++;
7618           quantities.push_back(loopLen);
7619           for (; iC < curLast; iC++) {
7620             poly_nodes.push_back(simpleNodes[iC]);
7621           }
7622         }
7623         // shift the rest nodes (place from the first loop position)
7624         for (iC = curLast + 1; iC < nbSimple; iC++) {
7625           simpleNodes[iC - loopLen] = simpleNodes[iC];
7626         }
7627         nbSimple -= loopLen;
7628         iSimple -= loopLen;
7629       }
7630     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7631   } // while (foundLoop)
7632
7633   if (iSimple > 2) {
7634     nbNew++;
7635     quantities.push_back(iSimple);
7636     for (int i = 0; i < iSimple; i++)
7637       poly_nodes.push_back(simpleNodes[i]);
7638   }
7639
7640   return nbNew;
7641 }
7642
7643 //=======================================================================
7644 //function : MergeNodes
7645 //purpose  : In each group, the cdr of nodes are substituted by the first one
7646 //           in all elements.
7647 //=======================================================================
7648
7649 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7650 {
7651   MESSAGE("MergeNodes");
7652   myLastCreatedElems.Clear();
7653   myLastCreatedNodes.Clear();
7654
7655   SMESHDS_Mesh* aMesh = GetMeshDS();
7656
7657   TNodeNodeMap nodeNodeMap; // node to replace - new node
7658   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7659   list< int > rmElemIds, rmNodeIds;
7660
7661   // Fill nodeNodeMap and elems
7662
7663   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7664   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7665     list<const SMDS_MeshNode*>& nodes = *grIt;
7666     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7667     const SMDS_MeshNode* nToKeep = *nIt;
7668     //MESSAGE("node to keep " << nToKeep->GetID());
7669     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7670       const SMDS_MeshNode* nToRemove = *nIt;
7671       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7672       if ( nToRemove != nToKeep ) {
7673         //MESSAGE("  node to remove " << nToRemove->GetID());
7674         rmNodeIds.push_back( nToRemove->GetID() );
7675         AddToSameGroups( nToKeep, nToRemove, aMesh );
7676         // set _alwaysComputed to a sub-mesh of VERTEX to enable mesh computing
7677         // after MergeNodes() w/o creating node in place of merged ones.
7678         const SMDS_PositionPtr& pos = nToRemove->GetPosition();
7679         if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
7680           if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
7681             sm->SetIsAlwaysComputed( true );
7682       }
7683
7684       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7685       while ( invElemIt->more() ) {
7686         const SMDS_MeshElement* elem = invElemIt->next();
7687         elems.insert(elem);
7688       }
7689     }
7690   }
7691   // Change element nodes or remove an element
7692
7693   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7694   for ( ; eIt != elems.end(); eIt++ ) {
7695     const SMDS_MeshElement* elem = *eIt;
7696     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7697     int nbNodes = elem->NbNodes();
7698     int aShapeId = FindShape( elem );
7699
7700     set<const SMDS_MeshNode*> nodeSet;
7701     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7702     int iUnique = 0, iCur = 0, nbRepl = 0;
7703     vector<int> iRepl( nbNodes );
7704
7705     // get new seq of nodes
7706     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7707     while ( itN->more() ) {
7708       const SMDS_MeshNode* n =
7709         static_cast<const SMDS_MeshNode*>( itN->next() );
7710
7711       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7712       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7713         n = (*nnIt).second;
7714         // BUG 0020185: begin
7715         {
7716           bool stopRecur = false;
7717           set<const SMDS_MeshNode*> nodesRecur;
7718           nodesRecur.insert(n);
7719           while (!stopRecur) {
7720             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7721             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7722               n = (*nnIt_i).second;
7723               if (!nodesRecur.insert(n).second) {
7724                 // error: recursive dependancy
7725                 stopRecur = true;
7726               }
7727             }
7728             else
7729               stopRecur = true;
7730           }
7731         }
7732         // BUG 0020185: end
7733       }
7734       curNodes[ iCur ] = n;
7735       bool isUnique = nodeSet.insert( n ).second;
7736       if ( isUnique )
7737         uniqueNodes[ iUnique++ ] = n;
7738       else
7739         iRepl[ nbRepl++ ] = iCur;
7740       iCur++;
7741     }
7742
7743     // Analyse element topology after replacement
7744
7745     bool isOk = true;
7746     int nbUniqueNodes = nodeSet.size();
7747     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7748     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7749       // Polygons and Polyhedral volumes
7750       if (elem->IsPoly()) {
7751
7752         if (elem->GetType() == SMDSAbs_Face) {
7753           // Polygon
7754           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7755           int inode = 0;
7756           for (; inode < nbNodes; inode++) {
7757             face_nodes[inode] = curNodes[inode];
7758           }
7759
7760           vector<const SMDS_MeshNode *> polygons_nodes;
7761           vector<int> quantities;
7762           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7763           if (nbNew > 0) {
7764             inode = 0;
7765             for (int iface = 0; iface < nbNew; iface++) {
7766               int nbNodes = quantities[iface];
7767               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7768               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7769                 poly_nodes[ii] = polygons_nodes[inode];
7770               }
7771               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7772               myLastCreatedElems.Append(newElem);
7773               if (aShapeId)
7774                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7775             }
7776
7777             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7778             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7779             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7780             int quid =0;
7781             if (nbNew > 0) quid = nbNew - 1;
7782             vector<int> newquant(quantities.begin()+quid, quantities.end());
7783             const SMDS_MeshElement* newElem = 0;
7784             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7785             myLastCreatedElems.Append(newElem);
7786             if ( aShapeId && newElem )
7787               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7788             rmElemIds.push_back(elem->GetID());
7789           }
7790           else {
7791             rmElemIds.push_back(elem->GetID());
7792           }
7793
7794         }
7795         else if (elem->GetType() == SMDSAbs_Volume) {
7796           // Polyhedral volume
7797           if (nbUniqueNodes < 4) {
7798             rmElemIds.push_back(elem->GetID());
7799           }
7800           else {
7801             // each face has to be analyzed in order to check volume validity
7802             const SMDS_VtkVolume* aPolyedre =
7803               dynamic_cast<const SMDS_VtkVolume*>( elem );
7804             if (aPolyedre) {
7805               int nbFaces = aPolyedre->NbFaces();
7806
7807               vector<const SMDS_MeshNode *> poly_nodes;
7808               vector<int> quantities;
7809
7810               for (int iface = 1; iface <= nbFaces; iface++) {
7811                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7812                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7813
7814                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7815                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7816                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7817                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7818                     faceNode = (*nnIt).second;
7819                   }
7820                   faceNodes[inode - 1] = faceNode;
7821                 }
7822
7823                 SimplifyFace(faceNodes, poly_nodes, quantities);
7824               }
7825
7826               if (quantities.size() > 3) {
7827                 // to be done: remove coincident faces
7828               }
7829
7830               if (quantities.size() > 3)
7831                 {
7832                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7833                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7834                   const SMDS_MeshElement* newElem = 0;
7835                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7836                   myLastCreatedElems.Append(newElem);
7837                   if ( aShapeId && newElem )
7838                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7839                   rmElemIds.push_back(elem->GetID());
7840                 }
7841             }
7842             else {
7843               rmElemIds.push_back(elem->GetID());
7844             }
7845           }
7846         }
7847         else {
7848         }
7849
7850         continue;
7851       } // poly element
7852
7853       // Regular elements
7854       // TODO not all the possible cases are solved. Find something more generic?
7855       switch ( nbNodes ) {
7856       case 2: ///////////////////////////////////// EDGE
7857         isOk = false; break;
7858       case 3: ///////////////////////////////////// TRIANGLE
7859         isOk = false; break;
7860       case 4:
7861         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7862           isOk = false;
7863         else { //////////////////////////////////// QUADRANGLE
7864           if ( nbUniqueNodes < 3 )
7865             isOk = false;
7866           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7867             isOk = false; // opposite nodes stick
7868           //MESSAGE("isOk " << isOk);
7869         }
7870         break;
7871       case 6: ///////////////////////////////////// PENTAHEDRON
7872         if ( nbUniqueNodes == 4 ) {
7873           // ---------------------------------> tetrahedron
7874           if (nbRepl == 3 &&
7875               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7876             // all top nodes stick: reverse a bottom
7877             uniqueNodes[ 0 ] = curNodes [ 1 ];
7878             uniqueNodes[ 1 ] = curNodes [ 0 ];
7879           }
7880           else if (nbRepl == 3 &&
7881                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7882             // all bottom nodes stick: set a top before
7883             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7884             uniqueNodes[ 0 ] = curNodes [ 3 ];
7885             uniqueNodes[ 1 ] = curNodes [ 4 ];
7886             uniqueNodes[ 2 ] = curNodes [ 5 ];
7887           }
7888           else if (nbRepl == 4 &&
7889                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7890             // a lateral face turns into a line: reverse a bottom
7891             uniqueNodes[ 0 ] = curNodes [ 1 ];
7892             uniqueNodes[ 1 ] = curNodes [ 0 ];
7893           }
7894           else
7895             isOk = false;
7896         }
7897         else if ( nbUniqueNodes == 5 ) {
7898           // PENTAHEDRON --------------------> 2 tetrahedrons
7899           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7900             // a bottom node sticks with a linked top one
7901             // 1.
7902             SMDS_MeshElement* newElem =
7903               aMesh->AddVolume(curNodes[ 3 ],
7904                                curNodes[ 4 ],
7905                                curNodes[ 5 ],
7906                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7907             myLastCreatedElems.Append(newElem);
7908             if ( aShapeId )
7909               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7910             // 2. : reverse a bottom
7911             uniqueNodes[ 0 ] = curNodes [ 1 ];
7912             uniqueNodes[ 1 ] = curNodes [ 0 ];
7913             nbUniqueNodes = 4;
7914           }
7915           else
7916             isOk = false;
7917         }
7918         else
7919           isOk = false;
7920         break;
7921       case 8: {
7922         if(elem->IsQuadratic()) { // Quadratic quadrangle
7923           //   1    5    2
7924           //    +---+---+
7925           //    |       |
7926           //    |       |
7927           //   4+       +6
7928           //    |       |
7929           //    |       |
7930           //    +---+---+
7931           //   0    7    3
7932           isOk = false;
7933           if(nbRepl==2) {
7934             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7935           }
7936           if(nbRepl==3) {
7937             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7938             nbUniqueNodes = 6;
7939             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7940               uniqueNodes[0] = curNodes[0];
7941               uniqueNodes[1] = curNodes[2];
7942               uniqueNodes[2] = curNodes[3];
7943               uniqueNodes[3] = curNodes[5];
7944               uniqueNodes[4] = curNodes[6];
7945               uniqueNodes[5] = curNodes[7];
7946               isOk = true;
7947             }
7948             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7949               uniqueNodes[0] = curNodes[0];
7950               uniqueNodes[1] = curNodes[1];
7951               uniqueNodes[2] = curNodes[2];
7952               uniqueNodes[3] = curNodes[4];
7953               uniqueNodes[4] = curNodes[5];
7954               uniqueNodes[5] = curNodes[6];
7955               isOk = true;
7956             }
7957             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7958               uniqueNodes[0] = curNodes[1];
7959               uniqueNodes[1] = curNodes[2];
7960               uniqueNodes[2] = curNodes[3];
7961               uniqueNodes[3] = curNodes[5];
7962               uniqueNodes[4] = curNodes[6];
7963               uniqueNodes[5] = curNodes[0];
7964               isOk = true;
7965             }
7966             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7967               uniqueNodes[0] = curNodes[0];
7968               uniqueNodes[1] = curNodes[1];
7969               uniqueNodes[2] = curNodes[3];
7970               uniqueNodes[3] = curNodes[4];
7971               uniqueNodes[4] = curNodes[6];
7972               uniqueNodes[5] = curNodes[7];
7973               isOk = true;
7974             }
7975             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7976               uniqueNodes[0] = curNodes[0];
7977               uniqueNodes[1] = curNodes[2];
7978               uniqueNodes[2] = curNodes[3];
7979               uniqueNodes[3] = curNodes[1];
7980               uniqueNodes[4] = curNodes[6];
7981               uniqueNodes[5] = curNodes[7];
7982               isOk = true;
7983             }
7984             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7985               uniqueNodes[0] = curNodes[0];
7986               uniqueNodes[1] = curNodes[1];
7987               uniqueNodes[2] = curNodes[2];
7988               uniqueNodes[3] = curNodes[4];
7989               uniqueNodes[4] = curNodes[5];
7990               uniqueNodes[5] = curNodes[7];
7991               isOk = true;
7992             }
7993             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7994               uniqueNodes[0] = curNodes[0];
7995               uniqueNodes[1] = curNodes[1];
7996               uniqueNodes[2] = curNodes[3];
7997               uniqueNodes[3] = curNodes[4];
7998               uniqueNodes[4] = curNodes[2];
7999               uniqueNodes[5] = curNodes[7];
8000               isOk = true;
8001             }
8002             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
8003               uniqueNodes[0] = curNodes[0];
8004               uniqueNodes[1] = curNodes[1];
8005               uniqueNodes[2] = curNodes[2];
8006               uniqueNodes[3] = curNodes[4];
8007               uniqueNodes[4] = curNodes[5];
8008               uniqueNodes[5] = curNodes[3];
8009               isOk = true;
8010             }
8011           }
8012           if(nbRepl==4) {
8013             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
8014           }
8015           if(nbRepl==5) {
8016             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
8017           }
8018           break;
8019         }
8020         //////////////////////////////////// HEXAHEDRON
8021         isOk = false;
8022         SMDS_VolumeTool hexa (elem);
8023         hexa.SetExternalNormal();
8024         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
8025           //////////////////////// HEX ---> 1 tetrahedron
8026           for ( int iFace = 0; iFace < 6; iFace++ ) {
8027             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
8028             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
8029                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
8030                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
8031               // one face turns into a point ...
8032               int iOppFace = hexa.GetOppFaceIndex( iFace );
8033               ind = hexa.GetFaceNodesIndices( iOppFace );
8034               int nbStick = 0;
8035               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
8036                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
8037                   nbStick++;
8038               }
8039               if ( nbStick == 1 ) {
8040                 // ... and the opposite one - into a triangle.
8041                 // set a top node
8042                 ind = hexa.GetFaceNodesIndices( iFace );
8043                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
8044                 isOk = true;
8045               }
8046               break;
8047             }
8048           }
8049         }
8050         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
8051           //////////////////////// HEX ---> 1 prism
8052           int nbTria = 0, iTria[3];
8053           const int *ind; // indices of face nodes
8054           // look for triangular faces
8055           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
8056             ind = hexa.GetFaceNodesIndices( iFace );
8057             TIDSortedNodeSet faceNodes;
8058             for ( iCur = 0; iCur < 4; iCur++ )
8059               faceNodes.insert( curNodes[ind[iCur]] );
8060             if ( faceNodes.size() == 3 )
8061               iTria[ nbTria++ ] = iFace;
8062           }
8063           // check if triangles are opposite
8064           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
8065           {
8066             isOk = true;
8067             // set nodes of the bottom triangle
8068             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
8069             vector<int> indB;
8070             for ( iCur = 0; iCur < 4; iCur++ )
8071               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
8072                 indB.push_back( ind[iCur] );
8073             if ( !hexa.IsForward() )
8074               std::swap( indB[0], indB[2] );
8075             for ( iCur = 0; iCur < 3; iCur++ )
8076               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
8077             // set nodes of the top triangle
8078             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
8079             for ( iCur = 0; iCur < 3; ++iCur )
8080               for ( int j = 0; j < 4; ++j )
8081                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
8082                 {
8083                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
8084                   break;
8085                 }
8086           }
8087           break;
8088         }
8089         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
8090           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
8091           for ( int iFace = 0; iFace < 6; iFace++ ) {
8092             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
8093             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
8094                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
8095                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
8096               // one face turns into a point ...
8097               int iOppFace = hexa.GetOppFaceIndex( iFace );
8098               ind = hexa.GetFaceNodesIndices( iOppFace );
8099               int nbStick = 0;
8100               iUnique = 2;  // reverse a tetrahedron 1 bottom
8101               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
8102                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
8103                   nbStick++;
8104                 else if ( iUnique >= 0 )
8105                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
8106               }
8107               if ( nbStick == 0 ) {
8108                 // ... and the opposite one is a quadrangle
8109                 // set a top node
8110                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
8111                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
8112                 nbUniqueNodes = 4;
8113                 // tetrahedron 2
8114                 SMDS_MeshElement* newElem =
8115                   aMesh->AddVolume(curNodes[ind[ 0 ]],
8116                                    curNodes[ind[ 3 ]],
8117                                    curNodes[ind[ 2 ]],
8118                                    curNodes[indTop[ 0 ]]);
8119                 myLastCreatedElems.Append(newElem);
8120                 if ( aShapeId )
8121                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
8122                 isOk = true;
8123               }
8124               break;
8125             }
8126           }
8127         }
8128         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
8129           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
8130           // find indices of quad and tri faces
8131           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
8132           for ( iFace = 0; iFace < 6; iFace++ ) {
8133             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
8134             nodeSet.clear();
8135             for ( iCur = 0; iCur < 4; iCur++ )
8136               nodeSet.insert( curNodes[ind[ iCur ]] );
8137             nbUniqueNodes = nodeSet.size();
8138             if ( nbUniqueNodes == 3 )
8139               iTriFace[ nbTri++ ] = iFace;
8140             else if ( nbUniqueNodes == 4 )
8141               iQuadFace[ nbQuad++ ] = iFace;
8142           }
8143           if (nbQuad == 2 && nbTri == 4 &&
8144               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
8145             // 2 opposite quadrangles stuck with a diagonal;
8146             // sample groups of merged indices: (0-4)(2-6)
8147             // --------------------------------------------> 2 tetrahedrons
8148             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
8149             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
8150             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
8151             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
8152                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
8153               // stuck with 0-2 diagonal
8154               i0  = ind1[ 3 ];
8155               i1d = ind1[ 0 ];
8156               i2  = ind1[ 1 ];
8157               i3d = ind1[ 2 ];
8158               i0t = ind2[ 1 ];
8159               i2t = ind2[ 3 ];
8160             }
8161             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
8162                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
8163               // stuck with 1-3 diagonal
8164               i0  = ind1[ 0 ];
8165               i1d = ind1[ 1 ];
8166               i2  = ind1[ 2 ];
8167               i3d = ind1[ 3 ];
8168               i0t = ind2[ 0 ];
8169               i2t = ind2[ 1 ];
8170             }
8171             else {
8172               ASSERT(0);
8173             }
8174             // tetrahedron 1
8175             uniqueNodes[ 0 ] = curNodes [ i0 ];
8176             uniqueNodes[ 1 ] = curNodes [ i1d ];
8177             uniqueNodes[ 2 ] = curNodes [ i3d ];
8178             uniqueNodes[ 3 ] = curNodes [ i0t ];
8179             nbUniqueNodes = 4;
8180             // tetrahedron 2
8181             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
8182                                                          curNodes[ i2 ],
8183                                                          curNodes[ i3d ],
8184                                                          curNodes[ i2t ]);
8185             myLastCreatedElems.Append(newElem);
8186             if ( aShapeId )
8187               aMesh->SetMeshElementOnShape( newElem, aShapeId );
8188             isOk = true;
8189           }
8190           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
8191                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
8192             // --------------------------------------------> prism
8193             // find 2 opposite triangles
8194             nbUniqueNodes = 6;
8195             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
8196               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
8197                 // find indices of kept and replaced nodes
8198                 // and fill unique nodes of 2 opposite triangles
8199                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
8200                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
8201                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
8202                 // fill unique nodes
8203                 iUnique = 0;
8204                 isOk = true;
8205                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
8206                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
8207                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
8208                   if ( n == nInit ) {
8209                     // iCur of a linked node of the opposite face (make normals co-directed):
8210                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
8211                     // check that correspondent corners of triangles are linked
8212                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
8213                       isOk = false;
8214                     else {
8215                       uniqueNodes[ iUnique ] = n;
8216                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
8217                       iUnique++;
8218                     }
8219                   }
8220                 }
8221                 break;
8222               }
8223             }
8224           }
8225         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
8226         else
8227         {
8228           MESSAGE("MergeNodes() removes hexahedron "<< elem);
8229         }
8230         break;
8231       } // HEXAHEDRON
8232
8233       default:
8234         isOk = false;
8235       } // switch ( nbNodes )
8236
8237     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
8238
8239     if ( isOk ) { // the elem remains valid after sticking nodes
8240       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
8241       {
8242         // Change nodes of polyedre
8243         const SMDS_VtkVolume* aPolyedre =
8244           dynamic_cast<const SMDS_VtkVolume*>( elem );
8245         if (aPolyedre) {
8246           int nbFaces = aPolyedre->NbFaces();
8247
8248           vector<const SMDS_MeshNode *> poly_nodes;
8249           vector<int> quantities (nbFaces);
8250
8251           for (int iface = 1; iface <= nbFaces; iface++) {
8252             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
8253             quantities[iface - 1] = nbFaceNodes;
8254
8255             for (inode = 1; inode <= nbFaceNodes; inode++) {
8256               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
8257
8258               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
8259               if (nnIt != nodeNodeMap.end()) { // curNode sticks
8260                 curNode = (*nnIt).second;
8261               }
8262               poly_nodes.push_back(curNode);
8263             }
8264           }
8265           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
8266         }
8267       }
8268       else // replace non-polyhedron elements
8269       {
8270         const SMDSAbs_ElementType etyp = elem->GetType();
8271         const int elemId               = elem->GetID();
8272         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
8273         uniqueNodes.resize(nbUniqueNodes);
8274
8275         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
8276
8277         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
8278         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
8279         if ( sm && newElem )
8280           sm->AddElement( newElem );
8281         if ( elem != newElem )
8282           ReplaceElemInGroups( elem, newElem, aMesh );
8283       }
8284     }
8285     else {
8286       // Remove invalid regular element or invalid polygon
8287       rmElemIds.push_back( elem->GetID() );
8288     }
8289
8290   } // loop on elements
8291
8292   // Remove bad elements, then equal nodes (order important)
8293
8294   Remove( rmElemIds, false );
8295   Remove( rmNodeIds, true );
8296
8297 }
8298
8299
8300 // ========================================================
8301 // class   : SortableElement
8302 // purpose : allow sorting elements basing on their nodes
8303 // ========================================================
8304 class SortableElement : public set <const SMDS_MeshElement*>
8305 {
8306 public:
8307
8308   SortableElement( const SMDS_MeshElement* theElem )
8309   {
8310     myElem = theElem;
8311     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
8312     while ( nodeIt->more() )
8313       this->insert( nodeIt->next() );
8314   }
8315
8316   const SMDS_MeshElement* Get() const
8317   { return myElem; }
8318
8319   void Set(const SMDS_MeshElement* e) const
8320   { myElem = e; }
8321
8322
8323 private:
8324   mutable const SMDS_MeshElement* myElem;
8325 };
8326
8327 //=======================================================================
8328 //function : FindEqualElements
8329 //purpose  : Return list of group of elements built on the same nodes.
8330 //           Search among theElements or in the whole mesh if theElements is empty
8331 //=======================================================================
8332
8333 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
8334                                          TListOfListOfElementsID & theGroupsOfElementsID)
8335 {
8336   myLastCreatedElems.Clear();
8337   myLastCreatedNodes.Clear();
8338
8339   typedef map< SortableElement, int > TMapOfNodeSet;
8340   typedef list<int> TGroupOfElems;
8341
8342   if ( theElements.empty() )
8343   { // get all elements in the mesh
8344     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8345     while ( eIt->more() )
8346       theElements.insert( theElements.end(), eIt->next());
8347   }
8348
8349   vector< TGroupOfElems > arrayOfGroups;
8350   TGroupOfElems groupOfElems;
8351   TMapOfNodeSet mapOfNodeSet;
8352
8353   TIDSortedElemSet::iterator elemIt = theElements.begin();
8354   for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
8355     const SMDS_MeshElement* curElem = *elemIt;
8356     SortableElement SE(curElem);
8357     int ind = -1;
8358     // check uniqueness
8359     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8360     if( !(pp.second) ) {
8361       TMapOfNodeSet::iterator& itSE = pp.first;
8362       ind = (*itSE).second;
8363       arrayOfGroups[ind].push_back(curElem->GetID());
8364     }
8365     else {
8366       groupOfElems.clear();
8367       groupOfElems.push_back(curElem->GetID());
8368       arrayOfGroups.push_back(groupOfElems);
8369       i++;
8370     }
8371   }
8372
8373   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8374   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8375     groupOfElems = *groupIt;
8376     if ( groupOfElems.size() > 1 ) {
8377       groupOfElems.sort();
8378       theGroupsOfElementsID.push_back(groupOfElems);
8379     }
8380   }
8381 }
8382
8383 //=======================================================================
8384 //function : MergeElements
8385 //purpose  : In each given group, substitute all elements by the first one.
8386 //=======================================================================
8387
8388 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8389 {
8390   myLastCreatedElems.Clear();
8391   myLastCreatedNodes.Clear();
8392
8393   typedef list<int> TListOfIDs;
8394   TListOfIDs rmElemIds; // IDs of elems to remove
8395
8396   SMESHDS_Mesh* aMesh = GetMeshDS();
8397
8398   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8399   while ( groupsIt != theGroupsOfElementsID.end() ) {
8400     TListOfIDs& aGroupOfElemID = *groupsIt;
8401     aGroupOfElemID.sort();
8402     int elemIDToKeep = aGroupOfElemID.front();
8403     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8404     aGroupOfElemID.pop_front();
8405     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8406     while ( idIt != aGroupOfElemID.end() ) {
8407       int elemIDToRemove = *idIt;
8408       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8409       // add the kept element in groups of removed one (PAL15188)
8410       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8411       rmElemIds.push_back( elemIDToRemove );
8412       ++idIt;
8413     }
8414     ++groupsIt;
8415   }
8416
8417   Remove( rmElemIds, false );
8418 }
8419
8420 //=======================================================================
8421 //function : MergeEqualElements
8422 //purpose  : Remove all but one of elements built on the same nodes.
8423 //=======================================================================
8424
8425 void SMESH_MeshEditor::MergeEqualElements()
8426 {
8427   TIDSortedElemSet aMeshElements; /* empty input ==
8428                                      to merge equal elements in the whole mesh */
8429   TListOfListOfElementsID aGroupsOfElementsID;
8430   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8431   MergeElements(aGroupsOfElementsID);
8432 }
8433
8434 //=======================================================================
8435 //function : FindFaceInSet
8436 //purpose  : Return a face having linked nodes n1 and n2 and which is
8437 //           - not in avoidSet,
8438 //           - in elemSet provided that !elemSet.empty()
8439 //           i1 and i2 optionally returns indices of n1 and n2
8440 //=======================================================================
8441
8442 const SMDS_MeshElement*
8443 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8444                                 const SMDS_MeshNode*    n2,
8445                                 const TIDSortedElemSet& elemSet,
8446                                 const TIDSortedElemSet& avoidSet,
8447                                 int*                    n1ind,
8448                                 int*                    n2ind)
8449
8450 {
8451   int i1, i2;
8452   const SMDS_MeshElement* face = 0;
8453
8454   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8455   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8456   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8457   {
8458     //MESSAGE("in while ( invElemIt->more() && !face )");
8459     const SMDS_MeshElement* elem = invElemIt->next();
8460     if (avoidSet.count( elem ))
8461       continue;
8462     if ( !elemSet.empty() && !elemSet.count( elem ))
8463       continue;
8464     // index of n1
8465     i1 = elem->GetNodeIndex( n1 );
8466     // find a n2 linked to n1
8467     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8468     for ( int di = -1; di < 2 && !face; di += 2 )
8469     {
8470       i2 = (i1+di+nbN) % nbN;
8471       if ( elem->GetNode( i2 ) == n2 )
8472         face = elem;
8473     }
8474     if ( !face && elem->IsQuadratic())
8475     {
8476       // analysis for quadratic elements using all nodes
8477       const SMDS_VtkFace* F =
8478         dynamic_cast<const SMDS_VtkFace*>(elem);
8479       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8480       // use special nodes iterator
8481       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8482       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8483       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8484       {
8485         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8486         if ( n1 == prevN && n2 == n )
8487         {
8488           face = elem;
8489         }
8490         else if ( n2 == prevN && n1 == n )
8491         {
8492           face = elem; swap( i1, i2 );
8493         }
8494         prevN = n;
8495       }
8496     }
8497   }
8498   if ( n1ind ) *n1ind = i1;
8499   if ( n2ind ) *n2ind = i2;
8500   return face;
8501 }
8502
8503 //=======================================================================
8504 //function : findAdjacentFace
8505 //purpose  :
8506 //=======================================================================
8507
8508 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8509                                                 const SMDS_MeshNode* n2,
8510                                                 const SMDS_MeshElement* elem)
8511 {
8512   TIDSortedElemSet elemSet, avoidSet;
8513   if ( elem )
8514     avoidSet.insert ( elem );
8515   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8516 }
8517
8518 //=======================================================================
8519 //function : FindFreeBorder
8520 //purpose  :
8521 //=======================================================================
8522
8523 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8524
8525 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8526                                        const SMDS_MeshNode*             theSecondNode,
8527                                        const SMDS_MeshNode*             theLastNode,
8528                                        list< const SMDS_MeshNode* > &   theNodes,
8529                                        list< const SMDS_MeshElement* >& theFaces)
8530 {
8531   if ( !theFirstNode || !theSecondNode )
8532     return false;
8533   // find border face between theFirstNode and theSecondNode
8534   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8535   if ( !curElem )
8536     return false;
8537
8538   theFaces.push_back( curElem );
8539   theNodes.push_back( theFirstNode );
8540   theNodes.push_back( theSecondNode );
8541
8542   //vector<const SMDS_MeshNode*> nodes;
8543   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8544   TIDSortedElemSet foundElems;
8545   bool needTheLast = ( theLastNode != 0 );
8546
8547   while ( nStart != theLastNode ) {
8548     if ( nStart == theFirstNode )
8549       return !needTheLast;
8550
8551     // find all free border faces sharing form nStart
8552
8553     list< const SMDS_MeshElement* > curElemList;
8554     list< const SMDS_MeshNode* > nStartList;
8555     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8556     while ( invElemIt->more() ) {
8557       const SMDS_MeshElement* e = invElemIt->next();
8558       if ( e == curElem || foundElems.insert( e ).second ) {
8559         // get nodes
8560         int iNode = 0, nbNodes = e->NbNodes();
8561         //const SMDS_MeshNode* nodes[nbNodes+1];
8562         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8563
8564         if(e->IsQuadratic()) {
8565           const SMDS_VtkFace* F =
8566             dynamic_cast<const SMDS_VtkFace*>(e);
8567           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8568           // use special nodes iterator
8569           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8570           while( anIter->more() ) {
8571             nodes[ iNode++ ] = cast2Node(anIter->next());
8572           }
8573         }
8574         else {
8575           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8576           while ( nIt->more() )
8577             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8578         }
8579         nodes[ iNode ] = nodes[ 0 ];
8580         // check 2 links
8581         for ( iNode = 0; iNode < nbNodes; iNode++ )
8582           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8583                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8584               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8585           {
8586             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8587             curElemList.push_back( e );
8588           }
8589       }
8590     }
8591     // analyse the found
8592
8593     int nbNewBorders = curElemList.size();
8594     if ( nbNewBorders == 0 ) {
8595       // no free border furthermore
8596       return !needTheLast;
8597     }
8598     else if ( nbNewBorders == 1 ) {
8599       // one more element found
8600       nIgnore = nStart;
8601       nStart = nStartList.front();
8602       curElem = curElemList.front();
8603       theFaces.push_back( curElem );
8604       theNodes.push_back( nStart );
8605     }
8606     else {
8607       // several continuations found
8608       list< const SMDS_MeshElement* >::iterator curElemIt;
8609       list< const SMDS_MeshNode* >::iterator nStartIt;
8610       // check if one of them reached the last node
8611       if ( needTheLast ) {
8612         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8613              curElemIt!= curElemList.end();
8614              curElemIt++, nStartIt++ )
8615           if ( *nStartIt == theLastNode ) {
8616             theFaces.push_back( *curElemIt );
8617             theNodes.push_back( *nStartIt );
8618             return true;
8619           }
8620       }
8621       // find the best free border by the continuations
8622       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8623       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8624       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8625            curElemIt!= curElemList.end();
8626            curElemIt++, nStartIt++ )
8627       {
8628         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8629         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8630         // find one more free border
8631         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8632           cNL->clear();
8633           cFL->clear();
8634         }
8635         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8636           // choice: clear a worse one
8637           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8638           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8639           contNodes[ iWorse ].clear();
8640           contFaces[ iWorse ].clear();
8641         }
8642       }
8643       if ( contNodes[0].empty() && contNodes[1].empty() )
8644         return false;
8645
8646       // append the best free border
8647       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8648       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8649       theNodes.pop_back(); // remove nIgnore
8650       theNodes.pop_back(); // remove nStart
8651       theFaces.pop_back(); // remove curElem
8652       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8653       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8654       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8655       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8656       return true;
8657
8658     } // several continuations found
8659   } // while ( nStart != theLastNode )
8660
8661   return true;
8662 }
8663
8664 //=======================================================================
8665 //function : CheckFreeBorderNodes
8666 //purpose  : Return true if the tree nodes are on a free border
8667 //=======================================================================
8668
8669 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8670                                             const SMDS_MeshNode* theNode2,
8671                                             const SMDS_MeshNode* theNode3)
8672 {
8673   list< const SMDS_MeshNode* > nodes;
8674   list< const SMDS_MeshElement* > faces;
8675   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8676 }
8677
8678 //=======================================================================
8679 //function : SewFreeBorder
8680 //purpose  :
8681 //=======================================================================
8682
8683 SMESH_MeshEditor::Sew_Error
8684 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8685                                  const SMDS_MeshNode* theBordSecondNode,
8686                                  const SMDS_MeshNode* theBordLastNode,
8687                                  const SMDS_MeshNode* theSideFirstNode,
8688                                  const SMDS_MeshNode* theSideSecondNode,
8689                                  const SMDS_MeshNode* theSideThirdNode,
8690                                  const bool           theSideIsFreeBorder,
8691                                  const bool           toCreatePolygons,
8692                                  const bool           toCreatePolyedrs)
8693 {
8694   myLastCreatedElems.Clear();
8695   myLastCreatedNodes.Clear();
8696
8697   MESSAGE("::SewFreeBorder()");
8698   Sew_Error aResult = SEW_OK;
8699
8700   // ====================================
8701   //    find side nodes and elements
8702   // ====================================
8703
8704   list< const SMDS_MeshNode* > nSide[ 2 ];
8705   list< const SMDS_MeshElement* > eSide[ 2 ];
8706   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8707   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8708
8709   // Free border 1
8710   // --------------
8711   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8712                       nSide[0], eSide[0])) {
8713     MESSAGE(" Free Border 1 not found " );
8714     aResult = SEW_BORDER1_NOT_FOUND;
8715   }
8716   if (theSideIsFreeBorder) {
8717     // Free border 2
8718     // --------------
8719     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8720                         nSide[1], eSide[1])) {
8721       MESSAGE(" Free Border 2 not found " );
8722       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8723     }
8724   }
8725   if ( aResult != SEW_OK )
8726     return aResult;
8727
8728   if (!theSideIsFreeBorder) {
8729     // Side 2
8730     // --------------
8731
8732     // -------------------------------------------------------------------------
8733     // Algo:
8734     // 1. If nodes to merge are not coincident, move nodes of the free border
8735     //    from the coord sys defined by the direction from the first to last
8736     //    nodes of the border to the correspondent sys of the side 2
8737     // 2. On the side 2, find the links most co-directed with the correspondent
8738     //    links of the free border
8739     // -------------------------------------------------------------------------
8740
8741     // 1. Since sewing may break if there are volumes to split on the side 2,
8742     //    we wont move nodes but just compute new coordinates for them
8743     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8744     TNodeXYZMap nBordXYZ;
8745     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8746     list< const SMDS_MeshNode* >::iterator nBordIt;
8747
8748     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8749     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8750     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8751     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8752     double tol2 = 1.e-8;
8753     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8754     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8755       // Need node movement.
8756
8757       // find X and Z axes to create trsf
8758       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8759       gp_Vec X = Zs ^ Zb;
8760       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8761         // Zb || Zs
8762         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8763
8764       // coord systems
8765       gp_Ax3 toBordAx( Pb1, Zb, X );
8766       gp_Ax3 fromSideAx( Ps1, Zs, X );
8767       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8768       // set trsf
8769       gp_Trsf toBordSys, fromSide2Sys;
8770       toBordSys.SetTransformation( toBordAx );
8771       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8772       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8773
8774       // move
8775       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8776         const SMDS_MeshNode* n = *nBordIt;
8777         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8778         toBordSys.Transforms( xyz );
8779         fromSide2Sys.Transforms( xyz );
8780         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8781       }
8782     }
8783     else {
8784       // just insert nodes XYZ in the nBordXYZ map
8785       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8786         const SMDS_MeshNode* n = *nBordIt;
8787         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8788       }
8789     }
8790
8791     // 2. On the side 2, find the links most co-directed with the correspondent
8792     //    links of the free border
8793
8794     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8795     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8796     sideNodes.push_back( theSideFirstNode );
8797
8798     bool hasVolumes = false;
8799     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8800     set<long> foundSideLinkIDs, checkedLinkIDs;
8801     SMDS_VolumeTool volume;
8802     //const SMDS_MeshNode* faceNodes[ 4 ];
8803
8804     const SMDS_MeshNode*    sideNode;
8805     const SMDS_MeshElement* sideElem;
8806     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8807     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8808     nBordIt = bordNodes.begin();
8809     nBordIt++;
8810     // border node position and border link direction to compare with
8811     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8812     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8813     // choose next side node by link direction or by closeness to
8814     // the current border node:
8815     bool searchByDir = ( *nBordIt != theBordLastNode );
8816     do {
8817       // find the next node on the Side 2
8818       sideNode = 0;
8819       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8820       long linkID;
8821       checkedLinkIDs.clear();
8822       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8823
8824       // loop on inverse elements of current node (prevSideNode) on the Side 2
8825       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8826       while ( invElemIt->more() )
8827       {
8828         const SMDS_MeshElement* elem = invElemIt->next();
8829         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8830         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8831         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8832         bool isVolume = volume.Set( elem );
8833         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8834         if ( isVolume ) // --volume
8835           hasVolumes = true;
8836         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8837           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8838           if(elem->IsQuadratic()) {
8839             const SMDS_VtkFace* F =
8840               dynamic_cast<const SMDS_VtkFace*>(elem);
8841             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8842             // use special nodes iterator
8843             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8844             while( anIter->more() ) {
8845               nodes[ iNode ] = cast2Node(anIter->next());
8846               if ( nodes[ iNode++ ] == prevSideNode )
8847                 iPrevNode = iNode - 1;
8848             }
8849           }
8850           else {
8851             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8852             while ( nIt->more() ) {
8853               nodes[ iNode ] = cast2Node( nIt->next() );
8854               if ( nodes[ iNode++ ] == prevSideNode )
8855                 iPrevNode = iNode - 1;
8856             }
8857           }
8858           // there are 2 links to check
8859           nbNodes = 2;
8860         }
8861         else // --edge
8862           continue;
8863         // loop on links, to be precise, on the second node of links
8864         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8865           const SMDS_MeshNode* n = nodes[ iNode ];
8866           if ( isVolume ) {
8867             if ( !volume.IsLinked( n, prevSideNode ))
8868               continue;
8869           }
8870           else {
8871             if ( iNode ) // a node before prevSideNode
8872               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8873             else         // a node after prevSideNode
8874               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8875           }
8876           // check if this link was already used
8877           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8878           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8879           if (!isJustChecked &&
8880               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8881           {
8882             // test a link geometrically
8883             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8884             bool linkIsBetter = false;
8885             double dot = 0.0, dist = 0.0;
8886             if ( searchByDir ) { // choose most co-directed link
8887               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8888               linkIsBetter = ( dot > maxDot );
8889             }
8890             else { // choose link with the node closest to bordPos
8891               dist = ( nextXYZ - bordPos ).SquareModulus();
8892               linkIsBetter = ( dist < minDist );
8893             }
8894             if ( linkIsBetter ) {
8895               maxDot = dot;
8896               minDist = dist;
8897               linkID = iLink;
8898               sideNode = n;
8899               sideElem = elem;
8900             }
8901           }
8902         }
8903       } // loop on inverse elements of prevSideNode
8904
8905       if ( !sideNode ) {
8906         MESSAGE(" Cant find path by links of the Side 2 ");
8907         return SEW_BAD_SIDE_NODES;
8908       }
8909       sideNodes.push_back( sideNode );
8910       sideElems.push_back( sideElem );
8911       foundSideLinkIDs.insert ( linkID );
8912       prevSideNode = sideNode;
8913
8914       if ( *nBordIt == theBordLastNode )
8915         searchByDir = false;
8916       else {
8917         // find the next border link to compare with
8918         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8919         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8920         // move to next border node if sideNode is before forward border node (bordPos)
8921         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8922           prevBordNode = *nBordIt;
8923           nBordIt++;
8924           bordPos = nBordXYZ[ *nBordIt ];
8925           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8926           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8927         }
8928       }
8929     }
8930     while ( sideNode != theSideSecondNode );
8931
8932     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8933       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8934       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8935     }
8936   } // end nodes search on the side 2
8937
8938   // ============================
8939   // sew the border to the side 2
8940   // ============================
8941
8942   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8943   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8944
8945   TListOfListOfNodes nodeGroupsToMerge;
8946   if ( nbNodes[0] == nbNodes[1] ||
8947        ( theSideIsFreeBorder && !theSideThirdNode)) {
8948
8949     // all nodes are to be merged
8950
8951     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8952          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8953          nIt[0]++, nIt[1]++ )
8954     {
8955       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8956       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8957       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8958     }
8959   }
8960   else {
8961
8962     // insert new nodes into the border and the side to get equal nb of segments
8963
8964     // get normalized parameters of nodes on the borders
8965     //double param[ 2 ][ maxNbNodes ];
8966     double* param[ 2 ];
8967     param[0] = new double [ maxNbNodes ];
8968     param[1] = new double [ maxNbNodes ];
8969     int iNode, iBord;
8970     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8971       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8972       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8973       const SMDS_MeshNode* nPrev = *nIt;
8974       double bordLength = 0;
8975       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8976         const SMDS_MeshNode* nCur = *nIt;
8977         gp_XYZ segment (nCur->X() - nPrev->X(),
8978                         nCur->Y() - nPrev->Y(),
8979                         nCur->Z() - nPrev->Z());
8980         double segmentLen = segment.Modulus();
8981         bordLength += segmentLen;
8982         param[ iBord ][ iNode ] = bordLength;
8983         nPrev = nCur;
8984       }
8985       // normalize within [0,1]
8986       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8987         param[ iBord ][ iNode ] /= bordLength;
8988       }
8989     }
8990
8991     // loop on border segments
8992     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8993     int i[ 2 ] = { 0, 0 };
8994     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8995     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8996
8997     TElemOfNodeListMap insertMap;
8998     TElemOfNodeListMap::iterator insertMapIt;
8999     // insertMap is
9000     // key:   elem to insert nodes into
9001     // value: 2 nodes to insert between + nodes to be inserted
9002     do {
9003       bool next[ 2 ] = { false, false };
9004
9005       // find min adjacent segment length after sewing
9006       double nextParam = 10., prevParam = 0;
9007       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
9008         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
9009           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
9010         if ( i[ iBord ] > 0 )
9011           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
9012       }
9013       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
9014       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
9015       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
9016
9017       // choose to insert or to merge nodes
9018       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
9019       if ( Abs( du ) <= minSegLen * 0.2 ) {
9020         // merge
9021         // ------
9022         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
9023         const SMDS_MeshNode* n0 = *nIt[0];
9024         const SMDS_MeshNode* n1 = *nIt[1];
9025         nodeGroupsToMerge.back().push_back( n1 );
9026         nodeGroupsToMerge.back().push_back( n0 );
9027         // position of node of the border changes due to merge
9028         param[ 0 ][ i[0] ] += du;
9029         // move n1 for the sake of elem shape evaluation during insertion.
9030         // n1 will be removed by MergeNodes() anyway
9031         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
9032         next[0] = next[1] = true;
9033       }
9034       else {
9035         // insert
9036         // ------
9037         int intoBord = ( du < 0 ) ? 0 : 1;
9038         const SMDS_MeshElement* elem = *eIt[ intoBord ];
9039         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
9040         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
9041         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
9042         if ( intoBord == 1 ) {
9043           // move node of the border to be on a link of elem of the side
9044           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
9045           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
9046           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
9047           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
9048           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
9049         }
9050         insertMapIt = insertMap.find( elem );
9051         bool notFound = ( insertMapIt == insertMap.end() );
9052         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
9053         if ( otherLink ) {
9054           // insert into another link of the same element:
9055           // 1. perform insertion into the other link of the elem
9056           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
9057           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
9058           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
9059           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
9060           // 2. perform insertion into the link of adjacent faces
9061           while (true) {
9062             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
9063             if ( adjElem )
9064               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
9065             else
9066               break;
9067           }
9068           if (toCreatePolyedrs) {
9069             // perform insertion into the links of adjacent volumes
9070             UpdateVolumes(n12, n22, nodeList);
9071           }
9072           // 3. find an element appeared on n1 and n2 after the insertion
9073           insertMap.erase( elem );
9074           elem = findAdjacentFace( n1, n2, 0 );
9075         }
9076         if ( notFound || otherLink ) {
9077           // add element and nodes of the side into the insertMap
9078           insertMapIt = insertMap.insert
9079             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
9080           (*insertMapIt).second.push_back( n1 );
9081           (*insertMapIt).second.push_back( n2 );
9082         }
9083         // add node to be inserted into elem
9084         (*insertMapIt).second.push_back( nIns );
9085         next[ 1 - intoBord ] = true;
9086       }
9087
9088       // go to the next segment
9089       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
9090         if ( next[ iBord ] ) {
9091           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
9092             eIt[ iBord ]++;
9093           nPrev[ iBord ] = *nIt[ iBord ];
9094           nIt[ iBord ]++; i[ iBord ]++;
9095         }
9096       }
9097     }
9098     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
9099
9100     // perform insertion of nodes into elements
9101
9102     for (insertMapIt = insertMap.begin();
9103          insertMapIt != insertMap.end();
9104          insertMapIt++ )
9105     {
9106       const SMDS_MeshElement* elem = (*insertMapIt).first;
9107       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
9108       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
9109       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
9110
9111       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
9112
9113       if ( !theSideIsFreeBorder ) {
9114         // look for and insert nodes into the faces adjacent to elem
9115         while (true) {
9116           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
9117           if ( adjElem )
9118             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
9119           else
9120             break;
9121         }
9122       }
9123       if (toCreatePolyedrs) {
9124         // perform insertion into the links of adjacent volumes
9125         UpdateVolumes(n1, n2, nodeList);
9126       }
9127     }
9128
9129     delete param[0];
9130     delete param[1];
9131   } // end: insert new nodes
9132
9133   MergeNodes ( nodeGroupsToMerge );
9134
9135   return aResult;
9136 }
9137
9138 //=======================================================================
9139 //function : InsertNodesIntoLink
9140 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
9141 //           and theBetweenNode2 and split theElement
9142 //=======================================================================
9143
9144 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
9145                                            const SMDS_MeshNode*        theBetweenNode1,
9146                                            const SMDS_MeshNode*        theBetweenNode2,
9147                                            list<const SMDS_MeshNode*>& theNodesToInsert,
9148                                            const bool                  toCreatePoly)
9149 {
9150   if ( theFace->GetType() != SMDSAbs_Face ) return;
9151
9152   // find indices of 2 link nodes and of the rest nodes
9153   int iNode = 0, il1, il2, i3, i4;
9154   il1 = il2 = i3 = i4 = -1;
9155   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
9156   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
9157
9158   if(theFace->IsQuadratic()) {
9159     const SMDS_VtkFace* F =
9160       dynamic_cast<const SMDS_VtkFace*>(theFace);
9161     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9162     // use special nodes iterator
9163     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9164     while( anIter->more() ) {
9165       const SMDS_MeshNode* n = cast2Node(anIter->next());
9166       if ( n == theBetweenNode1 )
9167         il1 = iNode;
9168       else if ( n == theBetweenNode2 )
9169         il2 = iNode;
9170       else if ( i3 < 0 )
9171         i3 = iNode;
9172       else
9173         i4 = iNode;
9174       nodes[ iNode++ ] = n;
9175     }
9176   }
9177   else {
9178     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9179     while ( nodeIt->more() ) {
9180       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9181       if ( n == theBetweenNode1 )
9182         il1 = iNode;
9183       else if ( n == theBetweenNode2 )
9184         il2 = iNode;
9185       else if ( i3 < 0 )
9186         i3 = iNode;
9187       else
9188         i4 = iNode;
9189       nodes[ iNode++ ] = n;
9190     }
9191   }
9192   if ( il1 < 0 || il2 < 0 || i3 < 0 )
9193     return ;
9194
9195   // arrange link nodes to go one after another regarding the face orientation
9196   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
9197   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
9198   if ( reverse ) {
9199     iNode = il1;
9200     il1 = il2;
9201     il2 = iNode;
9202     aNodesToInsert.reverse();
9203   }
9204   // check that not link nodes of a quadrangles are in good order
9205   int nbFaceNodes = theFace->NbNodes();
9206   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
9207     iNode = i3;
9208     i3 = i4;
9209     i4 = iNode;
9210   }
9211
9212   if (toCreatePoly || theFace->IsPoly()) {
9213
9214     iNode = 0;
9215     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
9216
9217     // add nodes of face up to first node of link
9218     bool isFLN = false;
9219
9220     if(theFace->IsQuadratic()) {
9221       const SMDS_VtkFace* F =
9222         dynamic_cast<const SMDS_VtkFace*>(theFace);
9223       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9224       // use special nodes iterator
9225       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9226       while( anIter->more()  && !isFLN ) {
9227         const SMDS_MeshNode* n = cast2Node(anIter->next());
9228         poly_nodes[iNode++] = n;
9229         if (n == nodes[il1]) {
9230           isFLN = true;
9231         }
9232       }
9233       // add nodes to insert
9234       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9235       for (; nIt != aNodesToInsert.end(); nIt++) {
9236         poly_nodes[iNode++] = *nIt;
9237       }
9238       // add nodes of face starting from last node of link
9239       while ( anIter->more() ) {
9240         poly_nodes[iNode++] = cast2Node(anIter->next());
9241       }
9242     }
9243     else {
9244       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9245       while ( nodeIt->more() && !isFLN ) {
9246         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9247         poly_nodes[iNode++] = n;
9248         if (n == nodes[il1]) {
9249           isFLN = true;
9250         }
9251       }
9252       // add nodes to insert
9253       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9254       for (; nIt != aNodesToInsert.end(); nIt++) {
9255         poly_nodes[iNode++] = *nIt;
9256       }
9257       // add nodes of face starting from last node of link
9258       while ( nodeIt->more() ) {
9259         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9260         poly_nodes[iNode++] = n;
9261       }
9262     }
9263
9264     // edit or replace the face
9265     SMESHDS_Mesh *aMesh = GetMeshDS();
9266
9267     if (theFace->IsPoly()) {
9268       aMesh->ChangePolygonNodes(theFace, poly_nodes);
9269     }
9270     else {
9271       int aShapeId = FindShape( theFace );
9272
9273       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
9274       myLastCreatedElems.Append(newElem);
9275       if ( aShapeId && newElem )
9276         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9277
9278       aMesh->RemoveElement(theFace);
9279     }
9280     return;
9281   }
9282
9283   SMESHDS_Mesh *aMesh = GetMeshDS();
9284   if( !theFace->IsQuadratic() ) {
9285
9286     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
9287     int nbLinkNodes = 2 + aNodesToInsert.size();
9288     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
9289     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
9290     linkNodes[ 0 ] = nodes[ il1 ];
9291     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
9292     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9293     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9294       linkNodes[ iNode++ ] = *nIt;
9295     }
9296     // decide how to split a quadrangle: compare possible variants
9297     // and choose which of splits to be a quadrangle
9298     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
9299     if ( nbFaceNodes == 3 ) {
9300       iBestQuad = nbSplits;
9301       i4 = i3;
9302     }
9303     else if ( nbFaceNodes == 4 ) {
9304       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
9305       double aBestRate = DBL_MAX;
9306       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
9307         i1 = 0; i2 = 1;
9308         double aBadRate = 0;
9309         // evaluate elements quality
9310         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
9311           if ( iSplit == iQuad ) {
9312             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
9313                                    linkNodes[ i2++ ],
9314                                    nodes[ i3 ],
9315                                    nodes[ i4 ]);
9316             aBadRate += getBadRate( &quad, aCrit );
9317           }
9318           else {
9319             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
9320                                    linkNodes[ i2++ ],
9321                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
9322             aBadRate += getBadRate( &tria, aCrit );
9323           }
9324         }
9325         // choice
9326         if ( aBadRate < aBestRate ) {
9327           iBestQuad = iQuad;
9328           aBestRate = aBadRate;
9329         }
9330       }
9331     }
9332
9333     // create new elements
9334     int aShapeId = FindShape( theFace );
9335
9336     i1 = 0; i2 = 1;
9337     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
9338       SMDS_MeshElement* newElem = 0;
9339       if ( iSplit == iBestQuad )
9340         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9341                                   linkNodes[ i2++ ],
9342                                   nodes[ i3 ],
9343                                   nodes[ i4 ]);
9344       else
9345         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9346                                   linkNodes[ i2++ ],
9347                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9348       myLastCreatedElems.Append(newElem);
9349       if ( aShapeId && newElem )
9350         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9351     }
9352
9353     // change nodes of theFace
9354     const SMDS_MeshNode* newNodes[ 4 ];
9355     newNodes[ 0 ] = linkNodes[ i1 ];
9356     newNodes[ 1 ] = linkNodes[ i2 ];
9357     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9358     newNodes[ 3 ] = nodes[ i4 ];
9359     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9360     const SMDS_MeshElement* newElem = 0;
9361     if (iSplit == iBestQuad)
9362       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9363     else
9364       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9365     myLastCreatedElems.Append(newElem);
9366     if ( aShapeId && newElem )
9367       aMesh->SetMeshElementOnShape( newElem, aShapeId );
9368 } // end if(!theFace->IsQuadratic())
9369   else { // theFace is quadratic
9370     // we have to split theFace on simple triangles and one simple quadrangle
9371     int tmp = il1/2;
9372     int nbshift = tmp*2;
9373     // shift nodes in nodes[] by nbshift
9374     int i,j;
9375     for(i=0; i<nbshift; i++) {
9376       const SMDS_MeshNode* n = nodes[0];
9377       for(j=0; j<nbFaceNodes-1; j++) {
9378         nodes[j] = nodes[j+1];
9379       }
9380       nodes[nbFaceNodes-1] = n;
9381     }
9382     il1 = il1 - nbshift;
9383     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9384     //   n0      n1     n2    n0      n1     n2
9385     //     +-----+-----+        +-----+-----+
9386     //      \         /         |           |
9387     //       \       /          |           |
9388     //      n5+     +n3       n7+           +n3
9389     //         \   /            |           |
9390     //          \ /             |           |
9391     //           +              +-----+-----+
9392     //           n4           n6      n5     n4
9393
9394     // create new elements
9395     int aShapeId = FindShape( theFace );
9396
9397     int n1,n2,n3;
9398     if(nbFaceNodes==6) { // quadratic triangle
9399       SMDS_MeshElement* newElem =
9400         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9401       myLastCreatedElems.Append(newElem);
9402       if ( aShapeId && newElem )
9403         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9404       if(theFace->IsMediumNode(nodes[il1])) {
9405         // create quadrangle
9406         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9407         myLastCreatedElems.Append(newElem);
9408         if ( aShapeId && newElem )
9409           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9410         n1 = 1;
9411         n2 = 2;
9412         n3 = 3;
9413       }
9414       else {
9415         // create quadrangle
9416         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9417         myLastCreatedElems.Append(newElem);
9418         if ( aShapeId && newElem )
9419           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9420         n1 = 0;
9421         n2 = 1;
9422         n3 = 5;
9423       }
9424     }
9425     else { // nbFaceNodes==8 - quadratic quadrangle
9426       SMDS_MeshElement* newElem =
9427         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9428       myLastCreatedElems.Append(newElem);
9429       if ( aShapeId && newElem )
9430         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9431       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9432       myLastCreatedElems.Append(newElem);
9433       if ( aShapeId && newElem )
9434         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9435       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9436       myLastCreatedElems.Append(newElem);
9437       if ( aShapeId && newElem )
9438         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9439       if(theFace->IsMediumNode(nodes[il1])) {
9440         // create quadrangle
9441         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9442         myLastCreatedElems.Append(newElem);
9443         if ( aShapeId && newElem )
9444           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9445         n1 = 1;
9446         n2 = 2;
9447         n3 = 3;
9448       }
9449       else {
9450         // create quadrangle
9451         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9452         myLastCreatedElems.Append(newElem);
9453         if ( aShapeId && newElem )
9454           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9455         n1 = 0;
9456         n2 = 1;
9457         n3 = 7;
9458       }
9459     }
9460     // create needed triangles using n1,n2,n3 and inserted nodes
9461     int nbn = 2 + aNodesToInsert.size();
9462     //const SMDS_MeshNode* aNodes[nbn];
9463     vector<const SMDS_MeshNode*> aNodes(nbn);
9464     aNodes[0] = nodes[n1];
9465     aNodes[nbn-1] = nodes[n2];
9466     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9467     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9468       aNodes[iNode++] = *nIt;
9469     }
9470     for(i=1; i<nbn; i++) {
9471       SMDS_MeshElement* newElem =
9472         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9473       myLastCreatedElems.Append(newElem);
9474       if ( aShapeId && newElem )
9475         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9476     }
9477   }
9478   // remove old face
9479   aMesh->RemoveElement(theFace);
9480 }
9481
9482 //=======================================================================
9483 //function : UpdateVolumes
9484 //purpose  :
9485 //=======================================================================
9486 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9487                                       const SMDS_MeshNode*        theBetweenNode2,
9488                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9489 {
9490   myLastCreatedElems.Clear();
9491   myLastCreatedNodes.Clear();
9492
9493   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9494   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9495     const SMDS_MeshElement* elem = invElemIt->next();
9496
9497     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9498     SMDS_VolumeTool aVolume (elem);
9499     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9500       continue;
9501
9502     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9503     int iface, nbFaces = aVolume.NbFaces();
9504     vector<const SMDS_MeshNode *> poly_nodes;
9505     vector<int> quantities (nbFaces);
9506
9507     for (iface = 0; iface < nbFaces; iface++) {
9508       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9509       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9510       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9511
9512       for (int inode = 0; inode < nbFaceNodes; inode++) {
9513         poly_nodes.push_back(faceNodes[inode]);
9514
9515         if (nbInserted == 0) {
9516           if (faceNodes[inode] == theBetweenNode1) {
9517             if (faceNodes[inode + 1] == theBetweenNode2) {
9518               nbInserted = theNodesToInsert.size();
9519
9520               // add nodes to insert
9521               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9522               for (; nIt != theNodesToInsert.end(); nIt++) {
9523                 poly_nodes.push_back(*nIt);
9524               }
9525             }
9526           }
9527           else if (faceNodes[inode] == theBetweenNode2) {
9528             if (faceNodes[inode + 1] == theBetweenNode1) {
9529               nbInserted = theNodesToInsert.size();
9530
9531               // add nodes to insert in reversed order
9532               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9533               nIt--;
9534               for (; nIt != theNodesToInsert.begin(); nIt--) {
9535                 poly_nodes.push_back(*nIt);
9536               }
9537               poly_nodes.push_back(*nIt);
9538             }
9539           }
9540           else {
9541           }
9542         }
9543       }
9544       quantities[iface] = nbFaceNodes + nbInserted;
9545     }
9546
9547     // Replace or update the volume
9548     SMESHDS_Mesh *aMesh = GetMeshDS();
9549
9550     if (elem->IsPoly()) {
9551       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9552
9553     }
9554     else {
9555       int aShapeId = FindShape( elem );
9556
9557       SMDS_MeshElement* newElem =
9558         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9559       myLastCreatedElems.Append(newElem);
9560       if (aShapeId && newElem)
9561         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9562
9563       aMesh->RemoveElement(elem);
9564     }
9565   }
9566 }
9567
9568 namespace
9569 {
9570   //================================================================================
9571   /*!
9572    * \brief Transform any volume into data of SMDSEntity_Polyhedra
9573    */
9574   //================================================================================
9575
9576   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
9577                            vector<const SMDS_MeshNode *> & nodes,
9578                            vector<int> &                   nbNodeInFaces )
9579   {
9580     nodes.clear();
9581     nbNodeInFaces.clear();
9582     SMDS_VolumeTool vTool ( elem );
9583     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
9584     {
9585       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
9586       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
9587       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
9588     }
9589   }
9590 }
9591
9592 //=======================================================================
9593 /*!
9594  * \brief Convert elements contained in a submesh to quadratic
9595  * \return int - nb of checked elements
9596  */
9597 //=======================================================================
9598
9599 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9600                                              SMESH_MesherHelper& theHelper,
9601                                              const bool          theForce3d)
9602 {
9603   int nbElem = 0;
9604   if( !theSm ) return nbElem;
9605
9606   vector<int> nbNodeInFaces;
9607   vector<const SMDS_MeshNode *> nodes;
9608   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9609   while(ElemItr->more())
9610   {
9611     nbElem++;
9612     const SMDS_MeshElement* elem = ElemItr->next();
9613     if( !elem ) continue;
9614
9615     const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
9616     if ( elem->IsQuadratic() )
9617     {
9618       bool alreadyOK;
9619       switch ( aGeomType ) {
9620       case SMDSEntity_Quad_Quadrangle:
9621       case SMDSEntity_Quad_Hexa:         alreadyOK = !theHelper.GetIsBiQuadratic(); break;
9622       case SMDSEntity_BiQuad_Quadrangle:
9623       case SMDSEntity_TriQuad_Hexa:      alreadyOK = theHelper.GetIsBiQuadratic(); break;
9624       default:                           alreadyOK = true;
9625       }
9626       if ( alreadyOK ) continue;
9627     }
9628     // get elem data needed to re-create it
9629     //
9630     const int id                     = elem->GetID();
9631     const int nbNodes                = elem->NbCornerNodes();
9632     const SMDSAbs_ElementType aType  = elem->GetType();
9633     nodes.assign(elem->begin_nodes(), elem->end_nodes());
9634     if ( aGeomType == SMDSEntity_Polyhedra )
9635       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9636     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
9637       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9638
9639     // remove a linear element
9640     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9641
9642     const SMDS_MeshElement* NewElem = 0;
9643
9644     switch( aType )
9645     {
9646     case SMDSAbs_Edge :
9647       {
9648         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9649         break;
9650       }
9651     case SMDSAbs_Face :
9652       {
9653         switch(nbNodes)
9654         {
9655         case 3:
9656           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9657           break;
9658         case 4:
9659           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9660           break;
9661         default:
9662           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9663           continue;
9664         }
9665         break;
9666       }
9667     case SMDSAbs_Volume :
9668       {
9669         switch( aGeomType )
9670         {
9671         case SMDSEntity_Tetra:
9672           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9673           break;
9674         case SMDSEntity_Pyramid:
9675           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9676           break;
9677         case SMDSEntity_Penta:
9678           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9679           break;
9680         case SMDSEntity_Hexa:
9681         case SMDSEntity_Quad_Hexa:
9682         case SMDSEntity_TriQuad_Hexa:
9683           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9684                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9685           break;
9686         case SMDSEntity_Hexagonal_Prism:
9687         default:
9688           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9689         }
9690         break;
9691       }
9692     default :
9693       continue;
9694     }
9695     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9696     if( NewElem )
9697       theSm->AddElement( NewElem );
9698   }
9699   return nbElem;
9700 }
9701 //=======================================================================
9702 //function : ConvertToQuadratic
9703 //purpose  :
9704 //=======================================================================
9705
9706 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
9707 {
9708   SMESHDS_Mesh* meshDS = GetMeshDS();
9709
9710   SMESH_MesherHelper aHelper(*myMesh);
9711
9712   aHelper.SetIsQuadratic( true );
9713   aHelper.SetIsBiQuadratic( theToBiQuad );
9714   aHelper.SetElementsOnShape(true);
9715
9716   int nbCheckedElems = 0;
9717   if ( myMesh->HasShapeToMesh() )
9718   {
9719     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9720     {
9721       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9722       while ( smIt->more() ) {
9723         SMESH_subMesh* sm = smIt->next();
9724         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9725           aHelper.SetSubShape( sm->GetSubShape() );
9726           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9727         }
9728       }
9729     }
9730   }
9731   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9732   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9733   {
9734     aHelper.SetElementsOnShape(false);
9735     SMESHDS_SubMesh *smDS = 0;
9736     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9737     while(aEdgeItr->more())
9738     {
9739       const SMDS_MeshEdge* edge = aEdgeItr->next();
9740       if(edge && !edge->IsQuadratic())
9741       {
9742         int id = edge->GetID();
9743         //MESSAGE("edge->GetID() " << id);
9744         const SMDS_MeshNode* n1 = edge->GetNode(0);
9745         const SMDS_MeshNode* n2 = edge->GetNode(1);
9746
9747         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9748
9749         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9750         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9751       }
9752     }
9753     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9754     while(aFaceItr->more())
9755     {
9756       const SMDS_MeshFace* face = aFaceItr->next();
9757       if ( !face ) continue;
9758       
9759       const SMDSAbs_EntityType type = face->GetEntityType();
9760       if (( theToBiQuad  && type == SMDSEntity_BiQuad_Quadrangle ) ||
9761           ( !theToBiQuad && type == SMDSEntity_Quad_Quadrangle ))
9762         continue;
9763
9764       const int id = face->GetID();
9765       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9766
9767       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9768
9769       SMDS_MeshFace * NewFace = 0;
9770       switch( type )
9771       {
9772       case SMDSEntity_Triangle:
9773         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9774         break;
9775       case SMDSEntity_Quadrangle:
9776         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9777         break;
9778       default:
9779         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9780       }
9781       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9782     }
9783     vector<int> nbNodeInFaces;
9784     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9785     while(aVolumeItr->more())
9786     {
9787       const SMDS_MeshVolume* volume = aVolumeItr->next();
9788       if(!volume || volume->IsQuadratic() ) continue;
9789
9790       const SMDSAbs_EntityType type = volume->GetEntityType();
9791       if (( theToBiQuad  && type == SMDSEntity_TriQuad_Hexa ) ||
9792           ( !theToBiQuad && type == SMDSEntity_Quad_Hexa ))
9793         continue;
9794
9795       const int id = volume->GetID();
9796       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9797       if ( type == SMDSEntity_Polyhedra )
9798         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9799       else if ( type == SMDSEntity_Hexagonal_Prism )
9800         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9801
9802       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9803
9804       SMDS_MeshVolume * NewVolume = 0;
9805       switch ( type )
9806       {
9807       case SMDSEntity_Tetra:
9808         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
9809         break;
9810       case SMDSEntity_Hexa:
9811       case SMDSEntity_Quad_Hexa:
9812       case SMDSEntity_TriQuad_Hexa:
9813         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9814                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9815         break;
9816       case SMDSEntity_Pyramid:
9817         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9818                                       nodes[3], nodes[4], id, theForce3d);
9819         break;
9820       case SMDSEntity_Penta:
9821         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9822                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9823         break;
9824       case SMDSEntity_Hexagonal_Prism:
9825       default:
9826         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9827       }
9828       ReplaceElemInGroups(volume, NewVolume, meshDS);
9829     }
9830   }
9831
9832   if ( !theForce3d )
9833   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9834     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9835     aHelper.FixQuadraticElements(myError);
9836   }
9837 }
9838
9839 //================================================================================
9840 /*!
9841  * \brief Makes given elements quadratic
9842  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9843  *  \param theElements - elements to make quadratic
9844  */
9845 //================================================================================
9846
9847 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9848                                           TIDSortedElemSet& theElements,
9849                                           const bool        theToBiQuad)
9850 {
9851   if ( theElements.empty() ) return;
9852
9853   // we believe that all theElements are of the same type
9854   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9855
9856   // get all nodes shared by theElements
9857   TIDSortedNodeSet allNodes;
9858   TIDSortedElemSet::iterator eIt = theElements.begin();
9859   for ( ; eIt != theElements.end(); ++eIt )
9860     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9861
9862   // complete theElements with elements of lower dim whose all nodes are in allNodes
9863
9864   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9865   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9866   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9867   for ( ; nIt != allNodes.end(); ++nIt )
9868   {
9869     const SMDS_MeshNode* n = *nIt;
9870     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9871     while ( invIt->more() )
9872     {
9873       const SMDS_MeshElement* e = invIt->next();
9874       if ( e->IsQuadratic() )
9875       {
9876         bool alreadyOK;
9877         switch ( e->GetEntityType() ) {
9878         case SMDSEntity_Quad_Quadrangle:
9879         case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
9880         case SMDSEntity_BiQuad_Quadrangle:
9881         case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
9882         default:                           alreadyOK = true;
9883         }
9884         if ( alreadyOK )
9885         {
9886           quadAdjacentElems[ e->GetType() ].insert( e );
9887           continue;
9888         }
9889       }
9890       if ( e->GetType() >= elemType )
9891       {
9892         continue; // same type of more complex linear element
9893       }
9894
9895       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9896         continue; // e is already checked
9897
9898       // check nodes
9899       bool allIn = true;
9900       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9901       while ( nodeIt->more() && allIn )
9902         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9903       if ( allIn )
9904         theElements.insert(e );
9905     }
9906   }
9907
9908   SMESH_MesherHelper helper(*myMesh);
9909   helper.SetIsQuadratic( true );
9910   helper.SetIsBiQuadratic( theToBiQuad );
9911
9912   // add links of quadratic adjacent elements to the helper
9913
9914   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9915     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9916           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9917     {
9918       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9919     }
9920   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9921     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9922           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9923     {
9924       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9925     }
9926   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9927     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9928           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9929     {
9930       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9931     }
9932
9933   // make quadratic (or bi-tri-quadratic) elements instead of linear ones
9934
9935   SMESHDS_Mesh*  meshDS = GetMeshDS();
9936   SMESHDS_SubMesh* smDS = 0;
9937   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9938   {
9939     const SMDS_MeshElement* elem = *eIt;
9940     if( elem->NbNodes() < 2 || elem->IsPoly() )
9941       continue;
9942
9943     if ( elem->IsQuadratic() )
9944     {
9945       bool alreadyOK;
9946       switch ( elem->GetEntityType() ) {
9947       case SMDSEntity_Quad_Quadrangle:
9948       case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
9949       case SMDSEntity_BiQuad_Quadrangle:
9950       case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
9951       default:                           alreadyOK = true;
9952       }
9953       if ( alreadyOK ) continue;
9954     }
9955
9956     const SMDSAbs_ElementType type = elem->GetType();
9957     const int                   id = elem->GetID();
9958     const int              nbNodes = elem->NbCornerNodes();
9959     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9960
9961     if ( !smDS || !smDS->Contains( elem ))
9962       smDS = meshDS->MeshElements( elem->getshapeId() );
9963     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9964
9965     SMDS_MeshElement * newElem = 0;
9966     switch( nbNodes )
9967     {
9968     case 4: // cases for most frequently used element types go first (for optimization)
9969       if ( type == SMDSAbs_Volume )
9970         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9971       else
9972         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9973       break;
9974     case 8:
9975       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9976                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9977       break;
9978     case 3:
9979       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9980       break;
9981     case 2:
9982       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9983       break;
9984     case 5:
9985       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9986                                  nodes[4], id, theForce3d);
9987       break;
9988     case 6:
9989       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9990                                  nodes[4], nodes[5], id, theForce3d);
9991       break;
9992     default:;
9993     }
9994     ReplaceElemInGroups( elem, newElem, meshDS);
9995     if( newElem && smDS )
9996       smDS->AddElement( newElem );
9997   }
9998
9999   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
10000   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
10001     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
10002     helper.FixQuadraticElements( myError );
10003   }
10004 }
10005
10006 //=======================================================================
10007 /*!
10008  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
10009  * \return int - nb of checked elements
10010  */
10011 //=======================================================================
10012
10013 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
10014                                      SMDS_ElemIteratorPtr theItr,
10015                                      const int            theShapeID)
10016 {
10017   int nbElem = 0;
10018   SMESHDS_Mesh* meshDS = GetMeshDS();
10019
10020   while( theItr->more() )
10021   {
10022     const SMDS_MeshElement* elem = theItr->next();
10023     nbElem++;
10024     if( elem && elem->IsQuadratic())
10025     {
10026       int id                    = elem->GetID();
10027       int nbCornerNodes         = elem->NbCornerNodes();
10028       SMDSAbs_ElementType aType = elem->GetType();
10029
10030       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
10031
10032       //remove a quadratic element
10033       if ( !theSm || !theSm->Contains( elem ))
10034         theSm = meshDS->MeshElements( elem->getshapeId() );
10035       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
10036
10037       // remove medium nodes
10038       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
10039         if ( nodes[i]->NbInverseElements() == 0 )
10040           meshDS->RemoveFreeNode( nodes[i], theSm );
10041
10042       // add a linear element
10043       nodes.resize( nbCornerNodes );
10044       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
10045       ReplaceElemInGroups(elem, newElem, meshDS);
10046       if( theSm && newElem )
10047         theSm->AddElement( newElem );
10048     }
10049   }
10050   return nbElem;
10051 }
10052
10053 //=======================================================================
10054 //function : ConvertFromQuadratic
10055 //purpose  :
10056 //=======================================================================
10057
10058 bool SMESH_MeshEditor::ConvertFromQuadratic()
10059 {
10060   int nbCheckedElems = 0;
10061   if ( myMesh->HasShapeToMesh() )
10062   {
10063     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
10064     {
10065       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
10066       while ( smIt->more() ) {
10067         SMESH_subMesh* sm = smIt->next();
10068         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
10069           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
10070       }
10071     }
10072   }
10073
10074   int totalNbElems =
10075     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
10076   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
10077   {
10078     SMESHDS_SubMesh *aSM = 0;
10079     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
10080   }
10081
10082   return true;
10083 }
10084
10085 namespace
10086 {
10087   //================================================================================
10088   /*!
10089    * \brief Return true if all medium nodes of the element are in the node set
10090    */
10091   //================================================================================
10092
10093   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
10094   {
10095     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
10096       if ( !nodeSet.count( elem->GetNode(i) ))
10097         return false;
10098     return true;
10099   }
10100 }
10101
10102 //================================================================================
10103 /*!
10104  * \brief Makes given elements linear
10105  */
10106 //================================================================================
10107
10108 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
10109 {
10110   if ( theElements.empty() ) return;
10111
10112   // collect IDs of medium nodes of theElements; some of these nodes will be removed
10113   set<int> mediumNodeIDs;
10114   TIDSortedElemSet::iterator eIt = theElements.begin();
10115   for ( ; eIt != theElements.end(); ++eIt )
10116   {
10117     const SMDS_MeshElement* e = *eIt;
10118     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
10119       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
10120   }
10121
10122   // replace given elements by linear ones
10123   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
10124   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
10125   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
10126
10127   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
10128   // except those elements sharing medium nodes of quadratic element whose medium nodes
10129   // are not all in mediumNodeIDs
10130
10131   // get remaining medium nodes
10132   TIDSortedNodeSet mediumNodes;
10133   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
10134   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
10135     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
10136       mediumNodes.insert( mediumNodes.end(), n );
10137
10138   // find more quadratic elements to convert
10139   TIDSortedElemSet moreElemsToConvert;
10140   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
10141   for ( ; nIt != mediumNodes.end(); ++nIt )
10142   {
10143     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
10144     while ( invIt->more() )
10145     {
10146       const SMDS_MeshElement* e = invIt->next();
10147       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
10148       {
10149         // find a more complex element including e and
10150         // whose medium nodes are not in mediumNodes
10151         bool complexFound = false;
10152         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
10153         {
10154           SMDS_ElemIteratorPtr invIt2 =
10155             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
10156           while ( invIt2->more() )
10157           {
10158             const SMDS_MeshElement* eComplex = invIt2->next();
10159             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
10160             {
10161               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
10162               if ( nbCommonNodes == e->NbNodes())
10163               {
10164                 complexFound = true;
10165                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
10166                 break;
10167               }
10168             }
10169           }
10170         }
10171         if ( !complexFound )
10172           moreElemsToConvert.insert( e );
10173       }
10174     }
10175   }
10176   elemIt = SMDS_ElemIteratorPtr
10177     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
10178   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
10179 }
10180
10181 //=======================================================================
10182 //function : SewSideElements
10183 //purpose  :
10184 //=======================================================================
10185
10186 SMESH_MeshEditor::Sew_Error
10187 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
10188                                    TIDSortedElemSet&    theSide2,
10189                                    const SMDS_MeshNode* theFirstNode1,
10190                                    const SMDS_MeshNode* theFirstNode2,
10191                                    const SMDS_MeshNode* theSecondNode1,
10192                                    const SMDS_MeshNode* theSecondNode2)
10193 {
10194   myLastCreatedElems.Clear();
10195   myLastCreatedNodes.Clear();
10196
10197   MESSAGE ("::::SewSideElements()");
10198   if ( theSide1.size() != theSide2.size() )
10199     return SEW_DIFF_NB_OF_ELEMENTS;
10200
10201   Sew_Error aResult = SEW_OK;
10202   // Algo:
10203   // 1. Build set of faces representing each side
10204   // 2. Find which nodes of the side 1 to merge with ones on the side 2
10205   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10206
10207   // =======================================================================
10208   // 1. Build set of faces representing each side:
10209   // =======================================================================
10210   // a. build set of nodes belonging to faces
10211   // b. complete set of faces: find missing faces whose nodes are in set of nodes
10212   // c. create temporary faces representing side of volumes if correspondent
10213   //    face does not exist
10214
10215   SMESHDS_Mesh* aMesh = GetMeshDS();
10216   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
10217   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
10218   TIDSortedElemSet             faceSet1, faceSet2;
10219   set<const SMDS_MeshElement*> volSet1,  volSet2;
10220   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
10221   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
10222   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
10223   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
10224   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
10225   int iSide, iFace, iNode;
10226
10227   list<const SMDS_MeshElement* > tempFaceList;
10228   for ( iSide = 0; iSide < 2; iSide++ ) {
10229     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
10230     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
10231     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
10232     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
10233     set<const SMDS_MeshElement*>::iterator vIt;
10234     TIDSortedElemSet::iterator eIt;
10235     set<const SMDS_MeshNode*>::iterator    nIt;
10236
10237     // check that given nodes belong to given elements
10238     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
10239     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
10240     int firstIndex = -1, secondIndex = -1;
10241     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
10242       const SMDS_MeshElement* elem = *eIt;
10243       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
10244       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
10245       if ( firstIndex > -1 && secondIndex > -1 ) break;
10246     }
10247     if ( firstIndex < 0 || secondIndex < 0 ) {
10248       // we can simply return until temporary faces created
10249       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
10250     }
10251
10252     // -----------------------------------------------------------
10253     // 1a. Collect nodes of existing faces
10254     //     and build set of face nodes in order to detect missing
10255     //     faces corresponding to sides of volumes
10256     // -----------------------------------------------------------
10257
10258     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
10259
10260     // loop on the given element of a side
10261     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
10262       //const SMDS_MeshElement* elem = *eIt;
10263       const SMDS_MeshElement* elem = *eIt;
10264       if ( elem->GetType() == SMDSAbs_Face ) {
10265         faceSet->insert( elem );
10266         set <const SMDS_MeshNode*> faceNodeSet;
10267         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
10268         while ( nodeIt->more() ) {
10269           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10270           nodeSet->insert( n );
10271           faceNodeSet.insert( n );
10272         }
10273         setOfFaceNodeSet.insert( faceNodeSet );
10274       }
10275       else if ( elem->GetType() == SMDSAbs_Volume )
10276         volSet->insert( elem );
10277     }
10278     // ------------------------------------------------------------------------------
10279     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
10280     // ------------------------------------------------------------------------------
10281
10282     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10283       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10284       while ( fIt->more() ) { // loop on faces sharing a node
10285         const SMDS_MeshElement* f = fIt->next();
10286         if ( faceSet->find( f ) == faceSet->end() ) {
10287           // check if all nodes are in nodeSet and
10288           // complete setOfFaceNodeSet if they are
10289           set <const SMDS_MeshNode*> faceNodeSet;
10290           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10291           bool allInSet = true;
10292           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10293             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10294             if ( nodeSet->find( n ) == nodeSet->end() )
10295               allInSet = false;
10296             else
10297               faceNodeSet.insert( n );
10298           }
10299           if ( allInSet ) {
10300             faceSet->insert( f );
10301             setOfFaceNodeSet.insert( faceNodeSet );
10302           }
10303         }
10304       }
10305     }
10306
10307     // -------------------------------------------------------------------------
10308     // 1c. Create temporary faces representing sides of volumes if correspondent
10309     //     face does not exist
10310     // -------------------------------------------------------------------------
10311
10312     if ( !volSet->empty() ) {
10313       //int nodeSetSize = nodeSet->size();
10314
10315       // loop on given volumes
10316       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
10317         SMDS_VolumeTool vol (*vIt);
10318         // loop on volume faces: find free faces
10319         // --------------------------------------
10320         list<const SMDS_MeshElement* > freeFaceList;
10321         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
10322           if ( !vol.IsFreeFace( iFace ))
10323             continue;
10324           // check if there is already a face with same nodes in a face set
10325           const SMDS_MeshElement* aFreeFace = 0;
10326           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
10327           int nbNodes = vol.NbFaceNodes( iFace );
10328           set <const SMDS_MeshNode*> faceNodeSet;
10329           vol.GetFaceNodes( iFace, faceNodeSet );
10330           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
10331           if ( isNewFace ) {
10332             // no such a face is given but it still can exist, check it
10333             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
10334             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
10335           }
10336           if ( !aFreeFace ) {
10337             // create a temporary face
10338             if ( nbNodes == 3 ) {
10339               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
10340               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
10341             }
10342             else if ( nbNodes == 4 ) {
10343               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10344               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10345             }
10346             else {
10347               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10348               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
10349               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
10350             }
10351             if ( aFreeFace )
10352               tempFaceList.push_back( aFreeFace );
10353           }
10354
10355           if ( aFreeFace )
10356             freeFaceList.push_back( aFreeFace );
10357
10358         } // loop on faces of a volume
10359
10360         // choose one of several free faces of a volume
10361         // --------------------------------------------
10362         if ( freeFaceList.size() > 1 ) {
10363           // choose a face having max nb of nodes shared by other elems of a side
10364           int maxNbNodes = -1;
10365           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
10366           while ( fIt != freeFaceList.end() ) { // loop on free faces
10367             int nbSharedNodes = 0;
10368             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10369             while ( nodeIt->more() ) { // loop on free face nodes
10370               const SMDS_MeshNode* n =
10371                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10372               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
10373               while ( invElemIt->more() ) {
10374                 const SMDS_MeshElement* e = invElemIt->next();
10375                 nbSharedNodes += faceSet->count( e );
10376                 nbSharedNodes += elemSet->count( e );
10377               }
10378             }
10379             if ( nbSharedNodes > maxNbNodes ) {
10380               maxNbNodes = nbSharedNodes;
10381               freeFaceList.erase( freeFaceList.begin(), fIt++ );
10382             }
10383             else if ( nbSharedNodes == maxNbNodes ) {
10384               fIt++;
10385             }
10386             else {
10387               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
10388             }
10389           }
10390           if ( freeFaceList.size() > 1 )
10391           {
10392             // could not choose one face, use another way
10393             // choose a face most close to the bary center of the opposite side
10394             gp_XYZ aBC( 0., 0., 0. );
10395             set <const SMDS_MeshNode*> addedNodes;
10396             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
10397             eIt = elemSet2->begin();
10398             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
10399               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
10400               while ( nodeIt->more() ) { // loop on free face nodes
10401                 const SMDS_MeshNode* n =
10402                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10403                 if ( addedNodes.insert( n ).second )
10404                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
10405               }
10406             }
10407             aBC /= addedNodes.size();
10408             double minDist = DBL_MAX;
10409             fIt = freeFaceList.begin();
10410             while ( fIt != freeFaceList.end() ) { // loop on free faces
10411               double dist = 0;
10412               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10413               while ( nodeIt->more() ) { // loop on free face nodes
10414                 const SMDS_MeshNode* n =
10415                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10416                 gp_XYZ p( n->X(),n->Y(),n->Z() );
10417                 dist += ( aBC - p ).SquareModulus();
10418               }
10419               if ( dist < minDist ) {
10420                 minDist = dist;
10421                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10422               }
10423               else
10424                 fIt = freeFaceList.erase( fIt++ );
10425             }
10426           }
10427         } // choose one of several free faces of a volume
10428
10429         if ( freeFaceList.size() == 1 ) {
10430           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10431           faceSet->insert( aFreeFace );
10432           // complete a node set with nodes of a found free face
10433           //           for ( iNode = 0; iNode < ; iNode++ )
10434           //             nodeSet->insert( fNodes[ iNode ] );
10435         }
10436
10437       } // loop on volumes of a side
10438
10439       //       // complete a set of faces if new nodes in a nodeSet appeared
10440       //       // ----------------------------------------------------------
10441       //       if ( nodeSetSize != nodeSet->size() ) {
10442       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10443       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10444       //           while ( fIt->more() ) { // loop on faces sharing a node
10445       //             const SMDS_MeshElement* f = fIt->next();
10446       //             if ( faceSet->find( f ) == faceSet->end() ) {
10447       //               // check if all nodes are in nodeSet and
10448       //               // complete setOfFaceNodeSet if they are
10449       //               set <const SMDS_MeshNode*> faceNodeSet;
10450       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10451       //               bool allInSet = true;
10452       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10453       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10454       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10455       //                   allInSet = false;
10456       //                 else
10457       //                   faceNodeSet.insert( n );
10458       //               }
10459       //               if ( allInSet ) {
10460       //                 faceSet->insert( f );
10461       //                 setOfFaceNodeSet.insert( faceNodeSet );
10462       //               }
10463       //             }
10464       //           }
10465       //         }
10466       //       }
10467     } // Create temporary faces, if there are volumes given
10468   } // loop on sides
10469
10470   if ( faceSet1.size() != faceSet2.size() ) {
10471     // delete temporary faces: they are in reverseElements of actual nodes
10472 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10473 //    while ( tmpFaceIt->more() )
10474 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10475 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10476 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10477 //      aMesh->RemoveElement(*tmpFaceIt);
10478     MESSAGE("Diff nb of faces");
10479     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10480   }
10481
10482   // ============================================================
10483   // 2. Find nodes to merge:
10484   //              bind a node to remove to a node to put instead
10485   // ============================================================
10486
10487   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10488   if ( theFirstNode1 != theFirstNode2 )
10489     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10490   if ( theSecondNode1 != theSecondNode2 )
10491     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10492
10493   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10494   set< long > linkIdSet; // links to process
10495   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10496
10497   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10498   list< NLink > linkList[2];
10499   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10500   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10501   // loop on links in linkList; find faces by links and append links
10502   // of the found faces to linkList
10503   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10504   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
10505   {
10506     NLink link[] = { *linkIt[0], *linkIt[1] };
10507     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10508     if ( !linkIdSet.count( linkID ) )
10509       continue;
10510
10511     // by links, find faces in the face sets,
10512     // and find indices of link nodes in the found faces;
10513     // in a face set, there is only one or no face sharing a link
10514     // ---------------------------------------------------------------
10515
10516     const SMDS_MeshElement* face[] = { 0, 0 };
10517     vector<const SMDS_MeshNode*> fnodes[2];
10518     int iLinkNode[2][2];
10519     TIDSortedElemSet avoidSet;
10520     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10521       const SMDS_MeshNode* n1 = link[iSide].first;
10522       const SMDS_MeshNode* n2 = link[iSide].second;
10523       //cout << "Side " << iSide << " ";
10524       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
10525       // find a face by two link nodes
10526       face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
10527                                      &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
10528       if ( face[ iSide ])
10529       {
10530         //cout << " F " << face[ iSide]->GetID() <<endl;
10531         faceSetPtr[ iSide ]->erase( face[ iSide ]);
10532         // put face nodes to fnodes
10533         if ( face[ iSide ]->IsQuadratic() )
10534         {
10535           // use interlaced nodes iterator
10536           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
10537           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10538           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
10539           while ( nIter->more() )
10540             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
10541         }
10542         else
10543         {
10544           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
10545                                   face[ iSide ]->end_nodes() );
10546         }
10547         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
10548       }
10549     }
10550
10551     // check similarity of elements of the sides
10552     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10553       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10554       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10555         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10556       }
10557       else {
10558         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10559       }
10560       break; // do not return because it's necessary to remove tmp faces
10561     }
10562
10563     // set nodes to merge
10564     // -------------------
10565
10566     if ( face[0] && face[1] )  {
10567       const int nbNodes = face[0]->NbNodes();
10568       if ( nbNodes != face[1]->NbNodes() ) {
10569         MESSAGE("Diff nb of face nodes");
10570         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10571         break; // do not return because it s necessary to remove tmp faces
10572       }
10573       bool reverse[] = { false, false }; // order of nodes in the link
10574       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10575         // analyse link orientation in faces
10576         int i1 = iLinkNode[ iSide ][ 0 ];
10577         int i2 = iLinkNode[ iSide ][ 1 ];
10578         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10579       }
10580       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
10581       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
10582       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
10583       {
10584         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
10585                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
10586       }
10587
10588       // add other links of the faces to linkList
10589       // -----------------------------------------
10590
10591       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10592         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
10593         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10594         if ( !iter_isnew.second ) { // already in a set: no need to process
10595           linkIdSet.erase( iter_isnew.first );
10596         }
10597         else // new in set == encountered for the first time: add
10598         {
10599           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
10600           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
10601           linkList[0].push_back ( NLink( n1, n2 ));
10602           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10603         }
10604       }
10605     } // 2 faces found
10606
10607     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
10608       break;
10609
10610   } // loop on link lists
10611
10612   if ( aResult == SEW_OK &&
10613        ( //linkIt[0] != linkList[0].end() ||
10614          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10615     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10616              " " << (faceSetPtr[1]->empty()));
10617     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10618   }
10619
10620   // ====================================================================
10621   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10622   // ====================================================================
10623
10624   // delete temporary faces
10625 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10626 //  while ( tmpFaceIt->more() )
10627 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10628   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10629   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10630     aMesh->RemoveElement(*tmpFaceIt);
10631
10632   if ( aResult != SEW_OK)
10633     return aResult;
10634
10635   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10636   // loop on nodes replacement map
10637   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10638   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10639     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10640       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10641       nodeIDsToRemove.push_back( nToRemove->GetID() );
10642       // loop on elements sharing nToRemove
10643       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10644       while ( invElemIt->more() ) {
10645         const SMDS_MeshElement* e = invElemIt->next();
10646         // get a new suite of nodes: make replacement
10647         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10648         vector< const SMDS_MeshNode*> nodes( nbNodes );
10649         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10650         while ( nIt->more() ) {
10651           const SMDS_MeshNode* n =
10652             static_cast<const SMDS_MeshNode*>( nIt->next() );
10653           nnIt = nReplaceMap.find( n );
10654           if ( nnIt != nReplaceMap.end() ) {
10655             nbReplaced++;
10656             n = (*nnIt).second;
10657           }
10658           nodes[ i++ ] = n;
10659         }
10660         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10661         //         elemIDsToRemove.push_back( e->GetID() );
10662         //       else
10663         if ( nbReplaced )
10664           {
10665             SMDSAbs_ElementType etyp = e->GetType();
10666             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10667             if (newElem)
10668               {
10669                 myLastCreatedElems.Append(newElem);
10670                 AddToSameGroups(newElem, e, aMesh);
10671                 int aShapeId = e->getshapeId();
10672                 if ( aShapeId )
10673                   {
10674                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10675                   }
10676               }
10677             aMesh->RemoveElement(e);
10678           }
10679       }
10680     }
10681
10682   Remove( nodeIDsToRemove, true );
10683
10684   return aResult;
10685 }
10686
10687 //================================================================================
10688 /*!
10689  * \brief Find corresponding nodes in two sets of faces
10690  * \param theSide1 - first face set
10691  * \param theSide2 - second first face
10692  * \param theFirstNode1 - a boundary node of set 1
10693  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10694  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10695  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10696  * \param nReplaceMap - output map of corresponding nodes
10697  * \return bool  - is a success or not
10698  */
10699 //================================================================================
10700
10701 #ifdef _DEBUG_
10702 //#define DEBUG_MATCHING_NODES
10703 #endif
10704
10705 SMESH_MeshEditor::Sew_Error
10706 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10707                                     set<const SMDS_MeshElement*>& theSide2,
10708                                     const SMDS_MeshNode*          theFirstNode1,
10709                                     const SMDS_MeshNode*          theFirstNode2,
10710                                     const SMDS_MeshNode*          theSecondNode1,
10711                                     const SMDS_MeshNode*          theSecondNode2,
10712                                     TNodeNodeMap &                nReplaceMap)
10713 {
10714   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10715
10716   nReplaceMap.clear();
10717   if ( theFirstNode1 != theFirstNode2 )
10718     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10719   if ( theSecondNode1 != theSecondNode2 )
10720     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10721
10722   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10723   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10724
10725   list< NLink > linkList[2];
10726   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10727   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10728
10729   // loop on links in linkList; find faces by links and append links
10730   // of the found faces to linkList
10731   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10732   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10733     NLink link[] = { *linkIt[0], *linkIt[1] };
10734     if ( linkSet.find( link[0] ) == linkSet.end() )
10735       continue;
10736
10737     // by links, find faces in the face sets,
10738     // and find indices of link nodes in the found faces;
10739     // in a face set, there is only one or no face sharing a link
10740     // ---------------------------------------------------------------
10741
10742     const SMDS_MeshElement* face[] = { 0, 0 };
10743     list<const SMDS_MeshNode*> notLinkNodes[2];
10744     //bool reverse[] = { false, false }; // order of notLinkNodes
10745     int nbNodes[2];
10746     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10747     {
10748       const SMDS_MeshNode* n1 = link[iSide].first;
10749       const SMDS_MeshNode* n2 = link[iSide].second;
10750       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10751       set< const SMDS_MeshElement* > facesOfNode1;
10752       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10753       {
10754         // during a loop of the first node, we find all faces around n1,
10755         // during a loop of the second node, we find one face sharing both n1 and n2
10756         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10757         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10758         while ( fIt->more() ) { // loop on faces sharing a node
10759           const SMDS_MeshElement* f = fIt->next();
10760           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10761               ! facesOfNode1.insert( f ).second ) // f encounters twice
10762           {
10763             if ( face[ iSide ] ) {
10764               MESSAGE( "2 faces per link " );
10765               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10766             }
10767             face[ iSide ] = f;
10768             faceSet->erase( f );
10769
10770             // get not link nodes
10771             int nbN = f->NbNodes();
10772             if ( f->IsQuadratic() )
10773               nbN /= 2;
10774             nbNodes[ iSide ] = nbN;
10775             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10776             int i1 = f->GetNodeIndex( n1 );
10777             int i2 = f->GetNodeIndex( n2 );
10778             int iEnd = nbN, iBeg = -1, iDelta = 1;
10779             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10780             if ( reverse ) {
10781               std::swap( iEnd, iBeg ); iDelta = -1;
10782             }
10783             int i = i2;
10784             while ( true ) {
10785               i += iDelta;
10786               if ( i == iEnd ) i = iBeg + iDelta;
10787               if ( i == i1 ) break;
10788               nodes.push_back ( f->GetNode( i ) );
10789             }
10790           }
10791         }
10792       }
10793     }
10794     // check similarity of elements of the sides
10795     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10796       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10797       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10798         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10799       }
10800       else {
10801         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10802       }
10803     }
10804
10805     // set nodes to merge
10806     // -------------------
10807
10808     if ( face[0] && face[1] )  {
10809       if ( nbNodes[0] != nbNodes[1] ) {
10810         MESSAGE("Diff nb of face nodes");
10811         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10812       }
10813 #ifdef DEBUG_MATCHING_NODES
10814       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10815                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10816                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10817 #endif
10818       int nbN = nbNodes[0];
10819       {
10820         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10821         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10822         for ( int i = 0 ; i < nbN - 2; ++i ) {
10823 #ifdef DEBUG_MATCHING_NODES
10824           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10825 #endif
10826           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10827         }
10828       }
10829
10830       // add other links of the face 1 to linkList
10831       // -----------------------------------------
10832
10833       const SMDS_MeshElement* f0 = face[0];
10834       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10835       for ( int i = 0; i < nbN; i++ )
10836       {
10837         const SMDS_MeshNode* n2 = f0->GetNode( i );
10838         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10839           linkSet.insert( SMESH_TLink( n1, n2 ));
10840         if ( !iter_isnew.second ) { // already in a set: no need to process
10841           linkSet.erase( iter_isnew.first );
10842         }
10843         else // new in set == encountered for the first time: add
10844         {
10845 #ifdef DEBUG_MATCHING_NODES
10846           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10847                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10848 #endif
10849           linkList[0].push_back ( NLink( n1, n2 ));
10850           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10851         }
10852         n1 = n2;
10853       }
10854     } // 2 faces found
10855   } // loop on link lists
10856
10857   return SEW_OK;
10858 }
10859
10860 //================================================================================
10861 /*!
10862   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10863   \param theElems - the list of elements (edges or faces) to be replicated
10864   The nodes for duplication could be found from these elements
10865   \param theNodesNot - list of nodes to NOT replicate
10866   \param theAffectedElems - the list of elements (cells and edges) to which the
10867   replicated nodes should be associated to.
10868   \return TRUE if operation has been completed successfully, FALSE otherwise
10869 */
10870 //================================================================================
10871
10872 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10873                                     const TIDSortedElemSet& theNodesNot,
10874                                     const TIDSortedElemSet& theAffectedElems )
10875 {
10876   myLastCreatedElems.Clear();
10877   myLastCreatedNodes.Clear();
10878
10879   if ( theElems.size() == 0 )
10880     return false;
10881
10882   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10883   if ( !aMeshDS )
10884     return false;
10885
10886   bool res = false;
10887   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10888   // duplicate elements and nodes
10889   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10890   // replce nodes by duplications
10891   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10892   return res;
10893 }
10894
10895 //================================================================================
10896 /*!
10897   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10898   \param theMeshDS - mesh instance
10899   \param theElems - the elements replicated or modified (nodes should be changed)
10900   \param theNodesNot - nodes to NOT replicate
10901   \param theNodeNodeMap - relation of old node to new created node
10902   \param theIsDoubleElem - flag os to replicate element or modify
10903   \return TRUE if operation has been completed successfully, FALSE otherwise
10904 */
10905 //================================================================================
10906
10907 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10908                                     const TIDSortedElemSet& theElems,
10909                                     const TIDSortedElemSet& theNodesNot,
10910                                     std::map< const SMDS_MeshNode*,
10911                                     const SMDS_MeshNode* >& theNodeNodeMap,
10912                                     const bool theIsDoubleElem )
10913 {
10914   MESSAGE("doubleNodes");
10915   // iterate on through element and duplicate them (by nodes duplication)
10916   bool res = false;
10917   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10918   for ( ;  elemItr != theElems.end(); ++elemItr )
10919   {
10920     const SMDS_MeshElement* anElem = *elemItr;
10921     if (!anElem)
10922       continue;
10923
10924     bool isDuplicate = false;
10925     // duplicate nodes to duplicate element
10926     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10927     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10928     int ind = 0;
10929     while ( anIter->more() )
10930     {
10931
10932       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10933       SMDS_MeshNode* aNewNode = aCurrNode;
10934       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10935         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10936       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10937       {
10938         // duplicate node
10939         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10940         theNodeNodeMap[ aCurrNode ] = aNewNode;
10941         myLastCreatedNodes.Append( aNewNode );
10942       }
10943       isDuplicate |= (aCurrNode != aNewNode);
10944       newNodes[ ind++ ] = aNewNode;
10945     }
10946     if ( !isDuplicate )
10947       continue;
10948
10949     if ( theIsDoubleElem )
10950       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10951     else
10952       {
10953       MESSAGE("ChangeElementNodes");
10954       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10955       }
10956     res = true;
10957   }
10958   return res;
10959 }
10960
10961 //================================================================================
10962 /*!
10963   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10964   \param theNodes - identifiers of nodes to be doubled
10965   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10966          nodes. If list of element identifiers is empty then nodes are doubled but
10967          they not assigned to elements
10968   \return TRUE if operation has been completed successfully, FALSE otherwise
10969 */
10970 //================================================================================
10971
10972 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10973                                     const std::list< int >& theListOfModifiedElems )
10974 {
10975   MESSAGE("DoubleNodes");
10976   myLastCreatedElems.Clear();
10977   myLastCreatedNodes.Clear();
10978
10979   if ( theListOfNodes.size() == 0 )
10980     return false;
10981
10982   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10983   if ( !aMeshDS )
10984     return false;
10985
10986   // iterate through nodes and duplicate them
10987
10988   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10989
10990   std::list< int >::const_iterator aNodeIter;
10991   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10992   {
10993     int aCurr = *aNodeIter;
10994     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10995     if ( !aNode )
10996       continue;
10997
10998     // duplicate node
10999
11000     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
11001     if ( aNewNode )
11002     {
11003       anOldNodeToNewNode[ aNode ] = aNewNode;
11004       myLastCreatedNodes.Append( aNewNode );
11005     }
11006   }
11007
11008   // Create map of new nodes for modified elements
11009
11010   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
11011
11012   std::list< int >::const_iterator anElemIter;
11013   for ( anElemIter = theListOfModifiedElems.begin();
11014         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
11015   {
11016     int aCurr = *anElemIter;
11017     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
11018     if ( !anElem )
11019       continue;
11020
11021     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
11022
11023     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
11024     int ind = 0;
11025     while ( anIter->more() )
11026     {
11027       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
11028       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
11029       {
11030         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
11031         aNodeArr[ ind++ ] = aNewNode;
11032       }
11033       else
11034         aNodeArr[ ind++ ] = aCurrNode;
11035     }
11036     anElemToNodes[ anElem ] = aNodeArr;
11037   }
11038
11039   // Change nodes of elements
11040
11041   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
11042     anElemToNodesIter = anElemToNodes.begin();
11043   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
11044   {
11045     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
11046     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
11047     if ( anElem )
11048       {
11049       MESSAGE("ChangeElementNodes");
11050       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
11051       }
11052   }
11053
11054   return true;
11055 }
11056
11057 namespace {
11058
11059   //================================================================================
11060   /*!
11061   \brief Check if element located inside shape
11062   \return TRUE if IN or ON shape, FALSE otherwise
11063   */
11064   //================================================================================
11065
11066   template<class Classifier>
11067   bool isInside(const SMDS_MeshElement* theElem,
11068                 Classifier&             theClassifier,
11069                 const double            theTol)
11070   {
11071     gp_XYZ centerXYZ (0, 0, 0);
11072     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
11073     while (aNodeItr->more())
11074       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
11075
11076     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
11077     theClassifier.Perform(aPnt, theTol);
11078     TopAbs_State aState = theClassifier.State();
11079     return (aState == TopAbs_IN || aState == TopAbs_ON );
11080   }
11081
11082   //================================================================================
11083   /*!
11084    * \brief Classifier of the 3D point on the TopoDS_Face
11085    *        with interaface suitable for isInside()
11086    */
11087   //================================================================================
11088
11089   struct _FaceClassifier
11090   {
11091     Extrema_ExtPS       _extremum;
11092     BRepAdaptor_Surface _surface;
11093     TopAbs_State        _state;
11094
11095     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
11096     {
11097       _extremum.Initialize( _surface,
11098                             _surface.FirstUParameter(), _surface.LastUParameter(),
11099                             _surface.FirstVParameter(), _surface.LastVParameter(),
11100                             _surface.Tolerance(), _surface.Tolerance() );
11101     }
11102     void Perform(const gp_Pnt& aPnt, double theTol)
11103     {
11104       _state = TopAbs_OUT;
11105       _extremum.Perform(aPnt);
11106       if ( _extremum.IsDone() )
11107         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
11108 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
11109           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
11110 #else
11111           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
11112 #endif
11113     }
11114     TopAbs_State State() const
11115     {
11116       return _state;
11117     }
11118   };
11119 }
11120
11121 //================================================================================
11122 /*!
11123   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed).
11124   This method is the first step of DoubleNodeElemGroupsInRegion.
11125   \param theElems - list of groups of elements (edges or faces) to be replicated
11126   \param theNodesNot - list of groups of nodes not to replicated
11127   \param theShape - shape to detect affected elements (element which geometric center
11128          located on or inside shape). If the shape is null, detection is done on faces orientations
11129          (select elements with a gravity center on the side given by faces normals).
11130          This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations.
11131          The replicated nodes should be associated to affected elements.
11132   \return groups of affected elements
11133   \sa DoubleNodeElemGroupsInRegion()
11134  */
11135 //================================================================================
11136
11137 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
11138                                                    const TIDSortedElemSet& theNodesNot,
11139                                                    const TopoDS_Shape&     theShape,
11140                                                    TIDSortedElemSet&       theAffectedElems)
11141 {
11142   if ( theShape.IsNull() )
11143   {
11144     std::set<const SMDS_MeshNode*> alreadyCheckedNodes;
11145     std::set<const SMDS_MeshElement*> alreadyCheckedElems;
11146     std::set<const SMDS_MeshElement*> edgesToCheck;
11147     alreadyCheckedNodes.clear();
11148     alreadyCheckedElems.clear();
11149     edgesToCheck.clear();
11150
11151     // --- iterates on elements to be replicated and get elements by back references from their nodes
11152
11153     TIDSortedElemSet::const_iterator elemItr = theElems.begin();
11154     int ielem = 1;
11155     for ( ;  elemItr != theElems.end(); ++elemItr )
11156     {
11157       SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
11158       if (!anElem || (anElem->GetType() != SMDSAbs_Face))
11159         continue;
11160       gp_XYZ normal;
11161       SMESH_Algo::FaceNormal( anElem, normal, /*normalized=*/true );
11162       MESSAGE("element " << ielem++ <<  " normal " << normal.X() << " " << normal.Y() << " " << normal.Z());
11163       std::set<const SMDS_MeshNode*> nodesElem;
11164       nodesElem.clear();
11165       SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
11166       while ( nodeItr->more() )
11167       {
11168         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11169         nodesElem.insert(aNode);
11170       }
11171       std::set<const SMDS_MeshNode*>::iterator nodit = nodesElem.begin();
11172       for (; nodit != nodesElem.end(); nodit++)
11173       {
11174         MESSAGE("  noeud ");
11175         const SMDS_MeshNode* aNode = *nodit;
11176         if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
11177           continue;
11178         if (alreadyCheckedNodes.find(aNode) != alreadyCheckedNodes.end())
11179           continue;
11180         alreadyCheckedNodes.insert(aNode);
11181         SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
11182         while ( backElemItr->more() )
11183         {
11184           MESSAGE("    backelem ");
11185           const SMDS_MeshElement* curElem = backElemItr->next();
11186           if (alreadyCheckedElems.find(curElem) != alreadyCheckedElems.end())
11187             continue;
11188           if (theElems.find(curElem) != theElems.end())
11189             continue;
11190           alreadyCheckedElems.insert(curElem);
11191           double x=0, y=0, z=0;
11192           int nb = 0;
11193           SMDS_ElemIteratorPtr nodeItr2 = curElem->nodesIterator();
11194           while ( nodeItr2->more() )
11195           {
11196             const SMDS_MeshNode* anotherNode = cast2Node(nodeItr2->next());
11197             x += anotherNode->X();
11198             y += anotherNode->Y();
11199             z += anotherNode->Z();
11200             nb++;
11201           }
11202           gp_XYZ p;
11203           p.SetCoord( x/nb -aNode->X(),
11204                       y/nb -aNode->Y(),
11205                       z/nb -aNode->Z() );
11206           MESSAGE("      check " << p.X() << " " << p.Y() << " " << p.Z());
11207           if (normal*p > 0)
11208           {
11209             MESSAGE("    --- inserted")
11210             theAffectedElems.insert( curElem );
11211           }
11212           else if (curElem->GetType() == SMDSAbs_Edge)
11213             edgesToCheck.insert(curElem);
11214         }
11215       }
11216     }
11217     // --- add also edges lying on the set of faces (all nodes in alreadyCheckedNodes)
11218     std::set<const SMDS_MeshElement*>::iterator eit = edgesToCheck.begin();
11219     for( ; eit != edgesToCheck.end(); eit++)
11220     {
11221       bool onside = true;
11222       const SMDS_MeshElement* anEdge = *eit;
11223       SMDS_ElemIteratorPtr nodeItr = anEdge->nodesIterator();
11224       while ( nodeItr->more() )
11225       {
11226         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11227         if (alreadyCheckedNodes.find(aNode) == alreadyCheckedNodes.end())
11228         {
11229           onside = false;
11230           break;
11231         }
11232       }
11233       if (onside)
11234       {
11235         MESSAGE("    --- edge onside inserted")
11236         theAffectedElems.insert(anEdge);
11237       }
11238     }
11239   }
11240   else
11241   {
11242     const double aTol = Precision::Confusion();
11243     auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
11244     auto_ptr<_FaceClassifier>              aFaceClassifier;
11245     if ( theShape.ShapeType() == TopAbs_SOLID )
11246     {
11247       bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
11248       bsc3d->PerformInfinitePoint(aTol);
11249     }
11250     else if (theShape.ShapeType() == TopAbs_FACE )
11251     {
11252       aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
11253     }
11254
11255     // iterates on indicated elements and get elements by back references from their nodes
11256     TIDSortedElemSet::const_iterator elemItr = theElems.begin();
11257     int ielem = 1;
11258     for ( ;  elemItr != theElems.end(); ++elemItr )
11259     {
11260       MESSAGE("element " << ielem++);
11261       SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
11262       if (!anElem)
11263         continue;
11264       SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
11265       while ( nodeItr->more() )
11266       {
11267         MESSAGE("  noeud ");
11268         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11269         if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
11270           continue;
11271         SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
11272         while ( backElemItr->more() )
11273         {
11274           MESSAGE("    backelem ");
11275           const SMDS_MeshElement* curElem = backElemItr->next();
11276           if ( curElem && theElems.find(curElem) == theElems.end() &&
11277               ( bsc3d.get() ?
11278                 isInside( curElem, *bsc3d, aTol ) :
11279                 isInside( curElem, *aFaceClassifier, aTol )))
11280             theAffectedElems.insert( curElem );
11281         }
11282       }
11283     }
11284   }
11285   return true;
11286 }
11287
11288 //================================================================================
11289 /*!
11290   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
11291   \param theElems - group of of elements (edges or faces) to be replicated
11292   \param theNodesNot - group of nodes not to replicate
11293   \param theShape - shape to detect affected elements (element which geometric center
11294   located on or inside shape).
11295   The replicated nodes should be associated to affected elements.
11296   \return TRUE if operation has been completed successfully, FALSE otherwise
11297 */
11298 //================================================================================
11299
11300 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
11301                                             const TIDSortedElemSet& theNodesNot,
11302                                             const TopoDS_Shape&     theShape )
11303 {
11304   if ( theShape.IsNull() )
11305     return false;
11306
11307   const double aTol = Precision::Confusion();
11308   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
11309   auto_ptr<_FaceClassifier>              aFaceClassifier;
11310   if ( theShape.ShapeType() == TopAbs_SOLID )
11311   {
11312     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
11313     bsc3d->PerformInfinitePoint(aTol);
11314   }
11315   else if (theShape.ShapeType() == TopAbs_FACE )
11316   {
11317     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
11318   }
11319
11320   // iterates on indicated elements and get elements by back references from their nodes
11321   TIDSortedElemSet anAffected;
11322   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
11323   for ( ;  elemItr != theElems.end(); ++elemItr )
11324   {
11325     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
11326     if (!anElem)
11327       continue;
11328
11329     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
11330     while ( nodeItr->more() )
11331     {
11332       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11333       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
11334         continue;
11335       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
11336       while ( backElemItr->more() )
11337       {
11338         const SMDS_MeshElement* curElem = backElemItr->next();
11339         if ( curElem && theElems.find(curElem) == theElems.end() &&
11340              ( bsc3d.get() ?
11341                isInside( curElem, *bsc3d, aTol ) :
11342                isInside( curElem, *aFaceClassifier, aTol )))
11343           anAffected.insert( curElem );
11344       }
11345     }
11346   }
11347   return DoubleNodes( theElems, theNodesNot, anAffected );
11348 }
11349
11350 /*!
11351  *  \brief compute an oriented angle between two planes defined by four points.
11352  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
11353  *  @param p0 base of the rotation axe
11354  *  @param p1 extremity of the rotation axe
11355  *  @param g1 belongs to the first plane
11356  *  @param g2 belongs to the second plane
11357  */
11358 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
11359 {
11360 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
11361 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
11362 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
11363 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
11364   gp_Vec vref(p0, p1);
11365   gp_Vec v1(p0, g1);
11366   gp_Vec v2(p0, g2);
11367   gp_Vec n1 = vref.Crossed(v1);
11368   gp_Vec n2 = vref.Crossed(v2);
11369   return n2.AngleWithRef(n1, vref);
11370 }
11371
11372 /*!
11373  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
11374  *  The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
11375  * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
11376  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
11377  * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
11378  * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list.
11379  * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created.
11380  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
11381  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
11382  * @param theElems - list of groups of volumes, where a group of volume is a set of
11383  * SMDS_MeshElements sorted by Id.
11384  * @param createJointElems - if TRUE, create the elements
11385  * @return TRUE if operation has been completed successfully, FALSE otherwise
11386  */
11387 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
11388                                                      bool createJointElems)
11389 {
11390   MESSAGE("----------------------------------------------");
11391   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
11392   MESSAGE("----------------------------------------------");
11393
11394   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11395   meshDS->BuildDownWardConnectivity(true);
11396   CHRONO(50);
11397   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
11398
11399   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
11400   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
11401   //     build the list of nodes shared by 2 or more domains, with their domain indexes
11402
11403   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
11404   std::map<int,int>celldom; // cell vtkId --> domain
11405   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
11406   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
11407   faceDomains.clear();
11408   celldom.clear();
11409   cellDomains.clear();
11410   nodeDomains.clear();
11411   std::map<int,int> emptyMap;
11412   std::set<int> emptySet;
11413   emptyMap.clear();
11414
11415   MESSAGE(".. Number of domains :"<<theElems.size());
11416
11417   // Check if the domains do not share an element
11418   for (int idom = 0; idom < theElems.size()-1; idom++)
11419     {
11420 //       MESSAGE("... Check of domain #" << idom);
11421       const TIDSortedElemSet& domain = theElems[idom];
11422       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11423       for (; elemItr != domain.end(); ++elemItr)
11424         {
11425           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11426           int idombisdeb = idom + 1 ;
11427           for (int idombis = idombisdeb; idombis < theElems.size(); idombis++) // check if the element belongs to a domain further in the list
11428           {
11429             const TIDSortedElemSet& domainbis = theElems[idombis];
11430             if ( domainbis.count(anElem) )
11431             {
11432               MESSAGE(".... Domain #" << idom);
11433               MESSAGE(".... Domain #" << idombis);
11434               throw SALOME_Exception("The domains are not disjoint.");
11435               return false ;
11436             }
11437           }
11438         }
11439     }
11440
11441   for (int idom = 0; idom < theElems.size(); idom++)
11442     {
11443
11444       // --- build a map (face to duplicate --> volume to modify)
11445       //     with all the faces shared by 2 domains (group of elements)
11446       //     and corresponding volume of this domain, for each shared face.
11447       //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
11448
11449       MESSAGE("... Neighbors of domain #" << idom);
11450       const TIDSortedElemSet& domain = theElems[idom];
11451       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11452       for (; elemItr != domain.end(); ++elemItr)
11453         {
11454           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11455           if (!anElem)
11456             continue;
11457           int vtkId = anElem->getVtkId();
11458           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
11459           int neighborsVtkIds[NBMAXNEIGHBORS];
11460           int downIds[NBMAXNEIGHBORS];
11461           unsigned char downTypes[NBMAXNEIGHBORS];
11462           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11463           for (int n = 0; n < nbNeighbors; n++)
11464             {
11465               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11466               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11467               if (! domain.count(elem)) // neighbor is in another domain : face is shared
11468                 {
11469                   bool ok = false ;
11470                   for (int idombis = 0; idombis < theElems.size(); idombis++) // check if the neighbor belongs to another domain of the list
11471                   {
11472                     // MESSAGE("Domain " << idombis);
11473                     const TIDSortedElemSet& domainbis = theElems[idombis];
11474                     if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
11475                   }
11476                   if ( ok ) // the characteristics of the face is stored
11477                   {
11478                     DownIdType face(downIds[n], downTypes[n]);
11479                     if (!faceDomains.count(face))
11480                       faceDomains[face] = emptyMap; // create an empty entry for face
11481                     if (!faceDomains[face].count(idom))
11482                       {
11483                         faceDomains[face][idom] = vtkId; // volume associated to face in this domain
11484                         celldom[vtkId] = idom;
11485                         //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
11486                       }
11487                   }
11488                 }
11489             }
11490         }
11491     }
11492
11493   //MESSAGE("Number of shared faces " << faceDomains.size());
11494   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
11495
11496   // --- explore the shared faces domain by domain,
11497   //     explore the nodes of the face and see if they belong to a cell in the domain,
11498   //     which has only a node or an edge on the border (not a shared face)
11499
11500   for (int idomain = 0; idomain < theElems.size(); idomain++)
11501     {
11502       //MESSAGE("Domain " << idomain);
11503       const TIDSortedElemSet& domain = theElems[idomain];
11504       itface = faceDomains.begin();
11505       for (; itface != faceDomains.end(); ++itface)
11506         {
11507           std::map<int, int> domvol = itface->second;
11508           if (!domvol.count(idomain))
11509             continue;
11510           DownIdType face = itface->first;
11511           //MESSAGE(" --- face " << face.cellId);
11512           std::set<int> oldNodes;
11513           oldNodes.clear();
11514           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11515           std::set<int>::iterator itn = oldNodes.begin();
11516           for (; itn != oldNodes.end(); ++itn)
11517             {
11518               int oldId = *itn;
11519               //MESSAGE("     node " << oldId);
11520               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11521               for (int i=0; i<l.ncells; i++)
11522                 {
11523                   int vtkId = l.cells[i];
11524                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11525                   if (!domain.count(anElem))
11526                     continue;
11527                   int vtkType = grid->GetCellType(vtkId);
11528                   int downId = grid->CellIdToDownId(vtkId);
11529                   if (downId < 0)
11530                     {
11531                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11532                       continue; // not OK at this stage of the algorithm:
11533                                 //no cells created after BuildDownWardConnectivity
11534                     }
11535                   DownIdType aCell(downId, vtkType);
11536                   if (!cellDomains.count(aCell))
11537                     cellDomains[aCell] = emptyMap; // create an empty entry for cell
11538                   cellDomains[aCell][idomain] = vtkId;
11539                   celldom[vtkId] = idomain;
11540                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
11541                 }
11542             }
11543         }
11544     }
11545
11546   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11547   //     for each shared face, get the nodes
11548   //     for each node, for each domain of the face, create a clone of the node
11549
11550   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11551   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11552   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11553
11554   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11555   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
11556   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
11557
11558   MESSAGE(".. Duplication of the nodes");
11559   for (int idomain = 0; idomain < theElems.size(); idomain++)
11560     {
11561       itface = faceDomains.begin();
11562       for (; itface != faceDomains.end(); ++itface)
11563         {
11564           std::map<int, int> domvol = itface->second;
11565           if (!domvol.count(idomain))
11566             continue;
11567           DownIdType face = itface->first;
11568           //MESSAGE(" --- face " << face.cellId);
11569           std::set<int> oldNodes;
11570           oldNodes.clear();
11571           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11572           std::set<int>::iterator itn = oldNodes.begin();
11573           for (; itn != oldNodes.end(); ++itn)
11574             {
11575               int oldId = *itn;
11576               //MESSAGE("-+-+-a node " << oldId);
11577               if (!nodeDomains.count(oldId))
11578                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11579               if (nodeDomains[oldId].empty())
11580                 {
11581                   nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11582                   //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
11583                 }
11584               std::map<int, int>::iterator itdom = domvol.begin();
11585               for (; itdom != domvol.end(); ++itdom)
11586                 {
11587                   int idom = itdom->first;
11588                   //MESSAGE("         domain " << idom);
11589                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11590                     {
11591                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11592                         {
11593                           vector<int> orderedDoms;
11594                           //MESSAGE("multiple node " << oldId);
11595                           if (mutipleNodes.count(oldId))
11596                             orderedDoms = mutipleNodes[oldId];
11597                           else
11598                             {
11599                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11600                               for (; it != nodeDomains[oldId].end(); ++it)
11601                                 orderedDoms.push_back(it->first);
11602                             }
11603                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11604                           //stringstream txt;
11605                           //for (int i=0; i<orderedDoms.size(); i++)
11606                           //  txt << orderedDoms[i] << " ";
11607                           //MESSAGE("orderedDoms " << txt.str());
11608                           mutipleNodes[oldId] = orderedDoms;
11609                         }
11610                       double *coords = grid->GetPoint(oldId);
11611                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11612                       int newId = newNode->getVtkId();
11613                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11614                       //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
11615                     }
11616                 }
11617             }
11618         }
11619     }
11620
11621   MESSAGE(".. Creation of elements");
11622   for (int idomain = 0; idomain < theElems.size(); idomain++)
11623     {
11624       itface = faceDomains.begin();
11625       for (; itface != faceDomains.end(); ++itface)
11626         {
11627           std::map<int, int> domvol = itface->second;
11628           if (!domvol.count(idomain))
11629             continue;
11630           DownIdType face = itface->first;
11631           //MESSAGE(" --- face " << face.cellId);
11632           std::set<int> oldNodes;
11633           oldNodes.clear();
11634           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11635           int nbMultipleNodes = 0;
11636           std::set<int>::iterator itn = oldNodes.begin();
11637           for (; itn != oldNodes.end(); ++itn)
11638             {
11639               int oldId = *itn;
11640               if (mutipleNodes.count(oldId))
11641                 nbMultipleNodes++;
11642             }
11643           if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
11644             {
11645               //MESSAGE("multiple Nodes detected on a shared face");
11646               int downId = itface->first.cellId;
11647               unsigned char cellType = itface->first.cellType;
11648               // --- shared edge or shared face ?
11649               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
11650                 {
11651                   int nodes[3];
11652                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
11653                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
11654                     if (mutipleNodes.count(nodes[i]))
11655                       if (!mutipleNodesToFace.count(nodes[i]))
11656                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
11657                 }
11658               else // shared face (between two volumes)
11659                 {
11660                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11661                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11662                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11663                   for (int ie =0; ie < nbEdges; ie++)
11664                     {
11665                       int nodes[3];
11666                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11667                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11668                         {
11669                           vector<int> vn0 = mutipleNodes[nodes[0]];
11670                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11671                           vector<int> doms;
11672                           for (int i0 = 0; i0 < vn0.size(); i0++)
11673                             for (int i1 = 0; i1 < vn1.size(); i1++)
11674                               if (vn0[i0] == vn1[i1])
11675                                 doms.push_back(vn0[i0]);
11676                           if (doms.size() >2)
11677                             {
11678                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11679                               double *coords = grid->GetPoint(nodes[0]);
11680                               gp_Pnt p0(coords[0], coords[1], coords[2]);
11681                               coords = grid->GetPoint(nodes[nbNodes - 1]);
11682                               gp_Pnt p1(coords[0], coords[1], coords[2]);
11683                               gp_Pnt gref;
11684                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11685                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11686                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11687                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11688                               for (int id=0; id < doms.size(); id++)
11689                                 {
11690                                   int idom = doms[id];
11691                                   for (int ivol=0; ivol<nbvol; ivol++)
11692                                     {
11693                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11694                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11695                                       if (theElems[idom].count(elem))
11696                                         {
11697                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11698                                           domvol[idom] = svol;
11699                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11700                                           double values[3];
11701                                           vtkIdType npts = 0;
11702                                           vtkIdType* pts = 0;
11703                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11704                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11705                                           if (id ==0)
11706                                             {
11707                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11708                                               angleDom[idom] = 0;
11709                                             }
11710                                           else
11711                                             {
11712                                               gp_Pnt g(values[0], values[1], values[2]);
11713                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11714                                               //MESSAGE("  angle=" << angleDom[idom]);
11715                                             }
11716                                           break;
11717                                         }
11718                                     }
11719                                 }
11720                               map<double, int> sortedDom; // sort domains by angle
11721                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11722                                 sortedDom[ia->second] = ia->first;
11723                               vector<int> vnodes;
11724                               vector<int> vdom;
11725                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11726                                 {
11727                                   vdom.push_back(ib->second);
11728                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11729                                 }
11730                               for (int ino = 0; ino < nbNodes; ino++)
11731                                 vnodes.push_back(nodes[ino]);
11732                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11733                             }
11734                         }
11735                     }
11736                 }
11737             }
11738         }
11739     }
11740
11741   // --- iterate on shared faces (volumes to modify, face to extrude)
11742   //     get node id's of the face (id SMDS = id VTK)
11743   //     create flat element with old and new nodes if requested
11744
11745   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11746   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11747
11748   std::map<int, std::map<long,int> > nodeQuadDomains;
11749   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11750
11751   MESSAGE(".. Creation of elements: simple junction");
11752   if (createJointElems)
11753     {
11754       int idg;
11755       string joints2DName = "joints2D";
11756       mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
11757       SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
11758       string joints3DName = "joints3D";
11759       mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
11760       SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
11761
11762       itface = faceDomains.begin();
11763       for (; itface != faceDomains.end(); ++itface)
11764         {
11765           DownIdType face = itface->first;
11766           std::set<int> oldNodes;
11767           std::set<int>::iterator itn;
11768           oldNodes.clear();
11769           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11770
11771           std::map<int, int> domvol = itface->second;
11772           std::map<int, int>::iterator itdom = domvol.begin();
11773           int dom1 = itdom->first;
11774           int vtkVolId = itdom->second;
11775           itdom++;
11776           int dom2 = itdom->first;
11777           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11778                                                              nodeQuadDomains);
11779           stringstream grpname;
11780           grpname << "j_";
11781           if (dom1 < dom2)
11782             grpname << dom1 << "_" << dom2;
11783           else
11784             grpname << dom2 << "_" << dom1;
11785           string namegrp = grpname.str();
11786           if (!mapOfJunctionGroups.count(namegrp))
11787             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
11788           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11789           if (sgrp)
11790             sgrp->Add(vol->GetID());
11791           if (vol->GetType() == SMDSAbs_Volume)
11792             joints3DGrp->Add(vol->GetID());
11793           else if (vol->GetType() == SMDSAbs_Face)
11794             joints2DGrp->Add(vol->GetID());
11795         }
11796     }
11797
11798   // --- create volumes on multiple domain intersection if requested
11799   //     iterate on mutipleNodesToFace
11800   //     iterate on edgesMultiDomains
11801
11802   MESSAGE(".. Creation of elements: multiple junction");
11803   if (createJointElems)
11804     {
11805       // --- iterate on mutipleNodesToFace
11806
11807       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
11808       for (; itn != mutipleNodesToFace.end(); ++itn)
11809         {
11810           int node = itn->first;
11811           vector<int> orderDom = itn->second;
11812           vector<vtkIdType> orderedNodes;
11813           for (int idom = 0; idom <orderDom.size(); idom++)
11814             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
11815             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
11816
11817             stringstream grpname;
11818             grpname << "m2j_";
11819             grpname << 0 << "_" << 0;
11820             int idg;
11821             string namegrp = grpname.str();
11822             if (!mapOfJunctionGroups.count(namegrp))
11823               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
11824             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11825             if (sgrp)
11826               sgrp->Add(face->GetID());
11827         }
11828
11829       // --- iterate on edgesMultiDomains
11830
11831       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11832       for (; ite != edgesMultiDomains.end(); ++ite)
11833         {
11834           vector<int> nodes = ite->first;
11835           vector<int> orderDom = ite->second;
11836           vector<vtkIdType> orderedNodes;
11837           if (nodes.size() == 2)
11838             {
11839               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11840               for (int ino=0; ino < nodes.size(); ino++)
11841                 if (orderDom.size() == 3)
11842                   for (int idom = 0; idom <orderDom.size(); idom++)
11843                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11844                 else
11845                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11846                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11847               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11848
11849               int idg;
11850               string namegrp = "jointsMultiples";
11851               if (!mapOfJunctionGroups.count(namegrp))
11852                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11853               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11854               if (sgrp)
11855                 sgrp->Add(vol->GetID());
11856             }
11857           else
11858             {
11859               INFOS("Quadratic multiple joints not implemented");
11860               // TODO quadratic nodes
11861             }
11862         }
11863     }
11864
11865   // --- list the explicit faces and edges of the mesh that need to be modified,
11866   //     i.e. faces and edges built with one or more duplicated nodes.
11867   //     associate these faces or edges to their corresponding domain.
11868   //     only the first domain found is kept when a face or edge is shared
11869
11870   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11871   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11872   faceOrEdgeDom.clear();
11873   feDom.clear();
11874
11875   MESSAGE(".. Modification of elements");
11876   for (int idomain = 0; idomain < theElems.size(); idomain++)
11877     {
11878       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11879       for (; itnod != nodeDomains.end(); ++itnod)
11880         {
11881           int oldId = itnod->first;
11882           //MESSAGE("     node " << oldId);
11883           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11884           for (int i = 0; i < l.ncells; i++)
11885             {
11886               int vtkId = l.cells[i];
11887               int vtkType = grid->GetCellType(vtkId);
11888               int downId = grid->CellIdToDownId(vtkId);
11889               if (downId < 0)
11890                 continue; // new cells: not to be modified
11891               DownIdType aCell(downId, vtkType);
11892               int volParents[1000];
11893               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11894               for (int j = 0; j < nbvol; j++)
11895                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11896                   if (!feDom.count(vtkId))
11897                     {
11898                       feDom[vtkId] = idomain;
11899                       faceOrEdgeDom[aCell] = emptyMap;
11900                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11901                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11902                       //        << " type " << vtkType << " downId " << downId);
11903                     }
11904             }
11905         }
11906     }
11907
11908   // --- iterate on shared faces (volumes to modify, face to extrude)
11909   //     get node id's of the face
11910   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11911
11912   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11913   for (int m=0; m<3; m++)
11914     {
11915       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11916       itface = (*amap).begin();
11917       for (; itface != (*amap).end(); ++itface)
11918         {
11919           DownIdType face = itface->first;
11920           std::set<int> oldNodes;
11921           std::set<int>::iterator itn;
11922           oldNodes.clear();
11923           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11924           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11925           std::map<int, int> localClonedNodeIds;
11926
11927           std::map<int, int> domvol = itface->second;
11928           std::map<int, int>::iterator itdom = domvol.begin();
11929           for (; itdom != domvol.end(); ++itdom)
11930             {
11931               int idom = itdom->first;
11932               int vtkVolId = itdom->second;
11933               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11934               localClonedNodeIds.clear();
11935               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11936                 {
11937                   int oldId = *itn;
11938                   if (nodeDomains[oldId].count(idom))
11939                     {
11940                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11941                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11942                     }
11943                 }
11944               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11945             }
11946         }
11947     }
11948
11949   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11950   grid->BuildLinks();
11951
11952   CHRONOSTOP(50);
11953   counters::stats();
11954   return true;
11955 }
11956
11957 /*!
11958  * \brief Double nodes on some external faces and create flat elements.
11959  * Flat elements are mainly used by some types of mechanic calculations.
11960  *
11961  * Each group of the list must be constituted of faces.
11962  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11963  * @param theElems - list of groups of faces, where a group of faces is a set of
11964  * SMDS_MeshElements sorted by Id.
11965  * @return TRUE if operation has been completed successfully, FALSE otherwise
11966  */
11967 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11968 {
11969   MESSAGE("-------------------------------------------------");
11970   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11971   MESSAGE("-------------------------------------------------");
11972
11973   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11974
11975   // --- For each group of faces
11976   //     duplicate the nodes, create a flat element based on the face
11977   //     replace the nodes of the faces by their clones
11978
11979   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11980   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11981   clonedNodes.clear();
11982   intermediateNodes.clear();
11983   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11984   mapOfJunctionGroups.clear();
11985
11986   for (int idom = 0; idom < theElems.size(); idom++)
11987     {
11988       const TIDSortedElemSet& domain = theElems[idom];
11989       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11990       for (; elemItr != domain.end(); ++elemItr)
11991         {
11992           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11993           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11994           if (!aFace)
11995             continue;
11996           // MESSAGE("aFace=" << aFace->GetID());
11997           bool isQuad = aFace->IsQuadratic();
11998           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11999
12000           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
12001
12002           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
12003           while (nodeIt->more())
12004             {
12005               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
12006               bool isMedium = isQuad && (aFace->IsMediumNode(node));
12007               if (isMedium)
12008                 ln2.push_back(node);
12009               else
12010                 ln0.push_back(node);
12011
12012               const SMDS_MeshNode* clone = 0;
12013               if (!clonedNodes.count(node))
12014                 {
12015                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
12016                   clonedNodes[node] = clone;
12017                 }
12018               else
12019                 clone = clonedNodes[node];
12020
12021               if (isMedium)
12022                 ln3.push_back(clone);
12023               else
12024                 ln1.push_back(clone);
12025
12026               const SMDS_MeshNode* inter = 0;
12027               if (isQuad && (!isMedium))
12028                 {
12029                   if (!intermediateNodes.count(node))
12030                     {
12031                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
12032                       intermediateNodes[node] = inter;
12033                     }
12034                   else
12035                     inter = intermediateNodes[node];
12036                   ln4.push_back(inter);
12037                 }
12038             }
12039
12040           // --- extrude the face
12041
12042           vector<const SMDS_MeshNode*> ln;
12043           SMDS_MeshVolume* vol = 0;
12044           vtkIdType aType = aFace->GetVtkType();
12045           switch (aType)
12046           {
12047             case VTK_TRIANGLE:
12048               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
12049               // MESSAGE("vol prism " << vol->GetID());
12050               ln.push_back(ln1[0]);
12051               ln.push_back(ln1[1]);
12052               ln.push_back(ln1[2]);
12053               break;
12054             case VTK_QUAD:
12055               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
12056               // MESSAGE("vol hexa " << vol->GetID());
12057               ln.push_back(ln1[0]);
12058               ln.push_back(ln1[1]);
12059               ln.push_back(ln1[2]);
12060               ln.push_back(ln1[3]);
12061               break;
12062             case VTK_QUADRATIC_TRIANGLE:
12063               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
12064                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
12065               // MESSAGE("vol quad prism " << vol->GetID());
12066               ln.push_back(ln1[0]);
12067               ln.push_back(ln1[1]);
12068               ln.push_back(ln1[2]);
12069               ln.push_back(ln3[0]);
12070               ln.push_back(ln3[1]);
12071               ln.push_back(ln3[2]);
12072               break;
12073             case VTK_QUADRATIC_QUAD:
12074 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
12075 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
12076 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
12077               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
12078                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
12079                                       ln4[0], ln4[1], ln4[2], ln4[3]);
12080               // MESSAGE("vol quad hexa " << vol->GetID());
12081               ln.push_back(ln1[0]);
12082               ln.push_back(ln1[1]);
12083               ln.push_back(ln1[2]);
12084               ln.push_back(ln1[3]);
12085               ln.push_back(ln3[0]);
12086               ln.push_back(ln3[1]);
12087               ln.push_back(ln3[2]);
12088               ln.push_back(ln3[3]);
12089               break;
12090             case VTK_POLYGON:
12091               break;
12092             default:
12093               break;
12094           }
12095
12096           if (vol)
12097             {
12098               stringstream grpname;
12099               grpname << "jf_";
12100               grpname << idom;
12101               int idg;
12102               string namegrp = grpname.str();
12103               if (!mapOfJunctionGroups.count(namegrp))
12104                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
12105               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
12106               if (sgrp)
12107                 sgrp->Add(vol->GetID());
12108             }
12109
12110           // --- modify the face
12111
12112           aFace->ChangeNodes(&ln[0], ln.size());
12113         }
12114     }
12115   return true;
12116 }
12117
12118 /*!
12119  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
12120  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
12121  *  groups of faces to remove inside the object, (idem edges).
12122  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
12123  */
12124 void SMESH_MeshEditor::CreateHoleSkin(double radius,
12125                                       const TopoDS_Shape& theShape,
12126                                       SMESH_NodeSearcher* theNodeSearcher,
12127                                       const char* groupName,
12128                                       std::vector<double>&   nodesCoords,
12129                                       std::vector<std::vector<int> >& listOfListOfNodes)
12130 {
12131   MESSAGE("--------------------------------");
12132   MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
12133   MESSAGE("--------------------------------");
12134
12135   // --- zone of volumes to remove is given :
12136   //     1 either by a geom shape (one or more vertices) and a radius,
12137   //     2 either by a group of nodes (representative of the shape)to use with the radius,
12138   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
12139   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
12140   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
12141   //     defined by it's name.
12142
12143   SMESHDS_GroupBase* groupDS = 0;
12144   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
12145   while ( groupIt->more() )
12146     {
12147       groupDS = 0;
12148       SMESH_Group * group = groupIt->next();
12149       if ( !group ) continue;
12150       groupDS = group->GetGroupDS();
12151       if ( !groupDS || groupDS->IsEmpty() ) continue;
12152       std::string grpName = group->GetName();
12153       //MESSAGE("grpName=" << grpName);
12154       if (grpName == groupName)
12155         break;
12156       else
12157         groupDS = 0;
12158     }
12159
12160   bool isNodeGroup = false;
12161   bool isNodeCoords = false;
12162   if (groupDS)
12163     {
12164       if (groupDS->GetType() != SMDSAbs_Node)
12165         return;
12166       isNodeGroup = true;     // a group of nodes exists and it is in this mesh
12167     }
12168
12169   if (nodesCoords.size() > 0)
12170     isNodeCoords = true; // a list o nodes given by their coordinates
12171   //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
12172
12173   // --- define groups to build
12174
12175   int idg; // --- group of SMDS volumes
12176   string grpvName = groupName;
12177   grpvName += "_vol";
12178   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
12179   if (!grp)
12180     {
12181       MESSAGE("group not created " << grpvName);
12182       return;
12183     }
12184   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
12185
12186   int idgs; // --- group of SMDS faces on the skin
12187   string grpsName = groupName;
12188   grpsName += "_skin";
12189   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
12190   if (!grps)
12191     {
12192       MESSAGE("group not created " << grpsName);
12193       return;
12194     }
12195   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
12196
12197   int idgi; // --- group of SMDS faces internal (several shapes)
12198   string grpiName = groupName;
12199   grpiName += "_internalFaces";
12200   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
12201   if (!grpi)
12202     {
12203       MESSAGE("group not created " << grpiName);
12204       return;
12205     }
12206   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
12207
12208   int idgei; // --- group of SMDS faces internal (several shapes)
12209   string grpeiName = groupName;
12210   grpeiName += "_internalEdges";
12211   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
12212   if (!grpei)
12213     {
12214       MESSAGE("group not created " << grpeiName);
12215       return;
12216     }
12217   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
12218
12219   // --- build downward connectivity
12220
12221   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
12222   meshDS->BuildDownWardConnectivity(true);
12223   SMDS_UnstructuredGrid* grid = meshDS->getGrid();
12224
12225   // --- set of volumes detected inside
12226
12227   std::set<int> setOfInsideVol;
12228   std::set<int> setOfVolToCheck;
12229
12230   std::vector<gp_Pnt> gpnts;
12231   gpnts.clear();
12232
12233   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
12234     {
12235       MESSAGE("group of nodes provided");
12236       SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
12237       while ( elemIt->more() )
12238         {
12239           const SMDS_MeshElement* elem = elemIt->next();
12240           if (!elem)
12241             continue;
12242           const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
12243           if (!node)
12244             continue;
12245           SMDS_MeshElement* vol = 0;
12246           SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
12247           while (volItr->more())
12248             {
12249               vol = (SMDS_MeshElement*)volItr->next();
12250               setOfInsideVol.insert(vol->getVtkId());
12251               sgrp->Add(vol->GetID());
12252             }
12253         }
12254     }
12255   else if (isNodeCoords)
12256     {
12257       MESSAGE("list of nodes coordinates provided");
12258       int i = 0;
12259       int k = 0;
12260       while (i < nodesCoords.size()-2)
12261         {
12262           double x = nodesCoords[i++];
12263           double y = nodesCoords[i++];
12264           double z = nodesCoords[i++];
12265           gp_Pnt p = gp_Pnt(x, y ,z);
12266           gpnts.push_back(p);
12267           MESSAGE("TopoDS_Vertex " << k++ << " " << p.X() << " " << p.Y() << " " << p.Z());
12268         }
12269     }
12270   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
12271     {
12272       MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
12273       TopTools_IndexedMapOfShape vertexMap;
12274       TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
12275       gp_Pnt p = gp_Pnt(0,0,0);
12276       if (vertexMap.Extent() < 1)
12277         return;
12278
12279       for ( int i = 1; i <= vertexMap.Extent(); ++i )
12280         {
12281           const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
12282           p = BRep_Tool::Pnt(vertex);
12283           gpnts.push_back(p);
12284           MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
12285         }
12286     }
12287
12288   if (gpnts.size() > 0)
12289     {
12290       int nodeId = 0;
12291       const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
12292       if (startNode)
12293         nodeId = startNode->GetID();
12294       MESSAGE("nodeId " << nodeId);
12295
12296       double radius2 = radius*radius;
12297       MESSAGE("radius2 " << radius2);
12298
12299       // --- volumes on start node
12300
12301       setOfVolToCheck.clear();
12302       SMDS_MeshElement* startVol = 0;
12303       SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
12304       while (volItr->more())
12305         {
12306           startVol = (SMDS_MeshElement*)volItr->next();
12307           setOfVolToCheck.insert(startVol->getVtkId());
12308         }
12309       if (setOfVolToCheck.empty())
12310         {
12311           MESSAGE("No volumes found");
12312           return;
12313         }
12314
12315       // --- starting with central volumes then their neighbors, check if they are inside
12316       //     or outside the domain, until no more new neighbor volume is inside.
12317       //     Fill the group of inside volumes
12318
12319       std::map<int, double> mapOfNodeDistance2;
12320       mapOfNodeDistance2.clear();
12321       std::set<int> setOfOutsideVol;
12322       while (!setOfVolToCheck.empty())
12323         {
12324           std::set<int>::iterator it = setOfVolToCheck.begin();
12325           int vtkId = *it;
12326           MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12327           bool volInside = false;
12328           vtkIdType npts = 0;
12329           vtkIdType* pts = 0;
12330           grid->GetCellPoints(vtkId, npts, pts);
12331           for (int i=0; i<npts; i++)
12332             {
12333               double distance2 = 0;
12334               if (mapOfNodeDistance2.count(pts[i]))
12335                 {
12336                   distance2 = mapOfNodeDistance2[pts[i]];
12337                   MESSAGE("point " << pts[i] << " distance2 " << distance2);
12338                 }
12339               else
12340                 {
12341                   double *coords = grid->GetPoint(pts[i]);
12342                   gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
12343                   distance2 = 1.E40;
12344                   for (int j=0; j<gpnts.size(); j++)
12345                     {
12346                       double d2 = aPoint.SquareDistance(gpnts[j]);
12347                       if (d2 < distance2)
12348                         {
12349                           distance2 = d2;
12350                           if (distance2 < radius2)
12351                             break;
12352                         }
12353                     }
12354                   mapOfNodeDistance2[pts[i]] = distance2;
12355                   MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
12356                 }
12357               if (distance2 < radius2)
12358                 {
12359                   volInside = true; // one or more nodes inside the domain
12360                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
12361                   break;
12362                 }
12363             }
12364           if (volInside)
12365             {
12366               setOfInsideVol.insert(vtkId);
12367               MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12368               int neighborsVtkIds[NBMAXNEIGHBORS];
12369               int downIds[NBMAXNEIGHBORS];
12370               unsigned char downTypes[NBMAXNEIGHBORS];
12371               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12372               for (int n = 0; n < nbNeighbors; n++)
12373                 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
12374                   setOfVolToCheck.insert(neighborsVtkIds[n]);
12375             }
12376           else
12377             {
12378               setOfOutsideVol.insert(vtkId);
12379               MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12380             }
12381           setOfVolToCheck.erase(vtkId);
12382         }
12383     }
12384
12385   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
12386   //     If yes, add the volume to the inside set
12387
12388   bool addedInside = true;
12389   std::set<int> setOfVolToReCheck;
12390   while (addedInside)
12391     {
12392       MESSAGE(" --------------------------- re check");
12393       addedInside = false;
12394       std::set<int>::iterator itv = setOfInsideVol.begin();
12395       for (; itv != setOfInsideVol.end(); ++itv)
12396         {
12397           int vtkId = *itv;
12398           int neighborsVtkIds[NBMAXNEIGHBORS];
12399           int downIds[NBMAXNEIGHBORS];
12400           unsigned char downTypes[NBMAXNEIGHBORS];
12401           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12402           for (int n = 0; n < nbNeighbors; n++)
12403             if (!setOfInsideVol.count(neighborsVtkIds[n]))
12404               setOfVolToReCheck.insert(neighborsVtkIds[n]);
12405         }
12406       setOfVolToCheck = setOfVolToReCheck;
12407       setOfVolToReCheck.clear();
12408       while  (!setOfVolToCheck.empty())
12409         {
12410           std::set<int>::iterator it = setOfVolToCheck.begin();
12411           int vtkId = *it;
12412           if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
12413             {
12414               MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12415               int countInside = 0;
12416               int neighborsVtkIds[NBMAXNEIGHBORS];
12417               int downIds[NBMAXNEIGHBORS];
12418               unsigned char downTypes[NBMAXNEIGHBORS];
12419               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12420               for (int n = 0; n < nbNeighbors; n++)
12421                 if (setOfInsideVol.count(neighborsVtkIds[n]))
12422                   countInside++;
12423               MESSAGE("countInside " << countInside);
12424               if (countInside > 1)
12425                 {
12426                   MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12427                   setOfInsideVol.insert(vtkId);
12428                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
12429                   addedInside = true;
12430                 }
12431               else
12432                 setOfVolToReCheck.insert(vtkId);
12433             }
12434           setOfVolToCheck.erase(vtkId);
12435         }
12436     }
12437
12438   // --- map of Downward faces at the boundary, inside the global volume
12439   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
12440   //     fill group of SMDS faces inside the volume (when several volume shapes)
12441   //     fill group of SMDS faces on the skin of the global volume (if skin)
12442
12443   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
12444   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
12445   std::set<int>::iterator it = setOfInsideVol.begin();
12446   for (; it != setOfInsideVol.end(); ++it)
12447     {
12448       int vtkId = *it;
12449       //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12450       int neighborsVtkIds[NBMAXNEIGHBORS];
12451       int downIds[NBMAXNEIGHBORS];
12452       unsigned char downTypes[NBMAXNEIGHBORS];
12453       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
12454       for (int n = 0; n < nbNeighbors; n++)
12455         {
12456           int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
12457           if (neighborDim == 3)
12458             {
12459               if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
12460                 {
12461                   DownIdType face(downIds[n], downTypes[n]);
12462                   boundaryFaces[face] = vtkId;
12463                 }
12464               // if the face between to volumes is in the mesh, get it (internal face between shapes)
12465               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12466               if (vtkFaceId >= 0)
12467                 {
12468                   sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
12469                   // find also the smds edges on this face
12470                   int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
12471                   const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
12472                   const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
12473                   for (int i = 0; i < nbEdges; i++)
12474                     {
12475                       int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
12476                       if (vtkEdgeId >= 0)
12477                         sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
12478                     }
12479                 }
12480             }
12481           else if (neighborDim == 2) // skin of the volume
12482             {
12483               DownIdType face(downIds[n], downTypes[n]);
12484               skinFaces[face] = vtkId;
12485               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12486               if (vtkFaceId >= 0)
12487                 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
12488             }
12489         }
12490     }
12491
12492   // --- identify the edges constituting the wire of each subshape on the skin
12493   //     define polylines with the nodes of edges, equivalent to wires
12494   //     project polylines on subshapes, and partition, to get geom faces
12495
12496   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
12497   std::set<int> emptySet;
12498   emptySet.clear();
12499   std::set<int> shapeIds;
12500
12501   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
12502   while (itelem->more())
12503     {
12504       const SMDS_MeshElement *elem = itelem->next();
12505       int shapeId = elem->getshapeId();
12506       int vtkId = elem->getVtkId();
12507       if (!shapeIdToVtkIdSet.count(shapeId))
12508         {
12509           shapeIdToVtkIdSet[shapeId] = emptySet;
12510           shapeIds.insert(shapeId);
12511         }
12512       shapeIdToVtkIdSet[shapeId].insert(vtkId);
12513     }
12514
12515   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
12516   std::set<DownIdType, DownIdCompare> emptyEdges;
12517   emptyEdges.clear();
12518
12519   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
12520   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
12521     {
12522       int shapeId = itShape->first;
12523       MESSAGE(" --- Shape ID --- "<< shapeId);
12524       shapeIdToEdges[shapeId] = emptyEdges;
12525
12526       std::vector<int> nodesEdges;
12527
12528       std::set<int>::iterator its = itShape->second.begin();
12529       for (; its != itShape->second.end(); ++its)
12530         {
12531           int vtkId = *its;
12532           MESSAGE("     " << vtkId);
12533           int neighborsVtkIds[NBMAXNEIGHBORS];
12534           int downIds[NBMAXNEIGHBORS];
12535           unsigned char downTypes[NBMAXNEIGHBORS];
12536           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12537           for (int n = 0; n < nbNeighbors; n++)
12538             {
12539               if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
12540                 continue;
12541               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
12542               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
12543               if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
12544                 {
12545                   DownIdType edge(downIds[n], downTypes[n]);
12546                   if (!shapeIdToEdges[shapeId].count(edge))
12547                     {
12548                       shapeIdToEdges[shapeId].insert(edge);
12549                       int vtkNodeId[3];
12550                       int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
12551                       nodesEdges.push_back(vtkNodeId[0]);
12552                       nodesEdges.push_back(vtkNodeId[nbNodes-1]);
12553                       MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
12554                     }
12555                 }
12556             }
12557         }
12558
12559       std::list<int> order;
12560       order.clear();
12561       if (nodesEdges.size() > 0)
12562         {
12563           order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
12564           nodesEdges[0] = -1;
12565           order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
12566           nodesEdges[1] = -1; // do not reuse this edge
12567           bool found = true;
12568           while (found)
12569             {
12570               int nodeTofind = order.back(); // try first to push back
12571               int i = 0;
12572               for (i = 0; i<nodesEdges.size(); i++)
12573                 if (nodesEdges[i] == nodeTofind)
12574                   break;
12575               if (i == nodesEdges.size())
12576                 found = false; // no follower found on back
12577               else
12578                 {
12579                   if (i%2) // odd ==> use the previous one
12580                     if (nodesEdges[i-1] < 0)
12581                       found = false;
12582                     else
12583                       {
12584                         order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
12585                         nodesEdges[i-1] = -1;
12586                       }
12587                   else // even ==> use the next one
12588                     if (nodesEdges[i+1] < 0)
12589                       found = false;
12590                     else
12591                       {
12592                         order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
12593                         nodesEdges[i+1] = -1;
12594                       }
12595                 }
12596               if (found)
12597                 continue;
12598               // try to push front
12599               found = true;
12600               nodeTofind = order.front(); // try to push front
12601               for (i = 0; i<nodesEdges.size(); i++)
12602                 if (nodesEdges[i] == nodeTofind)
12603                   break;
12604               if (i == nodesEdges.size())
12605                 {
12606                   found = false; // no predecessor found on front
12607                   continue;
12608                 }
12609               if (i%2) // odd ==> use the previous one
12610                 if (nodesEdges[i-1] < 0)
12611                   found = false;
12612                 else
12613                   {
12614                     order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
12615                     nodesEdges[i-1] = -1;
12616                   }
12617               else // even ==> use the next one
12618                 if (nodesEdges[i+1] < 0)
12619                   found = false;
12620                 else
12621                   {
12622                     order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
12623                     nodesEdges[i+1] = -1;
12624                   }
12625             }
12626         }
12627
12628
12629       std::vector<int> nodes;
12630       nodes.push_back(shapeId);
12631       std::list<int>::iterator itl = order.begin();
12632       for (; itl != order.end(); itl++)
12633         {
12634           nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
12635           MESSAGE("              ordered node " << nodes[nodes.size()-1]);
12636         }
12637       listOfListOfNodes.push_back(nodes);
12638     }
12639
12640   //     partition geom faces with blocFissure
12641   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
12642   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
12643
12644   return;
12645 }
12646
12647
12648 //================================================================================
12649 /*!
12650  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
12651  * The created 2D mesh elements based on nodes of free faces of boundary volumes
12652  * \return TRUE if operation has been completed successfully, FALSE otherwise
12653  */
12654 //================================================================================
12655
12656 bool SMESH_MeshEditor::Make2DMeshFrom3D()
12657 {
12658   // iterates on volume elements and detect all free faces on them
12659   SMESHDS_Mesh* aMesh = GetMeshDS();
12660   if (!aMesh)
12661     return false;
12662   //bool res = false;
12663   int nbFree = 0, nbExisted = 0, nbCreated = 0;
12664   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
12665   while(vIt->more())
12666   {
12667     const SMDS_MeshVolume* volume = vIt->next();
12668     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
12669     vTool.SetExternalNormal();
12670     //const bool isPoly = volume->IsPoly();
12671     const int iQuad = volume->IsQuadratic();
12672     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12673     {
12674       if (!vTool.IsFreeFace(iface))
12675         continue;
12676       nbFree++;
12677       vector<const SMDS_MeshNode *> nodes;
12678       int nbFaceNodes = vTool.NbFaceNodes(iface);
12679       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
12680       int inode = 0;
12681       for ( ; inode < nbFaceNodes; inode += iQuad+1)
12682         nodes.push_back(faceNodes[inode]);
12683       if (iQuad) { // add medium nodes
12684         for ( inode = 1; inode < nbFaceNodes; inode += 2)
12685           nodes.push_back(faceNodes[inode]);
12686         if ( nbFaceNodes == 9 ) // bi-quadratic quad
12687           nodes.push_back(faceNodes[8]);
12688       }
12689       // add new face based on volume nodes
12690       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
12691         nbExisted++;
12692         continue; // face already exsist
12693       }
12694       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
12695       nbCreated++;
12696     }
12697   }
12698   return ( nbFree==(nbExisted+nbCreated) );
12699 }
12700
12701 namespace
12702 {
12703   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
12704   {
12705     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
12706       return n;
12707     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
12708   }
12709 }
12710 //================================================================================
12711 /*!
12712  * \brief Creates missing boundary elements
12713  *  \param elements - elements whose boundary is to be checked
12714  *  \param dimension - defines type of boundary elements to create
12715  *  \param group - a group to store created boundary elements in
12716  *  \param targetMesh - a mesh to store created boundary elements in
12717  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
12718  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
12719  *                                boundary elements will be copied into the targetMesh
12720  *  \param toAddExistingBondary - if true, not only new but also pre-existing
12721  *                                boundary elements will be added into the new group
12722  *  \param aroundElements - if true, elements will be created on boundary of given
12723  *                          elements else, on boundary of the whole mesh.
12724  * \return nb of added boundary elements
12725  */
12726 //================================================================================
12727
12728 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
12729                                        Bnd_Dimension           dimension,
12730                                        SMESH_Group*            group/*=0*/,
12731                                        SMESH_Mesh*             targetMesh/*=0*/,
12732                                        bool                    toCopyElements/*=false*/,
12733                                        bool                    toCopyExistingBoundary/*=false*/,
12734                                        bool                    toAddExistingBondary/*= false*/,
12735                                        bool                    aroundElements/*= false*/)
12736 {
12737   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
12738   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
12739   // hope that all elements are of the same type, do not check them all
12740   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
12741     throw SALOME_Exception(LOCALIZED("wrong element type"));
12742
12743   if ( !targetMesh )
12744     toCopyElements = toCopyExistingBoundary = false;
12745
12746   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
12747   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
12748   int nbAddedBnd = 0;
12749
12750   // editor adding present bnd elements and optionally holding elements to add to the group
12751   SMESH_MeshEditor* presentEditor;
12752   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
12753   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
12754
12755   SMESH_MesherHelper helper( *myMesh );
12756   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
12757   SMDS_VolumeTool vTool;
12758   TIDSortedElemSet avoidSet;
12759   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
12760   int inode;
12761
12762   typedef vector<const SMDS_MeshNode*> TConnectivity;
12763
12764   SMDS_ElemIteratorPtr eIt;
12765   if (elements.empty())
12766     eIt = aMesh->elementsIterator(elemType);
12767   else
12768     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
12769
12770   while (eIt->more())
12771   {
12772     const SMDS_MeshElement* elem = eIt->next();
12773     const int iQuad = elem->IsQuadratic();
12774
12775     // ------------------------------------------------------------------------------------
12776     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
12777     // ------------------------------------------------------------------------------------
12778     vector<const SMDS_MeshElement*> presentBndElems;
12779     vector<TConnectivity>           missingBndElems;
12780     TConnectivity nodes;
12781     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
12782     {
12783       vTool.SetExternalNormal();
12784       const SMDS_MeshElement* otherVol = 0;
12785       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12786       {
12787         if ( !vTool.IsFreeFace(iface, &otherVol) &&
12788              ( !aroundElements || elements.count( otherVol )))
12789           continue;
12790         const int nbFaceNodes = vTool.NbFaceNodes(iface);
12791         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
12792         if ( missType == SMDSAbs_Edge ) // boundary edges
12793         {
12794           nodes.resize( 2+iQuad );
12795           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
12796           {
12797             for ( int j = 0; j < nodes.size(); ++j )
12798               nodes[j] =nn[i+j];
12799             if ( const SMDS_MeshElement* edge =
12800                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
12801               presentBndElems.push_back( edge );
12802             else
12803               missingBndElems.push_back( nodes );
12804           }
12805         }
12806         else // boundary face
12807         {
12808           nodes.clear();
12809           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12810             nodes.push_back( nn[inode] );
12811           if (iQuad) // add medium nodes
12812             for ( inode = 1; inode < nbFaceNodes; inode += 2)
12813               nodes.push_back( nn[inode] );
12814           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
12815           if ( iCenter > 0 )
12816             nodes.push_back( vTool.GetNodes()[ iCenter ] );
12817
12818           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
12819                                                                SMDSAbs_Face, /*noMedium=*/false ))
12820             presentBndElems.push_back( f );
12821           else
12822             missingBndElems.push_back( nodes );
12823
12824           if ( targetMesh != myMesh )
12825           {
12826             // add 1D elements on face boundary to be added to a new mesh
12827             const SMDS_MeshElement* edge;
12828             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12829             {
12830               if ( iQuad )
12831                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
12832               else
12833                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
12834               if ( edge && avoidSet.insert( edge ).second )
12835                 presentBndElems.push_back( edge );
12836             }
12837           }
12838         }
12839       }
12840     }
12841     else                     // elem is a face ------------------------------------------
12842     {
12843       avoidSet.clear(), avoidSet.insert( elem );
12844       int nbNodes = elem->NbCornerNodes();
12845       nodes.resize( 2 /*+ iQuad*/);
12846       for ( int i = 0; i < nbNodes; i++ )
12847       {
12848         nodes[0] = elem->GetNode(i);
12849         nodes[1] = elem->GetNode((i+1)%nbNodes);
12850         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
12851           continue; // not free link
12852
12853         //if ( iQuad )
12854         //nodes[2] = elem->GetNode( i + nbNodes );
12855         if ( const SMDS_MeshElement* edge =
12856              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
12857           presentBndElems.push_back( edge );
12858         else
12859           missingBndElems.push_back( nodes );
12860       }
12861     }
12862
12863     // ---------------------------------
12864     // 2. Add missing boundary elements
12865     // ---------------------------------
12866     if ( targetMesh != myMesh )
12867       // instead of making a map of nodes in this mesh and targetMesh,
12868       // we create nodes with same IDs.
12869       for ( int i = 0; i < missingBndElems.size(); ++i )
12870       {
12871         TConnectivity& srcNodes = missingBndElems[i];
12872         TConnectivity  nodes( srcNodes.size() );
12873         for ( inode = 0; inode < nodes.size(); ++inode )
12874           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
12875         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
12876                                                                    missType,
12877                                                                    /*noMedium=*/false))
12878           continue;
12879         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
12880         ++nbAddedBnd;
12881       }
12882     else
12883       for ( int i = 0; i < missingBndElems.size(); ++i )
12884       {
12885         TConnectivity& nodes = missingBndElems[i];
12886         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
12887                                                                    missType,
12888                                                                    /*noMedium=*/false))
12889           continue;
12890         SMDS_MeshElement* elem =
12891           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
12892         ++nbAddedBnd;
12893
12894         // try to set a new element to a shape
12895         if ( myMesh->HasShapeToMesh() )
12896         {
12897           bool ok = true;
12898           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
12899           const int nbN = nodes.size() / (iQuad+1 );
12900           for ( inode = 0; inode < nbN && ok; ++inode )
12901           {
12902             pair<int, TopAbs_ShapeEnum> i_stype =
12903               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
12904             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
12905               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
12906           }
12907           if ( ok && mediumShapes.size() > 1 )
12908           {
12909             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
12910             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
12911             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
12912             {
12913               if (( ok = ( stype_i->first != stype_i_0.first )))
12914                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
12915                                         aMesh->IndexToShape( stype_i_0.second ));
12916             }
12917           }
12918           if ( ok && mediumShapes.begin()->first == missShapeType )
12919             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
12920         }
12921       }
12922
12923     // ----------------------------------
12924     // 3. Copy present boundary elements
12925     // ----------------------------------
12926     if ( toCopyExistingBoundary )
12927       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12928       {
12929         const SMDS_MeshElement* e = presentBndElems[i];
12930         TConnectivity nodes( e->NbNodes() );
12931         for ( inode = 0; inode < nodes.size(); ++inode )
12932           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
12933         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
12934       }
12935     else // store present elements to add them to a group
12936       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12937       {
12938         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
12939       }
12940
12941   } // loop on given elements
12942
12943   // ---------------------------------------------
12944   // 4. Fill group with boundary elements
12945   // ---------------------------------------------
12946   if ( group )
12947   {
12948     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
12949       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
12950         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
12951   }
12952   tgtEditor.myLastCreatedElems.Clear();
12953   tgtEditor2.myLastCreatedElems.Clear();
12954
12955   // -----------------------
12956   // 5. Copy given elements
12957   // -----------------------
12958   if ( toCopyElements && targetMesh != myMesh )
12959   {
12960     if (elements.empty())
12961       eIt = aMesh->elementsIterator(elemType);
12962     else
12963       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
12964     while (eIt->more())
12965     {
12966       const SMDS_MeshElement* elem = eIt->next();
12967       TConnectivity nodes( elem->NbNodes() );
12968       for ( inode = 0; inode < nodes.size(); ++inode )
12969         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
12970       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
12971
12972       tgtEditor.myLastCreatedElems.Clear();
12973     }
12974   }
12975   return nbAddedBnd;
12976 }