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