Salome HOME
NPAL16631: EDF281: Crash on update mesh if computation failed because of memory lack.
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
2 //
3 //  Copyright (C) 2003  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 //
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27
28
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 #include "SMDS_QuadraticFaceOfNodes.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_subMesh.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_MesherHelper.hxx"
45 #include "SMESH_OctreeNode.hxx"
46
47 #include "utilities.h"
48
49 #include <TopTools_ListIteratorOfListOfShape.hxx>
50 #include <TopTools_ListOfShape.hxx>
51 #include <math.h>
52 #include <gp_Dir.hxx>
53 #include <gp_Vec.hxx>
54 #include <gp_Ax1.hxx>
55 #include <gp_Trsf.hxx>
56 #include <gp_Lin.hxx>
57 #include <gp_XYZ.hxx>
58 #include <gp_XY.hxx>
59 #include <gp.hxx>
60 #include <gp_Pln.hxx>
61 #include <BRep_Tool.hxx>
62 #include <Geom_Curve.hxx>
63 #include <Geom_Surface.hxx>
64 #include <Geom2d_Curve.hxx>
65 #include <Extrema_GenExtPS.hxx>
66 #include <Extrema_POnSurf.hxx>
67 #include <GeomAdaptor_Surface.hxx>
68 #include <ElCLib.hxx>
69 #include <TColStd_ListOfInteger.hxx>
70 #include <TopoDS_Face.hxx>
71
72 #include <map>
73 #include <set>
74
75 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
76
77 using namespace std;
78 using namespace SMESH::Controls;
79
80 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
81 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
82 typedef map<const SMDS_MeshNode*, list<const SMDS_MeshNode*> >       TNodeOfNodeListMap;
83 typedef TNodeOfNodeListMap::iterator                                 TNodeOfNodeListMapItr;
84 //typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> >     TNodeOfNodeVecMap;
85 //typedef TNodeOfNodeVecMap::iterator                                  TNodeOfNodeVecMapItr;
86 typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeListMapItr> > TElemOfVecOfNnlmiMap;
87 //typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeVecMapItr> >  TElemOfVecOfMapNodesMap;
88
89 struct TNodeXYZ : public gp_XYZ {
90   TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {}
91 };
92
93 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
94
95 /*!
96  * \brief A sorted pair of nodes
97  */
98 struct TLink: public NLink
99 {
100   TLink(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 ):NLink( n1, n2 )
101   { if ( n1->GetID() < n2->GetID() ) std::swap( first, second ); }
102   TLink(const NLink& link ):NLink( link )
103   { if ( first->GetID() < second->GetID() ) std::swap( first, second ); }
104 };
105
106 //=======================================================================
107 //function : SMESH_MeshEditor
108 //purpose  :
109 //=======================================================================
110
111 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh ):
112 myMesh( theMesh )
113 {
114 }
115
116 //=======================================================================
117 /*!
118  * \brief Add element
119  */
120 //=======================================================================
121
122 SMDS_MeshElement*
123 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
124                              const SMDSAbs_ElementType            type,
125                              const bool                           isPoly,
126                              const int                            ID)
127 {
128   SMDS_MeshElement* e = 0;
129   int nbnode = node.size();
130   SMESHDS_Mesh* mesh = GetMeshDS();
131   switch ( type ) {
132   case SMDSAbs_Edge:
133     if ( nbnode == 2 )
134       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
135       else      e = mesh->AddEdge      (node[0], node[1] );
136     else if ( nbnode == 3 )
137       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
138       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
139     break;
140   case SMDSAbs_Face:
141     if ( !isPoly ) {
142       if      (nbnode == 3)
143         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
144         else      e = mesh->AddFace      (node[0], node[1], node[2] );
145       else if (nbnode == 4) 
146         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
147         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
148       else if (nbnode == 6)
149         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
150                                           node[4], node[5], ID);
151         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
152                                           node[4], node[5] );
153       else if (nbnode == 8)
154         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                           node[4], node[5], node[6], node[7], ID);
156         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                           node[4], node[5], node[6], node[7] );
158     } else {
159       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
160       else      e = mesh->AddPolygonalFace      (node    );
161     }
162     break;
163   case SMDSAbs_Volume:
164     if ( !isPoly ) {
165       if      (nbnode == 4)
166         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
168       else if (nbnode == 5)
169         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
170                                             node[4], ID);
171         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
172                                             node[4] );
173       else if (nbnode == 6)
174         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175                                             node[4], node[5], ID);
176         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
177                                             node[4], node[5] );
178       else if (nbnode == 8)
179         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180                                             node[4], node[5], node[6], node[7], ID);
181         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
182                                             node[4], node[5], node[6], node[7] );
183       else if (nbnode == 10)
184         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                             node[4], node[5], node[6], node[7],
186                                             node[8], node[9], ID);
187         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
188                                             node[4], node[5], node[6], node[7],
189                                             node[8], node[9] );
190       else if (nbnode == 13)
191         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192                                             node[4], node[5], node[6], node[7],
193                                             node[8], node[9], node[10],node[11],
194                                             node[12],ID);
195         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
196                                             node[4], node[5], node[6], node[7],
197                                             node[8], node[9], node[10],node[11],
198                                             node[12] );
199       else if (nbnode == 15)
200         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201                                             node[4], node[5], node[6], node[7],
202                                             node[8], node[9], node[10],node[11],
203                                             node[12],node[13],node[14],ID);
204         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
205                                             node[4], node[5], node[6], node[7],
206                                             node[8], node[9], node[10],node[11],
207                                             node[12],node[13],node[14] );
208       else if (nbnode == 20)
209         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
210                                             node[4], node[5], node[6], node[7],
211                                             node[8], node[9], node[10],node[11],
212                                             node[12],node[13],node[14],node[15],
213                                             node[16],node[17],node[18],node[19],ID);
214         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
215                                             node[4], node[5], node[6], node[7],
216                                             node[8], node[9], node[10],node[11],
217                                             node[12],node[13],node[14],node[15],
218                                             node[16],node[17],node[18],node[19] );
219     }
220   }
221   return e;
222 }
223
224 //=======================================================================
225 /*!
226  * \brief Add element
227  */
228 //=======================================================================
229
230 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
231                                                const SMDSAbs_ElementType type,
232                                                const bool                isPoly,
233                                                const int                 ID)
234 {
235   vector<const SMDS_MeshNode*> nodes;
236   nodes.reserve( nodeIDs.size() );
237   vector<int>::const_iterator id = nodeIDs.begin();
238   while ( id != nodeIDs.end() ) {
239     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
240       nodes.push_back( node );
241     else
242       return 0;
243   }
244   return AddElement( nodes, type, isPoly, ID );
245 }
246
247 //=======================================================================
248 //function : Remove
249 //purpose  : Remove a node or an element.
250 //           Modify a compute state of sub-meshes which become empty
251 //=======================================================================
252
253 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
254                                const bool         isNodes )
255 {
256   myLastCreatedElems.Clear();
257   myLastCreatedNodes.Clear();
258
259   SMESHDS_Mesh* aMesh = GetMeshDS();
260   set< SMESH_subMesh *> smmap;
261
262   list<int>::const_iterator it = theIDs.begin();
263   for ( ; it != theIDs.end(); it++ ) {
264     const SMDS_MeshElement * elem;
265     if ( isNodes )
266       elem = aMesh->FindNode( *it );
267     else
268       elem = aMesh->FindElement( *it );
269     if ( !elem )
270       continue;
271
272     // Notify VERTEX sub-meshes about modification
273     if ( isNodes ) {
274       const SMDS_MeshNode* node = cast2Node( elem );
275       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
276         if ( int aShapeID = node->GetPosition()->GetShapeId() )
277           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
278             smmap.insert( sm );
279     }
280     // Find sub-meshes to notify about modification
281 //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
282 //     while ( nodeIt->more() ) {
283 //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
284 //       const SMDS_PositionPtr& aPosition = node->GetPosition();
285 //       if ( aPosition.get() ) {
286 //         if ( int aShapeID = aPosition->GetShapeId() ) {
287 //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
288 //             smmap.insert( sm );
289 //         }
290 //       }
291 //     }
292
293     // Do remove
294     if ( isNodes )
295       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
296     else
297       aMesh->RemoveElement( elem );
298   }
299
300   // Notify sub-meshes about modification
301   if ( !smmap.empty() ) {
302     set< SMESH_subMesh *>::iterator smIt;
303     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
304       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
305   }
306
307 //   // Check if the whole mesh becomes empty
308 //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
309 //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
310
311   return true;
312 }
313
314 //=======================================================================
315 //function : FindShape
316 //purpose  : Return an index of the shape theElem is on
317 //           or zero if a shape not found
318 //=======================================================================
319
320 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
321 {
322   myLastCreatedElems.Clear();
323   myLastCreatedNodes.Clear();
324
325   SMESHDS_Mesh * aMesh = GetMeshDS();
326   if ( aMesh->ShapeToMesh().IsNull() )
327     return 0;
328
329   if ( theElem->GetType() == SMDSAbs_Node ) {
330     const SMDS_PositionPtr& aPosition =
331       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
332     if ( aPosition.get() )
333       return aPosition->GetShapeId();
334     else
335       return 0;
336   }
337
338   TopoDS_Shape aShape; // the shape a node is on
339   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
340   while ( nodeIt->more() ) {
341     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
342     const SMDS_PositionPtr& aPosition = node->GetPosition();
343     if ( aPosition.get() ) {
344       int aShapeID = aPosition->GetShapeId();
345       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
346       if ( sm ) {
347         if ( sm->Contains( theElem ))
348           return aShapeID;
349         if ( aShape.IsNull() )
350           aShape = aMesh->IndexToShape( aShapeID );
351       }
352       else {
353         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
354       }
355     }
356   }
357
358   // None of nodes is on a proper shape,
359   // find the shape among ancestors of aShape on which a node is
360   if ( aShape.IsNull() ) {
361     //MESSAGE ("::FindShape() - NONE node is on shape")
362     return 0;
363   }
364   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
365   for ( ; ancIt.More(); ancIt.Next() ) {
366     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
367     if ( sm && sm->Contains( theElem ))
368       return aMesh->ShapeToIndex( ancIt.Value() );
369   }
370
371   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
372   return 0;
373 }
374
375 //=======================================================================
376 //function : IsMedium
377 //purpose  :
378 //=======================================================================
379
380 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
381                                 const SMDSAbs_ElementType typeToCheck)
382 {
383   bool isMedium = false;
384   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
385   while (it->more() && !isMedium ) {
386     const SMDS_MeshElement* elem = it->next();
387     isMedium = elem->IsMediumNode(node);
388   }
389   return isMedium;
390 }
391
392 //=======================================================================
393 //function : ShiftNodesQuadTria
394 //purpose  : auxilary
395 //           Shift nodes in the array corresponded to quadratic triangle
396 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
397 //=======================================================================
398 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
399 {
400   const SMDS_MeshNode* nd1 = aNodes[0];
401   aNodes[0] = aNodes[1];
402   aNodes[1] = aNodes[2];
403   aNodes[2] = nd1;
404   const SMDS_MeshNode* nd2 = aNodes[3];
405   aNodes[3] = aNodes[4];
406   aNodes[4] = aNodes[5];
407   aNodes[5] = nd2;
408 }
409
410 //=======================================================================
411 //function : GetNodesFromTwoTria
412 //purpose  : auxilary
413 //           Shift nodes in the array corresponded to quadratic triangle
414 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
415 //=======================================================================
416 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
417                                 const SMDS_MeshElement * theTria2,
418                                 const SMDS_MeshNode* N1[],
419                                 const SMDS_MeshNode* N2[])
420 {
421   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
422   int i=0;
423   while(i<6) {
424     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
425     i++;
426   }
427   if(it->more()) return false;
428   it = theTria2->nodesIterator();
429   i=0;
430   while(i<6) {
431     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
432     i++;
433   }
434   if(it->more()) return false;
435
436   int sames[3] = {-1,-1,-1};
437   int nbsames = 0;
438   int j;
439   for(i=0; i<3; i++) {
440     for(j=0; j<3; j++) {
441       if(N1[i]==N2[j]) {
442         sames[i] = j;
443         nbsames++;
444         break;
445       }
446     }
447   }
448   if(nbsames!=2) return false;
449   if(sames[0]>-1) {
450     ShiftNodesQuadTria(N1);
451     if(sames[1]>-1) {
452       ShiftNodesQuadTria(N1);
453     }
454   }
455   i = sames[0] + sames[1] + sames[2];
456   for(; i<2; i++) {
457     ShiftNodesQuadTria(N2);
458   }
459   // now we receive following N1 and N2 (using numeration as above image)
460   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
461   // i.e. first nodes from both arrays determ new diagonal
462   return true;
463 }
464
465 //=======================================================================
466 //function : InverseDiag
467 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
468 //           but having other common link.
469 //           Return False if args are improper
470 //=======================================================================
471
472 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
473                                     const SMDS_MeshElement * theTria2 )
474 {
475   myLastCreatedElems.Clear();
476   myLastCreatedNodes.Clear();
477
478   if (!theTria1 || !theTria2)
479     return false;
480
481   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
482   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
483   if (F1 && F2) {
484
485     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
486     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
487     //    |/ |                                         | \|
488     //  B +--+ 2                                     B +--+ 2
489
490     // put nodes in array and find out indices of the same ones
491     const SMDS_MeshNode* aNodes [6];
492     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
493     int i = 0;
494     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
495     while ( it->more() ) {
496       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
497
498       if ( i > 2 ) // theTria2
499         // find same node of theTria1
500         for ( int j = 0; j < 3; j++ )
501           if ( aNodes[ i ] == aNodes[ j ]) {
502             sameInd[ j ] = i;
503             sameInd[ i ] = j;
504             break;
505           }
506       // next
507       i++;
508       if ( i == 3 ) {
509         if ( it->more() )
510           return false; // theTria1 is not a triangle
511         it = theTria2->nodesIterator();
512       }
513       if ( i == 6 && it->more() )
514         return false; // theTria2 is not a triangle
515     }
516
517     // find indices of 1,2 and of A,B in theTria1
518     int iA = 0, iB = 0, i1 = 0, i2 = 0;
519     for ( i = 0; i < 6; i++ ) {
520       if ( sameInd [ i ] == 0 )
521         if ( i < 3 ) i1 = i;
522         else         i2 = i;
523       else if (i < 3)
524         if ( iA ) iB = i;
525         else      iA = i;
526     }
527     // nodes 1 and 2 should not be the same
528     if ( aNodes[ i1 ] == aNodes[ i2 ] )
529       return false;
530
531     // theTria1: A->2
532     aNodes[ iA ] = aNodes[ i2 ];
533     // theTria2: B->1
534     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
535
536     //MESSAGE( theTria1 << theTria2 );
537
538     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
539     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
540
541     //MESSAGE( theTria1 << theTria2 );
542
543     return true;
544
545   } // end if(F1 && F2)
546
547   // check case of quadratic faces
548   const SMDS_QuadraticFaceOfNodes* QF1 =
549     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
550   if(!QF1) return false;
551   const SMDS_QuadraticFaceOfNodes* QF2 =
552     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
553   if(!QF2) return false;
554
555   //       5
556   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
557   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
558   //    |   / |
559   //  7 +  +  + 6
560   //    | /9  |
561   //    |/    |
562   //  4 +--+--+ 3
563   //       8
564
565   const SMDS_MeshNode* N1 [6];
566   const SMDS_MeshNode* N2 [6];
567   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
568     return false;
569   // now we receive following N1 and N2 (using numeration as above image)
570   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
571   // i.e. first nodes from both arrays determ new diagonal
572
573   const SMDS_MeshNode* N1new [6];
574   const SMDS_MeshNode* N2new [6];
575   N1new[0] = N1[0];
576   N1new[1] = N2[0];
577   N1new[2] = N2[1];
578   N1new[3] = N1[4];
579   N1new[4] = N2[3];
580   N1new[5] = N1[5];
581   N2new[0] = N1[0];
582   N2new[1] = N1[1];
583   N2new[2] = N2[0];
584   N2new[3] = N1[3];
585   N2new[4] = N2[5];
586   N2new[5] = N1[4];
587   // replaces nodes in faces
588   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
589   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
590
591   return true;
592 }
593
594 //=======================================================================
595 //function : findTriangles
596 //purpose  : find triangles sharing theNode1-theNode2 link
597 //=======================================================================
598
599 static bool findTriangles(const SMDS_MeshNode *    theNode1,
600                           const SMDS_MeshNode *    theNode2,
601                           const SMDS_MeshElement*& theTria1,
602                           const SMDS_MeshElement*& theTria2)
603 {
604   if ( !theNode1 || !theNode2 ) return false;
605
606   theTria1 = theTria2 = 0;
607
608   set< const SMDS_MeshElement* > emap;
609   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
610   while (it->more()) {
611     const SMDS_MeshElement* elem = it->next();
612     if ( elem->NbNodes() == 3 )
613       emap.insert( elem );
614   }
615   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
616   while (it->more()) {
617     const SMDS_MeshElement* elem = it->next();
618     if ( emap.find( elem ) != emap.end() )
619       if ( theTria1 ) {
620         // theTria1 must be element with minimum ID
621         if( theTria1->GetID() < elem->GetID() ) {
622           theTria2 = elem;
623         }
624         else {
625           theTria2 = theTria1;
626           theTria1 = elem;
627         }
628         break;
629       }
630       else {
631         theTria1 = elem;
632       }
633   }
634   return ( theTria1 && theTria2 );
635 }
636
637 //=======================================================================
638 //function : InverseDiag
639 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
640 //           with ones built on the same 4 nodes but having other common link.
641 //           Return false if proper faces not found
642 //=======================================================================
643
644 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
645                                     const SMDS_MeshNode * theNode2)
646 {
647   myLastCreatedElems.Clear();
648   myLastCreatedNodes.Clear();
649
650   MESSAGE( "::InverseDiag()" );
651
652   const SMDS_MeshElement *tr1, *tr2;
653   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
654     return false;
655
656   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
657   //if (!F1) return false;
658   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
659   //if (!F2) return false;
660   if (F1 && F2) {
661
662     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
663     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
664     //    |/ |                                    | \|
665     //  B +--+ 2                                B +--+ 2
666
667     // put nodes in array
668     // and find indices of 1,2 and of A in tr1 and of B in tr2
669     int i, iA1 = 0, i1 = 0;
670     const SMDS_MeshNode* aNodes1 [3];
671     SMDS_ElemIteratorPtr it;
672     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
673       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
674       if ( aNodes1[ i ] == theNode1 )
675         iA1 = i; // node A in tr1
676       else if ( aNodes1[ i ] != theNode2 )
677         i1 = i;  // node 1
678     }
679     int iB2 = 0, i2 = 0;
680     const SMDS_MeshNode* aNodes2 [3];
681     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
682       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
683       if ( aNodes2[ i ] == theNode2 )
684         iB2 = i; // node B in tr2
685       else if ( aNodes2[ i ] != theNode1 )
686         i2 = i;  // node 2
687     }
688
689     // nodes 1 and 2 should not be the same
690     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
691       return false;
692
693     // tr1: A->2
694     aNodes1[ iA1 ] = aNodes2[ i2 ];
695     // tr2: B->1
696     aNodes2[ iB2 ] = aNodes1[ i1 ];
697
698     //MESSAGE( tr1 << tr2 );
699
700     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
701     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
702
703     //MESSAGE( tr1 << tr2 );
704
705     return true;
706   }
707
708   // check case of quadratic faces
709   const SMDS_QuadraticFaceOfNodes* QF1 =
710     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
711   if(!QF1) return false;
712   const SMDS_QuadraticFaceOfNodes* QF2 =
713     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
714   if(!QF2) return false;
715   return InverseDiag(tr1,tr2);
716 }
717
718 //=======================================================================
719 //function : getQuadrangleNodes
720 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
721 //           fusion of triangles tr1 and tr2 having shared link on
722 //           theNode1 and theNode2
723 //=======================================================================
724
725 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
726                         const SMDS_MeshNode *    theNode1,
727                         const SMDS_MeshNode *    theNode2,
728                         const SMDS_MeshElement * tr1,
729                         const SMDS_MeshElement * tr2 )
730 {
731   if( tr1->NbNodes() != tr2->NbNodes() )
732     return false;
733   // find the 4-th node to insert into tr1
734   const SMDS_MeshNode* n4 = 0;
735   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
736   int i=0;
737   while ( !n4 && i<3 ) {
738     const SMDS_MeshNode * n = cast2Node( it->next() );
739     i++;
740     bool isDiag = ( n == theNode1 || n == theNode2 );
741     if ( !isDiag )
742       n4 = n;
743   }
744   // Make an array of nodes to be in a quadrangle
745   int iNode = 0, iFirstDiag = -1;
746   it = tr1->nodesIterator();
747   i=0;
748   while ( i<3 ) {
749     const SMDS_MeshNode * n = cast2Node( it->next() );
750     i++;
751     bool isDiag = ( n == theNode1 || n == theNode2 );
752     if ( isDiag ) {
753       if ( iFirstDiag < 0 )
754         iFirstDiag = iNode;
755       else if ( iNode - iFirstDiag == 1 )
756         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
757     }
758     else if ( n == n4 ) {
759       return false; // tr1 and tr2 should not have all the same nodes
760     }
761     theQuadNodes[ iNode++ ] = n;
762   }
763   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
764     theQuadNodes[ iNode ] = n4;
765
766   return true;
767 }
768
769 //=======================================================================
770 //function : DeleteDiag
771 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
772 //           with a quadrangle built on the same 4 nodes.
773 //           Return false if proper faces not found
774 //=======================================================================
775
776 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
777                                    const SMDS_MeshNode * theNode2)
778 {
779   myLastCreatedElems.Clear();
780   myLastCreatedNodes.Clear();
781
782   MESSAGE( "::DeleteDiag()" );
783
784   const SMDS_MeshElement *tr1, *tr2;
785   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
786     return false;
787
788   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
789   //if (!F1) return false;
790   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
791   //if (!F2) return false;
792   if (F1 && F2) {
793
794     const SMDS_MeshNode* aNodes [ 4 ];
795     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
796       return false;
797
798     //MESSAGE( endl << tr1 << tr2 );
799
800     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
801     myLastCreatedElems.Append(tr1);
802     GetMeshDS()->RemoveElement( tr2 );
803
804     //MESSAGE( endl << tr1 );
805
806     return true;
807   }
808
809   // check case of quadratic faces
810   const SMDS_QuadraticFaceOfNodes* QF1 =
811     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
812   if(!QF1) return false;
813   const SMDS_QuadraticFaceOfNodes* QF2 =
814     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
815   if(!QF2) return false;
816
817   //       5
818   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
819   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
820   //    |   / |
821   //  7 +  +  + 6
822   //    | /9  |
823   //    |/    |
824   //  4 +--+--+ 3
825   //       8
826
827   const SMDS_MeshNode* N1 [6];
828   const SMDS_MeshNode* N2 [6];
829   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
830     return false;
831   // now we receive following N1 and N2 (using numeration as above image)
832   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
833   // i.e. first nodes from both arrays determ new diagonal
834
835   const SMDS_MeshNode* aNodes[8];
836   aNodes[0] = N1[0];
837   aNodes[1] = N1[1];
838   aNodes[2] = N2[0];
839   aNodes[3] = N2[1];
840   aNodes[4] = N1[3];
841   aNodes[5] = N2[5];
842   aNodes[6] = N2[3];
843   aNodes[7] = N1[5];
844
845   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
846   myLastCreatedElems.Append(tr1);
847   GetMeshDS()->RemoveElement( tr2 );
848
849   // remove middle node (9)
850   GetMeshDS()->RemoveNode( N1[4] );
851
852   return true;
853 }
854
855 //=======================================================================
856 //function : Reorient
857 //purpose  : Reverse theElement orientation
858 //=======================================================================
859
860 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
861 {
862   myLastCreatedElems.Clear();
863   myLastCreatedNodes.Clear();
864
865   if (!theElem)
866     return false;
867   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
868   if ( !it || !it->more() )
869     return false;
870
871   switch ( theElem->GetType() ) {
872
873   case SMDSAbs_Edge:
874   case SMDSAbs_Face: {
875     if(!theElem->IsQuadratic()) {
876       int i = theElem->NbNodes();
877       vector<const SMDS_MeshNode*> aNodes( i );
878       while ( it->more() )
879         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
880       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
881     }
882     else {
883       // quadratic elements
884       if(theElem->GetType()==SMDSAbs_Edge) {
885         vector<const SMDS_MeshNode*> aNodes(3);
886         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
887         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
888         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
889         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
890       }
891       else {
892         int nbn = theElem->NbNodes();
893         vector<const SMDS_MeshNode*> aNodes(nbn);
894         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
895         int i=1;
896         for(; i<nbn/2; i++) {
897           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
898         }
899         for(i=0; i<nbn/2; i++) {
900           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
901         }
902         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
903       }
904     }
905   }
906   case SMDSAbs_Volume: {
907     if (theElem->IsPoly()) {
908       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
909         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
910       if (!aPolyedre) {
911         MESSAGE("Warning: bad volumic element");
912         return false;
913       }
914
915       int nbFaces = aPolyedre->NbFaces();
916       vector<const SMDS_MeshNode *> poly_nodes;
917       vector<int> quantities (nbFaces);
918
919       // reverse each face of the polyedre
920       for (int iface = 1; iface <= nbFaces; iface++) {
921         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
922         quantities[iface - 1] = nbFaceNodes;
923
924         for (inode = nbFaceNodes; inode >= 1; inode--) {
925           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
926           poly_nodes.push_back(curNode);
927         }
928       }
929
930       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
931
932     }
933     else {
934       SMDS_VolumeTool vTool;
935       if ( !vTool.Set( theElem ))
936         return false;
937       vTool.Inverse();
938       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
939     }
940   }
941   default:;
942   }
943
944   return false;
945 }
946
947 //=======================================================================
948 //function : getBadRate
949 //purpose  :
950 //=======================================================================
951
952 static double getBadRate (const SMDS_MeshElement*               theElem,
953                           SMESH::Controls::NumericalFunctorPtr& theCrit)
954 {
955   SMESH::Controls::TSequenceOfXYZ P;
956   if ( !theElem || !theCrit->GetPoints( theElem, P ))
957     return 1e100;
958   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
959   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
960 }
961
962 //=======================================================================
963 //function : QuadToTri
964 //purpose  : Cut quadrangles into triangles.
965 //           theCrit is used to select a diagonal to cut
966 //=======================================================================
967
968 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
969                                   SMESH::Controls::NumericalFunctorPtr theCrit)
970 {
971   myLastCreatedElems.Clear();
972   myLastCreatedNodes.Clear();
973
974   MESSAGE( "::QuadToTri()" );
975
976   if ( !theCrit.get() )
977     return false;
978
979   SMESHDS_Mesh * aMesh = GetMeshDS();
980
981   Handle(Geom_Surface) surface;
982   SMESH_MesherHelper   helper( *GetMesh() );
983
984   TIDSortedElemSet::iterator itElem;
985   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
986     const SMDS_MeshElement* elem = *itElem;
987     if ( !elem || elem->GetType() != SMDSAbs_Face )
988       continue;
989     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
990       continue;
991
992     // retrieve element nodes
993     const SMDS_MeshNode* aNodes [8];
994     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
995     int i = 0;
996     while ( itN->more() )
997       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
998
999     // compare two sets of possible triangles
1000     double aBadRate1, aBadRate2; // to what extent a set is bad
1001     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1002     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1003     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1004
1005     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1006     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1007     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1008
1009     int aShapeId = FindShape( elem );
1010     const SMDS_MeshElement* newElem = 0;
1011
1012     if( !elem->IsQuadratic() ) {
1013
1014       // split liner quadrangle
1015
1016       if ( aBadRate1 <= aBadRate2 ) {
1017         // tr1 + tr2 is better
1018         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1019         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1020       }
1021       else {
1022         // tr3 + tr4 is better
1023         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1024         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1025       }
1026     }
1027     else {
1028
1029       // split quadratic quadrangle
1030
1031       // get surface elem is on
1032       if ( aShapeId != helper.GetSubShapeID() ) {
1033         surface.Nullify();
1034         TopoDS_Shape shape;
1035         if ( aShapeId > 0 )
1036           shape = aMesh->IndexToShape( aShapeId );
1037         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1038           TopoDS_Face face = TopoDS::Face( shape );
1039           surface = BRep_Tool::Surface( face );
1040           if ( !surface.IsNull() )
1041             helper.SetSubShape( shape );
1042         }
1043       }
1044       // get elem nodes
1045       const SMDS_MeshNode* aNodes [8];
1046       const SMDS_MeshNode* inFaceNode = 0;
1047       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1048       int i = 0;
1049       while ( itN->more() ) {
1050         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1051         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1052              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1053         {
1054           inFaceNode = aNodes[ i-1 ];
1055         }
1056       }
1057       // find middle point for (0,1,2,3)
1058       // and create a node in this point;
1059       gp_XYZ p( 0,0,0 );
1060       if ( surface.IsNull() ) {
1061         for(i=0; i<4; i++)
1062           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1063         p /= 4;
1064       }
1065       else {
1066         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1067         gp_XY uv( 0,0 );
1068         for(i=0; i<4; i++)
1069           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1070         uv /= 4.;
1071         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1072       }
1073       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1074       myLastCreatedNodes.Append(newN);
1075
1076       // create a new element
1077       const SMDS_MeshNode* N[6];
1078       if ( aBadRate1 <= aBadRate2 ) {
1079         N[0] = aNodes[0];
1080         N[1] = aNodes[1];
1081         N[2] = aNodes[2];
1082         N[3] = aNodes[4];
1083         N[4] = aNodes[5];
1084         N[5] = newN;
1085         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1086                                  aNodes[6], aNodes[7], newN );
1087       }
1088       else {
1089         N[0] = aNodes[1];
1090         N[1] = aNodes[2];
1091         N[2] = aNodes[3];
1092         N[3] = aNodes[5];
1093         N[4] = aNodes[6];
1094         N[5] = newN;
1095         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1096                                  aNodes[7], aNodes[4], newN );
1097       }
1098       aMesh->ChangeElementNodes( elem, N, 6 );
1099
1100     } // quadratic case
1101
1102     // care of a new element
1103
1104     myLastCreatedElems.Append(newElem);
1105     AddToSameGroups( newElem, elem, aMesh );
1106
1107     // put a new triangle on the same shape
1108     if ( aShapeId )
1109       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1110   }
1111   return true;
1112 }
1113
1114 //=======================================================================
1115 //function : BestSplit
1116 //purpose  : Find better diagonal for cutting.
1117 //=======================================================================
1118 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1119                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1120 {
1121   myLastCreatedElems.Clear();
1122   myLastCreatedNodes.Clear();
1123
1124   if (!theCrit.get())
1125     return -1;
1126
1127   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1128     return -1;
1129
1130   if( theQuad->NbNodes()==4 ||
1131       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1132
1133     // retrieve element nodes
1134     const SMDS_MeshNode* aNodes [4];
1135     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1136     int i = 0;
1137     //while (itN->more())
1138     while (i<4) {
1139       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1140     }
1141     // compare two sets of possible triangles
1142     double aBadRate1, aBadRate2; // to what extent a set is bad
1143     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1144     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1145     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1146
1147     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1148     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1149     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1150
1151     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1152       return 1; // diagonal 1-3
1153
1154     return 2; // diagonal 2-4
1155   }
1156   return -1;
1157 }
1158
1159 //=======================================================================
1160 //function : AddToSameGroups
1161 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1162 //=======================================================================
1163
1164 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1165                                         const SMDS_MeshElement* elemInGroups,
1166                                         SMESHDS_Mesh *          aMesh)
1167 {
1168   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1169   set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1170   for ( ; grIt != groups.end(); grIt++ ) {
1171     SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1172     if ( group && group->SMDSGroup().Contains( elemInGroups ))
1173       group->SMDSGroup().Add( elemToAdd );
1174   }
1175 }
1176
1177
1178 //=======================================================================
1179 //function : RemoveElemFromGroups
1180 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1181 //=======================================================================
1182 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1183                                              SMESHDS_Mesh *          aMesh)
1184 {
1185   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1186   if (!groups.empty())
1187   {
1188     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1189     for (; GrIt != groups.end(); GrIt++)
1190     {
1191       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1192       if (!grp || grp->IsEmpty()) continue;
1193       grp->SMDSGroup().Remove(removeelem);
1194     }
1195   }
1196 }
1197
1198
1199 //=======================================================================
1200 //function : QuadToTri
1201 //purpose  : Cut quadrangles into triangles.
1202 //           theCrit is used to select a diagonal to cut
1203 //=======================================================================
1204
1205 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1206                                   const bool         the13Diag)
1207 {
1208   myLastCreatedElems.Clear();
1209   myLastCreatedNodes.Clear();
1210
1211   MESSAGE( "::QuadToTri()" );
1212
1213   SMESHDS_Mesh * aMesh = GetMeshDS();
1214
1215   Handle(Geom_Surface) surface;
1216   SMESH_MesherHelper   helper( *GetMesh() );
1217
1218   TIDSortedElemSet::iterator itElem;
1219   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1220     const SMDS_MeshElement* elem = *itElem;
1221     if ( !elem || elem->GetType() != SMDSAbs_Face )
1222       continue;
1223     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1224     if(!isquad) continue;
1225
1226     if(elem->NbNodes()==4) {
1227       // retrieve element nodes
1228       const SMDS_MeshNode* aNodes [4];
1229       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1230       int i = 0;
1231       while ( itN->more() )
1232         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1233
1234       int aShapeId = FindShape( elem );
1235       const SMDS_MeshElement* newElem = 0;
1236       if ( the13Diag ) {
1237         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1238         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1239       }
1240       else {
1241         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1242         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1243       }
1244       myLastCreatedElems.Append(newElem);
1245       // put a new triangle on the same shape and add to the same groups
1246       if ( aShapeId )
1247         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1248       AddToSameGroups( newElem, elem, aMesh );
1249     }
1250
1251     // Quadratic quadrangle
1252
1253     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1254
1255       // get surface elem is on
1256       int aShapeId = FindShape( elem );
1257       if ( aShapeId != helper.GetSubShapeID() ) {
1258         surface.Nullify();
1259         TopoDS_Shape shape;
1260         if ( aShapeId > 0 )
1261           shape = aMesh->IndexToShape( aShapeId );
1262         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1263           TopoDS_Face face = TopoDS::Face( shape );
1264           surface = BRep_Tool::Surface( face );
1265           if ( !surface.IsNull() )
1266             helper.SetSubShape( shape );
1267         }
1268       }
1269
1270       const SMDS_MeshNode* aNodes [8];
1271       const SMDS_MeshNode* inFaceNode = 0;
1272       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1273       int i = 0;
1274       while ( itN->more() ) {
1275         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1276         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1277              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1278         {
1279           inFaceNode = aNodes[ i-1 ];
1280         }
1281       }
1282
1283       // find middle point for (0,1,2,3)
1284       // and create a node in this point;
1285       gp_XYZ p( 0,0,0 );
1286       if ( surface.IsNull() ) {
1287         for(i=0; i<4; i++)
1288           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1289         p /= 4;
1290       }
1291       else {
1292         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1293         gp_XY uv( 0,0 );
1294         for(i=0; i<4; i++)
1295           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1296         uv /= 4.;
1297         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1298       }
1299       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1300       myLastCreatedNodes.Append(newN);
1301
1302       // create a new element
1303       const SMDS_MeshElement* newElem = 0;
1304       const SMDS_MeshNode* N[6];
1305       if ( the13Diag ) {
1306         N[0] = aNodes[0];
1307         N[1] = aNodes[1];
1308         N[2] = aNodes[2];
1309         N[3] = aNodes[4];
1310         N[4] = aNodes[5];
1311         N[5] = newN;
1312         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1313                                  aNodes[6], aNodes[7], newN );
1314       }
1315       else {
1316         N[0] = aNodes[1];
1317         N[1] = aNodes[2];
1318         N[2] = aNodes[3];
1319         N[3] = aNodes[5];
1320         N[4] = aNodes[6];
1321         N[5] = newN;
1322         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1323                                  aNodes[7], aNodes[4], newN );
1324       }
1325       myLastCreatedElems.Append(newElem);
1326       aMesh->ChangeElementNodes( elem, N, 6 );
1327       // put a new triangle on the same shape and add to the same groups
1328       if ( aShapeId )
1329         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1330       AddToSameGroups( newElem, elem, aMesh );
1331     }
1332   }
1333
1334   return true;
1335 }
1336
1337 //=======================================================================
1338 //function : getAngle
1339 //purpose  :
1340 //=======================================================================
1341
1342 double getAngle(const SMDS_MeshElement * tr1,
1343                 const SMDS_MeshElement * tr2,
1344                 const SMDS_MeshNode *    n1,
1345                 const SMDS_MeshNode *    n2)
1346 {
1347   double angle = 2*PI; // bad angle
1348
1349   // get normals
1350   SMESH::Controls::TSequenceOfXYZ P1, P2;
1351   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1352        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1353     return angle;
1354   gp_Vec N1,N2;
1355   if(!tr1->IsQuadratic())
1356     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1357   else
1358     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1359   if ( N1.SquareMagnitude() <= gp::Resolution() )
1360     return angle;
1361   if(!tr2->IsQuadratic())
1362     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1363   else
1364     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1365   if ( N2.SquareMagnitude() <= gp::Resolution() )
1366     return angle;
1367
1368   // find the first diagonal node n1 in the triangles:
1369   // take in account a diagonal link orientation
1370   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1371   for ( int t = 0; t < 2; t++ ) {
1372     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1373     int i = 0, iDiag = -1;
1374     while ( it->more()) {
1375       const SMDS_MeshElement *n = it->next();
1376       if ( n == n1 || n == n2 )
1377         if ( iDiag < 0)
1378           iDiag = i;
1379         else {
1380           if ( i - iDiag == 1 )
1381             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1382           else
1383             nFirst[ t ] = n;
1384           break;
1385         }
1386       i++;
1387     }
1388   }
1389   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1390     N2.Reverse();
1391
1392   angle = N1.Angle( N2 );
1393   //SCRUTE( angle );
1394   return angle;
1395 }
1396
1397 // =================================================
1398 // class generating a unique ID for a pair of nodes
1399 // and able to return nodes by that ID
1400 // =================================================
1401 class LinkID_Gen {
1402  public:
1403
1404   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1405     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1406   {}
1407
1408   long GetLinkID (const SMDS_MeshNode * n1,
1409                   const SMDS_MeshNode * n2) const
1410   {
1411     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1412   }
1413
1414   bool GetNodes (const long             theLinkID,
1415                  const SMDS_MeshNode* & theNode1,
1416                  const SMDS_MeshNode* & theNode2) const
1417   {
1418     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1419     if ( !theNode1 ) return false;
1420     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1421     if ( !theNode2 ) return false;
1422     return true;
1423   }
1424
1425  private:
1426   LinkID_Gen();
1427   const SMESHDS_Mesh* myMesh;
1428   long                myMaxID;
1429 };
1430
1431
1432 //=======================================================================
1433 //function : TriToQuad
1434 //purpose  : Fuse neighbour triangles into quadrangles.
1435 //           theCrit is used to select a neighbour to fuse with.
1436 //           theMaxAngle is a max angle between element normals at which
1437 //           fusion is still performed.
1438 //=======================================================================
1439
1440 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1441                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1442                                   const double                         theMaxAngle)
1443 {
1444   myLastCreatedElems.Clear();
1445   myLastCreatedNodes.Clear();
1446
1447   MESSAGE( "::TriToQuad()" );
1448
1449   if ( !theCrit.get() )
1450     return false;
1451
1452   SMESHDS_Mesh * aMesh = GetMeshDS();
1453
1454   // Prepare data for algo: build
1455   // 1. map of elements with their linkIDs
1456   // 2. map of linkIDs with their elements
1457
1458   map< TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1459   map< TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1460   map< const SMDS_MeshElement*, set< TLink > >  mapEl_setLi;
1461   map< const SMDS_MeshElement*, set< TLink > >::iterator itEL;
1462
1463   TIDSortedElemSet::iterator itElem;
1464   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1465     const SMDS_MeshElement* elem = *itElem;
1466     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1467     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1468     if(!IsTria) continue;
1469
1470     // retrieve element nodes
1471     const SMDS_MeshNode* aNodes [4];
1472     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1473     int i = 0;
1474     while ( i<3 )
1475       aNodes[ i++ ] = cast2Node( itN->next() );
1476     aNodes[ 3 ] = aNodes[ 0 ];
1477
1478     // fill maps
1479     for ( i = 0; i < 3; i++ ) {
1480       TLink link( aNodes[i], aNodes[i+1] );
1481       // check if elements sharing a link can be fused
1482       itLE = mapLi_listEl.find( link );
1483       if ( itLE != mapLi_listEl.end() ) {
1484         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1485           continue;
1486         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1487         //if ( FindShape( elem ) != FindShape( elem2 ))
1488         //  continue; // do not fuse triangles laying on different shapes
1489         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1490           continue; // avoid making badly shaped quads
1491         (*itLE).second.push_back( elem );
1492       }
1493       else {
1494         mapLi_listEl[ link ].push_back( elem );
1495       }
1496       mapEl_setLi [ elem ].insert( link );
1497     }
1498   }
1499   // Clean the maps from the links shared by a sole element, ie
1500   // links to which only one element is bound in mapLi_listEl
1501
1502   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1503     int nbElems = (*itLE).second.size();
1504     if ( nbElems < 2  ) {
1505       const SMDS_MeshElement* elem = (*itLE).second.front();
1506       TLink link = (*itLE).first;
1507       mapEl_setLi[ elem ].erase( link );
1508       if ( mapEl_setLi[ elem ].empty() )
1509         mapEl_setLi.erase( elem );
1510     }
1511   }
1512
1513   // Algo: fuse triangles into quadrangles
1514
1515   while ( ! mapEl_setLi.empty() ) {
1516     // Look for the start element:
1517     // the element having the least nb of shared links
1518     const SMDS_MeshElement* startElem = 0;
1519     int minNbLinks = 4;
1520     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1521       int nbLinks = (*itEL).second.size();
1522       if ( nbLinks < minNbLinks ) {
1523         startElem = (*itEL).first;
1524         minNbLinks = nbLinks;
1525         if ( minNbLinks == 1 )
1526           break;
1527       }
1528     }
1529
1530     // search elements to fuse starting from startElem or links of elements
1531     // fused earlyer - startLinks
1532     list< TLink > startLinks;
1533     while ( startElem || !startLinks.empty() ) {
1534       while ( !startElem && !startLinks.empty() ) {
1535         // Get an element to start, by a link
1536         TLink linkId = startLinks.front();
1537         startLinks.pop_front();
1538         itLE = mapLi_listEl.find( linkId );
1539         if ( itLE != mapLi_listEl.end() ) {
1540           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1541           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1542           for ( ; itE != listElem.end() ; itE++ )
1543             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1544               startElem = (*itE);
1545           mapLi_listEl.erase( itLE );
1546         }
1547       }
1548
1549       if ( startElem ) {
1550         // Get candidates to be fused
1551         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1552         const TLink *link12, *link13;
1553         startElem = 0;
1554         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1555         set< TLink >& setLi = mapEl_setLi[ tr1 ];
1556         ASSERT( !setLi.empty() );
1557         set< TLink >::iterator itLi;
1558         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1559         {
1560           const TLink & link = (*itLi);
1561           itLE = mapLi_listEl.find( link );
1562           if ( itLE == mapLi_listEl.end() )
1563             continue;
1564
1565           const SMDS_MeshElement* elem = (*itLE).second.front();
1566           if ( elem == tr1 )
1567             elem = (*itLE).second.back();
1568           mapLi_listEl.erase( itLE );
1569           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1570             continue;
1571           if ( tr2 ) {
1572             tr3 = elem;
1573             link13 = &link;
1574           }
1575           else {
1576             tr2 = elem;
1577             link12 = &link;
1578           }
1579
1580           // add other links of elem to list of links to re-start from
1581           set< TLink >& links = mapEl_setLi[ elem ];
1582           set< TLink >::iterator it;
1583           for ( it = links.begin(); it != links.end(); it++ ) {
1584             const TLink& link2 = (*it);
1585             if ( link2 != link )
1586               startLinks.push_back( link2 );
1587           }
1588         }
1589
1590         // Get nodes of possible quadrangles
1591         const SMDS_MeshNode *n12 [4], *n13 [4];
1592         bool Ok12 = false, Ok13 = false;
1593         const SMDS_MeshNode *linkNode1, *linkNode2;
1594         if(tr2) {
1595           linkNode1 = link12->first;
1596           linkNode2 = link12->second;
1597           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1598             Ok12 = true;
1599         }
1600         if(tr3) {
1601           linkNode1 = link13->first;
1602           linkNode2 = link13->second;
1603           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1604             Ok13 = true;
1605         }
1606
1607         // Choose a pair to fuse
1608         if ( Ok12 && Ok13 ) {
1609           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1610           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1611           double aBadRate12 = getBadRate( &quad12, theCrit );
1612           double aBadRate13 = getBadRate( &quad13, theCrit );
1613           if (  aBadRate13 < aBadRate12 )
1614             Ok12 = false;
1615           else
1616             Ok13 = false;
1617         }
1618
1619         // Make quadrangles
1620         // and remove fused elems and removed links from the maps
1621         mapEl_setLi.erase( tr1 );
1622         if ( Ok12 ) {
1623           mapEl_setLi.erase( tr2 );
1624           mapLi_listEl.erase( *link12 );
1625           if(tr1->NbNodes()==3) {
1626             if( tr1->GetID() < tr2->GetID() ) {
1627               aMesh->ChangeElementNodes( tr1, n12, 4 );
1628               myLastCreatedElems.Append(tr1);
1629               aMesh->RemoveElement( tr2 );
1630             }
1631             else {
1632               aMesh->ChangeElementNodes( tr2, n12, 4 );
1633               myLastCreatedElems.Append(tr2);
1634               aMesh->RemoveElement( tr1);
1635             }
1636           }
1637           else {
1638             const SMDS_MeshNode* N1 [6];
1639             const SMDS_MeshNode* N2 [6];
1640             GetNodesFromTwoTria(tr1,tr2,N1,N2);
1641             // now we receive following N1 and N2 (using numeration as above image)
1642             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1643             // i.e. first nodes from both arrays determ new diagonal
1644             const SMDS_MeshNode* aNodes[8];
1645             aNodes[0] = N1[0];
1646             aNodes[1] = N1[1];
1647             aNodes[2] = N2[0];
1648             aNodes[3] = N2[1];
1649             aNodes[4] = N1[3];
1650             aNodes[5] = N2[5];
1651             aNodes[6] = N2[3];
1652             aNodes[7] = N1[5];
1653             if( tr1->GetID() < tr2->GetID() ) {
1654               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1655               myLastCreatedElems.Append(tr1);
1656               GetMeshDS()->RemoveElement( tr2 );
1657             }
1658             else {
1659               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1660               myLastCreatedElems.Append(tr2);
1661               GetMeshDS()->RemoveElement( tr1 );
1662             }
1663             // remove middle node (9)
1664             GetMeshDS()->RemoveNode( N1[4] );
1665           }
1666         }
1667         else if ( Ok13 ) {
1668           mapEl_setLi.erase( tr3 );
1669           mapLi_listEl.erase( *link13 );
1670           if(tr1->NbNodes()==3) {
1671             if( tr1->GetID() < tr2->GetID() ) {
1672               aMesh->ChangeElementNodes( tr1, n13, 4 );
1673               myLastCreatedElems.Append(tr1);
1674               aMesh->RemoveElement( tr3 );
1675             }
1676             else {
1677               aMesh->ChangeElementNodes( tr3, n13, 4 );
1678               myLastCreatedElems.Append(tr3);
1679               aMesh->RemoveElement( tr1 );
1680             }
1681           }
1682           else {
1683             const SMDS_MeshNode* N1 [6];
1684             const SMDS_MeshNode* N2 [6];
1685             GetNodesFromTwoTria(tr1,tr3,N1,N2);
1686             // now we receive following N1 and N2 (using numeration as above image)
1687             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1688             // i.e. first nodes from both arrays determ new diagonal
1689             const SMDS_MeshNode* aNodes[8];
1690             aNodes[0] = N1[0];
1691             aNodes[1] = N1[1];
1692             aNodes[2] = N2[0];
1693             aNodes[3] = N2[1];
1694             aNodes[4] = N1[3];
1695             aNodes[5] = N2[5];
1696             aNodes[6] = N2[3];
1697             aNodes[7] = N1[5];
1698             if( tr1->GetID() < tr2->GetID() ) {
1699               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1700               myLastCreatedElems.Append(tr1);
1701               GetMeshDS()->RemoveElement( tr3 );
1702             }
1703             else {
1704               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1705               myLastCreatedElems.Append(tr3);
1706               GetMeshDS()->RemoveElement( tr1 );
1707             }
1708             // remove middle node (9)
1709             GetMeshDS()->RemoveNode( N1[4] );
1710           }
1711         }
1712
1713         // Next element to fuse: the rejected one
1714         if ( tr3 )
1715           startElem = Ok12 ? tr3 : tr2;
1716
1717       } // if ( startElem )
1718     } // while ( startElem || !startLinks.empty() )
1719   } // while ( ! mapEl_setLi.empty() )
1720
1721   return true;
1722 }
1723
1724
1725 /*#define DUMPSO(txt) \
1726 //  cout << txt << endl;
1727 //=============================================================================
1728 //
1729 //
1730 //
1731 //=============================================================================
1732 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1733 {
1734   if ( i1 == i2 )
1735     return;
1736   int tmp = idNodes[ i1 ];
1737   idNodes[ i1 ] = idNodes[ i2 ];
1738   idNodes[ i2 ] = tmp;
1739   gp_Pnt Ptmp = P[ i1 ];
1740   P[ i1 ] = P[ i2 ];
1741   P[ i2 ] = Ptmp;
1742   DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1743 }
1744
1745 //=======================================================================
1746 //function : SortQuadNodes
1747 //purpose  : Set 4 nodes of a quadrangle face in a good order.
1748 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
1749 //           1 or 2 else 0.
1750 //=======================================================================
1751
1752 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1753                                      int               idNodes[] )
1754 {
1755   gp_Pnt P[4];
1756   int i;
1757   for ( i = 0; i < 4; i++ ) {
1758     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1759     if ( !n ) return 0;
1760     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1761   }
1762
1763   gp_Vec V1(P[0], P[1]);
1764   gp_Vec V2(P[0], P[2]);
1765   gp_Vec V3(P[0], P[3]);
1766
1767   gp_Vec Cross1 = V1 ^ V2;
1768   gp_Vec Cross2 = V2 ^ V3;
1769
1770   i = 0;
1771   if (Cross1.Dot(Cross2) < 0)
1772   {
1773     Cross1 = V2 ^ V1;
1774     Cross2 = V1 ^ V3;
1775
1776     if (Cross1.Dot(Cross2) < 0)
1777       i = 2;
1778     else
1779       i = 1;
1780     swap ( i, i + 1, idNodes, P );
1781
1782 //     for ( int ii = 0; ii < 4; ii++ ) {
1783 //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1784 //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1785 //     }
1786   }
1787   return i;
1788 }
1789
1790 //=======================================================================
1791 //function : SortHexaNodes
1792 //purpose  : Set 8 nodes of a hexahedron in a good order.
1793 //           Return success status
1794 //=======================================================================
1795
1796 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1797                                       int               idNodes[] )
1798 {
1799   gp_Pnt P[8];
1800   int i;
1801   DUMPSO( "INPUT: ========================================");
1802   for ( i = 0; i < 8; i++ ) {
1803     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1804     if ( !n ) return false;
1805     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1806     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1807   }
1808   DUMPSO( "========================================");
1809
1810
1811   set<int> faceNodes;  // ids of bottom face nodes, to be found
1812   set<int> checkedId1; // ids of tried 2-nd nodes
1813   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1814   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
1815   int iMin, iLoop1 = 0;
1816
1817   // Loop to try the 2-nd nodes
1818
1819   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1820   {
1821     // Find not checked 2-nd node
1822     for ( i = 1; i < 8; i++ )
1823       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1824         int id1 = idNodes[i];
1825         swap ( 1, i, idNodes, P );
1826         checkedId1.insert ( id1 );
1827         break;
1828       }
1829
1830     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
1831     // ie that all but meybe one (id3 which is on the same face) nodes
1832     // lay on the same side from the triangle plane.
1833
1834     bool manyInPlane = false; // more than 4 nodes lay in plane
1835     int iLoop2 = 0;
1836     while ( ++iLoop2 < 6 ) {
1837
1838       // get 1-2-3 plane coeffs
1839       Standard_Real A, B, C, D;
1840       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1841       if ( N.SquareMagnitude() > gp::Resolution() )
1842       {
1843         gp_Pln pln ( P[0], N );
1844         pln.Coefficients( A, B, C, D );
1845
1846         // find the node (iMin) closest to pln
1847         Standard_Real dist[ 8 ], minDist = DBL_MAX;
1848         set<int> idInPln;
1849         for ( i = 3; i < 8; i++ ) {
1850           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
1851           if ( fabs( dist[i] ) < minDist ) {
1852             minDist = fabs( dist[i] );
1853             iMin = i;
1854           }
1855           if ( fabs( dist[i] ) <= tol )
1856             idInPln.insert( idNodes[i] );
1857         }
1858
1859         // there should not be more than 4 nodes in bottom plane
1860         if ( idInPln.size() > 1 )
1861         {
1862           DUMPSO( "### idInPln.size() = " << idInPln.size());
1863           // idInPlane does not contain the first 3 nodes
1864           if ( manyInPlane || idInPln.size() == 5)
1865             return false; // all nodes in one plane
1866           manyInPlane = true;
1867
1868           // set the 1-st node to be not in plane
1869           for ( i = 3; i < 8; i++ ) {
1870             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
1871               DUMPSO( "### Reset 0-th node");
1872               swap( 0, i, idNodes, P );
1873               break;
1874             }
1875           }
1876
1877           // reset to re-check second nodes
1878           leastDist = DBL_MAX;
1879           faceNodes.clear();
1880           checkedId1.clear();
1881           iLoop1 = 0;
1882           break; // from iLoop2;
1883         }
1884
1885         // check that the other 4 nodes are on the same side
1886         bool sameSide = true;
1887         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
1888         for ( i = 3; sameSide && i < 8; i++ ) {
1889           if ( i != iMin )
1890             sameSide = ( isNeg == dist[i] <= 0.);
1891         }
1892
1893         // keep best solution
1894         if ( sameSide && minDist < leastDist ) {
1895           leastDist = minDist;
1896           faceNodes.clear();
1897           faceNodes.insert( idNodes[ 1 ] );
1898           faceNodes.insert( idNodes[ 2 ] );
1899           faceNodes.insert( idNodes[ iMin ] );
1900           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
1901             << " leastDist = " << leastDist);
1902           if ( leastDist <= DBL_MIN )
1903             break;
1904         }
1905       }
1906
1907       // set next 3-d node to check
1908       int iNext = 2 + iLoop2;
1909       if ( iNext < 8 ) {
1910         DUMPSO( "Try 2-nd");
1911         swap ( 2, iNext, idNodes, P );
1912       }
1913     } // while ( iLoop2 < 6 )
1914   } // iLoop1
1915
1916   if ( faceNodes.empty() ) return false;
1917
1918   // Put the faceNodes in proper places
1919   for ( i = 4; i < 8; i++ ) {
1920     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
1921       // find a place to put
1922       int iTo = 1;
1923       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
1924         iTo++;
1925       DUMPSO( "Set faceNodes");
1926       swap ( iTo, i, idNodes, P );
1927     }
1928   }
1929
1930
1931   // Set nodes of the found bottom face in good order
1932   DUMPSO( " Found bottom face: ");
1933   i = SortQuadNodes( theMesh, idNodes );
1934   if ( i ) {
1935     gp_Pnt Ptmp = P[ i ];
1936     P[ i ] = P[ i+1 ];
1937     P[ i+1 ] = Ptmp;
1938   }
1939 //   else
1940 //     for ( int ii = 0; ii < 4; ii++ ) {
1941 //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1942 //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1943 //    }
1944
1945   // Gravity center of the top and bottom faces
1946   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
1947   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
1948
1949   // Get direction from the bottom to the top face
1950   gp_Vec upDir ( aGCb, aGCt );
1951   Standard_Real upDirSize = upDir.Magnitude();
1952   if ( upDirSize <= gp::Resolution() ) return false;
1953   upDir / upDirSize;
1954
1955   // Assure that the bottom face normal points up
1956   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1957   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
1958   if ( Nb.Dot( upDir ) < 0 ) {
1959     DUMPSO( "Reverse bottom face");
1960     swap( 1, 3, idNodes, P );
1961   }
1962
1963   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
1964   Standard_Real minDist = DBL_MAX;
1965   for ( i = 4; i < 8; i++ ) {
1966     // projection of P[i] to the plane defined by P[0] and upDir
1967     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
1968     Standard_Real sqDist = P[0].SquareDistance( Pp );
1969     if ( sqDist < minDist ) {
1970       minDist = sqDist;
1971       iMin = i;
1972     }
1973   }
1974   DUMPSO( "Set 4-th");
1975   swap ( 4, iMin, idNodes, P );
1976
1977   // Set nodes of the top face in good order
1978   DUMPSO( "Sort top face");
1979   i = SortQuadNodes( theMesh, &idNodes[4] );
1980   if ( i ) {
1981     i += 4;
1982     gp_Pnt Ptmp = P[ i ];
1983     P[ i ] = P[ i+1 ];
1984     P[ i+1 ] = Ptmp;
1985   }
1986
1987   // Assure that direction of the top face normal is from the bottom face
1988   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
1989   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
1990   if ( Nt.Dot( upDir ) < 0 ) {
1991     DUMPSO( "Reverse top face");
1992     swap( 5, 7, idNodes, P );
1993   }
1994
1995 //   DUMPSO( "OUTPUT: ========================================");
1996 //   for ( i = 0; i < 8; i++ ) {
1997 //     float *p = ugrid->GetPoint(idNodes[i]);
1998 //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
1999 //   }
2000
2001   return true;
2002 }*/
2003
2004 //================================================================================
2005 /*!
2006  * \brief Return nodes linked to the given one
2007   * \param theNode - the node
2008   * \param linkedNodes - the found nodes
2009   * \param type - the type of elements to check
2010   *
2011   * Medium nodes are ignored
2012  */
2013 //================================================================================
2014
2015 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2016                                        TIDSortedElemSet &   linkedNodes,
2017                                        SMDSAbs_ElementType  type )
2018 {
2019   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2020   while ( elemIt->more() )
2021   {
2022     const SMDS_MeshElement* elem = elemIt->next();
2023     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2024     if ( elem->GetType() == SMDSAbs_Volume )
2025     {
2026       SMDS_VolumeTool vol( elem );
2027       while ( nodeIt->more() ) {
2028         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2029         if ( theNode != n && vol.IsLinked( theNode, n ))
2030           linkedNodes.insert( n );
2031       }
2032     }
2033     else
2034     {
2035       for ( int i = 0; nodeIt->more(); ++i ) {
2036         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2037         if ( n == theNode ) {
2038           int iBefore = i - 1;
2039           int iAfter  = i + 1;
2040           if ( elem->IsQuadratic() ) {
2041             int nb = elem->NbNodes() / 2;
2042             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2043             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2044           }
2045           linkedNodes.insert( elem->GetNode( iAfter ));
2046           linkedNodes.insert( elem->GetNode( iBefore ));
2047         }
2048       }
2049     }
2050   }
2051 }
2052
2053 //=======================================================================
2054 //function : laplacianSmooth
2055 //purpose  : pulls theNode toward the center of surrounding nodes directly
2056 //           connected to that node along an element edge
2057 //=======================================================================
2058
2059 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2060                      const Handle(Geom_Surface)&          theSurface,
2061                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2062 {
2063   // find surrounding nodes
2064
2065   TIDSortedElemSet nodeSet;
2066   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2067
2068   // compute new coodrs
2069
2070   double coord[] = { 0., 0., 0. };
2071   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2072   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2073     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2074     if ( theSurface.IsNull() ) { // smooth in 3D
2075       coord[0] += node->X();
2076       coord[1] += node->Y();
2077       coord[2] += node->Z();
2078     }
2079     else { // smooth in 2D
2080       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2081       gp_XY* uv = theUVMap[ node ];
2082       coord[0] += uv->X();
2083       coord[1] += uv->Y();
2084     }
2085   }
2086   int nbNodes = nodeSet.size();
2087   if ( !nbNodes )
2088     return;
2089   coord[0] /= nbNodes;
2090   coord[1] /= nbNodes;
2091
2092   if ( !theSurface.IsNull() ) {
2093     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2094     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2095     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2096     coord[0] = p3d.X();
2097     coord[1] = p3d.Y();
2098     coord[2] = p3d.Z();
2099   }
2100   else
2101     coord[2] /= nbNodes;
2102
2103   // move node
2104
2105   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2106 }
2107
2108 //=======================================================================
2109 //function : centroidalSmooth
2110 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2111 //           surrounding elements
2112 //=======================================================================
2113
2114 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2115                       const Handle(Geom_Surface)&          theSurface,
2116                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2117 {
2118   gp_XYZ aNewXYZ(0.,0.,0.);
2119   SMESH::Controls::Area anAreaFunc;
2120   double totalArea = 0.;
2121   int nbElems = 0;
2122
2123   // compute new XYZ
2124
2125   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2126   while ( elemIt->more() )
2127   {
2128     const SMDS_MeshElement* elem = elemIt->next();
2129     nbElems++;
2130
2131     gp_XYZ elemCenter(0.,0.,0.);
2132     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2133     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2134     int nn = elem->NbNodes();
2135     if(elem->IsQuadratic()) nn = nn/2;
2136     int i=0;
2137     //while ( itN->more() ) {
2138     while ( i<nn ) {
2139       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2140       i++;
2141       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2142       aNodePoints.push_back( aP );
2143       if ( !theSurface.IsNull() ) { // smooth in 2D
2144         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2145         gp_XY* uv = theUVMap[ aNode ];
2146         aP.SetCoord( uv->X(), uv->Y(), 0. );
2147       }
2148       elemCenter += aP;
2149     }
2150     double elemArea = anAreaFunc.GetValue( aNodePoints );
2151     totalArea += elemArea;
2152     elemCenter /= nn;
2153     aNewXYZ += elemCenter * elemArea;
2154   }
2155   aNewXYZ /= totalArea;
2156   if ( !theSurface.IsNull() ) {
2157     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2158     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2159   }
2160
2161   // move node
2162
2163   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2164 }
2165
2166 //=======================================================================
2167 //function : getClosestUV
2168 //purpose  : return UV of closest projection
2169 //=======================================================================
2170
2171 static bool getClosestUV (Extrema_GenExtPS& projector,
2172                           const gp_Pnt&     point,
2173                           gp_XY &           result)
2174 {
2175   projector.Perform( point );
2176   if ( projector.IsDone() ) {
2177     double u, v, minVal = DBL_MAX;
2178     for ( int i = projector.NbExt(); i > 0; i-- )
2179       if ( projector.Value( i ) < minVal ) {
2180         minVal = projector.Value( i );
2181         projector.Point( i ).Parameter( u, v );
2182       }
2183     result.SetCoord( u, v );
2184     return true;
2185   }
2186   return false;
2187 }
2188
2189 //=======================================================================
2190 //function : Smooth
2191 //purpose  : Smooth theElements during theNbIterations or until a worst
2192 //           element has aspect ratio <= theTgtAspectRatio.
2193 //           Aspect Ratio varies in range [1.0, inf].
2194 //           If theElements is empty, the whole mesh is smoothed.
2195 //           theFixedNodes contains additionally fixed nodes. Nodes built
2196 //           on edges and boundary nodes are always fixed.
2197 //=======================================================================
2198
2199 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2200                                set<const SMDS_MeshNode*> & theFixedNodes,
2201                                const SmoothMethod          theSmoothMethod,
2202                                const int                   theNbIterations,
2203                                double                      theTgtAspectRatio,
2204                                const bool                  the2D)
2205 {
2206   myLastCreatedElems.Clear();
2207   myLastCreatedNodes.Clear();
2208
2209   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2210
2211   if ( theTgtAspectRatio < 1.0 )
2212     theTgtAspectRatio = 1.0;
2213
2214   const double disttol = 1.e-16;
2215
2216   SMESH::Controls::AspectRatio aQualityFunc;
2217
2218   SMESHDS_Mesh* aMesh = GetMeshDS();
2219
2220   if ( theElems.empty() ) {
2221     // add all faces to theElems
2222     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2223     while ( fIt->more() ) {
2224       const SMDS_MeshElement* face = fIt->next();
2225       theElems.insert( face );
2226     }
2227   }
2228   // get all face ids theElems are on
2229   set< int > faceIdSet;
2230   TIDSortedElemSet::iterator itElem;
2231   if ( the2D )
2232     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2233       int fId = FindShape( *itElem );
2234       // check that corresponding submesh exists and a shape is face
2235       if (fId &&
2236           faceIdSet.find( fId ) == faceIdSet.end() &&
2237           aMesh->MeshElements( fId )) {
2238         TopoDS_Shape F = aMesh->IndexToShape( fId );
2239         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2240           faceIdSet.insert( fId );
2241       }
2242     }
2243   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2244
2245   // ===============================================
2246   // smooth elements on each TopoDS_Face separately
2247   // ===============================================
2248
2249   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2250   for ( ; fId != faceIdSet.rend(); ++fId ) {
2251     // get face surface and submesh
2252     Handle(Geom_Surface) surface;
2253     SMESHDS_SubMesh* faceSubMesh = 0;
2254     TopoDS_Face face;
2255     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2256     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2257     bool isUPeriodic = false, isVPeriodic = false;
2258     if ( *fId ) {
2259       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2260       surface = BRep_Tool::Surface( face );
2261       faceSubMesh = aMesh->MeshElements( *fId );
2262       fToler2 = BRep_Tool::Tolerance( face );
2263       fToler2 *= fToler2 * 10.;
2264       isUPeriodic = surface->IsUPeriodic();
2265       if ( isUPeriodic )
2266         vPeriod = surface->UPeriod();
2267       isVPeriodic = surface->IsVPeriodic();
2268       if ( isVPeriodic )
2269         uPeriod = surface->VPeriod();
2270       surface->Bounds( u1, u2, v1, v2 );
2271     }
2272     // ---------------------------------------------------------
2273     // for elements on a face, find movable and fixed nodes and
2274     // compute UV for them
2275     // ---------------------------------------------------------
2276     bool checkBoundaryNodes = false;
2277     bool isQuadratic = false;
2278     set<const SMDS_MeshNode*> setMovableNodes;
2279     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2280     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2281     list< const SMDS_MeshElement* > elemsOnFace;
2282
2283     Extrema_GenExtPS projector;
2284     GeomAdaptor_Surface surfAdaptor;
2285     if ( !surface.IsNull() ) {
2286       surfAdaptor.Load( surface );
2287       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2288     }
2289     int nbElemOnFace = 0;
2290     itElem = theElems.begin();
2291      // loop on not yet smoothed elements: look for elems on a face
2292     while ( itElem != theElems.end() ) {
2293       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2294         break; // all elements found
2295
2296       const SMDS_MeshElement* elem = *itElem;
2297       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2298           ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2299         ++itElem;
2300         continue;
2301       }
2302       elemsOnFace.push_back( elem );
2303       theElems.erase( itElem++ );
2304       nbElemOnFace++;
2305
2306       if ( !isQuadratic )
2307         isQuadratic = elem->IsQuadratic();
2308
2309       // get movable nodes of elem
2310       const SMDS_MeshNode* node;
2311       SMDS_TypeOfPosition posType;
2312       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2313       int nn = 0, nbn =  elem->NbNodes();
2314       if(elem->IsQuadratic())
2315         nbn = nbn/2;
2316       while ( nn++ < nbn ) {
2317         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2318         const SMDS_PositionPtr& pos = node->GetPosition();
2319         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2320         if (posType != SMDS_TOP_EDGE &&
2321             posType != SMDS_TOP_VERTEX &&
2322             theFixedNodes.find( node ) == theFixedNodes.end())
2323         {
2324           // check if all faces around the node are on faceSubMesh
2325           // because a node on edge may be bound to face
2326           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2327           bool all = true;
2328           if ( faceSubMesh ) {
2329             while ( eIt->more() && all ) {
2330               const SMDS_MeshElement* e = eIt->next();
2331               all = faceSubMesh->Contains( e );
2332             }
2333           }
2334           if ( all )
2335             setMovableNodes.insert( node );
2336           else
2337             checkBoundaryNodes = true;
2338         }
2339         if ( posType == SMDS_TOP_3DSPACE )
2340           checkBoundaryNodes = true;
2341       }
2342
2343       if ( surface.IsNull() )
2344         continue;
2345
2346       // get nodes to check UV
2347       list< const SMDS_MeshNode* > uvCheckNodes;
2348       itN = elem->nodesIterator();
2349       nn = 0; nbn =  elem->NbNodes();
2350       if(elem->IsQuadratic())
2351         nbn = nbn/2;
2352       while ( nn++ < nbn ) {
2353         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2354         if ( uvMap.find( node ) == uvMap.end() )
2355           uvCheckNodes.push_back( node );
2356         // add nodes of elems sharing node
2357 //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2358 //         while ( eIt->more() ) {
2359 //           const SMDS_MeshElement* e = eIt->next();
2360 //           if ( e != elem ) {
2361 //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2362 //             while ( nIt->more() ) {
2363 //               const SMDS_MeshNode* n =
2364 //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2365 //               if ( uvMap.find( n ) == uvMap.end() )
2366 //                 uvCheckNodes.push_back( n );
2367 //             }
2368 //           }
2369 //         }
2370       }
2371       // check UV on face
2372       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2373       for ( ; n != uvCheckNodes.end(); ++n ) {
2374         node = *n;
2375         gp_XY uv( 0, 0 );
2376         const SMDS_PositionPtr& pos = node->GetPosition();
2377         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2378         // get existing UV
2379         switch ( posType ) {
2380         case SMDS_TOP_FACE: {
2381           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2382           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2383           break;
2384         }
2385         case SMDS_TOP_EDGE: {
2386           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2387           Handle(Geom2d_Curve) pcurve;
2388           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2389             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2390           if ( !pcurve.IsNull() ) {
2391             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2392             uv = pcurve->Value( u ).XY();
2393           }
2394           break;
2395         }
2396         case SMDS_TOP_VERTEX: {
2397           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2398           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2399             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2400           break;
2401         }
2402         default:;
2403         }
2404         // check existing UV
2405         bool project = true;
2406         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2407         double dist1 = DBL_MAX, dist2 = 0;
2408         if ( posType != SMDS_TOP_3DSPACE ) {
2409           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2410           project = dist1 > fToler2;
2411         }
2412         if ( project ) { // compute new UV
2413           gp_XY newUV;
2414           if ( !getClosestUV( projector, pNode, newUV )) {
2415             MESSAGE("Node Projection Failed " << node);
2416           }
2417           else {
2418             if ( isUPeriodic )
2419               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2420             if ( isVPeriodic )
2421               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2422             // check new UV
2423             if ( posType != SMDS_TOP_3DSPACE )
2424               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2425             if ( dist2 < dist1 )
2426               uv = newUV;
2427           }
2428         }
2429         // store UV in the map
2430         listUV.push_back( uv );
2431         uvMap.insert( make_pair( node, &listUV.back() ));
2432       }
2433     } // loop on not yet smoothed elements
2434
2435     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2436       checkBoundaryNodes = true;
2437
2438     // fix nodes on mesh boundary
2439
2440     if ( checkBoundaryNodes ) {
2441       typedef pair<const SMDS_MeshNode*, const SMDS_MeshNode*> TLink;
2442       map< TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2443       map< TLink, int >::iterator link_nb;
2444       // put all elements links to linkNbMap
2445       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2446       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2447         const SMDS_MeshElement* elem = (*elemIt);
2448         int nbn =  elem->NbNodes();
2449         if(elem->IsQuadratic())
2450           nbn = nbn/2;
2451         // loop on elem links: insert them in linkNbMap
2452         const SMDS_MeshNode* curNode, *prevNode = elem->GetNode( nbn );
2453         for ( int iN = 0; iN < nbn; ++iN ) {
2454           curNode = elem->GetNode( iN );
2455           TLink link;
2456           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2457           else                      link = make_pair( prevNode , curNode );
2458           prevNode = curNode;
2459           link_nb = linkNbMap.find( link );
2460           if ( link_nb == linkNbMap.end() )
2461             linkNbMap.insert( make_pair ( link, 1 ));
2462           else
2463             link_nb->second++;
2464         }
2465       }
2466       // remove nodes that are in links encountered only once from setMovableNodes
2467       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2468         if ( link_nb->second == 1 ) {
2469           setMovableNodes.erase( link_nb->first.first );
2470           setMovableNodes.erase( link_nb->first.second );
2471         }
2472       }
2473     }
2474
2475     // -----------------------------------------------------
2476     // for nodes on seam edge, compute one more UV ( uvMap2 );
2477     // find movable nodes linked to nodes on seam and which
2478     // are to be smoothed using the second UV ( uvMap2 )
2479     // -----------------------------------------------------
2480
2481     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2482     if ( !surface.IsNull() ) {
2483       TopExp_Explorer eExp( face, TopAbs_EDGE );
2484       for ( ; eExp.More(); eExp.Next() ) {
2485         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2486         if ( !BRep_Tool::IsClosed( edge, face ))
2487           continue;
2488         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2489         if ( !sm ) continue;
2490         // find out which parameter varies for a node on seam
2491         double f,l;
2492         gp_Pnt2d uv1, uv2;
2493         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2494         if ( pcurve.IsNull() ) continue;
2495         uv1 = pcurve->Value( f );
2496         edge.Reverse();
2497         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2498         if ( pcurve.IsNull() ) continue;
2499         uv2 = pcurve->Value( f );
2500         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2501         // assure uv1 < uv2
2502         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2503           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2504         }
2505         // get nodes on seam and its vertices
2506         list< const SMDS_MeshNode* > seamNodes;
2507         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2508         while ( nSeamIt->more() ) {
2509           const SMDS_MeshNode* node = nSeamIt->next();
2510           if ( !isQuadratic || !IsMedium( node ))
2511             seamNodes.push_back( node );
2512         }
2513         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2514         for ( ; vExp.More(); vExp.Next() ) {
2515           sm = aMesh->MeshElements( vExp.Current() );
2516           if ( sm ) {
2517             nSeamIt = sm->GetNodes();
2518             while ( nSeamIt->more() )
2519               seamNodes.push_back( nSeamIt->next() );
2520           }
2521         }
2522         // loop on nodes on seam
2523         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2524         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2525           const SMDS_MeshNode* nSeam = *noSeIt;
2526           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2527           if ( n_uv == uvMap.end() )
2528             continue;
2529           // set the first UV
2530           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2531           // set the second UV
2532           listUV.push_back( *n_uv->second );
2533           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2534           if ( uvMap2.empty() )
2535             uvMap2 = uvMap; // copy the uvMap contents
2536           uvMap2[ nSeam ] = &listUV.back();
2537
2538           // collect movable nodes linked to ones on seam in nodesNearSeam
2539           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2540           while ( eIt->more() ) {
2541             const SMDS_MeshElement* e = eIt->next();
2542             int nbUseMap1 = 0, nbUseMap2 = 0;
2543             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2544             int nn = 0, nbn =  e->NbNodes();
2545             if(e->IsQuadratic()) nbn = nbn/2;
2546             while ( nn++ < nbn )
2547             {
2548               const SMDS_MeshNode* n =
2549                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2550               if (n == nSeam ||
2551                   setMovableNodes.find( n ) == setMovableNodes.end() )
2552                 continue;
2553               // add only nodes being closer to uv2 than to uv1
2554               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2555                            0.5 * ( n->Y() + nSeam->Y() ),
2556                            0.5 * ( n->Z() + nSeam->Z() ));
2557               gp_XY uv;
2558               getClosestUV( projector, pMid, uv );
2559               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2560                 nodesNearSeam.insert( n );
2561                 nbUseMap2++;
2562               }
2563               else
2564                 nbUseMap1++;
2565             }
2566             // for centroidalSmooth all element nodes must
2567             // be on one side of a seam
2568             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2569               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2570               nn = 0;
2571               while ( nn++ < nbn ) {
2572                 const SMDS_MeshNode* n =
2573                   static_cast<const SMDS_MeshNode*>( nIt->next() );
2574                 setMovableNodes.erase( n );
2575               }
2576             }
2577           }
2578         } // loop on nodes on seam
2579       } // loop on edge of a face
2580     } // if ( !face.IsNull() )
2581
2582     if ( setMovableNodes.empty() ) {
2583       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2584       continue; // goto next face
2585     }
2586
2587     // -------------
2588     // SMOOTHING //
2589     // -------------
2590
2591     int it = -1;
2592     double maxRatio = -1., maxDisplacement = -1.;
2593     set<const SMDS_MeshNode*>::iterator nodeToMove;
2594     for ( it = 0; it < theNbIterations; it++ ) {
2595       maxDisplacement = 0.;
2596       nodeToMove = setMovableNodes.begin();
2597       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2598         const SMDS_MeshNode* node = (*nodeToMove);
2599         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2600
2601         // smooth
2602         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2603         if ( theSmoothMethod == LAPLACIAN )
2604           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2605         else
2606           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2607
2608         // node displacement
2609         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2610         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2611         if ( aDispl > maxDisplacement )
2612           maxDisplacement = aDispl;
2613       }
2614       // no node movement => exit
2615       //if ( maxDisplacement < 1.e-16 ) {
2616       if ( maxDisplacement < disttol ) {
2617         MESSAGE("-- no node movement --");
2618         break;
2619       }
2620
2621       // check elements quality
2622       maxRatio  = 0;
2623       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2624       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2625         const SMDS_MeshElement* elem = (*elemIt);
2626         if ( !elem || elem->GetType() != SMDSAbs_Face )
2627           continue;
2628         SMESH::Controls::TSequenceOfXYZ aPoints;
2629         if ( aQualityFunc.GetPoints( elem, aPoints )) {
2630           double aValue = aQualityFunc.GetValue( aPoints );
2631           if ( aValue > maxRatio )
2632             maxRatio = aValue;
2633         }
2634       }
2635       if ( maxRatio <= theTgtAspectRatio ) {
2636         MESSAGE("-- quality achived --");
2637         break;
2638       }
2639       if (it+1 == theNbIterations) {
2640         MESSAGE("-- Iteration limit exceeded --");
2641       }
2642     } // smoothing iterations
2643
2644     MESSAGE(" Face id: " << *fId <<
2645             " Nb iterstions: " << it <<
2646             " Displacement: " << maxDisplacement <<
2647             " Aspect Ratio " << maxRatio);
2648
2649     // ---------------------------------------
2650     // new nodes positions are computed,
2651     // record movement in DS and set new UV
2652     // ---------------------------------------
2653     nodeToMove = setMovableNodes.begin();
2654     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2655       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2656       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2657       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2658       if ( node_uv != uvMap.end() ) {
2659         gp_XY* uv = node_uv->second;
2660         node->SetPosition
2661           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2662       }
2663     }
2664
2665     // move medium nodes of quadratic elements
2666     if ( isQuadratic )
2667     {
2668       SMESH_MesherHelper helper( *GetMesh() );
2669       if ( !face.IsNull() )
2670         helper.SetSubShape( face );
2671       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2672       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2673         const SMDS_QuadraticFaceOfNodes* QF =
2674           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2675         if(QF) {
2676           vector<const SMDS_MeshNode*> Ns;
2677           Ns.reserve(QF->NbNodes()+1);
2678           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2679           while ( anIter->more() )
2680             Ns.push_back( anIter->next() );
2681           Ns.push_back( Ns[0] );
2682           double x, y, z;
2683           for(int i=0; i<QF->NbNodes(); i=i+2) {
2684             if ( !surface.IsNull() ) {
2685               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2686               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2687               gp_XY uv = ( uv1 + uv2 ) / 2.;
2688               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2689               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2690             }
2691             else {
2692               x = (Ns[i]->X() + Ns[i+2]->X())/2;
2693               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2694               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2695             }
2696             if( fabs( Ns[i+1]->X() - x ) > disttol ||
2697                 fabs( Ns[i+1]->Y() - y ) > disttol ||
2698                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2699               // we have to move i+1 node
2700               aMesh->MoveNode( Ns[i+1], x, y, z );
2701             }
2702           }
2703         }
2704       }
2705     }
2706
2707   } // loop on face ids
2708
2709 }
2710
2711 //=======================================================================
2712 //function : isReverse
2713 //purpose  : Return true if normal of prevNodes is not co-directied with
2714 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2715 //           iNotSame is where prevNodes and nextNodes are different
2716 //=======================================================================
2717
2718 static bool isReverse(const SMDS_MeshNode* prevNodes[],
2719                       const SMDS_MeshNode* nextNodes[],
2720                       const int            nbNodes,
2721                       const int            iNotSame)
2722 {
2723   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2724   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2725
2726   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2727   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2728   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2729   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2730
2731   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2732   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2733   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2734   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2735
2736   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2737
2738   return (vA ^ vB) * vN < 0.0;
2739 }
2740
2741 //=======================================================================
2742 //function : sweepElement
2743 //purpose  :
2744 //=======================================================================
2745
2746 static void sweepElement(SMESHDS_Mesh*                         aMesh,
2747                          const SMDS_MeshElement*               elem,
2748                          const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2749                          list<const SMDS_MeshElement*>&        newElems,
2750                          const int nbSteps,
2751                          SMESH_SequenceOfElemPtr& myLastCreatedElems)
2752 {
2753   // Loop on elem nodes:
2754   // find new nodes and detect same nodes indices
2755   int nbNodes = elem->NbNodes();
2756   //---PR
2757   //list<const SMDS_MeshNode*>::const_iterator itNN[ nbNodes ];
2758   vector < list< const SMDS_MeshNode* >::const_iterator > itNN;
2759   itNN.reserve(nbNodes);
2760   //---PR
2761   const SMDS_MeshNode* prevNod[ nbNodes ], *nextNod[ nbNodes ], *midlNod[ nbNodes ];
2762   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2763   vector<int> sames(nbNodes);
2764
2765   bool issimple[nbNodes];
2766
2767   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2768     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2769     const SMDS_MeshNode*                 node         = nnIt->first;
2770     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2771     if ( listNewNodes.empty() )
2772       return;
2773
2774     if(listNewNodes.size()==nbSteps) {
2775       issimple[iNode] = true;
2776     }
2777     else {
2778       issimple[iNode] = false;
2779     }
2780
2781     itNN[ iNode ] = listNewNodes.begin();
2782     prevNod[ iNode ] = node;
2783     nextNod[ iNode ] = listNewNodes.front();
2784 //cout<<"iNode="<<iNode<<endl;
2785 //cout<<" prevNod[iNode]="<< prevNod[iNode]<<" nextNod[iNode]="<< nextNod[iNode]<<endl;
2786     if ( prevNod[ iNode ] != nextNod [ iNode ])
2787       iNotSameNode = iNode;
2788     else {
2789       iSameNode = iNode;
2790       //nbSame++;
2791       sames[nbSame++] = iNode;
2792     }
2793   }
2794 //cout<<"1 nbSame="<<nbSame<<endl;
2795   if ( nbSame == nbNodes || nbSame > 2) {
2796     MESSAGE( " Too many same nodes of element " << elem->GetID() );
2797     return;
2798   }
2799
2800 //  if( elem->IsQuadratic() && nbSame>0 ) {
2801 //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2802 //    return;
2803 //  }
2804
2805   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2806   if ( nbSame > 0 ) {
2807     iBeforeSame = ( iSameNode == 0 ? nbNodes - 1 : iSameNode - 1 );
2808     iAfterSame  = ( iSameNode + 1 == nbNodes ? 0 : iSameNode + 1 );
2809     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
2810   }
2811
2812 //if(nbNodes==8)
2813 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2814 //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2815 //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2816 //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2817
2818   // check element orientation
2819   int i0 = 0, i2 = 2;
2820   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2821     //MESSAGE("Reversed elem " << elem );
2822     i0 = 2;
2823     i2 = 0;
2824     if ( nbSame > 0 ) {
2825       int iAB = iAfterSame + iBeforeSame;
2826       iBeforeSame = iAB - iBeforeSame;
2827       iAfterSame  = iAB - iAfterSame;
2828     }
2829   }
2830
2831   // make new elements
2832   int iStep;//, nbSteps = newNodesItVec[ 0 ]->second.size();
2833   for (iStep = 0; iStep < nbSteps; iStep++ ) {
2834     // get next nodes
2835     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2836       if(issimple[iNode]) {
2837         nextNod[ iNode ] = *itNN[ iNode ];
2838         itNN[ iNode ]++;
2839       }
2840       else {
2841         if( elem->GetType()==SMDSAbs_Node ) {
2842           // we have to use two nodes
2843           midlNod[ iNode ] = *itNN[ iNode ];
2844           itNN[ iNode ]++;
2845           nextNod[ iNode ] = *itNN[ iNode ];
2846           itNN[ iNode ]++;
2847         }
2848         else if(!elem->IsQuadratic() ||
2849            elem->IsQuadratic() && elem->IsMediumNode(prevNod[iNode]) ) {
2850           // we have to use each second node
2851           itNN[ iNode ]++;
2852           nextNod[ iNode ] = *itNN[ iNode ];
2853           itNN[ iNode ]++;
2854         }
2855         else {
2856           // we have to use two nodes
2857           midlNod[ iNode ] = *itNN[ iNode ];
2858           itNN[ iNode ]++;
2859           nextNod[ iNode ] = *itNN[ iNode ];
2860           itNN[ iNode ]++;
2861         }
2862       }
2863     }
2864     SMDS_MeshElement* aNewElem = 0;
2865     if(!elem->IsPoly()) {
2866       switch ( nbNodes ) {
2867       case 0:
2868         return;
2869       case 1: { // NODE
2870         if ( nbSame == 0 ) {
2871           if(issimple[0])
2872             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2873           else
2874             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2875         }
2876         break;
2877       }
2878       case 2: { // EDGE
2879         if ( nbSame == 0 )
2880           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2881                                     nextNod[ 1 ], nextNod[ 0 ] );
2882         else
2883           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2884                                     nextNod[ iNotSameNode ] );
2885         break;
2886       }
2887
2888       case 3: { // TRIANGLE or quadratic edge
2889         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2890
2891           if ( nbSame == 0 )       // --- pentahedron
2892             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2893                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2894
2895           else if ( nbSame == 1 )  // --- pyramid
2896             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
2897                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2898                                          nextNod[ iSameNode ]);
2899
2900           else // 2 same nodes:      --- tetrahedron
2901             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2902                                          nextNod[ iNotSameNode ]);
2903         }
2904         else { // quadratic edge
2905           if(nbSame==0) {     // quadratic quadrangle
2906             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2907                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2908           }
2909           else if(nbSame==1) { // quadratic triangle
2910             if(sames[0]==2)
2911               return; // medium node on axis
2912             else if(sames[0]==0) {
2913               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2914                                         nextNod[2], midlNod[1], prevNod[2]);
2915             }
2916             else { // sames[0]==1
2917               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2918                                         midlNod[0], nextNod[2], prevNod[2]);
2919             }
2920           }
2921           else
2922             return;
2923         }
2924         break;
2925       }
2926       case 4: { // QUADRANGLE
2927
2928         if ( nbSame == 0 )       // --- hexahedron
2929           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2930                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2931
2932         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2933           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
2934                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2935                                        nextNod[ iSameNode ]);
2936           newElems.push_back( aNewElem );
2937           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2938                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
2939                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
2940         }
2941         else if ( nbSame == 2 ) { // pentahedron
2942           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2943             // iBeforeSame is same too
2944             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2945                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
2946                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
2947           else
2948             // iAfterSame is same too
2949             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2950                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2951                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
2952         }
2953         break;
2954       }
2955       case 6: { // quadratic triangle
2956         // create pentahedron with 15 nodes
2957         if(i0>0) { // reversed case
2958           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2959                                        nextNod[0], nextNod[2], nextNod[1],
2960                                        prevNod[5], prevNod[4], prevNod[3],
2961                                        nextNod[5], nextNod[4], nextNod[3],
2962                                        midlNod[0], midlNod[2], midlNod[1]);
2963         }
2964         else { // not reversed case
2965           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2966                                        nextNod[0], nextNod[1], nextNod[2],
2967                                        prevNod[3], prevNod[4], prevNod[5],
2968                                        nextNod[3], nextNod[4], nextNod[5],
2969                                        midlNod[0], midlNod[1], midlNod[2]);
2970         }
2971         break;
2972       }
2973       case 8: { // quadratic quadrangle
2974         // create hexahedron with 20 nodes
2975         if(i0>0) { // reversed case
2976           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
2977                                        nextNod[0], nextNod[3], nextNod[2], nextNod[1],
2978                                        prevNod[7], prevNod[6], prevNod[5], prevNod[4],
2979                                        nextNod[7], nextNod[6], nextNod[5], nextNod[4],
2980                                        midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
2981         }
2982         else { // not reversed case
2983           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
2984                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
2985                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
2986                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
2987                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
2988         }
2989         break;
2990       }
2991       default: {
2992         // realized for extrusion only
2993         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
2994         //vector<int> quantities (nbNodes + 2);
2995
2996         //quantities[0] = nbNodes; // bottom of prism
2997         //for (int inode = 0; inode < nbNodes; inode++) {
2998         //  polyedre_nodes[inode] = prevNod[inode];
2999         //}
3000
3001         //quantities[1] = nbNodes; // top of prism
3002         //for (int inode = 0; inode < nbNodes; inode++) {
3003         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3004         //}
3005
3006         //for (int iface = 0; iface < nbNodes; iface++) {
3007         //  quantities[iface + 2] = 4;
3008         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3009         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3010         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3011         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3012         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3013         //}
3014         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3015         break;
3016       }
3017       }
3018     }
3019
3020     if(!aNewElem) {
3021       // realized for extrusion only
3022       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3023       vector<int> quantities (nbNodes + 2);
3024
3025       quantities[0] = nbNodes; // bottom of prism
3026       for (int inode = 0; inode < nbNodes; inode++) {
3027         polyedre_nodes[inode] = prevNod[inode];
3028       }
3029
3030       quantities[1] = nbNodes; // top of prism
3031       for (int inode = 0; inode < nbNodes; inode++) {
3032         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3033       }
3034
3035       for (int iface = 0; iface < nbNodes; iface++) {
3036         quantities[iface + 2] = 4;
3037         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3038         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3039         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3040         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3041         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3042       }
3043       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3044     }
3045
3046     if ( aNewElem ) {
3047       newElems.push_back( aNewElem );
3048       myLastCreatedElems.Append(aNewElem);
3049     }
3050
3051     // set new prev nodes
3052     for ( iNode = 0; iNode < nbNodes; iNode++ )
3053       prevNod[ iNode ] = nextNod[ iNode ];
3054
3055   } // for steps
3056 }
3057
3058 //=======================================================================
3059 //function : makeWalls
3060 //purpose  : create 1D and 2D elements around swept elements
3061 //=======================================================================
3062
3063 static void makeWalls (SMESHDS_Mesh*            aMesh,
3064                        TNodeOfNodeListMap &     mapNewNodes,
3065                        TElemOfElemListMap &     newElemsMap,
3066                        TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3067                        TIDSortedElemSet&        elemSet,
3068                        const int                nbSteps,
3069                        SMESH_SequenceOfElemPtr& myLastCreatedElems)
3070 {
3071   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3072
3073   // Find nodes belonging to only one initial element - sweep them to get edges.
3074
3075   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3076   for ( ; nList != mapNewNodes.end(); nList++ ) {
3077     const SMDS_MeshNode* node =
3078       static_cast<const SMDS_MeshNode*>( nList->first );
3079     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3080     int nbInitElems = 0;
3081     const SMDS_MeshElement* el = 0;
3082     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3083     while ( eIt->more() && nbInitElems < 2 ) {
3084       el = eIt->next();
3085       SMDSAbs_ElementType type = el->GetType();
3086       if ( type == SMDSAbs_Volume || type < highType ) continue;
3087       if ( type > highType ) {
3088         nbInitElems = 0;
3089         highType = type;
3090       }
3091       if ( elemSet.find(el) != elemSet.end() )
3092         nbInitElems++;
3093     }
3094     if ( nbInitElems < 2 ) {
3095       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3096       if(!NotCreateEdge) {
3097         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3098         list<const SMDS_MeshElement*> newEdges;
3099         sweepElement( aMesh, node, newNodesItVec, newEdges, nbSteps, myLastCreatedElems );
3100       }
3101     }
3102   }
3103
3104   // Make a ceiling for each element ie an equal element of last new nodes.
3105   // Find free links of faces - make edges and sweep them into faces.
3106
3107   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3108   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3109   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3110     const SMDS_MeshElement* elem = itElem->first;
3111     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3112
3113     if ( elem->GetType() == SMDSAbs_Edge ) {
3114       // create a ceiling edge
3115       if (!elem->IsQuadratic()) {
3116         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3117                                vecNewNodes[ 1 ]->second.back()))
3118           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3119                                                    vecNewNodes[ 1 ]->second.back()));
3120       }
3121       else {
3122         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3123                                vecNewNodes[ 1 ]->second.back(),
3124                                vecNewNodes[ 2 ]->second.back()))
3125           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3126                                                    vecNewNodes[ 1 ]->second.back(),
3127                                                    vecNewNodes[ 2 ]->second.back()));
3128       }
3129     }
3130     if ( elem->GetType() != SMDSAbs_Face )
3131       continue;
3132
3133     if(itElem->second.size()==0) continue;
3134
3135     bool hasFreeLinks = false;
3136
3137     TIDSortedElemSet avoidSet;
3138     avoidSet.insert( elem );
3139
3140     set<const SMDS_MeshNode*> aFaceLastNodes;
3141     int iNode, nbNodes = vecNewNodes.size();
3142     if(!elem->IsQuadratic()) {
3143       // loop on the face nodes
3144       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3145         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3146         // look for free links of the face
3147         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3148         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3149         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3150         // check if a link is free
3151         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3152           hasFreeLinks = true;
3153           // make an edge and a ceiling for a new edge
3154           if ( !aMesh->FindEdge( n1, n2 )) {
3155             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 ));
3156           }
3157           n1 = vecNewNodes[ iNode ]->second.back();
3158           n2 = vecNewNodes[ iNext ]->second.back();
3159           if ( !aMesh->FindEdge( n1, n2 )) {
3160             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 ));
3161           }
3162         }
3163       }
3164     }
3165     else { // elem is quadratic face
3166       int nbn = nbNodes/2;
3167       for ( iNode = 0; iNode < nbn; iNode++ ) {
3168         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3169         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3170         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3171         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3172         // check if a link is free
3173         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3174           hasFreeLinks = true;
3175           // make an edge and a ceiling for a new edge
3176           // find medium node
3177           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3178           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3179             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 ));
3180           }
3181           n1 = vecNewNodes[ iNode ]->second.back();
3182           n2 = vecNewNodes[ iNext ]->second.back();
3183           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3184           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3185             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 ));
3186           }
3187         }
3188       }
3189       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3190         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3191       }
3192     }
3193
3194     // sweep free links into faces
3195
3196     if ( hasFreeLinks )  {
3197       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3198       int iStep; //, nbSteps = vecNewNodes[0]->second.size();
3199       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3200
3201       set<const SMDS_MeshNode*> initNodeSet, faceNodeSet;
3202       for ( iNode = 0; iNode < nbNodes; iNode++ )
3203         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3204
3205       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3206         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3207         iVol = 0;
3208         while ( iVol++ < volNb ) v++;
3209         // find indices of free faces of a volume
3210         list< int > fInd;
3211         SMDS_VolumeTool vTool( *v );
3212         int iF, nbF = vTool.NbFaces();
3213         for ( iF = 0; iF < nbF; iF ++ ) {
3214           if (vTool.IsFreeFace( iF ) &&
3215               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3216               initNodeSet != faceNodeSet) // except an initial face
3217             fInd.push_back( iF );
3218         }
3219         if ( fInd.empty() )
3220           continue;
3221
3222         // create faces for all steps
3223         // if such a face has been already created by sweep of edge, assure that its orientation is OK
3224         for ( iStep = 0; iStep < nbSteps; iStep++ )  {
3225           vTool.Set( *v );
3226           vTool.SetExternalNormal();
3227           list< int >::iterator ind = fInd.begin();
3228           for ( ; ind != fInd.end(); ind++ ) {
3229             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3230             int nbn = vTool.NbFaceNodes( *ind );
3231             switch ( nbn ) {
3232             case 3: { ///// triangle
3233               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3234               if ( !f )
3235                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3236               else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3237                 aMesh->ChangeElementNodes( f, nodes, nbn );
3238               break;
3239             }
3240             case 4: { ///// quadrangle
3241               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3242               if ( !f )
3243                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3244               else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3245                 aMesh->ChangeElementNodes( f, nodes, nbn );
3246               break;
3247             }
3248             default:
3249               if( (*v)->IsQuadratic() ) {
3250                 if(nbn==6) { /////// quadratic triangle
3251                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3252                                                              nodes[1], nodes[3], nodes[5] );
3253                   if ( !f )
3254                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3255                                                              nodes[1], nodes[3], nodes[5]));
3256                   else if ( nodes[ 2 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3257                     aMesh->ChangeElementNodes( f, nodes, nbn );
3258                 }
3259                 else {       /////// quadratic quadrangle
3260                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3261                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3262                   if ( !f )
3263                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3264                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3265                   else if ( nodes[ 2 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3266                     aMesh->ChangeElementNodes( f, nodes, nbn );
3267                 }
3268               }
3269               else { //////// polygon
3270                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3271                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3272                 if ( !f )
3273                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3274                 else if ( nodes[ 1 ] != f->GetNode( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3275                   aMesh->ChangeElementNodes( f, nodes, nbn );
3276               }
3277             }
3278           }
3279           // go to the next volume
3280           iVol = 0;
3281           while ( iVol++ < nbVolumesByStep ) v++;
3282         }
3283       }
3284     } // sweep free links into faces
3285
3286     // make a ceiling face with a normal external to a volume
3287
3288     SMDS_VolumeTool lastVol( itElem->second.back() );
3289
3290     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3291     if ( iF >= 0 ) {
3292       lastVol.SetExternalNormal();
3293       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3294       int nbn = lastVol.NbFaceNodes( iF );
3295       switch ( nbn ) {
3296       case 3:
3297         if (!hasFreeLinks ||
3298             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3299           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3300         break;
3301       case 4:
3302         if (!hasFreeLinks ||
3303             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3304           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3305         break;
3306       default:
3307         if(itElem->second.back()->IsQuadratic()) {
3308           if(nbn==6) {
3309             if (!hasFreeLinks ||
3310                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3311                                  nodes[1], nodes[3], nodes[5]) ) {
3312               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3313                                                        nodes[1], nodes[3], nodes[5]));
3314             }
3315           }
3316           else { // nbn==8
3317             if (!hasFreeLinks ||
3318                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3319                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3320               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3321                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3322           }
3323         }
3324         else {
3325           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3326           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3327             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3328         }
3329       } // switch
3330     }
3331   } // loop on swept elements
3332 }
3333
3334 //=======================================================================
3335 //function : RotationSweep
3336 //purpose  :
3337 //=======================================================================
3338
3339 void SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3340                                      const gp_Ax1&      theAxis,
3341                                      const double       theAngle,
3342                                      const int          theNbSteps,
3343                                      const double       theTol,
3344                                      const bool         theMakeWalls)
3345 {
3346   myLastCreatedElems.Clear();
3347   myLastCreatedNodes.Clear();
3348
3349   MESSAGE( "RotationSweep()");
3350   gp_Trsf aTrsf;
3351   aTrsf.SetRotation( theAxis, theAngle );
3352   gp_Trsf aTrsf2;
3353   aTrsf2.SetRotation( theAxis, theAngle/2. );
3354
3355   gp_Lin aLine( theAxis );
3356   double aSqTol = theTol * theTol;
3357
3358   SMESHDS_Mesh* aMesh = GetMeshDS();
3359
3360   TNodeOfNodeListMap mapNewNodes;
3361   TElemOfVecOfNnlmiMap mapElemNewNodes;
3362   TElemOfElemListMap newElemsMap;
3363
3364   // loop on theElems
3365   TIDSortedElemSet::iterator itElem;
3366   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3367     const SMDS_MeshElement* elem = *itElem;
3368     if ( !elem || elem->GetType() == SMDSAbs_Volume )
3369       continue;
3370     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3371     newNodesItVec.reserve( elem->NbNodes() );
3372
3373     // loop on elem nodes
3374     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3375     while ( itN->more() ) {
3376
3377       // check if a node has been already sweeped
3378       const SMDS_MeshNode* node =
3379         static_cast<const SMDS_MeshNode*>( itN->next() );
3380       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3381       if ( nIt == mapNewNodes.end() ) {
3382         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3383         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3384
3385         // make new nodes
3386         gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3387         double coord[3];
3388         aXYZ.Coord( coord[0], coord[1], coord[2] );
3389         bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3390         const SMDS_MeshNode * newNode = node;
3391         for ( int i = 0; i < theNbSteps; i++ ) {
3392           if ( !isOnAxis ) {
3393             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3394               // create two nodes
3395               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3396               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3397               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3398               myLastCreatedNodes.Append(newNode);
3399               listNewNodes.push_back( newNode );
3400               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3401               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3402             }
3403             else {
3404               aTrsf.Transforms( coord[0], coord[1], coord[2] );
3405             }
3406             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3407             myLastCreatedNodes.Append(newNode);
3408           }
3409           listNewNodes.push_back( newNode );
3410         }
3411       }
3412       else {
3413         // if current elem is quadratic and current node is not medium
3414         // we have to check - may be it is needed to insert additional nodes
3415         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3416           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3417           if(listNewNodes.size()==theNbSteps) {
3418             listNewNodes.clear();
3419             // make new nodes
3420             gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3421             double coord[3];
3422             aXYZ.Coord( coord[0], coord[1], coord[2] );
3423             const SMDS_MeshNode * newNode = node;
3424             for(int i = 0; i<theNbSteps; i++) {
3425               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3426               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3427               myLastCreatedNodes.Append(newNode);
3428               listNewNodes.push_back( newNode );
3429               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3430               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3431               myLastCreatedNodes.Append(newNode);
3432               listNewNodes.push_back( newNode );
3433             }
3434           }
3435         }
3436       }
3437       newNodesItVec.push_back( nIt );
3438     }
3439     // make new elements
3440     sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], theNbSteps, myLastCreatedElems );
3441   }
3442
3443   if ( theMakeWalls )
3444     makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes,
3445                theElems, theNbSteps, myLastCreatedElems );
3446 }
3447
3448
3449 //=======================================================================
3450 //function : CreateNode
3451 //purpose  :
3452 //=======================================================================
3453 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3454                                                   const double y,
3455                                                   const double z,
3456                                                   const double tolnode,
3457                                                   SMESH_SequenceOfNode& aNodes)
3458 {
3459   myLastCreatedElems.Clear();
3460   myLastCreatedNodes.Clear();
3461
3462   gp_Pnt P1(x,y,z);
3463   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3464
3465   // try to search in sequence of existing nodes
3466   // if aNodes.Length()>0 we 'nave to use given sequence
3467   // else - use all nodes of mesh
3468   if(aNodes.Length()>0) {
3469     int i;
3470     for(i=1; i<=aNodes.Length(); i++) {
3471       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3472       if(P1.Distance(P2)<tolnode)
3473         return aNodes.Value(i);
3474     }
3475   }
3476   else {
3477     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3478     while(itn->more()) {
3479       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3480       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3481       if(P1.Distance(P2)<tolnode)
3482         return aN;
3483     }
3484   }
3485
3486   // create new node and return it
3487   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3488   myLastCreatedNodes.Append(NewNode);
3489   return NewNode;
3490 }
3491
3492
3493 //=======================================================================
3494 //function : ExtrusionSweep
3495 //purpose  :
3496 //=======================================================================
3497
3498 void SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
3499                                        const gp_Vec&       theStep,
3500                                        const int           theNbSteps,
3501                                        TElemOfElemListMap& newElemsMap,
3502                                        const int           theFlags,
3503                                        const double        theTolerance)
3504 {
3505   ExtrusParam aParams;
3506   aParams.myDir = gp_Dir(theStep);
3507   aParams.myNodes.Clear();
3508   aParams.mySteps = new TColStd_HSequenceOfReal;
3509   int i;
3510   for(i=1; i<=theNbSteps; i++)
3511     aParams.mySteps->Append(theStep.Magnitude());
3512
3513   ExtrusionSweep(theElems,aParams,newElemsMap,theFlags,theTolerance);
3514
3515 }
3516
3517
3518 //=======================================================================
3519 //function : ExtrusionSweep
3520 //purpose  :
3521 //=======================================================================
3522
3523 void SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
3524                                        ExtrusParam&        theParams,
3525                                        TElemOfElemListMap& newElemsMap,
3526                                        const int           theFlags,
3527                                        const double        theTolerance)
3528 {
3529   myLastCreatedElems.Clear();
3530   myLastCreatedNodes.Clear();
3531
3532   SMESHDS_Mesh* aMesh = GetMeshDS();
3533
3534   int nbsteps = theParams.mySteps->Length();
3535
3536   TNodeOfNodeListMap mapNewNodes;
3537   //TNodeOfNodeVecMap mapNewNodes;
3538   TElemOfVecOfNnlmiMap mapElemNewNodes;
3539   //TElemOfVecOfMapNodesMap mapElemNewNodes;
3540
3541   // loop on theElems
3542   TIDSortedElemSet::iterator itElem;
3543   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3544     // check element type
3545     const SMDS_MeshElement* elem = *itElem;
3546     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
3547       continue;
3548
3549     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3550     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3551     newNodesItVec.reserve( elem->NbNodes() );
3552
3553     // loop on elem nodes
3554     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3555     while ( itN->more() ) {
3556
3557       // check if a node has been already sweeped
3558       const SMDS_MeshNode* node =
3559         static_cast<const SMDS_MeshNode*>( itN->next() );
3560       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3561       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3562       if ( nIt == mapNewNodes.end() ) {
3563         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3564         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3565         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3566         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3567         //vecNewNodes.reserve(nbsteps);
3568
3569         // make new nodes
3570         double coord[] = { node->X(), node->Y(), node->Z() };
3571         //int nbsteps = theParams.mySteps->Length();
3572         for ( int i = 0; i < nbsteps; i++ ) {
3573           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3574             // create additional node
3575             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3576             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3577             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3578             if( theFlags & EXTRUSION_FLAG_SEW ) {
3579               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3580                                                          theTolerance, theParams.myNodes);
3581               listNewNodes.push_back( newNode );
3582             }
3583             else {
3584               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3585               myLastCreatedNodes.Append(newNode);
3586               listNewNodes.push_back( newNode );
3587             }
3588           }
3589           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3590           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3591           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3592           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3593           if( theFlags & EXTRUSION_FLAG_SEW ) {
3594             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3595                                                        theTolerance, theParams.myNodes);
3596             listNewNodes.push_back( newNode );
3597             //vecNewNodes[i]=newNode;
3598           }
3599           else {
3600             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3601             myLastCreatedNodes.Append(newNode);
3602             listNewNodes.push_back( newNode );
3603             //vecNewNodes[i]=newNode;
3604           }
3605         }
3606       }
3607       else {
3608         // if current elem is quadratic and current node is not medium
3609         // we have to check - may be it is needed to insert additional nodes
3610         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3611           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3612           if(listNewNodes.size()==nbsteps) {
3613             listNewNodes.clear();
3614             double coord[] = { node->X(), node->Y(), node->Z() };
3615             for ( int i = 0; i < nbsteps; i++ ) {
3616               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3617               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3618               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3619               if( theFlags & EXTRUSION_FLAG_SEW ) {
3620                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3621                                                            theTolerance, theParams.myNodes);
3622                 listNewNodes.push_back( newNode );
3623               }
3624               else {
3625                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3626                 myLastCreatedNodes.Append(newNode);
3627                 listNewNodes.push_back( newNode );
3628               }
3629               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3630               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3631               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3632               if( theFlags & EXTRUSION_FLAG_SEW ) {
3633                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3634                                                            theTolerance, theParams.myNodes);
3635                 listNewNodes.push_back( newNode );
3636               }
3637               else {
3638                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3639                 myLastCreatedNodes.Append(newNode);
3640                 listNewNodes.push_back( newNode );
3641               }
3642             }
3643           }
3644         }
3645       }
3646       newNodesItVec.push_back( nIt );
3647     }
3648     // make new elements
3649     sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem], nbsteps, myLastCreatedElems );
3650   }
3651
3652   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3653     makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, myLastCreatedElems );
3654   }
3655 }
3656
3657
3658 //=======================================================================
3659 //class    : SMESH_MeshEditor_PathPoint
3660 //purpose  : auxiliary class
3661 //=======================================================================
3662 class SMESH_MeshEditor_PathPoint {
3663 public:
3664   SMESH_MeshEditor_PathPoint() {
3665     myPnt.SetCoord(99., 99., 99.);
3666     myTgt.SetCoord(1.,0.,0.);
3667     myAngle=0.;
3668     myPrm=0.;
3669   }
3670   void SetPnt(const gp_Pnt& aP3D){
3671     myPnt=aP3D;
3672   }
3673   void SetTangent(const gp_Dir& aTgt){
3674     myTgt=aTgt;
3675   }
3676   void SetAngle(const double& aBeta){
3677     myAngle=aBeta;
3678   }
3679   void SetParameter(const double& aPrm){
3680     myPrm=aPrm;
3681   }
3682   const gp_Pnt& Pnt()const{
3683     return myPnt;
3684   }
3685   const gp_Dir& Tangent()const{
3686     return myTgt;
3687   }
3688   double Angle()const{
3689     return myAngle;
3690   }
3691   double Parameter()const{
3692     return myPrm;
3693   }
3694
3695 protected:
3696   gp_Pnt myPnt;
3697   gp_Dir myTgt;
3698   double myAngle;
3699   double myPrm;
3700 };
3701
3702 //=======================================================================
3703 //function : ExtrusionAlongTrack
3704 //purpose  :
3705 //=======================================================================
3706 SMESH_MeshEditor::Extrusion_Error
3707   SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
3708                                          SMESH_subMesh*       theTrack,
3709                                          const SMDS_MeshNode* theN1,
3710                                          const bool           theHasAngles,
3711                                          list<double>&        theAngles,
3712                                          const bool           theHasRefPoint,
3713                                          const gp_Pnt&        theRefPoint)
3714 {
3715   myLastCreatedElems.Clear();
3716   myLastCreatedNodes.Clear();
3717
3718   MESSAGE("SMESH_MeshEditor::ExtrusionAlongTrack")
3719   int j, aNbTP, aNbE, aNb;
3720   double aT1, aT2, aT, aAngle, aX, aY, aZ;
3721   std::list<double> aPrms;
3722   std::list<double>::iterator aItD;
3723   TIDSortedElemSet::iterator itElem;
3724
3725   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
3726   gp_Pnt aP3D, aV0;
3727   gp_Vec aVec;
3728   gp_XYZ aGC;
3729   Handle(Geom_Curve) aC3D;
3730   TopoDS_Edge aTrackEdge;
3731   TopoDS_Vertex aV1, aV2;
3732
3733   SMDS_ElemIteratorPtr aItE;
3734   SMDS_NodeIteratorPtr aItN;
3735   SMDSAbs_ElementType aTypeE;
3736
3737   TNodeOfNodeListMap mapNewNodes;
3738   TElemOfVecOfNnlmiMap mapElemNewNodes;
3739   TElemOfElemListMap newElemsMap;
3740
3741   aTolVec=1.e-7;
3742   aTolVec2=aTolVec*aTolVec;
3743
3744   // 1. Check data
3745   aNbE = theElements.size();
3746   // nothing to do
3747   if ( !aNbE )
3748     return EXTR_NO_ELEMENTS;
3749
3750   // 1.1 Track Pattern
3751   ASSERT( theTrack );
3752
3753   SMESHDS_SubMesh* pSubMeshDS=theTrack->GetSubMeshDS();
3754
3755   aItE = pSubMeshDS->GetElements();
3756   while ( aItE->more() ) {
3757     const SMDS_MeshElement* pE = aItE->next();
3758     aTypeE = pE->GetType();
3759     // Pattern must contain links only
3760     if ( aTypeE != SMDSAbs_Edge )
3761       return EXTR_PATH_NOT_EDGE;
3762   }
3763
3764   const TopoDS_Shape& aS = theTrack->GetSubShape();
3765   // Sub shape for the Pattern must be an Edge
3766   if ( aS.ShapeType() != TopAbs_EDGE )
3767     return EXTR_BAD_PATH_SHAPE;
3768
3769   aTrackEdge = TopoDS::Edge( aS );
3770   // the Edge must not be degenerated
3771   if ( BRep_Tool::Degenerated( aTrackEdge ) )
3772     return EXTR_BAD_PATH_SHAPE;
3773
3774   TopExp::Vertices( aTrackEdge, aV1, aV2 );
3775   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
3776   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
3777
3778   aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
3779   const SMDS_MeshNode* aN1 = aItN->next();
3780
3781   aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
3782   const SMDS_MeshNode* aN2 = aItN->next();
3783
3784   // starting node must be aN1 or aN2
3785   if ( !( aN1 == theN1 || aN2 == theN1 ) )
3786     return EXTR_BAD_STARTING_NODE;
3787
3788   aNbTP = pSubMeshDS->NbNodes() + 2;
3789
3790   // 1.2. Angles
3791   vector<double> aAngles( aNbTP );
3792
3793   for ( j=0; j < aNbTP; ++j ) {
3794     aAngles[j] = 0.;
3795   }
3796
3797   if ( theHasAngles ) {
3798     aItD = theAngles.begin();
3799     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
3800       aAngle = *aItD;
3801       aAngles[j] = aAngle;
3802     }
3803   }
3804
3805   // 2. Collect parameters on the track edge
3806   aPrms.push_back( aT1 );
3807   aPrms.push_back( aT2 );
3808
3809   aItN = pSubMeshDS->GetNodes();
3810   while ( aItN->more() ) {
3811     const SMDS_MeshNode* pNode = aItN->next();
3812     const SMDS_EdgePosition* pEPos =
3813       static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
3814     aT = pEPos->GetUParameter();
3815     aPrms.push_back( aT );
3816   }
3817
3818   // sort parameters
3819   aPrms.sort();
3820   if ( aN1 == theN1 ) {
3821     if ( aT1 > aT2 ) {
3822       aPrms.reverse();
3823     }
3824   }
3825   else {
3826     if ( aT2 > aT1 ) {
3827       aPrms.reverse();
3828     }
3829   }
3830
3831   // 3. Path Points
3832   SMESH_MeshEditor_PathPoint aPP;
3833   vector<SMESH_MeshEditor_PathPoint> aPPs( aNbTP );
3834   //
3835   aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
3836   //
3837   aItD = aPrms.begin();
3838   for ( j=0; aItD != aPrms.end(); ++aItD, ++j ) {
3839     aT = *aItD;
3840     aC3D->D1( aT, aP3D, aVec );
3841     aL2 = aVec.SquareMagnitude();
3842     if ( aL2 < aTolVec2 )
3843       return EXTR_CANT_GET_TANGENT;
3844
3845     gp_Dir aTgt( aVec );
3846     aAngle = aAngles[j];
3847
3848     aPP.SetPnt( aP3D );
3849     aPP.SetTangent( aTgt );
3850     aPP.SetAngle( aAngle );
3851     aPP.SetParameter( aT );
3852     aPPs[j]=aPP;
3853   }
3854
3855   // 3. Center of rotation aV0
3856   aV0 = theRefPoint;
3857   if ( !theHasRefPoint ) {
3858     aNb = 0;
3859     aGC.SetCoord( 0.,0.,0. );
3860
3861     itElem = theElements.begin();
3862     for ( ; itElem != theElements.end(); itElem++ ) {
3863       const SMDS_MeshElement* elem = *itElem;
3864
3865       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3866       while ( itN->more() ) {
3867         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
3868         aX = node->X();
3869         aY = node->Y();
3870         aZ = node->Z();
3871
3872         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
3873           list<const SMDS_MeshNode*> aLNx;
3874           mapNewNodes[node] = aLNx;
3875           //
3876           gp_XYZ aXYZ( aX, aY, aZ );
3877           aGC += aXYZ;
3878           ++aNb;
3879         }
3880       }
3881     }
3882     aGC /= aNb;
3883     aV0.SetXYZ( aGC );
3884   } // if (!theHasRefPoint) {
3885   mapNewNodes.clear();
3886
3887   // 4. Processing the elements
3888   SMESHDS_Mesh* aMesh = GetMeshDS();
3889
3890   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
3891     // check element type
3892     const SMDS_MeshElement* elem = *itElem;
3893     aTypeE = elem->GetType();
3894     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
3895       continue;
3896
3897     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3898     newNodesItVec.reserve( elem->NbNodes() );
3899
3900     // loop on elem nodes
3901     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3902     while ( itN->more() ) {
3903
3904       // check if a node has been already processed
3905       const SMDS_MeshNode* node =
3906         static_cast<const SMDS_MeshNode*>( itN->next() );
3907       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3908       if ( nIt == mapNewNodes.end() ) {
3909         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3910         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3911
3912         // make new nodes
3913         aX = node->X();  aY = node->Y(); aZ = node->Z();
3914
3915         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
3916         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
3917         gp_Ax1 anAx1, anAxT1T0;
3918         gp_Dir aDT1x, aDT0x, aDT1T0;
3919
3920         aTolAng=1.e-4;
3921
3922         aV0x = aV0;
3923         aPN0.SetCoord(aX, aY, aZ);
3924
3925         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
3926         aP0x = aPP0.Pnt();
3927         aDT0x= aPP0.Tangent();
3928
3929         for ( j = 1; j < aNbTP; ++j ) {
3930           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
3931           aP1x = aPP1.Pnt();
3932           aDT1x = aPP1.Tangent();
3933           aAngle1x = aPP1.Angle();
3934
3935           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
3936           // Translation
3937           gp_Vec aV01x( aP0x, aP1x );
3938           aTrsf.SetTranslation( aV01x );
3939
3940           // traslated point
3941           aV1x = aV0x.Transformed( aTrsf );
3942           aPN1 = aPN0.Transformed( aTrsf );
3943
3944           // rotation 1 [ T1,T0 ]
3945           aAngleT1T0=-aDT1x.Angle( aDT0x );
3946           if (fabs(aAngleT1T0) > aTolAng) {
3947             aDT1T0=aDT1x^aDT0x;
3948             anAxT1T0.SetLocation( aV1x );
3949             anAxT1T0.SetDirection( aDT1T0 );
3950             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
3951
3952             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
3953           }
3954
3955           // rotation 2
3956           if ( theHasAngles ) {
3957             anAx1.SetLocation( aV1x );
3958             anAx1.SetDirection( aDT1x );
3959             aTrsfRot.SetRotation( anAx1, aAngle1x );
3960
3961             aPN1 = aPN1.Transformed( aTrsfRot );
3962           }
3963
3964           // make new node
3965           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3966             // create additional node
3967             double x = ( aPN1.X() + aPN0.X() )/2.;
3968             double y = ( aPN1.Y() + aPN0.Y() )/2.;
3969             double z = ( aPN1.Z() + aPN0.Z() )/2.;
3970             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
3971             myLastCreatedNodes.Append(newNode);
3972             listNewNodes.push_back( newNode );
3973           }
3974           aX = aPN1.X();
3975           aY = aPN1.Y();
3976           aZ = aPN1.Z();
3977           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
3978           myLastCreatedNodes.Append(newNode);
3979           listNewNodes.push_back( newNode );
3980
3981           aPN0 = aPN1;
3982           aP0x = aP1x;
3983           aV0x = aV1x;
3984           aDT0x = aDT1x;
3985         }
3986       }
3987
3988       else {
3989         // if current elem is quadratic and current node is not medium
3990         // we have to check - may be it is needed to insert additional nodes
3991         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3992           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3993           if(listNewNodes.size()==aNbTP-1) {
3994             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
3995             gp_XYZ P(node->X(), node->Y(), node->Z());
3996             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
3997             int i;
3998             for(i=0; i<aNbTP-1; i++) {
3999               const SMDS_MeshNode* N = *it;
4000               double x = ( N->X() + P.X() )/2.;
4001               double y = ( N->Y() + P.Y() )/2.;
4002               double z = ( N->Z() + P.Z() )/2.;
4003               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4004               myLastCreatedNodes.Append(newN);
4005               aNodes[2*i] = newN;
4006               aNodes[2*i+1] = N;
4007               P = gp_XYZ(N->X(),N->Y(),N->Z());
4008             }
4009             listNewNodes.clear();
4010             for(i=0; i<2*(aNbTP-1); i++) {
4011               listNewNodes.push_back(aNodes[i]);
4012             }
4013           }
4014         }
4015       }
4016
4017       newNodesItVec.push_back( nIt );
4018     }
4019     // make new elements
4020     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4021     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
4022     sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4023                   aNbTP-1, myLastCreatedElems );
4024   }
4025
4026   makeWalls( aMesh, mapNewNodes, newElemsMap, mapElemNewNodes, theElements,
4027              aNbTP-1, myLastCreatedElems );
4028
4029   return EXTR_OK;
4030 }
4031
4032 //=======================================================================
4033 //function : Transform
4034 //purpose  :
4035 //=======================================================================
4036
4037 void SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4038                                   const gp_Trsf&     theTrsf,
4039                                   const bool         theCopy)
4040 {
4041   myLastCreatedElems.Clear();
4042   myLastCreatedNodes.Clear();
4043
4044   bool needReverse;
4045   switch ( theTrsf.Form() ) {
4046   case gp_PntMirror:
4047   case gp_Ax2Mirror:
4048     needReverse = true;
4049     break;
4050   default:
4051     needReverse = false;
4052   }
4053
4054   SMESHDS_Mesh* aMesh = GetMeshDS();
4055
4056   // map old node to new one
4057   TNodeNodeMap nodeMap;
4058
4059   // elements sharing moved nodes; those of them which have all
4060   // nodes mirrored but are not in theElems are to be reversed
4061   TIDSortedElemSet inverseElemSet;
4062
4063   // loop on theElems
4064   TIDSortedElemSet::iterator itElem;
4065   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4066     const SMDS_MeshElement* elem = *itElem;
4067     if ( !elem )
4068       continue;
4069
4070     // loop on elem nodes
4071     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4072     while ( itN->more() ) {
4073
4074       // check if a node has been already transformed
4075       const SMDS_MeshNode* node =
4076         static_cast<const SMDS_MeshNode*>( itN->next() );
4077       if (nodeMap.find( node ) != nodeMap.end() )
4078         continue;
4079
4080       double coord[3];
4081       coord[0] = node->X();
4082       coord[1] = node->Y();
4083       coord[2] = node->Z();
4084       theTrsf.Transforms( coord[0], coord[1], coord[2] );
4085       const SMDS_MeshNode * newNode = node;
4086       if ( theCopy ) {
4087         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4088         myLastCreatedNodes.Append(newNode);
4089       }
4090       else {
4091         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4092         // node position on shape becomes invalid
4093         const_cast< SMDS_MeshNode* > ( node )->SetPosition
4094           ( SMDS_SpacePosition::originSpacePosition() );
4095       }
4096       nodeMap.insert( TNodeNodeMap::value_type( node, newNode ));
4097
4098       // keep inverse elements
4099       if ( !theCopy && needReverse ) {
4100         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4101         while ( invElemIt->more() ) {
4102           const SMDS_MeshElement* iel = invElemIt->next();
4103           inverseElemSet.insert( iel );
4104         }
4105       }
4106     }
4107   }
4108
4109   // either new elements are to be created
4110   // or a mirrored element are to be reversed
4111   if ( !theCopy && !needReverse)
4112     return;
4113
4114   if ( !inverseElemSet.empty()) {
4115     TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4116     for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4117       theElems.insert( *invElemIt );
4118   }
4119
4120   // replicate or reverse elements
4121
4122   enum {
4123     REV_TETRA   = 0,  //  = nbNodes - 4
4124     REV_PYRAMID = 1,  //  = nbNodes - 4
4125     REV_PENTA   = 2,  //  = nbNodes - 4
4126     REV_FACE    = 3,
4127     REV_HEXA    = 4,  //  = nbNodes - 4
4128     FORWARD     = 5
4129     };
4130   int index[][8] = {
4131     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
4132     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
4133     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
4134     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
4135     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
4136     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
4137   };
4138
4139   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4140     const SMDS_MeshElement* elem = *itElem;
4141     if ( !elem || elem->GetType() == SMDSAbs_Node )
4142       continue;
4143
4144     int nbNodes = elem->NbNodes();
4145     int elemType = elem->GetType();
4146
4147     if (elem->IsPoly()) {
4148       // Polygon or Polyhedral Volume
4149       switch ( elemType ) {
4150       case SMDSAbs_Face:
4151         {
4152           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4153           int iNode = 0;
4154           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4155           while (itN->more()) {
4156             const SMDS_MeshNode* node =
4157               static_cast<const SMDS_MeshNode*>(itN->next());
4158             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4159             if (nodeMapIt == nodeMap.end())
4160               break; // not all nodes transformed
4161             if (needReverse) {
4162               // reverse mirrored faces and volumes
4163               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4164             } else {
4165               poly_nodes[iNode] = (*nodeMapIt).second;
4166             }
4167             iNode++;
4168           }
4169           if ( iNode != nbNodes )
4170             continue; // not all nodes transformed
4171
4172           if ( theCopy ) {
4173             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4174           }
4175           else {
4176             aMesh->ChangePolygonNodes(elem, poly_nodes);
4177           }
4178         }
4179         break;
4180       case SMDSAbs_Volume:
4181         {
4182           // ATTENTION: Reversing is not yet done!!!
4183           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4184             (const SMDS_PolyhedralVolumeOfNodes*) elem;
4185           if (!aPolyedre) {
4186             MESSAGE("Warning: bad volumic element");
4187             continue;
4188           }
4189
4190           vector<const SMDS_MeshNode*> poly_nodes;
4191           vector<int> quantities;
4192
4193           bool allTransformed = true;
4194           int nbFaces = aPolyedre->NbFaces();
4195           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4196             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4197             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4198               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4199               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4200               if (nodeMapIt == nodeMap.end()) {
4201                 allTransformed = false; // not all nodes transformed
4202               } else {
4203                 poly_nodes.push_back((*nodeMapIt).second);
4204               }
4205             }
4206             quantities.push_back(nbFaceNodes);
4207           }
4208           if ( !allTransformed )
4209             continue; // not all nodes transformed
4210
4211           if ( theCopy ) {
4212             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4213           }
4214           else {
4215             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4216           }
4217         }
4218         break;
4219       default:;
4220       }
4221       continue;
4222     }
4223
4224     // Regular elements
4225     int* i = index[ FORWARD ];
4226     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4227       if ( elemType == SMDSAbs_Face )
4228         i = index[ REV_FACE ];
4229       else
4230         i = index[ nbNodes - 4 ];
4231
4232     if(elem->IsQuadratic()) {
4233       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4234       i = anIds;
4235       if(needReverse) {
4236         if(nbNodes==3) { // quadratic edge
4237           static int anIds[] = {1,0,2};
4238           i = anIds;
4239         }
4240         else if(nbNodes==6) { // quadratic triangle
4241           static int anIds[] = {0,2,1,5,4,3};
4242           i = anIds;
4243         }
4244         else if(nbNodes==8) { // quadratic quadrangle
4245           static int anIds[] = {0,3,2,1,7,6,5,4};
4246           i = anIds;
4247         }
4248         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4249           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4250           i = anIds;
4251         }
4252         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4253           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4254           i = anIds;
4255         }
4256         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4257           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4258           i = anIds;
4259         }
4260         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4261           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4262           i = anIds;
4263         }
4264       }
4265     }
4266
4267     // find transformed nodes
4268     vector<const SMDS_MeshNode*> nodes(nbNodes);
4269     int iNode = 0;
4270     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4271     while ( itN->more() ) {
4272       const SMDS_MeshNode* node =
4273         static_cast<const SMDS_MeshNode*>( itN->next() );
4274       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4275       if ( nodeMapIt == nodeMap.end() )
4276         break; // not all nodes transformed
4277       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4278     }
4279     if ( iNode != nbNodes )
4280       continue; // not all nodes transformed
4281
4282     if ( theCopy ) {
4283       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() ))
4284         myLastCreatedElems.Append( copy );
4285     }
4286     else
4287     {
4288       // reverse element as it was reversed by transformation
4289       if ( nbNodes > 2 )
4290         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4291     }
4292   }
4293 }
4294
4295 //=======================================================================
4296 //function : FindCoincidentNodes
4297 //purpose  : Return list of group of nodes close to each other within theTolerance
4298 //           Search among theNodes or in the whole mesh if theNodes is empty using
4299 //           an Octree algorithm
4300 //=======================================================================
4301
4302 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
4303                                             const double                theTolerance,
4304                                             TListOfListOfNodes &        theGroupsOfNodes)
4305 {
4306   myLastCreatedElems.Clear();
4307   myLastCreatedNodes.Clear();
4308
4309   set<const SMDS_MeshNode*> nodes;
4310   if ( theNodes.empty() )
4311   { // get all nodes in the mesh
4312     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
4313     while ( nIt->more() )
4314       nodes.insert( nodes.end(),nIt->next());
4315   }
4316   else
4317     nodes=theNodes;
4318   SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
4319
4320 }
4321
4322 //=======================================================================
4323 /*!
4324  * \brief Implementation of search for the node closest to point
4325  */
4326 //=======================================================================
4327
4328 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
4329 {
4330   /*!
4331    * \brief Constructor
4332    */
4333   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
4334   {
4335     set<const SMDS_MeshNode*> nodes;
4336     if ( theMesh ) {
4337       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
4338       while ( nIt->more() )
4339         nodes.insert( nodes.end(), nIt->next() );
4340     }
4341     myOctreeNode = new SMESH_OctreeNode(nodes) ;
4342   }
4343   /*!
4344    * \brief Do it's job
4345    */
4346   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
4347   {
4348     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
4349     list<const SMDS_MeshNode*> nodes;
4350     const double precision = 1e-6;
4351     myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
4352
4353     double minSqDist = DBL_MAX;
4354     Bnd_B3d box;
4355     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
4356     {
4357       // sort leafs by their distance from thePnt
4358       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
4359       TDistTreeMap treeMap;
4360       list< SMESH_OctreeNode* > treeList;
4361       list< SMESH_OctreeNode* >::iterator trIt;
4362       treeList.push_back( myOctreeNode );
4363       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
4364       {
4365         SMESH_OctreeNode* tree = *trIt;
4366         if ( !tree->isLeaf() ) { // put children to the queue
4367           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
4368           while ( cIt->more() )
4369             treeList.push_back( cIt->next() );
4370         }
4371         else if ( tree->NbNodes() ) { // put tree to treeMap
4372           tree->getBox( box );
4373           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
4374           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
4375           if ( !it_in.second ) // not unique distance to box center
4376             treeMap.insert( it_in.first, make_pair( sqDist - 1e-13*treeMap.size(), tree ));
4377         }
4378       }
4379       // find distance after which there is no sense to check tree's
4380       double sqLimit = DBL_MAX;
4381       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
4382       if ( treeMap.size() > 5 ) {
4383         SMESH_OctreeNode* closestTree = sqDist_tree->second;
4384         closestTree->getBox( box );
4385         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
4386         sqLimit = limit * limit;
4387       }
4388       // get all nodes from trees
4389       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
4390         if ( sqDist_tree->first > sqLimit )
4391           break;
4392         SMESH_OctreeNode* tree = sqDist_tree->second;
4393         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
4394       }
4395     }
4396     // find closest among nodes
4397     minSqDist = DBL_MAX;
4398     const SMDS_MeshNode* closestNode = 0;
4399     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
4400     for ( ; nIt != nodes.end(); ++nIt ) {
4401       double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
4402       if ( minSqDist > sqDist ) {
4403         closestNode = *nIt;
4404         minSqDist = sqDist;
4405       }
4406     }
4407     return closestNode;
4408   }
4409   /*!
4410    * \brief Destructor
4411    */
4412   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
4413 private:
4414   SMESH_OctreeNode* myOctreeNode;
4415 };
4416
4417 //=======================================================================
4418 /*!
4419  * \brief Return SMESH_NodeSearcher
4420  */
4421 //=======================================================================
4422
4423 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
4424 {
4425   return new SMESH_NodeSearcherImpl( GetMeshDS() );
4426 }
4427
4428 //=======================================================================
4429 //function : SimplifyFace
4430 //purpose  :
4431 //=======================================================================
4432 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
4433                                     vector<const SMDS_MeshNode *>&      poly_nodes,
4434                                     vector<int>&                        quantities) const
4435 {
4436   int nbNodes = faceNodes.size();
4437
4438   if (nbNodes < 3)
4439     return 0;
4440
4441   set<const SMDS_MeshNode*> nodeSet;
4442
4443   // get simple seq of nodes
4444   const SMDS_MeshNode* simpleNodes[ nbNodes ];
4445   int iSimple = 0, nbUnique = 0;
4446
4447   simpleNodes[iSimple++] = faceNodes[0];
4448   nbUnique++;
4449   for (int iCur = 1; iCur < nbNodes; iCur++) {
4450     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
4451       simpleNodes[iSimple++] = faceNodes[iCur];
4452       if (nodeSet.insert( faceNodes[iCur] ).second)
4453         nbUnique++;
4454     }
4455   }
4456   int nbSimple = iSimple;
4457   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
4458     nbSimple--;
4459     iSimple--;
4460   }
4461
4462   if (nbUnique < 3)
4463     return 0;
4464
4465   // separate loops
4466   int nbNew = 0;
4467   bool foundLoop = (nbSimple > nbUnique);
4468   while (foundLoop) {
4469     foundLoop = false;
4470     set<const SMDS_MeshNode*> loopSet;
4471     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
4472       const SMDS_MeshNode* n = simpleNodes[iSimple];
4473       if (!loopSet.insert( n ).second) {
4474         foundLoop = true;
4475
4476         // separate loop
4477         int iC = 0, curLast = iSimple;
4478         for (; iC < curLast; iC++) {
4479           if (simpleNodes[iC] == n) break;
4480         }
4481         int loopLen = curLast - iC;
4482         if (loopLen > 2) {
4483           // create sub-element
4484           nbNew++;
4485           quantities.push_back(loopLen);
4486           for (; iC < curLast; iC++) {
4487             poly_nodes.push_back(simpleNodes[iC]);
4488           }
4489         }
4490         // shift the rest nodes (place from the first loop position)
4491         for (iC = curLast + 1; iC < nbSimple; iC++) {
4492           simpleNodes[iC - loopLen] = simpleNodes[iC];
4493         }
4494         nbSimple -= loopLen;
4495         iSimple -= loopLen;
4496       }
4497     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
4498   } // while (foundLoop)
4499
4500   if (iSimple > 2) {
4501     nbNew++;
4502     quantities.push_back(iSimple);
4503     for (int i = 0; i < iSimple; i++)
4504       poly_nodes.push_back(simpleNodes[i]);
4505   }
4506
4507   return nbNew;
4508 }
4509
4510 //=======================================================================
4511 //function : MergeNodes
4512 //purpose  : In each group, the cdr of nodes are substituted by the first one
4513 //           in all elements.
4514 //=======================================================================
4515
4516 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
4517 {
4518   myLastCreatedElems.Clear();
4519   myLastCreatedNodes.Clear();
4520
4521   SMESHDS_Mesh* aMesh = GetMeshDS();
4522
4523   TNodeNodeMap nodeNodeMap; // node to replace - new node
4524   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
4525   list< int > rmElemIds, rmNodeIds;
4526
4527   // Fill nodeNodeMap and elems
4528
4529   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
4530   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
4531     list<const SMDS_MeshNode*>& nodes = *grIt;
4532     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
4533     const SMDS_MeshNode* nToKeep = *nIt;
4534     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
4535       const SMDS_MeshNode* nToRemove = *nIt;
4536       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
4537       if ( nToRemove != nToKeep ) {
4538         rmNodeIds.push_back( nToRemove->GetID() );
4539         AddToSameGroups( nToKeep, nToRemove, aMesh );
4540       }
4541
4542       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
4543       while ( invElemIt->more() ) {
4544         const SMDS_MeshElement* elem = invElemIt->next();
4545           elems.insert(elem);
4546       }
4547     }
4548   }
4549   // Change element nodes or remove an element
4550
4551   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
4552   for ( ; eIt != elems.end(); eIt++ ) {
4553     const SMDS_MeshElement* elem = *eIt;
4554     int nbNodes = elem->NbNodes();
4555     int aShapeId = FindShape( elem );
4556
4557     set<const SMDS_MeshNode*> nodeSet;
4558     const SMDS_MeshNode* curNodes[ nbNodes ], *uniqueNodes[ nbNodes ];
4559     int iUnique = 0, iCur = 0, nbRepl = 0, iRepl [ nbNodes ];
4560
4561     // get new seq of nodes
4562     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4563     while ( itN->more() ) {
4564       const SMDS_MeshNode* n =
4565         static_cast<const SMDS_MeshNode*>( itN->next() );
4566
4567       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
4568       if ( nnIt != nodeNodeMap.end() ) { // n sticks
4569         n = (*nnIt).second;
4570         iRepl[ nbRepl++ ] = iCur;
4571       }
4572       curNodes[ iCur ] = n;
4573       bool isUnique = nodeSet.insert( n ).second;
4574       if ( isUnique )
4575         uniqueNodes[ iUnique++ ] = n;
4576       iCur++;
4577     }
4578
4579     // Analyse element topology after replacement
4580
4581     bool isOk = true;
4582     int nbUniqueNodes = nodeSet.size();
4583     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
4584       // Polygons and Polyhedral volumes
4585       if (elem->IsPoly()) {
4586
4587         if (elem->GetType() == SMDSAbs_Face) {
4588           // Polygon
4589           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
4590           int inode = 0;
4591           for (; inode < nbNodes; inode++) {
4592             face_nodes[inode] = curNodes[inode];
4593           }
4594
4595           vector<const SMDS_MeshNode *> polygons_nodes;
4596           vector<int> quantities;
4597           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
4598
4599           if (nbNew > 0) {
4600             inode = 0;
4601             for (int iface = 0; iface < nbNew - 1; iface++) {
4602               int nbNodes = quantities[iface];
4603               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
4604               for (int ii = 0; ii < nbNodes; ii++, inode++) {
4605                 poly_nodes[ii] = polygons_nodes[inode];
4606               }
4607               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
4608               myLastCreatedElems.Append(newElem);
4609               if (aShapeId)
4610                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
4611             }
4612             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
4613           }
4614           else {
4615             rmElemIds.push_back(elem->GetID());
4616           }
4617
4618         }
4619         else if (elem->GetType() == SMDSAbs_Volume) {
4620           // Polyhedral volume
4621           if (nbUniqueNodes < 4) {
4622             rmElemIds.push_back(elem->GetID());
4623           }
4624           else {
4625             // each face has to be analized in order to check volume validity
4626             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4627               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4628             if (aPolyedre) {
4629               int nbFaces = aPolyedre->NbFaces();
4630
4631               vector<const SMDS_MeshNode *> poly_nodes;
4632               vector<int> quantities;
4633
4634               for (int iface = 1; iface <= nbFaces; iface++) {
4635                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4636                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
4637
4638                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
4639                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
4640                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
4641                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
4642                     faceNode = (*nnIt).second;
4643                   }
4644                   faceNodes[inode - 1] = faceNode;
4645                 }
4646
4647                 SimplifyFace(faceNodes, poly_nodes, quantities);
4648               }
4649
4650               if (quantities.size() > 3) {
4651                 // to be done: remove coincident faces
4652               }
4653
4654               if (quantities.size() > 3)
4655                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4656               else
4657                 rmElemIds.push_back(elem->GetID());
4658
4659             }
4660             else {
4661               rmElemIds.push_back(elem->GetID());
4662             }
4663           }
4664         }
4665         else {
4666         }
4667
4668         continue;
4669       }
4670
4671       // Regular elements
4672       switch ( nbNodes ) {
4673       case 2: ///////////////////////////////////// EDGE
4674         isOk = false; break;
4675       case 3: ///////////////////////////////////// TRIANGLE
4676         isOk = false; break;
4677       case 4:
4678         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
4679           isOk = false;
4680         else { //////////////////////////////////// QUADRANGLE
4681           if ( nbUniqueNodes < 3 )
4682             isOk = false;
4683           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
4684             isOk = false; // opposite nodes stick
4685         }
4686         break;
4687       case 6: ///////////////////////////////////// PENTAHEDRON
4688         if ( nbUniqueNodes == 4 ) {
4689           // ---------------------------------> tetrahedron
4690           if (nbRepl == 3 &&
4691               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
4692             // all top nodes stick: reverse a bottom
4693             uniqueNodes[ 0 ] = curNodes [ 1 ];
4694             uniqueNodes[ 1 ] = curNodes [ 0 ];
4695           }
4696           else if (nbRepl == 3 &&
4697                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
4698             // all bottom nodes stick: set a top before
4699             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
4700             uniqueNodes[ 0 ] = curNodes [ 3 ];
4701             uniqueNodes[ 1 ] = curNodes [ 4 ];
4702             uniqueNodes[ 2 ] = curNodes [ 5 ];
4703           }
4704           else if (nbRepl == 4 &&
4705                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
4706             // a lateral face turns into a line: reverse a bottom
4707             uniqueNodes[ 0 ] = curNodes [ 1 ];
4708             uniqueNodes[ 1 ] = curNodes [ 0 ];
4709           }
4710           else
4711             isOk = false;
4712         }
4713         else if ( nbUniqueNodes == 5 ) {
4714           // PENTAHEDRON --------------------> 2 tetrahedrons
4715           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
4716             // a bottom node sticks with a linked top one
4717             // 1.
4718             SMDS_MeshElement* newElem =
4719               aMesh->AddVolume(curNodes[ 3 ],
4720                                curNodes[ 4 ],
4721                                curNodes[ 5 ],
4722                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
4723             myLastCreatedElems.Append(newElem);
4724             if ( aShapeId )
4725               aMesh->SetMeshElementOnShape( newElem, aShapeId );
4726             // 2. : reverse a bottom
4727             uniqueNodes[ 0 ] = curNodes [ 1 ];
4728             uniqueNodes[ 1 ] = curNodes [ 0 ];
4729             nbUniqueNodes = 4;
4730           }
4731           else
4732             isOk = false;
4733         }
4734         else
4735           isOk = false;
4736         break;
4737       case 8: {
4738         if(elem->IsQuadratic()) { // Quadratic quadrangle
4739           //   1    5    2
4740           //    +---+---+
4741           //    |       |
4742           //    |       |
4743           //   4+       +6
4744           //    |       |
4745           //    |       |
4746           //    +---+---+
4747           //   0    7    3
4748           isOk = false;
4749           if(nbRepl==3) {
4750             nbUniqueNodes = 6;
4751             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
4752               uniqueNodes[0] = curNodes[0];
4753               uniqueNodes[1] = curNodes[2];
4754               uniqueNodes[2] = curNodes[3];
4755               uniqueNodes[3] = curNodes[5];
4756               uniqueNodes[4] = curNodes[6];
4757               uniqueNodes[5] = curNodes[7];
4758               isOk = true;
4759             }
4760             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
4761               uniqueNodes[0] = curNodes[0];
4762               uniqueNodes[1] = curNodes[1];
4763               uniqueNodes[2] = curNodes[2];
4764               uniqueNodes[3] = curNodes[4];
4765               uniqueNodes[4] = curNodes[5];
4766               uniqueNodes[5] = curNodes[6];
4767               isOk = true;
4768             }
4769             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
4770               uniqueNodes[0] = curNodes[1];
4771               uniqueNodes[1] = curNodes[2];
4772               uniqueNodes[2] = curNodes[3];
4773               uniqueNodes[3] = curNodes[5];
4774               uniqueNodes[4] = curNodes[6];
4775               uniqueNodes[5] = curNodes[0];
4776               isOk = true;
4777             }
4778             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
4779               uniqueNodes[0] = curNodes[0];
4780               uniqueNodes[1] = curNodes[1];
4781               uniqueNodes[2] = curNodes[3];
4782               uniqueNodes[3] = curNodes[4];
4783               uniqueNodes[4] = curNodes[6];
4784               uniqueNodes[5] = curNodes[7];
4785               isOk = true;
4786             }
4787             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
4788               uniqueNodes[0] = curNodes[0];
4789               uniqueNodes[1] = curNodes[2];
4790               uniqueNodes[2] = curNodes[3];
4791               uniqueNodes[3] = curNodes[1];
4792               uniqueNodes[4] = curNodes[6];
4793               uniqueNodes[5] = curNodes[7];
4794               isOk = true;
4795             }
4796             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
4797               uniqueNodes[0] = curNodes[0];
4798               uniqueNodes[1] = curNodes[1];
4799               uniqueNodes[2] = curNodes[2];
4800               uniqueNodes[3] = curNodes[4];
4801               uniqueNodes[4] = curNodes[5];
4802               uniqueNodes[5] = curNodes[7];
4803               isOk = true;
4804             }
4805             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
4806               uniqueNodes[0] = curNodes[0];
4807               uniqueNodes[1] = curNodes[1];
4808               uniqueNodes[2] = curNodes[3];
4809               uniqueNodes[3] = curNodes[4];
4810               uniqueNodes[4] = curNodes[2];
4811               uniqueNodes[5] = curNodes[7];
4812               isOk = true;
4813             }
4814             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
4815               uniqueNodes[0] = curNodes[0];
4816               uniqueNodes[1] = curNodes[1];
4817               uniqueNodes[2] = curNodes[2];
4818               uniqueNodes[3] = curNodes[4];
4819               uniqueNodes[4] = curNodes[5];
4820               uniqueNodes[5] = curNodes[3];
4821               isOk = true;
4822             }
4823           }
4824           break;
4825         }
4826         //////////////////////////////////// HEXAHEDRON
4827         isOk = false;
4828         SMDS_VolumeTool hexa (elem);
4829         hexa.SetExternalNormal();
4830         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
4831           //////////////////////// ---> tetrahedron
4832           for ( int iFace = 0; iFace < 6; iFace++ ) {
4833             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
4834             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
4835                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
4836                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
4837               // one face turns into a point ...
4838               int iOppFace = hexa.GetOppFaceIndex( iFace );
4839               ind = hexa.GetFaceNodesIndices( iOppFace );
4840               int nbStick = 0;
4841               iUnique = 2; // reverse a tetrahedron bottom
4842               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
4843                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
4844                   nbStick++;
4845                 else if ( iUnique >= 0 )
4846                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
4847               }
4848               if ( nbStick == 1 ) {
4849                 // ... and the opposite one - into a triangle.
4850                 // set a top node
4851                 ind = hexa.GetFaceNodesIndices( iFace );
4852                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
4853                 isOk = true;
4854               }
4855               break;
4856             }
4857           }
4858         }
4859         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
4860           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
4861           for ( int iFace = 0; iFace < 6; iFace++ ) {
4862             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
4863             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
4864                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
4865                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
4866               // one face turns into a point ...
4867               int iOppFace = hexa.GetOppFaceIndex( iFace );
4868               ind = hexa.GetFaceNodesIndices( iOppFace );
4869               int nbStick = 0;
4870               iUnique = 2;  // reverse a tetrahedron 1 bottom
4871               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
4872                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
4873                   nbStick++;
4874                 else if ( iUnique >= 0 )
4875                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
4876               }
4877               if ( nbStick == 0 ) {
4878                 // ... and the opposite one is a quadrangle
4879                 // set a top node
4880                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
4881                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
4882                 nbUniqueNodes = 4;
4883                 // tetrahedron 2
4884                 SMDS_MeshElement* newElem =
4885                   aMesh->AddVolume(curNodes[ind[ 0 ]],
4886                                    curNodes[ind[ 3 ]],
4887                                    curNodes[ind[ 2 ]],
4888                                    curNodes[indTop[ 0 ]]);
4889                 myLastCreatedElems.Append(newElem);
4890                 if ( aShapeId )
4891                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
4892                 isOk = true;
4893               }
4894               break;
4895             }
4896           }
4897         }
4898         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
4899           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
4900           // find indices of quad and tri faces
4901           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
4902           for ( iFace = 0; iFace < 6; iFace++ ) {
4903             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
4904             nodeSet.clear();
4905             for ( iCur = 0; iCur < 4; iCur++ )
4906               nodeSet.insert( curNodes[ind[ iCur ]] );
4907             nbUniqueNodes = nodeSet.size();
4908             if ( nbUniqueNodes == 3 )
4909               iTriFace[ nbTri++ ] = iFace;
4910             else if ( nbUniqueNodes == 4 )
4911               iQuadFace[ nbQuad++ ] = iFace;
4912           }
4913           if (nbQuad == 2 && nbTri == 4 &&
4914               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
4915             // 2 opposite quadrangles stuck with a diagonal;
4916             // sample groups of merged indices: (0-4)(2-6)
4917             // --------------------------------------------> 2 tetrahedrons
4918             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
4919             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
4920             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
4921             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
4922                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
4923               // stuck with 0-2 diagonal
4924               i0  = ind1[ 3 ];
4925               i1d = ind1[ 0 ];
4926               i2  = ind1[ 1 ];
4927               i3d = ind1[ 2 ];
4928               i0t = ind2[ 1 ];
4929               i2t = ind2[ 3 ];
4930             }
4931             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
4932                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
4933               // stuck with 1-3 diagonal
4934               i0  = ind1[ 0 ];
4935               i1d = ind1[ 1 ];
4936               i2  = ind1[ 2 ];
4937               i3d = ind1[ 3 ];
4938               i0t = ind2[ 0 ];
4939               i2t = ind2[ 1 ];
4940             }
4941             else {
4942               ASSERT(0);
4943             }
4944             // tetrahedron 1
4945             uniqueNodes[ 0 ] = curNodes [ i0 ];
4946             uniqueNodes[ 1 ] = curNodes [ i1d ];
4947             uniqueNodes[ 2 ] = curNodes [ i3d ];
4948             uniqueNodes[ 3 ] = curNodes [ i0t ];
4949             nbUniqueNodes = 4;
4950             // tetrahedron 2
4951             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
4952                                                          curNodes[ i2 ],
4953                                                          curNodes[ i3d ],
4954                                                          curNodes[ i2t ]);
4955             myLastCreatedElems.Append(newElem);
4956             if ( aShapeId )
4957               aMesh->SetMeshElementOnShape( newElem, aShapeId );
4958             isOk = true;
4959           }
4960           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
4961                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
4962             // --------------------------------------------> prism
4963             // find 2 opposite triangles
4964             nbUniqueNodes = 6;
4965             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
4966               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
4967                 // find indices of kept and replaced nodes
4968                 // and fill unique nodes of 2 opposite triangles
4969                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
4970                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
4971                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
4972                 // fill unique nodes
4973                 iUnique = 0;
4974                 isOk = true;
4975                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
4976                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
4977                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
4978                   if ( n == nInit ) {
4979                     // iCur of a linked node of the opposite face (make normals co-directed):
4980                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
4981                     // check that correspondent corners of triangles are linked
4982                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
4983                       isOk = false;
4984                     else {
4985                       uniqueNodes[ iUnique ] = n;
4986                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
4987                       iUnique++;
4988                     }
4989                   }
4990                 }
4991                 break;
4992               }
4993             }
4994           }
4995         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
4996         break;
4997       } // HEXAHEDRON
4998
4999       default:
5000         isOk = false;
5001       } // switch ( nbNodes )
5002
5003     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
5004
5005     if ( isOk ) {
5006       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
5007         // Change nodes of polyedre
5008         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5009           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5010         if (aPolyedre) {
5011           int nbFaces = aPolyedre->NbFaces();
5012
5013           vector<const SMDS_MeshNode *> poly_nodes;
5014           vector<int> quantities (nbFaces);
5015
5016           for (int iface = 1; iface <= nbFaces; iface++) {
5017             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5018             quantities[iface - 1] = nbFaceNodes;
5019
5020             for (inode = 1; inode <= nbFaceNodes; inode++) {
5021               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
5022
5023               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
5024               if (nnIt != nodeNodeMap.end()) { // curNode sticks
5025                 curNode = (*nnIt).second;
5026               }
5027               poly_nodes.push_back(curNode);
5028             }
5029           }
5030           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
5031         }
5032       }
5033       else {
5034         // Change regular element or polygon
5035         aMesh->ChangeElementNodes( elem, uniqueNodes, nbUniqueNodes );
5036       }
5037     }
5038     else {
5039       // Remove invalid regular element or invalid polygon
5040       rmElemIds.push_back( elem->GetID() );
5041     }
5042
5043   } // loop on elements
5044
5045   // Remove equal nodes and bad elements
5046
5047   Remove( rmNodeIds, true );
5048   Remove( rmElemIds, false );
5049
5050 }
5051
5052
5053 // ========================================================
5054 // class   : SortableElement
5055 // purpose : allow sorting elements basing on their nodes
5056 // ========================================================
5057 class SortableElement : public set <const SMDS_MeshElement*>
5058 {
5059  public:
5060
5061   SortableElement( const SMDS_MeshElement* theElem )
5062     {
5063       myElem = theElem;
5064       SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
5065       while ( nodeIt->more() )
5066         this->insert( nodeIt->next() );
5067     }
5068
5069   const SMDS_MeshElement* Get() const
5070     { return myElem; }
5071
5072   void Set(const SMDS_MeshElement* e) const
5073     { myElem = e; }
5074
5075
5076  private:
5077   mutable const SMDS_MeshElement* myElem;
5078 };
5079
5080 //=======================================================================
5081 //function : FindEqualElements
5082 //purpose  : Return list of group of elements built on the same nodes.
5083 //           Search among theElements or in the whole mesh if theElements is empty
5084 //=======================================================================
5085 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
5086                                          TListOfListOfElementsID &      theGroupsOfElementsID)
5087 {
5088   myLastCreatedElems.Clear();
5089   myLastCreatedNodes.Clear();
5090
5091   typedef set<const SMDS_MeshElement*> TElemsSet;
5092   typedef map< SortableElement, int > TMapOfNodeSet;
5093   typedef list<int> TGroupOfElems;
5094
5095   TElemsSet elems;
5096   if ( theElements.empty() )
5097   { // get all elements in the mesh
5098     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
5099     while ( eIt->more() )
5100       elems.insert( elems.end(), eIt->next());
5101   }
5102   else
5103     elems = theElements;
5104
5105   vector< TGroupOfElems > arrayOfGroups;
5106   TGroupOfElems groupOfElems;
5107   TMapOfNodeSet mapOfNodeSet;
5108
5109   TElemsSet::iterator elemIt = elems.begin();
5110   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
5111     const SMDS_MeshElement* curElem = *elemIt;
5112     SortableElement SE(curElem);
5113     int ind = -1;
5114     // check uniqueness
5115     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
5116     if( !(pp.second) ) {
5117       TMapOfNodeSet::iterator& itSE = pp.first;
5118       ind = (*itSE).second;
5119       arrayOfGroups[ind].push_back(curElem->GetID());
5120     }
5121     else {
5122       groupOfElems.clear();
5123       groupOfElems.push_back(curElem->GetID());
5124       arrayOfGroups.push_back(groupOfElems);
5125       i++;
5126     }
5127   }
5128
5129   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
5130   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
5131     groupOfElems = *groupIt;
5132     if ( groupOfElems.size() > 1 ) {
5133       groupOfElems.sort();
5134       theGroupsOfElementsID.push_back(groupOfElems);
5135     }
5136   }
5137 }
5138
5139 //=======================================================================
5140 //function : MergeElements
5141 //purpose  : In each given group, substitute all elements by the first one.
5142 //=======================================================================
5143
5144 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
5145 {
5146   myLastCreatedElems.Clear();
5147   myLastCreatedNodes.Clear();
5148
5149   typedef list<int> TListOfIDs;
5150   TListOfIDs rmElemIds; // IDs of elems to remove
5151
5152   SMESHDS_Mesh* aMesh = GetMeshDS();
5153
5154   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
5155   while ( groupsIt != theGroupsOfElementsID.end() ) {
5156     TListOfIDs& aGroupOfElemID = *groupsIt;
5157     aGroupOfElemID.sort();
5158     int elemIDToKeep = aGroupOfElemID.front();
5159     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
5160     aGroupOfElemID.pop_front();
5161     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
5162     while ( idIt != aGroupOfElemID.end() ) {
5163       int elemIDToRemove = *idIt;
5164       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
5165       // add the kept element in groups of removed one (PAL15188)
5166       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
5167       rmElemIds.push_back( elemIDToRemove );
5168       ++idIt;
5169     }
5170     ++groupsIt;
5171   }
5172
5173   Remove( rmElemIds, false );
5174 }
5175
5176 //=======================================================================
5177 //function : MergeEqualElements
5178 //purpose  : Remove all but one of elements built on the same nodes.
5179 //=======================================================================
5180
5181 void SMESH_MeshEditor::MergeEqualElements()
5182 {
5183   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
5184                                                  to merge equal elements in the whole mesh */
5185   TListOfListOfElementsID aGroupsOfElementsID;
5186   FindEqualElements(aMeshElements, aGroupsOfElementsID);
5187   MergeElements(aGroupsOfElementsID);
5188 }
5189
5190 //=======================================================================
5191 //function : FindFaceInSet
5192 //purpose  : Return a face having linked nodes n1 and n2 and which is
5193 //           - not in avoidSet,
5194 //           - in elemSet provided that !elemSet.empty()
5195 //=======================================================================
5196
5197 const SMDS_MeshElement*
5198   SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
5199                                   const SMDS_MeshNode*    n2,
5200                                   const TIDSortedElemSet& elemSet,
5201                                   const TIDSortedElemSet& avoidSet)
5202
5203 {
5204   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
5205   while ( invElemIt->more() ) { // loop on inverse elements of n1
5206     const SMDS_MeshElement* elem = invElemIt->next();
5207     if (avoidSet.find( elem ) != avoidSet.end() )
5208       continue;
5209     if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
5210       continue;
5211     // get face nodes and find index of n1
5212     int i1, nbN = elem->NbNodes(), iNode = 0;
5213     const SMDS_MeshNode* faceNodes[ nbN ], *n;
5214     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5215     while ( nIt->more() ) {
5216       faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5217       if ( faceNodes[ iNode++ ] == n1 )
5218         i1 = iNode - 1;
5219     }
5220     // find a n2 linked to n1
5221     if(!elem->IsQuadratic()) {
5222       for ( iNode = 0; iNode < 2; iNode++ ) {
5223         if ( iNode ) // node before n1
5224           n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
5225         else         // node after n1
5226           n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
5227         if ( n == n2 )
5228           return elem;
5229       }
5230     }
5231     else { // analysis for quadratic elements
5232       bool IsFind = false;
5233       // check using only corner nodes
5234       for ( iNode = 0; iNode < 2; iNode++ ) {
5235         if ( iNode ) // node before n1
5236           n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
5237         else         // node after n1
5238           n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
5239         if ( n == n2 )
5240           IsFind = true;
5241       }
5242       if(IsFind) {
5243         return elem;
5244       }
5245       else {
5246         // check using all nodes
5247         const SMDS_QuadraticFaceOfNodes* F =
5248           static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
5249         // use special nodes iterator
5250         iNode = 0;
5251         SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5252         while ( anIter->more() ) {
5253           faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
5254           if ( faceNodes[ iNode++ ] == n1 )
5255             i1 = iNode - 1;
5256         }
5257         for ( iNode = 0; iNode < 2; iNode++ ) {
5258           if ( iNode ) // node before n1
5259             n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
5260           else         // node after n1
5261             n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
5262           if ( n == n2 ) {
5263             return elem;
5264           }
5265         }
5266       }
5267     } // end analysis for quadratic elements
5268   }
5269   return 0;
5270 }
5271
5272 //=======================================================================
5273 //function : findAdjacentFace
5274 //purpose  :
5275 //=======================================================================
5276
5277 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
5278                                                 const SMDS_MeshNode* n2,
5279                                                 const SMDS_MeshElement* elem)
5280 {
5281   TIDSortedElemSet elemSet, avoidSet;
5282   if ( elem )
5283     avoidSet.insert ( elem );
5284   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
5285 }
5286
5287 //=======================================================================
5288 //function : FindFreeBorder
5289 //purpose  :
5290 //=======================================================================
5291
5292 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
5293
5294 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
5295                                        const SMDS_MeshNode*             theSecondNode,
5296                                        const SMDS_MeshNode*             theLastNode,
5297                                        list< const SMDS_MeshNode* > &   theNodes,
5298                                        list< const SMDS_MeshElement* >& theFaces)
5299 {
5300   if ( !theFirstNode || !theSecondNode )
5301     return false;
5302   // find border face between theFirstNode and theSecondNode
5303   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
5304   if ( !curElem )
5305     return false;
5306
5307   theFaces.push_back( curElem );
5308   theNodes.push_back( theFirstNode );
5309   theNodes.push_back( theSecondNode );
5310
5311   //vector<const SMDS_MeshNode*> nodes;
5312   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
5313   set < const SMDS_MeshElement* > foundElems;
5314   bool needTheLast = ( theLastNode != 0 );
5315
5316   while ( nStart != theLastNode ) {
5317     if ( nStart == theFirstNode )
5318       return !needTheLast;
5319
5320     // find all free border faces sharing form nStart
5321
5322     list< const SMDS_MeshElement* > curElemList;
5323     list< const SMDS_MeshNode* > nStartList;
5324     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
5325     while ( invElemIt->more() ) {
5326       const SMDS_MeshElement* e = invElemIt->next();
5327       if ( e == curElem || foundElems.insert( e ).second ) {
5328         // get nodes
5329         int iNode = 0, nbNodes = e->NbNodes();
5330         const SMDS_MeshNode* nodes[nbNodes+1];
5331         if(e->IsQuadratic()) {
5332           const SMDS_QuadraticFaceOfNodes* F =
5333             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
5334           // use special nodes iterator
5335           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5336           while( anIter->more() ) {
5337             nodes[ iNode++ ] = anIter->next();
5338           }
5339         }
5340         else {
5341           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
5342           while ( nIt->more() )
5343             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5344         }
5345         nodes[ iNode ] = nodes[ 0 ];
5346         // check 2 links
5347         for ( iNode = 0; iNode < nbNodes; iNode++ )
5348           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
5349                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
5350               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
5351           {
5352             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
5353             curElemList.push_back( e );
5354           }
5355       }
5356     }
5357     // analyse the found
5358
5359     int nbNewBorders = curElemList.size();
5360     if ( nbNewBorders == 0 ) {
5361       // no free border furthermore
5362       return !needTheLast;
5363     }
5364     else if ( nbNewBorders == 1 ) {
5365       // one more element found
5366       nIgnore = nStart;
5367       nStart = nStartList.front();
5368       curElem = curElemList.front();
5369       theFaces.push_back( curElem );
5370       theNodes.push_back( nStart );
5371     }
5372     else {
5373       // several continuations found
5374       list< const SMDS_MeshElement* >::iterator curElemIt;
5375       list< const SMDS_MeshNode* >::iterator nStartIt;
5376       // check if one of them reached the last node
5377       if ( needTheLast ) {
5378         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
5379              curElemIt!= curElemList.end();
5380              curElemIt++, nStartIt++ )
5381           if ( *nStartIt == theLastNode ) {
5382             theFaces.push_back( *curElemIt );
5383             theNodes.push_back( *nStartIt );
5384             return true;
5385           }
5386       }
5387       // find the best free border by the continuations
5388       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
5389       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
5390       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
5391            curElemIt!= curElemList.end();
5392            curElemIt++, nStartIt++ )
5393       {
5394         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
5395         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
5396         // find one more free border
5397         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
5398           cNL->clear();
5399           cFL->clear();
5400         }
5401         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
5402           // choice: clear a worse one
5403           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
5404           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
5405           contNodes[ iWorse ].clear();
5406           contFaces[ iWorse ].clear();
5407         }
5408       }
5409       if ( contNodes[0].empty() && contNodes[1].empty() )
5410         return false;
5411
5412       // append the best free border
5413       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
5414       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
5415       theNodes.pop_back(); // remove nIgnore
5416       theNodes.pop_back(); // remove nStart
5417       theFaces.pop_back(); // remove curElem
5418       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
5419       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
5420       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
5421       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
5422       return true;
5423
5424     } // several continuations found
5425   } // while ( nStart != theLastNode )
5426
5427   return true;
5428 }
5429
5430 //=======================================================================
5431 //function : CheckFreeBorderNodes
5432 //purpose  : Return true if the tree nodes are on a free border
5433 //=======================================================================
5434
5435 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
5436                                             const SMDS_MeshNode* theNode2,
5437                                             const SMDS_MeshNode* theNode3)
5438 {
5439   list< const SMDS_MeshNode* > nodes;
5440   list< const SMDS_MeshElement* > faces;
5441   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
5442 }
5443
5444 //=======================================================================
5445 //function : SewFreeBorder
5446 //purpose  :
5447 //=======================================================================
5448
5449 SMESH_MeshEditor::Sew_Error
5450   SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
5451                                    const SMDS_MeshNode* theBordSecondNode,
5452                                    const SMDS_MeshNode* theBordLastNode,
5453                                    const SMDS_MeshNode* theSideFirstNode,
5454                                    const SMDS_MeshNode* theSideSecondNode,
5455                                    const SMDS_MeshNode* theSideThirdNode,
5456                                    const bool           theSideIsFreeBorder,
5457                                    const bool           toCreatePolygons,
5458                                    const bool           toCreatePolyedrs)
5459 {
5460   myLastCreatedElems.Clear();
5461   myLastCreatedNodes.Clear();
5462
5463   MESSAGE("::SewFreeBorder()");
5464   Sew_Error aResult = SEW_OK;
5465
5466   // ====================================
5467   //    find side nodes and elements
5468   // ====================================
5469
5470   list< const SMDS_MeshNode* > nSide[ 2 ];
5471   list< const SMDS_MeshElement* > eSide[ 2 ];
5472   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
5473   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
5474
5475   // Free border 1
5476   // --------------
5477   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
5478                       nSide[0], eSide[0])) {
5479     MESSAGE(" Free Border 1 not found " );
5480     aResult = SEW_BORDER1_NOT_FOUND;
5481   }
5482   if (theSideIsFreeBorder) {
5483     // Free border 2
5484     // --------------
5485     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
5486                         nSide[1], eSide[1])) {
5487       MESSAGE(" Free Border 2 not found " );
5488       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
5489     }
5490   }
5491   if ( aResult != SEW_OK )
5492     return aResult;
5493
5494   if (!theSideIsFreeBorder) {
5495     // Side 2
5496     // --------------
5497
5498     // -------------------------------------------------------------------------
5499     // Algo:
5500     // 1. If nodes to merge are not coincident, move nodes of the free border
5501     //    from the coord sys defined by the direction from the first to last
5502     //    nodes of the border to the correspondent sys of the side 2
5503     // 2. On the side 2, find the links most co-directed with the correspondent
5504     //    links of the free border
5505     // -------------------------------------------------------------------------
5506
5507     // 1. Since sewing may brake if there are volumes to split on the side 2,
5508     //    we wont move nodes but just compute new coordinates for them
5509     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
5510     TNodeXYZMap nBordXYZ;
5511     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
5512     list< const SMDS_MeshNode* >::iterator nBordIt;
5513
5514     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
5515     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
5516     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
5517     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
5518     double tol2 = 1.e-8;
5519     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
5520     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
5521       // Need node movement.
5522
5523       // find X and Z axes to create trsf
5524       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
5525       gp_Vec X = Zs ^ Zb;
5526       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
5527         // Zb || Zs
5528         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
5529
5530       // coord systems
5531       gp_Ax3 toBordAx( Pb1, Zb, X );
5532       gp_Ax3 fromSideAx( Ps1, Zs, X );
5533       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
5534       // set trsf
5535       gp_Trsf toBordSys, fromSide2Sys;
5536       toBordSys.SetTransformation( toBordAx );
5537       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
5538       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
5539
5540       // move
5541       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
5542         const SMDS_MeshNode* n = *nBordIt;
5543         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
5544         toBordSys.Transforms( xyz );
5545         fromSide2Sys.Transforms( xyz );
5546         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
5547       }
5548     }
5549     else {
5550       // just insert nodes XYZ in the nBordXYZ map
5551       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
5552         const SMDS_MeshNode* n = *nBordIt;
5553         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
5554       }
5555     }
5556
5557     // 2. On the side 2, find the links most co-directed with the correspondent
5558     //    links of the free border
5559
5560     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
5561     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
5562     sideNodes.push_back( theSideFirstNode );
5563
5564     bool hasVolumes = false;
5565     LinkID_Gen aLinkID_Gen( GetMeshDS() );
5566     set<long> foundSideLinkIDs, checkedLinkIDs;
5567     SMDS_VolumeTool volume;
5568     //const SMDS_MeshNode* faceNodes[ 4 ];
5569
5570     const SMDS_MeshNode*    sideNode;
5571     const SMDS_MeshElement* sideElem;
5572     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
5573     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
5574     nBordIt = bordNodes.begin();
5575     nBordIt++;
5576     // border node position and border link direction to compare with
5577     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
5578     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
5579     // choose next side node by link direction or by closeness to
5580     // the current border node:
5581     bool searchByDir = ( *nBordIt != theBordLastNode );
5582     do {
5583       // find the next node on the Side 2
5584       sideNode = 0;
5585       double maxDot = -DBL_MAX, minDist = DBL_MAX;
5586       long linkID;
5587       checkedLinkIDs.clear();
5588       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
5589
5590       // loop on inverse elements of current node (prevSideNode) on the Side 2
5591       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
5592       while ( invElemIt->more() )
5593       {
5594         const SMDS_MeshElement* elem = invElemIt->next();
5595         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
5596         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
5597         const SMDS_MeshNode* faceNodes[ nbNodes ];
5598         bool isVolume = volume.Set( elem );
5599         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : faceNodes;
5600         if ( isVolume ) // --volume
5601           hasVolumes = true;
5602         //else if ( nbNodes > 2 ) { // --face
5603         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
5604           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
5605           if(elem->IsQuadratic()) {
5606             const SMDS_QuadraticFaceOfNodes* F =
5607               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
5608             // use special nodes iterator
5609             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5610             while( anIter->more() ) {
5611               nodes[ iNode ] = anIter->next();
5612               if ( nodes[ iNode++ ] == prevSideNode )
5613                 iPrevNode = iNode - 1;
5614             }
5615           }
5616           else {
5617             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5618             while ( nIt->more() ) {
5619               nodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5620               if ( nodes[ iNode++ ] == prevSideNode )
5621                 iPrevNode = iNode - 1;
5622             }
5623           }
5624           // there are 2 links to check
5625           nbNodes = 2;
5626         }
5627         else // --edge
5628           continue;
5629         // loop on links, to be precise, on the second node of links
5630         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
5631           const SMDS_MeshNode* n = nodes[ iNode ];
5632           if ( isVolume ) {
5633             if ( !volume.IsLinked( n, prevSideNode ))
5634               continue;
5635           }
5636           else {
5637             if ( iNode ) // a node before prevSideNode
5638               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
5639             else         // a node after prevSideNode
5640               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
5641           }
5642           // check if this link was already used
5643           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
5644           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
5645           if (!isJustChecked &&
5646               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
5647           {
5648             // test a link geometrically
5649             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
5650             bool linkIsBetter = false;
5651             double dot, dist;
5652             if ( searchByDir ) { // choose most co-directed link
5653               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
5654               linkIsBetter = ( dot > maxDot );
5655             }
5656             else { // choose link with the node closest to bordPos
5657               dist = ( nextXYZ - bordPos ).SquareModulus();
5658               linkIsBetter = ( dist < minDist );
5659             }
5660             if ( linkIsBetter ) {
5661               maxDot = dot;
5662               minDist = dist;
5663               linkID = iLink;
5664               sideNode = n;
5665               sideElem = elem;
5666             }
5667           }
5668         }
5669       } // loop on inverse elements of prevSideNode
5670
5671       if ( !sideNode ) {
5672         MESSAGE(" Cant find path by links of the Side 2 ");
5673         return SEW_BAD_SIDE_NODES;
5674       }
5675       sideNodes.push_back( sideNode );
5676       sideElems.push_back( sideElem );
5677       foundSideLinkIDs.insert ( linkID );
5678       prevSideNode = sideNode;
5679
5680       if ( *nBordIt == theBordLastNode )
5681         searchByDir = false;
5682       else {
5683         // find the next border link to compare with
5684         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
5685         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
5686         // move to next border node if sideNode is before forward border node (bordPos)
5687         while ( *nBordIt != theBordLastNode && !searchByDir ) {
5688           prevBordNode = *nBordIt;
5689           nBordIt++;
5690           bordPos = nBordXYZ[ *nBordIt ];
5691           bordDir = bordPos - nBordXYZ[ prevBordNode ];
5692           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
5693         }
5694       }
5695     }
5696     while ( sideNode != theSideSecondNode );
5697
5698     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
5699       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
5700       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
5701     }
5702   } // end nodes search on the side 2
5703
5704   // ============================
5705   // sew the border to the side 2
5706   // ============================
5707
5708   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
5709   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
5710
5711   TListOfListOfNodes nodeGroupsToMerge;
5712   if ( nbNodes[0] == nbNodes[1] ||
5713       ( theSideIsFreeBorder && !theSideThirdNode)) {
5714
5715     // all nodes are to be merged
5716
5717     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
5718          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
5719          nIt[0]++, nIt[1]++ )
5720     {
5721       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
5722       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
5723       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
5724     }
5725   }
5726   else {
5727
5728     // insert new nodes into the border and the side to get equal nb of segments
5729
5730     // get normalized parameters of nodes on the borders
5731     double param[ 2 ][ maxNbNodes ];
5732     int iNode, iBord;
5733     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
5734       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
5735       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
5736       const SMDS_MeshNode* nPrev = *nIt;
5737       double bordLength = 0;
5738       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
5739         const SMDS_MeshNode* nCur = *nIt;
5740         gp_XYZ segment (nCur->X() - nPrev->X(),
5741                         nCur->Y() - nPrev->Y(),
5742                         nCur->Z() - nPrev->Z());
5743         double segmentLen = segment.Modulus();
5744         bordLength += segmentLen;
5745         param[ iBord ][ iNode ] = bordLength;
5746         nPrev = nCur;
5747       }
5748       // normalize within [0,1]
5749       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
5750         param[ iBord ][ iNode ] /= bordLength;
5751       }
5752     }
5753
5754     // loop on border segments
5755     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
5756     int i[ 2 ] = { 0, 0 };
5757     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
5758     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
5759
5760     TElemOfNodeListMap insertMap;
5761     TElemOfNodeListMap::iterator insertMapIt;
5762     // insertMap is
5763     // key:   elem to insert nodes into
5764     // value: 2 nodes to insert between + nodes to be inserted
5765     do {
5766       bool next[ 2 ] = { false, false };
5767
5768       // find min adjacent segment length after sewing
5769       double nextParam = 10., prevParam = 0;
5770       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
5771         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
5772           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
5773         if ( i[ iBord ] > 0 )
5774           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
5775       }
5776       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
5777       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
5778       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
5779
5780       // choose to insert or to merge nodes
5781       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
5782       if ( Abs( du ) <= minSegLen * 0.2 ) {
5783         // merge
5784         // ------
5785         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
5786         const SMDS_MeshNode* n0 = *nIt[0];
5787         const SMDS_MeshNode* n1 = *nIt[1];
5788         nodeGroupsToMerge.back().push_back( n1 );
5789         nodeGroupsToMerge.back().push_back( n0 );
5790         // position of node of the border changes due to merge
5791         param[ 0 ][ i[0] ] += du;
5792         // move n1 for the sake of elem shape evaluation during insertion.
5793         // n1 will be removed by MergeNodes() anyway
5794         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
5795         next[0] = next[1] = true;
5796       }
5797       else {
5798         // insert
5799         // ------
5800         int intoBord = ( du < 0 ) ? 0 : 1;
5801         const SMDS_MeshElement* elem = *eIt[ intoBord ];
5802         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
5803         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
5804         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
5805         if ( intoBord == 1 ) {
5806           // move node of the border to be on a link of elem of the side
5807           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
5808           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
5809           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
5810           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
5811           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
5812         }
5813         insertMapIt = insertMap.find( elem );
5814         bool notFound = ( insertMapIt == insertMap.end() );
5815         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
5816         if ( otherLink ) {
5817           // insert into another link of the same element:
5818           // 1. perform insertion into the other link of the elem
5819           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
5820           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
5821           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
5822           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
5823           // 2. perform insertion into the link of adjacent faces
5824           while (true) {
5825             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
5826             if ( adjElem )
5827               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
5828             else
5829               break;
5830           }
5831           if (toCreatePolyedrs) {
5832             // perform insertion into the links of adjacent volumes
5833             UpdateVolumes(n12, n22, nodeList);
5834           }
5835           // 3. find an element appeared on n1 and n2 after the insertion
5836           insertMap.erase( elem );
5837           elem = findAdjacentFace( n1, n2, 0 );
5838         }
5839         if ( notFound || otherLink ) {
5840           // add element and nodes of the side into the insertMap
5841           insertMapIt = insertMap.insert
5842             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
5843           (*insertMapIt).second.push_back( n1 );
5844           (*insertMapIt).second.push_back( n2 );
5845         }
5846         // add node to be inserted into elem
5847         (*insertMapIt).second.push_back( nIns );
5848         next[ 1 - intoBord ] = true;
5849       }
5850
5851       // go to the next segment
5852       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
5853         if ( next[ iBord ] ) {
5854           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
5855             eIt[ iBord ]++;
5856           nPrev[ iBord ] = *nIt[ iBord ];
5857           nIt[ iBord ]++; i[ iBord ]++;
5858         }
5859       }
5860     }
5861     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
5862
5863     // perform insertion of nodes into elements
5864
5865     for (insertMapIt = insertMap.begin();
5866          insertMapIt != insertMap.end();
5867          insertMapIt++ )
5868     {
5869       const SMDS_MeshElement* elem = (*insertMapIt).first;
5870       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
5871       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
5872       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
5873
5874       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
5875
5876       if ( !theSideIsFreeBorder ) {
5877         // look for and insert nodes into the faces adjacent to elem
5878         while (true) {
5879           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
5880           if ( adjElem )
5881             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
5882           else
5883             break;
5884         }
5885       }
5886       if (toCreatePolyedrs) {
5887         // perform insertion into the links of adjacent volumes
5888         UpdateVolumes(n1, n2, nodeList);
5889       }
5890     }
5891
5892   } // end: insert new nodes
5893
5894   MergeNodes ( nodeGroupsToMerge );
5895
5896   return aResult;
5897 }
5898
5899 //=======================================================================
5900 //function : InsertNodesIntoLink
5901 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
5902 //           and theBetweenNode2 and split theElement
5903 //=======================================================================
5904
5905 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
5906                                            const SMDS_MeshNode*        theBetweenNode1,
5907                                            const SMDS_MeshNode*        theBetweenNode2,
5908                                            list<const SMDS_MeshNode*>& theNodesToInsert,
5909                                            const bool                  toCreatePoly)
5910 {
5911   if ( theFace->GetType() != SMDSAbs_Face ) return;
5912
5913   // find indices of 2 link nodes and of the rest nodes
5914   int iNode = 0, il1, il2, i3, i4;
5915   il1 = il2 = i3 = i4 = -1;
5916   const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
5917
5918   if(theFace->IsQuadratic()) {
5919     const SMDS_QuadraticFaceOfNodes* F =
5920       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
5921     // use special nodes iterator
5922     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5923     while( anIter->more() ) {
5924       const SMDS_MeshNode* n = anIter->next();
5925       if ( n == theBetweenNode1 )
5926         il1 = iNode;
5927       else if ( n == theBetweenNode2 )
5928         il2 = iNode;
5929       else if ( i3 < 0 )
5930         i3 = iNode;
5931       else
5932         i4 = iNode;
5933       nodes[ iNode++ ] = n;
5934     }
5935   }
5936   else {
5937     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
5938     while ( nodeIt->more() ) {
5939       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
5940       if ( n == theBetweenNode1 )
5941         il1 = iNode;
5942       else if ( n == theBetweenNode2 )
5943         il2 = iNode;
5944       else if ( i3 < 0 )
5945         i3 = iNode;
5946       else
5947         i4 = iNode;
5948       nodes[ iNode++ ] = n;
5949     }
5950   }
5951   if ( il1 < 0 || il2 < 0 || i3 < 0 )
5952     return ;
5953
5954   // arrange link nodes to go one after another regarding the face orientation
5955   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
5956   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
5957   if ( reverse ) {
5958     iNode = il1;
5959     il1 = il2;
5960     il2 = iNode;
5961     aNodesToInsert.reverse();
5962   }
5963   // check that not link nodes of a quadrangles are in good order
5964   int nbFaceNodes = theFace->NbNodes();
5965   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
5966     iNode = i3;
5967     i3 = i4;
5968     i4 = iNode;
5969   }
5970
5971   if (toCreatePoly || theFace->IsPoly()) {
5972
5973     iNode = 0;
5974     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
5975
5976     // add nodes of face up to first node of link
5977     bool isFLN = false;
5978
5979     if(theFace->IsQuadratic()) {
5980       const SMDS_QuadraticFaceOfNodes* F =
5981         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
5982       // use special nodes iterator
5983       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5984       while( anIter->more()  && !isFLN ) {
5985         const SMDS_MeshNode* n = anIter->next();
5986         poly_nodes[iNode++] = n;
5987         if (n == nodes[il1]) {
5988           isFLN = true;
5989         }
5990       }
5991       // add nodes to insert
5992       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
5993       for (; nIt != aNodesToInsert.end(); nIt++) {
5994         poly_nodes[iNode++] = *nIt;
5995       }
5996       // add nodes of face starting from last node of link
5997       while ( anIter->more() ) {
5998         poly_nodes[iNode++] = anIter->next();
5999       }
6000     }
6001     else {
6002       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6003       while ( nodeIt->more() && !isFLN ) {
6004         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6005         poly_nodes[iNode++] = n;
6006         if (n == nodes[il1]) {
6007           isFLN = true;
6008         }
6009       }
6010       // add nodes to insert
6011       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6012       for (; nIt != aNodesToInsert.end(); nIt++) {
6013         poly_nodes[iNode++] = *nIt;
6014       }
6015       // add nodes of face starting from last node of link
6016       while ( nodeIt->more() ) {
6017         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6018         poly_nodes[iNode++] = n;
6019       }
6020     }
6021
6022     // edit or replace the face
6023     SMESHDS_Mesh *aMesh = GetMeshDS();
6024
6025     if (theFace->IsPoly()) {
6026       aMesh->ChangePolygonNodes(theFace, poly_nodes);
6027     }
6028     else {
6029       int aShapeId = FindShape( theFace );
6030
6031       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6032       myLastCreatedElems.Append(newElem);
6033       if ( aShapeId && newElem )
6034         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6035
6036       aMesh->RemoveElement(theFace);
6037     }
6038     return;
6039   }
6040
6041   if( !theFace->IsQuadratic() ) {
6042
6043     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
6044     int nbLinkNodes = 2 + aNodesToInsert.size();
6045     const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
6046     linkNodes[ 0 ] = nodes[ il1 ];
6047     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
6048     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6049     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6050       linkNodes[ iNode++ ] = *nIt;
6051     }
6052     // decide how to split a quadrangle: compare possible variants
6053     // and choose which of splits to be a quadrangle
6054     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
6055     if ( nbFaceNodes == 3 ) {
6056       iBestQuad = nbSplits;
6057       i4 = i3;
6058     }
6059     else if ( nbFaceNodes == 4 ) {
6060       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
6061       double aBestRate = DBL_MAX;
6062       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
6063         i1 = 0; i2 = 1;
6064         double aBadRate = 0;
6065         // evaluate elements quality
6066         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
6067           if ( iSplit == iQuad ) {
6068             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
6069                                    linkNodes[ i2++ ],
6070                                    nodes[ i3 ],
6071                                    nodes[ i4 ]);
6072             aBadRate += getBadRate( &quad, aCrit );
6073           }
6074           else {
6075             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
6076                                    linkNodes[ i2++ ],
6077                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
6078             aBadRate += getBadRate( &tria, aCrit );
6079           }
6080         }
6081         // choice
6082         if ( aBadRate < aBestRate ) {
6083           iBestQuad = iQuad;
6084           aBestRate = aBadRate;
6085         }
6086       }
6087     }
6088
6089     // create new elements
6090     SMESHDS_Mesh *aMesh = GetMeshDS();
6091     int aShapeId = FindShape( theFace );
6092
6093     i1 = 0; i2 = 1;
6094     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
6095       SMDS_MeshElement* newElem = 0;
6096       if ( iSplit == iBestQuad )
6097         newElem = aMesh->AddFace (linkNodes[ i1++ ],
6098                                   linkNodes[ i2++ ],
6099                                   nodes[ i3 ],
6100                                   nodes[ i4 ]);
6101       else
6102         newElem = aMesh->AddFace (linkNodes[ i1++ ],
6103                                   linkNodes[ i2++ ],
6104                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
6105       myLastCreatedElems.Append(newElem);
6106       if ( aShapeId && newElem )
6107         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6108     }
6109
6110     // change nodes of theFace
6111     const SMDS_MeshNode* newNodes[ 4 ];
6112     newNodes[ 0 ] = linkNodes[ i1 ];
6113     newNodes[ 1 ] = linkNodes[ i2 ];
6114     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
6115     newNodes[ 3 ] = nodes[ i4 ];
6116     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
6117   } // end if(!theFace->IsQuadratic())
6118   else { // theFace is quadratic
6119     // we have to split theFace on simple triangles and one simple quadrangle
6120     int tmp = il1/2;
6121     int nbshift = tmp*2;
6122     // shift nodes in nodes[] by nbshift
6123     int i,j;
6124     for(i=0; i<nbshift; i++) {
6125       const SMDS_MeshNode* n = nodes[0];
6126       for(j=0; j<nbFaceNodes-1; j++) {
6127         nodes[j] = nodes[j+1];
6128       }
6129       nodes[nbFaceNodes-1] = n;
6130     }
6131     il1 = il1 - nbshift;
6132     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
6133     //   n0      n1     n2    n0      n1     n2
6134     //     +-----+-----+        +-----+-----+
6135     //      \         /         |           |
6136     //       \       /          |           |
6137     //      n5+     +n3       n7+           +n3
6138     //         \   /            |           |
6139     //          \ /             |           |
6140     //           +              +-----+-----+
6141     //           n4           n6      n5     n4
6142
6143     // create new elements
6144     SMESHDS_Mesh *aMesh = GetMeshDS();
6145     int aShapeId = FindShape( theFace );
6146
6147     int n1,n2,n3;
6148     if(nbFaceNodes==6) { // quadratic triangle
6149       SMDS_MeshElement* newElem =
6150         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6151       myLastCreatedElems.Append(newElem);
6152       if ( aShapeId && newElem )
6153         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6154       if(theFace->IsMediumNode(nodes[il1])) {
6155         // create quadrangle
6156         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
6157         myLastCreatedElems.Append(newElem);
6158         if ( aShapeId && newElem )
6159           aMesh->SetMeshElementOnShape( newElem, aShapeId );
6160         n1 = 1;
6161         n2 = 2;
6162         n3 = 3;
6163       }
6164       else {
6165         // create quadrangle
6166         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
6167         myLastCreatedElems.Append(newElem);
6168         if ( aShapeId && newElem )
6169           aMesh->SetMeshElementOnShape( newElem, aShapeId );
6170         n1 = 0;
6171         n2 = 1;
6172         n3 = 5;
6173       }
6174     }
6175     else { // nbFaceNodes==8 - quadratic quadrangle
6176       SMDS_MeshElement* newElem =
6177         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6178       myLastCreatedElems.Append(newElem);
6179       if ( aShapeId && newElem )
6180         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6181       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
6182       myLastCreatedElems.Append(newElem);
6183       if ( aShapeId && newElem )
6184         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6185       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
6186       myLastCreatedElems.Append(newElem);
6187       if ( aShapeId && newElem )
6188         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6189       if(theFace->IsMediumNode(nodes[il1])) {
6190         // create quadrangle
6191         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
6192         myLastCreatedElems.Append(newElem);
6193         if ( aShapeId && newElem )
6194           aMesh->SetMeshElementOnShape( newElem, aShapeId );
6195         n1 = 1;
6196         n2 = 2;
6197         n3 = 3;
6198       }
6199       else {
6200         // create quadrangle
6201         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
6202         myLastCreatedElems.Append(newElem);
6203         if ( aShapeId && newElem )
6204           aMesh->SetMeshElementOnShape( newElem, aShapeId );
6205         n1 = 0;
6206         n2 = 1;
6207         n3 = 7;
6208       }
6209     }
6210     // create needed triangles using n1,n2,n3 and inserted nodes
6211     int nbn = 2 + aNodesToInsert.size();
6212     const SMDS_MeshNode* aNodes[nbn];
6213     aNodes[0] = nodes[n1];
6214     aNodes[nbn-1] = nodes[n2];
6215     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6216     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6217       aNodes[iNode++] = *nIt;
6218     }
6219     for(i=1; i<nbn; i++) {
6220       SMDS_MeshElement* newElem =
6221         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
6222       myLastCreatedElems.Append(newElem);
6223       if ( aShapeId && newElem )
6224         aMesh->SetMeshElementOnShape( newElem, aShapeId );
6225     }
6226     // remove old quadratic face
6227     aMesh->RemoveElement(theFace);
6228   }
6229 }
6230
6231 //=======================================================================
6232 //function : UpdateVolumes
6233 //purpose  :
6234 //=======================================================================
6235 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
6236                                       const SMDS_MeshNode*        theBetweenNode2,
6237                                       list<const SMDS_MeshNode*>& theNodesToInsert)
6238 {
6239   myLastCreatedElems.Clear();
6240   myLastCreatedNodes.Clear();
6241
6242   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
6243   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
6244     const SMDS_MeshElement* elem = invElemIt->next();
6245
6246     // check, if current volume has link theBetweenNode1 - theBetweenNode2
6247     SMDS_VolumeTool aVolume (elem);
6248     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
6249       continue;
6250
6251     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
6252     int iface, nbFaces = aVolume.NbFaces();
6253     vector<const SMDS_MeshNode *> poly_nodes;
6254     vector<int> quantities (nbFaces);
6255
6256     for (iface = 0; iface < nbFaces; iface++) {
6257       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
6258       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
6259       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
6260
6261       for (int inode = 0; inode < nbFaceNodes; inode++) {
6262         poly_nodes.push_back(faceNodes[inode]);
6263
6264         if (nbInserted == 0) {
6265           if (faceNodes[inode] == theBetweenNode1) {
6266             if (faceNodes[inode + 1] == theBetweenNode2) {
6267               nbInserted = theNodesToInsert.size();
6268
6269               // add nodes to insert
6270               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
6271               for (; nIt != theNodesToInsert.end(); nIt++) {
6272                 poly_nodes.push_back(*nIt);
6273               }
6274             }
6275           }
6276           else if (faceNodes[inode] == theBetweenNode2) {
6277             if (faceNodes[inode + 1] == theBetweenNode1) {
6278               nbInserted = theNodesToInsert.size();
6279
6280               // add nodes to insert in reversed order
6281               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
6282               nIt--;
6283               for (; nIt != theNodesToInsert.begin(); nIt--) {
6284                 poly_nodes.push_back(*nIt);
6285               }
6286               poly_nodes.push_back(*nIt);
6287             }
6288           }
6289           else {
6290           }
6291         }
6292       }
6293       quantities[iface] = nbFaceNodes + nbInserted;
6294     }
6295
6296     // Replace or update the volume
6297     SMESHDS_Mesh *aMesh = GetMeshDS();
6298
6299     if (elem->IsPoly()) {
6300       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6301
6302     }
6303     else {
6304       int aShapeId = FindShape( elem );
6305
6306       SMDS_MeshElement* newElem =
6307         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6308       myLastCreatedElems.Append(newElem);
6309       if (aShapeId && newElem)
6310         aMesh->SetMeshElementOnShape(newElem, aShapeId);
6311
6312       aMesh->RemoveElement(elem);
6313     }
6314   }
6315 }
6316
6317 //=======================================================================
6318 /*!
6319  * \brief Convert elements contained in a submesh to quadratic
6320  * \retval int - nb of checked elements
6321  */
6322 //=======================================================================
6323
6324 int SMESH_MeshEditor::ConvertElemToQuadratic(SMESHDS_SubMesh *   theSm,
6325                                               SMESH_MesherHelper& theHelper,
6326                                               const bool          theForce3d)
6327 {
6328   int nbElem = 0;
6329   if( !theSm ) return nbElem;
6330   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
6331   while(ElemItr->more())
6332   {
6333     nbElem++;
6334     const SMDS_MeshElement* elem = ElemItr->next();
6335     if( !elem || elem->IsQuadratic() ) continue;
6336
6337     int id = elem->GetID();
6338     int nbNodes = elem->NbNodes();
6339     vector<const SMDS_MeshNode *> aNds (nbNodes);
6340
6341     for(int i = 0; i < nbNodes; i++)
6342     {
6343       aNds[i] = elem->GetNode(i);
6344     }
6345     SMDSAbs_ElementType aType = elem->GetType();
6346
6347     theSm->RemoveElement(elem);
6348     GetMeshDS()->SMDS_Mesh::RemoveFreeElement(elem);
6349
6350     const SMDS_MeshElement* NewElem = 0;
6351
6352     switch( aType )
6353     {
6354     case SMDSAbs_Edge :
6355     {
6356       NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
6357       break;
6358     }
6359     case SMDSAbs_Face :
6360     {
6361       switch(nbNodes)
6362       {
6363       case 3:
6364         NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
6365         break;
6366       case 4:
6367         NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
6368         break;
6369       default:
6370         continue;
6371       }
6372       break;
6373     }
6374     case SMDSAbs_Volume :
6375     {
6376       switch(nbNodes)
6377       {
6378       case 4:
6379         NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, true);
6380         break;
6381       case 6:
6382         NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, true);
6383         break;
6384       case 8:
6385         NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
6386                                       aNds[4], aNds[5], aNds[6], aNds[7], id, true);
6387         break;
6388       default:
6389         continue;
6390       }
6391       break;
6392     }
6393     default :
6394       continue;
6395     }
6396     if( NewElem )
6397     {
6398       AddToSameGroups( NewElem, elem, GetMeshDS());
6399       theSm->AddElement( NewElem );
6400     }
6401     if ( NewElem != elem )
6402       RemoveElemFromGroups (elem, GetMeshDS());
6403   }
6404   return nbElem;
6405 }
6406
6407 //=======================================================================
6408 //function : ConvertToQuadratic
6409 //purpose  :
6410 //=======================================================================
6411 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
6412 {
6413   SMESHDS_Mesh* meshDS = GetMeshDS();
6414
6415   SMESH_MesherHelper aHelper(*myMesh);
6416   aHelper.SetIsQuadratic( true );
6417
6418   int nbCheckedElems = 0;
6419   if ( myMesh->HasShapeToMesh() )
6420   {
6421     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
6422     {
6423       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
6424       while ( smIt->more() ) {
6425         SMESH_subMesh* sm = smIt->next();
6426         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
6427           aHelper.SetSubShape( sm->GetSubShape() );
6428           nbCheckedElems += ConvertElemToQuadratic(smDS, aHelper, theForce3d);
6429         }
6430       }
6431     }
6432   }
6433   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
6434   if ( nbCheckedElems < totalNbElems ) // not all elements in submeshes
6435   {
6436     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
6437     while(aEdgeItr->more())
6438     {
6439       const SMDS_MeshEdge* edge = aEdgeItr->next();
6440       if(edge && !edge->IsQuadratic())
6441       {
6442         int id = edge->GetID();
6443         const SMDS_MeshNode* n1 = edge->GetNode(0);
6444         const SMDS_MeshNode* n2 = edge->GetNode(1);
6445
6446         meshDS->SMDS_Mesh::RemoveFreeElement(edge);
6447
6448         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
6449         if ( NewEdge )
6450           AddToSameGroups(NewEdge, edge, meshDS);
6451         if ( NewEdge != edge )
6452           RemoveElemFromGroups (edge, meshDS);
6453       }
6454     }
6455     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
6456     while(aFaceItr->more())
6457     {
6458       const SMDS_MeshFace* face = aFaceItr->next();
6459       if(!face || face->IsQuadratic() ) continue;
6460
6461       int id = face->GetID();
6462       int nbNodes = face->NbNodes();
6463       vector<const SMDS_MeshNode *> aNds (nbNodes);
6464
6465       for(int i = 0; i < nbNodes; i++)
6466       {
6467         aNds[i] = face->GetNode(i);
6468       }
6469
6470       meshDS->SMDS_Mesh::RemoveFreeElement(face);
6471
6472       SMDS_MeshFace * NewFace = 0;
6473       switch(nbNodes)
6474       {
6475       case 3:
6476         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
6477         break;
6478       case 4:
6479         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
6480         break;
6481       default:
6482         continue;
6483       }
6484       if ( NewFace )
6485         AddToSameGroups(NewFace, face, meshDS);
6486       if ( NewFace != face )
6487         RemoveElemFromGroups (face, meshDS);
6488     }
6489     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
6490     while(aVolumeItr->more())
6491     {
6492       const SMDS_MeshVolume* volume = aVolumeItr->next();
6493       if(!volume || volume->IsQuadratic() ) continue;
6494
6495       int id = volume->GetID();
6496       int nbNodes = volume->NbNodes();
6497       vector<const SMDS_MeshNode *> aNds (nbNodes);
6498
6499       for(int i = 0; i < nbNodes; i++)
6500       {
6501         aNds[i] = volume->GetNode(i);
6502       }
6503
6504       meshDS->SMDS_Mesh::RemoveFreeElement(volume);
6505
6506       SMDS_MeshVolume * NewVolume = 0;
6507       switch(nbNodes)
6508       {
6509       case 4:
6510         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
6511                                       aNds[3], id, true );
6512         break;
6513       case 6:
6514         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
6515                                       aNds[3], aNds[4], aNds[5], id, true);
6516         break;
6517       case 8:
6518         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
6519                                       aNds[4], aNds[5], aNds[6], aNds[7], id, true);
6520         break;
6521       default:
6522         continue;
6523       }
6524       if ( NewVolume )
6525         AddToSameGroups(NewVolume, volume, meshDS);
6526       if ( NewVolume != volume )
6527         RemoveElemFromGroups (volume, meshDS);
6528     }
6529   }
6530 }
6531
6532 //=======================================================================
6533 /*!
6534  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
6535  * \retval int - nb of checked elements
6536  */
6537 //=======================================================================
6538
6539 int SMESH_MeshEditor::RemoveQuadElem(SMESHDS_SubMesh *    theSm,
6540                                      SMDS_ElemIteratorPtr theItr,
6541                                      const int            theShapeID)
6542 {
6543   int nbElem = 0;
6544   SMESHDS_Mesh* meshDS = GetMeshDS();
6545   while( theItr->more() )
6546   {
6547     const SMDS_MeshElement* elem = theItr->next();
6548     nbElem++;
6549     if( elem && elem->IsQuadratic())
6550     {
6551       int id = elem->GetID();
6552       int nbNodes = elem->NbNodes();
6553       vector<const SMDS_MeshNode *> aNds, mediumNodes;
6554       aNds.reserve( nbNodes );
6555       mediumNodes.reserve( nbNodes );
6556
6557       for(int i = 0; i < nbNodes; i++)
6558       {
6559         const SMDS_MeshNode* n = elem->GetNode(i);
6560
6561         if( elem->IsMediumNode( n ) )
6562           mediumNodes.push_back( n );
6563         else
6564           aNds.push_back( n );
6565       }
6566       if( aNds.empty() ) continue;
6567       SMDSAbs_ElementType aType = elem->GetType();
6568
6569       //remove old quadratic element
6570       meshDS->SMDS_Mesh::RemoveFreeElement( elem );
6571       if ( theSm )
6572         theSm->RemoveElement( elem );
6573
6574       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
6575       if ( NewElem )
6576         AddToSameGroups(NewElem, elem, meshDS);
6577       if ( NewElem != elem )
6578         RemoveElemFromGroups (elem, meshDS);
6579       if( theSm && NewElem )
6580         theSm->AddElement( NewElem );
6581
6582       // remove medium nodes
6583       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
6584       for ( ; nIt != mediumNodes.end(); ++nIt ) {
6585         const SMDS_MeshNode* n = *nIt;
6586         if ( n->NbInverseNodes() == 0 ) {
6587           if ( n->GetPosition()->GetShapeId() != theShapeID )
6588             meshDS->RemoveFreeNode( n, meshDS->MeshElements
6589                                     ( n->GetPosition()->GetShapeId() ));
6590           else
6591             meshDS->RemoveFreeNode( n, theSm );
6592         }
6593       }
6594     }
6595   }
6596   return nbElem;
6597 }
6598
6599 //=======================================================================
6600 //function : ConvertFromQuadratic
6601 //purpose  :
6602 //=======================================================================
6603 bool  SMESH_MeshEditor::ConvertFromQuadratic()
6604 {
6605   int nbCheckedElems = 0;
6606   if ( myMesh->HasShapeToMesh() )
6607   {
6608     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
6609     {
6610       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
6611       while ( smIt->more() ) {
6612         SMESH_subMesh* sm = smIt->next();
6613         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
6614           nbCheckedElems += RemoveQuadElem( smDS, smDS->GetElements(), sm->GetId() );
6615       }
6616     }
6617   }
6618   
6619   int totalNbElems =
6620     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
6621   if ( nbCheckedElems < totalNbElems ) // not all elements in submeshes
6622   {
6623     SMESHDS_SubMesh *aSM = 0;
6624     RemoveQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
6625   }
6626
6627   return true;
6628 }
6629
6630 //=======================================================================
6631 //function : SewSideElements
6632 //purpose  :
6633 //=======================================================================
6634
6635 SMESH_MeshEditor::Sew_Error
6636   SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
6637                                      TIDSortedElemSet&    theSide2,
6638                                      const SMDS_MeshNode* theFirstNode1,
6639                                      const SMDS_MeshNode* theFirstNode2,
6640                                      const SMDS_MeshNode* theSecondNode1,
6641                                      const SMDS_MeshNode* theSecondNode2)
6642 {
6643   myLastCreatedElems.Clear();
6644   myLastCreatedNodes.Clear();
6645
6646   MESSAGE ("::::SewSideElements()");
6647   if ( theSide1.size() != theSide2.size() )
6648     return SEW_DIFF_NB_OF_ELEMENTS;
6649
6650   Sew_Error aResult = SEW_OK;
6651   // Algo:
6652   // 1. Build set of faces representing each side
6653   // 2. Find which nodes of the side 1 to merge with ones on the side 2
6654   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
6655
6656   // =======================================================================
6657   // 1. Build set of faces representing each side:
6658   // =======================================================================
6659   // a. build set of nodes belonging to faces
6660   // b. complete set of faces: find missing fices whose nodes are in set of nodes
6661   // c. create temporary faces representing side of volumes if correspondent
6662   //    face does not exist
6663
6664   SMESHDS_Mesh* aMesh = GetMeshDS();
6665   SMDS_Mesh aTmpFacesMesh;
6666   set<const SMDS_MeshElement*> faceSet1, faceSet2;
6667   set<const SMDS_MeshElement*> volSet1,  volSet2;
6668   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
6669   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
6670   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
6671   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
6672   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
6673   int iSide, iFace, iNode;
6674
6675   for ( iSide = 0; iSide < 2; iSide++ ) {
6676     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
6677     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
6678     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
6679     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
6680     set<const SMDS_MeshElement*>::iterator vIt;
6681     TIDSortedElemSet::iterator eIt;
6682     set<const SMDS_MeshNode*>::iterator    nIt;
6683
6684     // check that given nodes belong to given elements
6685     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
6686     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
6687     int firstIndex = -1, secondIndex = -1;
6688     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
6689       const SMDS_MeshElement* elem = *eIt;
6690       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
6691       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
6692       if ( firstIndex > -1 && secondIndex > -1 ) break;
6693     }
6694     if ( firstIndex < 0 || secondIndex < 0 ) {
6695       // we can simply return until temporary faces created
6696       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
6697     }
6698
6699     // -----------------------------------------------------------
6700     // 1a. Collect nodes of existing faces
6701     //     and build set of face nodes in order to detect missing
6702     //     faces corresponing to sides of volumes
6703     // -----------------------------------------------------------
6704
6705     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
6706
6707     // loop on the given element of a side
6708     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
6709       //const SMDS_MeshElement* elem = *eIt;
6710       const SMDS_MeshElement* elem = *eIt;
6711       if ( elem->GetType() == SMDSAbs_Face ) {
6712         faceSet->insert( elem );
6713         set <const SMDS_MeshNode*> faceNodeSet;
6714         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6715         while ( nodeIt->more() ) {
6716           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6717           nodeSet->insert( n );
6718           faceNodeSet.insert( n );
6719         }
6720         setOfFaceNodeSet.insert( faceNodeSet );
6721       }
6722       else if ( elem->GetType() == SMDSAbs_Volume )
6723         volSet->insert( elem );
6724     }
6725     // ------------------------------------------------------------------------------
6726     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
6727     // ------------------------------------------------------------------------------
6728
6729     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
6730       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
6731       while ( fIt->more() ) { // loop on faces sharing a node
6732         const SMDS_MeshElement* f = fIt->next();
6733         if ( faceSet->find( f ) == faceSet->end() ) {
6734           // check if all nodes are in nodeSet and
6735           // complete setOfFaceNodeSet if they are
6736           set <const SMDS_MeshNode*> faceNodeSet;
6737           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
6738           bool allInSet = true;
6739           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
6740             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6741             if ( nodeSet->find( n ) == nodeSet->end() )
6742               allInSet = false;
6743             else
6744               faceNodeSet.insert( n );
6745           }
6746           if ( allInSet ) {
6747             faceSet->insert( f );
6748             setOfFaceNodeSet.insert( faceNodeSet );
6749           }
6750         }
6751       }
6752     }
6753
6754     // -------------------------------------------------------------------------
6755     // 1c. Create temporary faces representing sides of volumes if correspondent
6756     //     face does not exist
6757     // -------------------------------------------------------------------------
6758
6759     if ( !volSet->empty() ) {
6760       //int nodeSetSize = nodeSet->size();
6761
6762       // loop on given volumes
6763       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
6764         SMDS_VolumeTool vol (*vIt);
6765         // loop on volume faces: find free faces
6766         // --------------------------------------
6767         list<const SMDS_MeshElement* > freeFaceList;
6768         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
6769           if ( !vol.IsFreeFace( iFace ))
6770             continue;
6771           // check if there is already a face with same nodes in a face set
6772           const SMDS_MeshElement* aFreeFace = 0;
6773           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
6774           int nbNodes = vol.NbFaceNodes( iFace );
6775           set <const SMDS_MeshNode*> faceNodeSet;
6776           vol.GetFaceNodes( iFace, faceNodeSet );
6777           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
6778           if ( isNewFace ) {
6779             // no such a face is given but it still can exist, check it
6780             if ( nbNodes == 3 ) {
6781               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
6782             }
6783             else if ( nbNodes == 4 ) {
6784               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
6785             }
6786             else {
6787               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
6788               aFreeFace = aMesh->FindFace(poly_nodes);
6789             }
6790           }
6791           if ( !aFreeFace ) {
6792             // create a temporary face
6793             if ( nbNodes == 3 ) {
6794               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
6795             }
6796             else if ( nbNodes == 4 ) {
6797               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
6798             }
6799             else {
6800               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
6801               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
6802             }
6803           }
6804           if ( aFreeFace )
6805             freeFaceList.push_back( aFreeFace );
6806
6807         } // loop on faces of a volume
6808
6809         // choose one of several free faces
6810         // --------------------------------------
6811         if ( freeFaceList.size() > 1 ) {
6812           // choose a face having max nb of nodes shared by other elems of a side
6813           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
6814           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
6815           while ( fIt != freeFaceList.end() ) { // loop on free faces
6816             int nbSharedNodes = 0;
6817             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
6818             while ( nodeIt->more() ) { // loop on free face nodes
6819               const SMDS_MeshNode* n =
6820                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6821               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
6822               while ( invElemIt->more() ) {
6823                 const SMDS_MeshElement* e = invElemIt->next();
6824                 if ( faceSet->find( e ) != faceSet->end() )
6825                   nbSharedNodes++;
6826                 if ( elemSet->find( e ) != elemSet->end() )
6827                   nbSharedNodes++;
6828               }
6829             }
6830             if ( nbSharedNodes >= maxNbNodes ) {
6831               maxNbNodes = nbSharedNodes;
6832               fIt++;
6833             }
6834             else
6835               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
6836           }
6837           if ( freeFaceList.size() > 1 )
6838           {
6839             // could not choose one face, use another way
6840             // choose a face most close to the bary center of the opposite side
6841             gp_XYZ aBC( 0., 0., 0. );
6842             set <const SMDS_MeshNode*> addedNodes;
6843             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
6844             eIt = elemSet2->begin();
6845             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
6846               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
6847               while ( nodeIt->more() ) { // loop on free face nodes
6848                 const SMDS_MeshNode* n =
6849                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6850                 if ( addedNodes.insert( n ).second )
6851                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
6852               }
6853             }
6854             aBC /= addedNodes.size();
6855             double minDist = DBL_MAX;
6856             fIt = freeFaceList.begin();
6857             while ( fIt != freeFaceList.end() ) { // loop on free faces
6858               double dist = 0;
6859               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
6860               while ( nodeIt->more() ) { // loop on free face nodes
6861                 const SMDS_MeshNode* n =
6862                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6863                 gp_XYZ p( n->X(),n->Y(),n->Z() );
6864                 dist += ( aBC - p ).SquareModulus();
6865               }
6866               if ( dist < minDist ) {
6867                 minDist = dist;
6868                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
6869               }
6870               else
6871                 fIt = freeFaceList.erase( fIt++ );
6872             }
6873           }
6874         } // choose one of several free faces of a volume
6875
6876         if ( freeFaceList.size() == 1 ) {
6877           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
6878           faceSet->insert( aFreeFace );
6879           // complete a node set with nodes of a found free face
6880 //           for ( iNode = 0; iNode < ; iNode++ )
6881 //             nodeSet->insert( fNodes[ iNode ] );
6882         }
6883
6884       } // loop on volumes of a side
6885
6886 //       // complete a set of faces if new nodes in a nodeSet appeared
6887 //       // ----------------------------------------------------------
6888 //       if ( nodeSetSize != nodeSet->size() ) {
6889 //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
6890 //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
6891 //           while ( fIt->more() ) { // loop on faces sharing a node
6892 //             const SMDS_MeshElement* f = fIt->next();
6893 //             if ( faceSet->find( f ) == faceSet->end() ) {
6894 //               // check if all nodes are in nodeSet and
6895 //               // complete setOfFaceNodeSet if they are
6896 //               set <const SMDS_MeshNode*> faceNodeSet;
6897 //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
6898 //               bool allInSet = true;
6899 //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
6900 //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6901 //                 if ( nodeSet->find( n ) == nodeSet->end() )
6902 //                   allInSet = false;
6903 //                 else
6904 //                   faceNodeSet.insert( n );
6905 //               }
6906 //               if ( allInSet ) {
6907 //                 faceSet->insert( f );
6908 //                 setOfFaceNodeSet.insert( faceNodeSet );
6909 //               }
6910 //             }
6911 //           }
6912 //         }
6913 //       }
6914     } // Create temporary faces, if there are volumes given
6915   } // loop on sides
6916
6917   if ( faceSet1.size() != faceSet2.size() ) {
6918     // delete temporary faces: they are in reverseElements of actual nodes
6919     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
6920     while ( tmpFaceIt->more() )
6921       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
6922     MESSAGE("Diff nb of faces");
6923     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
6924   }
6925
6926   // ============================================================
6927   // 2. Find nodes to merge:
6928   //              bind a node to remove to a node to put instead
6929   // ============================================================
6930
6931   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
6932   if ( theFirstNode1 != theFirstNode2 )
6933     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
6934   if ( theSecondNode1 != theSecondNode2 )
6935     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
6936
6937   LinkID_Gen aLinkID_Gen( GetMeshDS() );
6938   set< long > linkIdSet; // links to process
6939   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
6940
6941   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
6942   list< NLink > linkList[2];
6943   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
6944   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
6945   // loop on links in linkList; find faces by links and append links
6946   // of the found faces to linkList
6947   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
6948   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
6949     NLink link[] = { *linkIt[0], *linkIt[1] };
6950     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
6951     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
6952       continue;
6953
6954     // by links, find faces in the face sets,
6955     // and find indices of link nodes in the found faces;
6956     // in a face set, there is only one or no face sharing a link
6957     // ---------------------------------------------------------------
6958
6959     const SMDS_MeshElement* face[] = { 0, 0 };
6960     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
6961     vector<const SMDS_MeshNode*> fnodes1(9);
6962     vector<const SMDS_MeshNode*> fnodes2(9);
6963     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
6964     vector<const SMDS_MeshNode*> notLinkNodes1(6);
6965     vector<const SMDS_MeshNode*> notLinkNodes2(6);
6966     int iLinkNode[2][2];
6967     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
6968       const SMDS_MeshNode* n1 = link[iSide].first;
6969       const SMDS_MeshNode* n2 = link[iSide].second;
6970       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
6971       set< const SMDS_MeshElement* > fMap;
6972       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
6973         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
6974         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
6975         while ( fIt->more() ) { // loop on faces sharing a node
6976           const SMDS_MeshElement* f = fIt->next();
6977           if (faceSet->find( f ) != faceSet->end() && // f is in face set
6978               ! fMap.insert( f ).second ) // f encounters twice
6979           {
6980             if ( face[ iSide ] ) {
6981               MESSAGE( "2 faces per link " );
6982               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
6983               break;
6984             }
6985             face[ iSide ] = f;
6986             faceSet->erase( f );
6987             // get face nodes and find ones of a link
6988             iNode = 0;
6989             int nbl = -1;
6990             if(f->IsPoly()) {
6991               if(iSide==0) {
6992                 fnodes1.resize(f->NbNodes()+1);
6993                 notLinkNodes1.resize(f->NbNodes()-2);
6994               }
6995               else {
6996                 fnodes2.resize(f->NbNodes()+1);
6997                 notLinkNodes2.resize(f->NbNodes()-2);
6998               }
6999             }
7000             if(!f->IsQuadratic()) {
7001               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
7002               while ( nIt->more() ) {
7003                 const SMDS_MeshNode* n =
7004                   static_cast<const SMDS_MeshNode*>( nIt->next() );
7005                 if ( n == n1 ) {
7006                   iLinkNode[ iSide ][ 0 ] = iNode;
7007                 }
7008                 else if ( n == n2 ) {
7009                   iLinkNode[ iSide ][ 1 ] = iNode;
7010                 }
7011                 //else if ( notLinkNodes[ iSide ][ 0 ] )
7012                 //  notLinkNodes[ iSide ][ 1 ] = n;
7013                 //else
7014                 //  notLinkNodes[ iSide ][ 0 ] = n;
7015                 else {
7016                   nbl++;
7017                   if(iSide==0)
7018                     notLinkNodes1[nbl] = n;
7019                     //notLinkNodes1.push_back(n);
7020                   else
7021                     notLinkNodes2[nbl] = n;
7022                     //notLinkNodes2.push_back(n);
7023                 }
7024                 //faceNodes[ iSide ][ iNode++ ] = n;
7025                 if(iSide==0) {
7026                   fnodes1[iNode++] = n;
7027                 }
7028                 else {
7029                   fnodes2[iNode++] = n;
7030                 }
7031               }
7032             }
7033             else { // f->IsQuadratic()
7034               const SMDS_QuadraticFaceOfNodes* F =
7035                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
7036               // use special nodes iterator
7037               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7038               while ( anIter->more() ) {
7039                 const SMDS_MeshNode* n =
7040                   static_cast<const SMDS_MeshNode*>( anIter->next() );
7041                 if ( n == n1 ) {
7042                   iLinkNode[ iSide ][ 0 ] = iNode;
7043                 }
7044                 else if ( n == n2 ) {
7045                   iLinkNode[ iSide ][ 1 ] = iNode;
7046                 }
7047                 else {
7048                   nbl++;
7049                   if(iSide==0) {
7050                     notLinkNodes1[nbl] = n;
7051                   }
7052                   else {
7053                     notLinkNodes2[nbl] = n;
7054                   }
7055                 }
7056                 if(iSide==0) {
7057                   fnodes1[iNode++] = n;
7058                 }
7059                 else {
7060                   fnodes2[iNode++] = n;
7061                 }
7062               }
7063             }
7064             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
7065             if(iSide==0) {
7066               fnodes1[iNode] = fnodes1[0];
7067             }
7068             else {
7069               fnodes2[iNode] = fnodes1[0];
7070             }
7071           }
7072         }
7073       }
7074     }
7075
7076     // check similarity of elements of the sides
7077     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7078       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7079       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7080         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7081       }
7082       else {
7083         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7084       }
7085       break; // do not return because it s necessary to remove tmp faces
7086     }
7087
7088     // set nodes to merge
7089     // -------------------
7090
7091     if ( face[0] && face[1] )  {
7092       int nbNodes = face[0]->NbNodes();
7093       if ( nbNodes != face[1]->NbNodes() ) {
7094         MESSAGE("Diff nb of face nodes");
7095         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7096         break; // do not return because it s necessary to remove tmp faces
7097       }
7098       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
7099       if ( nbNodes == 3 ) {
7100         //nReplaceMap.insert( TNodeNodeMap::value_type
7101         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7102         nReplaceMap.insert( TNodeNodeMap::value_type
7103                            ( notLinkNodes1[0], notLinkNodes2[0] ));
7104       }
7105       else {
7106         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7107           // analyse link orientation in faces
7108           int i1 = iLinkNode[ iSide ][ 0 ];
7109           int i2 = iLinkNode[ iSide ][ 1 ];
7110           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
7111           // if notLinkNodes are the first and the last ones, then
7112           // their order does not correspond to the link orientation
7113           if (( i1 == 1 && i2 == 2 ) ||
7114               ( i1 == 2 && i2 == 1 ))
7115             reverse[ iSide ] = !reverse[ iSide ];
7116         }
7117         if ( reverse[0] == reverse[1] ) {
7118           //nReplaceMap.insert( TNodeNodeMap::value_type
7119           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7120           //nReplaceMap.insert( TNodeNodeMap::value_type
7121           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
7122           for(int nn=0; nn<nbNodes-2; nn++) {
7123             nReplaceMap.insert( TNodeNodeMap::value_type
7124                              ( notLinkNodes1[nn], notLinkNodes2[nn] ));
7125           }
7126         }
7127         else {
7128           //nReplaceMap.insert( TNodeNodeMap::value_type
7129           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
7130           //nReplaceMap.insert( TNodeNodeMap::value_type
7131           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
7132           for(int nn=0; nn<nbNodes-2; nn++) {
7133             nReplaceMap.insert( TNodeNodeMap::value_type
7134                              ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
7135           }
7136         }
7137       }
7138
7139       // add other links of the faces to linkList
7140       // -----------------------------------------
7141
7142       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
7143       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
7144         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
7145         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
7146         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
7147         if ( !iter_isnew.second ) { // already in a set: no need to process
7148           linkIdSet.erase( iter_isnew.first );
7149         }
7150         else // new in set == encountered for the first time: add
7151         {
7152           //const SMDS_MeshNode* n1 = nodes[ iNode ];
7153           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
7154           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
7155           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
7156           linkList[0].push_back ( NLink( n1, n2 ));
7157           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
7158         }
7159       }
7160     } // 2 faces found
7161   } // loop on link lists
7162
7163   if ( aResult == SEW_OK &&
7164       ( linkIt[0] != linkList[0].end() ||
7165        !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
7166     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
7167             " " << (faceSetPtr[1]->empty()));
7168     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7169   }
7170
7171   // ====================================================================
7172   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7173   // ====================================================================
7174
7175   // delete temporary faces: they are in reverseElements of actual nodes
7176   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7177   while ( tmpFaceIt->more() )
7178     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7179
7180   if ( aResult != SEW_OK)
7181     return aResult;
7182
7183   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
7184   // loop on nodes replacement map
7185   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
7186   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
7187     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
7188       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
7189       nodeIDsToRemove.push_back( nToRemove->GetID() );
7190       // loop on elements sharing nToRemove
7191       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7192       while ( invElemIt->more() ) {
7193         const SMDS_MeshElement* e = invElemIt->next();
7194         // get a new suite of nodes: make replacement
7195         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
7196         vector< const SMDS_MeshNode*> nodes( nbNodes );
7197         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7198         while ( nIt->more() ) {
7199           const SMDS_MeshNode* n =
7200             static_cast<const SMDS_MeshNode*>( nIt->next() );
7201           nnIt = nReplaceMap.find( n );
7202           if ( nnIt != nReplaceMap.end() ) {
7203             nbReplaced++;
7204             n = (*nnIt).second;
7205           }
7206           nodes[ i++ ] = n;
7207         }
7208         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
7209         //         elemIDsToRemove.push_back( e->GetID() );
7210         //       else
7211         if ( nbReplaced )
7212           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
7213       }
7214     }
7215
7216   Remove( nodeIDsToRemove, true );
7217
7218   return aResult;
7219 }
7220
7221 //================================================================================
7222   /*!
7223    * \brief Find corresponding nodes in two sets of faces
7224     * \param theSide1 - first face set
7225     * \param theSide2 - second first face
7226     * \param theFirstNode1 - a boundary node of set 1
7227     * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
7228     * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
7229     * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
7230     * \param nReplaceMap - output map of corresponding nodes
7231     * \retval bool  - is a success or not
7232    */
7233 //================================================================================
7234
7235 #ifdef _DEBUG_
7236 //#define DEBUG_MATCHING_NODES
7237 #endif
7238
7239 SMESH_MeshEditor::Sew_Error
7240 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
7241                                     set<const SMDS_MeshElement*>& theSide2,
7242                                     const SMDS_MeshNode*          theFirstNode1,
7243                                     const SMDS_MeshNode*          theFirstNode2,
7244                                     const SMDS_MeshNode*          theSecondNode1,
7245                                     const SMDS_MeshNode*          theSecondNode2,
7246                                     TNodeNodeMap &                nReplaceMap)
7247 {
7248   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
7249
7250   nReplaceMap.clear();
7251   if ( theFirstNode1 != theFirstNode2 )
7252     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
7253   if ( theSecondNode1 != theSecondNode2 )
7254     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
7255
7256   set< TLink > linkSet; // set of nodes where order of nodes is ignored
7257   linkSet.insert( TLink( theFirstNode1, theSecondNode1 ));
7258
7259   list< NLink > linkList[2];
7260   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
7261   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
7262
7263   // loop on links in linkList; find faces by links and append links
7264   // of the found faces to linkList
7265   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
7266   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
7267     NLink link[] = { *linkIt[0], *linkIt[1] };
7268     if ( linkSet.find( link[0] ) == linkSet.end() )
7269       continue;
7270
7271     // by links, find faces in the face sets,
7272     // and find indices of link nodes in the found faces;
7273     // in a face set, there is only one or no face sharing a link
7274     // ---------------------------------------------------------------
7275
7276     const SMDS_MeshElement* face[] = { 0, 0 };
7277     list<const SMDS_MeshNode*> notLinkNodes[2];
7278     //bool reverse[] = { false, false }; // order of notLinkNodes
7279     int nbNodes[2];
7280     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
7281     {
7282       const SMDS_MeshNode* n1 = link[iSide].first;
7283       const SMDS_MeshNode* n2 = link[iSide].second;
7284       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7285       set< const SMDS_MeshElement* > facesOfNode1;
7286       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
7287       {
7288         // during a loop of the first node, we find all faces around n1,
7289         // during a loop of the second node, we find one face sharing both n1 and n2
7290         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
7291         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
7292         while ( fIt->more() ) { // loop on faces sharing a node
7293           const SMDS_MeshElement* f = fIt->next();
7294           if (faceSet->find( f ) != faceSet->end() && // f is in face set
7295               ! facesOfNode1.insert( f ).second ) // f encounters twice
7296           {
7297             if ( face[ iSide ] ) {
7298               MESSAGE( "2 faces per link " );
7299               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7300             }
7301             face[ iSide ] = f;
7302             faceSet->erase( f );
7303
7304             // get not link nodes
7305             int nbN = f->NbNodes();
7306             if ( f->IsQuadratic() )
7307               nbN /= 2;
7308             nbNodes[ iSide ] = nbN;
7309             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
7310             int i1 = f->GetNodeIndex( n1 );
7311             int i2 = f->GetNodeIndex( n2 );
7312             int iEnd = nbN, iBeg = -1, iDelta = 1;
7313             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
7314             if ( reverse ) {
7315               std::swap( iEnd, iBeg ); iDelta = -1;
7316             }
7317             int i = i2;
7318             while ( true ) {
7319               i += iDelta;
7320               if ( i == iEnd ) i = iBeg + iDelta;
7321               if ( i == i1 ) break;
7322               nodes.push_back ( f->GetNode( i ) );
7323             }
7324           }
7325         }
7326       }
7327     }
7328     // check similarity of elements of the sides
7329     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7330       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7331       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7332         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7333       }
7334       else {
7335         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7336       }
7337     }
7338
7339     // set nodes to merge
7340     // -------------------
7341
7342     if ( face[0] && face[1] )  {
7343       if ( nbNodes[0] != nbNodes[1] ) {
7344         MESSAGE("Diff nb of face nodes");
7345         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7346       }
7347 #ifdef DEBUG_MATCHING_NODES
7348       cout << " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
7349            << " F 1: " << face[0];
7350       cout << "| Link 2: " << link[1].first->GetID() <<" "<< link[1].second->GetID()
7351            << " F 2: " << face[1] << " | Bind: "<<endl ;
7352 #endif
7353       int nbN = nbNodes[0];
7354       {
7355         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
7356         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
7357         for ( int i = 0 ; i < nbN - 2; ++i ) {
7358 #ifdef DEBUG_MATCHING_NODES
7359           cout << (*n1)->GetID() << " to " << (*n2)->GetID() << endl;
7360 #endif
7361           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
7362         }
7363       }
7364
7365       // add other links of the face 1 to linkList
7366       // -----------------------------------------
7367
7368       const SMDS_MeshElement* f0 = face[0];
7369       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
7370       for ( int i = 0; i < nbN; i++ )
7371       {
7372         const SMDS_MeshNode* n2 = f0->GetNode( i );
7373         pair< set< TLink >::iterator, bool > iter_isnew =
7374           linkSet.insert( TLink( n1, n2 ));
7375         if ( !iter_isnew.second ) { // already in a set: no need to process
7376           linkSet.erase( iter_isnew.first );
7377         }
7378         else // new in set == encountered for the first time: add
7379         {
7380 #ifdef DEBUG_MATCHING_NODES
7381           cout << "Add link 1: " << n1->GetID() << " " << n2->GetID() << " ";
7382           cout << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " << endl;
7383 #endif
7384           linkList[0].push_back ( NLink( n1, n2 ));
7385           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
7386         }
7387         n1 = n2;
7388       }
7389     } // 2 faces found
7390   } // loop on link lists
7391
7392   return SEW_OK;
7393 }