Salome HOME
08db3b3e903645be9abe8df340b71504062707e8
[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_Algo.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_Group.hxx"
44 #include "SMESH_MesherHelper.hxx"
45 #include "SMESH_OctreeNode.hxx"
46 #include "SMESH_subMesh.hxx"
47
48 #include "utilities.h"
49
50 #include <BRepAdaptor_Surface.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <BRep_Tool.hxx>
53 #include <ElCLib.hxx>
54 #include <Extrema_GenExtPS.hxx>
55 #include <Extrema_POnCurv.hxx>
56 #include <Extrema_POnSurf.hxx>
57 #include <GC_MakeSegment.hxx>
58 #include <Geom2d_Curve.hxx>
59 #include <GeomAPI_ExtremaCurveCurve.hxx>
60 #include <GeomAdaptor_Surface.hxx>
61 #include <Geom_Curve.hxx>
62 #include <Geom_Line.hxx>
63 #include <Geom_Surface.hxx>
64 #include <IntAna_IntConicQuad.hxx>
65 #include <IntAna_Quadric.hxx>
66 #include <Precision.hxx>
67 #include <TColStd_ListOfInteger.hxx>
68 #include <TopAbs_State.hxx>
69 #include <TopExp.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_ListIteratorOfListOfShape.hxx>
72 #include <TopTools_ListOfShape.hxx>
73 #include <TopTools_SequenceOfShape.hxx>
74 #include <TopoDS.hxx>
75 #include <TopoDS_Face.hxx>
76 #include <gp.hxx>
77 #include <gp_Ax1.hxx>
78 #include <gp_Dir.hxx>
79 #include <gp_Lin.hxx>
80 #include <gp_Pln.hxx>
81 #include <gp_Trsf.hxx>
82 #include <gp_Vec.hxx>
83 #include <gp_XY.hxx>
84 #include <gp_XYZ.hxx>
85
86 #include <math.h>
87
88 #include <map>
89 #include <set>
90 #include <numeric>
91 #include <limits>
92
93 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
94
95 using namespace std;
96 using namespace SMESH::Controls;
97
98 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
100
101 //=======================================================================
102 //function : SMESH_MeshEditor
103 //purpose  :
104 //=======================================================================
105
106 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
107   :myMesh( theMesh ) // theMesh may be NULL
108 {
109 }
110
111 //=======================================================================
112 /*!
113  * \brief Add element
114  */
115 //=======================================================================
116
117 SMDS_MeshElement*
118 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
119                              const SMDSAbs_ElementType            type,
120                              const bool                           isPoly,
121                              const int                            ID)
122 {
123   SMDS_MeshElement* e = 0;
124   int nbnode = node.size();
125   SMESHDS_Mesh* mesh = GetMeshDS();
126   switch ( type ) {
127   case SMDSAbs_0DElement:
128     if ( nbnode == 1 )
129       if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
130       else      e = mesh->Add0DElement      (node[0] );
131     break;
132   case SMDSAbs_Edge:
133     if ( nbnode == 2 )
134       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
135       else      e = mesh->AddEdge      (node[0], node[1] );
136     else if ( nbnode == 3 )
137       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
138       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
139     break;
140   case SMDSAbs_Face:
141     if ( !isPoly ) {
142       if      (nbnode == 3)
143         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
144         else      e = mesh->AddFace      (node[0], node[1], node[2] );
145       else if (nbnode == 4) 
146         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
147         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
148       else if (nbnode == 6)
149         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
150                                           node[4], node[5], ID);
151         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
152                                           node[4], node[5] );
153       else if (nbnode == 8)
154         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                           node[4], node[5], node[6], node[7], ID);
156         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                           node[4], node[5], node[6], node[7] );
158     } else {
159       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
160       else      e = mesh->AddPolygonalFace      (node    );
161     }
162     break;
163   case SMDSAbs_Volume:
164     if ( !isPoly ) {
165       if      (nbnode == 4)
166         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
168       else if (nbnode == 5)
169         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
170                                             node[4], ID);
171         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
172                                             node[4] );
173       else if (nbnode == 6)
174         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175                                             node[4], node[5], ID);
176         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
177                                             node[4], node[5] );
178       else if (nbnode == 8)
179         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180                                             node[4], node[5], node[6], node[7], ID);
181         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
182                                             node[4], node[5], node[6], node[7] );
183       else if (nbnode == 10)
184         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                             node[4], node[5], node[6], node[7],
186                                             node[8], node[9], ID);
187         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
188                                             node[4], node[5], node[6], node[7],
189                                             node[8], node[9] );
190       else if (nbnode == 13)
191         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192                                             node[4], node[5], node[6], node[7],
193                                             node[8], node[9], node[10],node[11],
194                                             node[12],ID);
195         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
196                                             node[4], node[5], node[6], node[7],
197                                             node[8], node[9], node[10],node[11],
198                                             node[12] );
199       else if (nbnode == 15)
200         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201                                             node[4], node[5], node[6], node[7],
202                                             node[8], node[9], node[10],node[11],
203                                             node[12],node[13],node[14],ID);
204         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
205                                             node[4], node[5], node[6], node[7],
206                                             node[8], node[9], node[10],node[11],
207                                             node[12],node[13],node[14] );
208       else if (nbnode == 20)
209         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
210                                             node[4], node[5], node[6], node[7],
211                                             node[8], node[9], node[10],node[11],
212                                             node[12],node[13],node[14],node[15],
213                                             node[16],node[17],node[18],node[19],ID);
214         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
215                                             node[4], node[5], node[6], node[7],
216                                             node[8], node[9], node[10],node[11],
217                                             node[12],node[13],node[14],node[15],
218                                             node[16],node[17],node[18],node[19] );
219     }
220   }
221   return e;
222 }
223
224 //=======================================================================
225 /*!
226  * \brief Add element
227  */
228 //=======================================================================
229
230 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
231                                                const SMDSAbs_ElementType type,
232                                                const bool                isPoly,
233                                                const int                 ID)
234 {
235   vector<const SMDS_MeshNode*> nodes;
236   nodes.reserve( nodeIDs.size() );
237   vector<int>::const_iterator id = nodeIDs.begin();
238   while ( id != nodeIDs.end() ) {
239     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
240       nodes.push_back( node );
241     else
242       return 0;
243   }
244   return AddElement( nodes, type, isPoly, ID );
245 }
246
247 //=======================================================================
248 //function : Remove
249 //purpose  : Remove a node or an element.
250 //           Modify a compute state of sub-meshes which become empty
251 //=======================================================================
252
253 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
254                                const bool         isNodes )
255 {
256   myLastCreatedElems.Clear();
257   myLastCreatedNodes.Clear();
258
259   SMESHDS_Mesh* aMesh = GetMeshDS();
260   set< SMESH_subMesh *> smmap;
261
262   list<int>::const_iterator it = theIDs.begin();
263   for ( ; it != theIDs.end(); it++ ) {
264     const SMDS_MeshElement * elem;
265     if ( isNodes )
266       elem = aMesh->FindNode( *it );
267     else
268       elem = aMesh->FindElement( *it );
269     if ( !elem )
270       continue;
271
272     // Notify VERTEX sub-meshes about modification
273     if ( isNodes ) {
274       const SMDS_MeshNode* node = cast2Node( elem );
275       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
276         if ( int aShapeID = node->GetPosition()->GetShapeId() )
277           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
278             smmap.insert( sm );
279     }
280     // Find sub-meshes to notify about modification
281     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
282     //     while ( nodeIt->more() ) {
283     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
284     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
285     //       if ( aPosition.get() ) {
286     //         if ( int aShapeID = aPosition->GetShapeId() ) {
287     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
288     //             smmap.insert( sm );
289     //         }
290     //       }
291     //     }
292
293     // Do remove
294     if ( isNodes )
295       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
296     else
297       aMesh->RemoveElement( elem );
298   }
299
300   // Notify sub-meshes about modification
301   if ( !smmap.empty() ) {
302     set< SMESH_subMesh *>::iterator smIt;
303     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
304       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
305   }
306
307   //   // Check if the whole mesh becomes empty
308   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
309   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
310
311   return true;
312 }
313
314 //=======================================================================
315 //function : FindShape
316 //purpose  : Return an index of the shape theElem is on
317 //           or zero if a shape not found
318 //=======================================================================
319
320 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
321 {
322   myLastCreatedElems.Clear();
323   myLastCreatedNodes.Clear();
324
325   SMESHDS_Mesh * aMesh = GetMeshDS();
326   if ( aMesh->ShapeToMesh().IsNull() )
327     return 0;
328
329   if ( theElem->GetType() == SMDSAbs_Node ) {
330     const SMDS_PositionPtr& aPosition =
331       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
332     if ( aPosition.get() )
333       return aPosition->GetShapeId();
334     else
335       return 0;
336   }
337
338   TopoDS_Shape aShape; // the shape a node is on
339   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
340   while ( nodeIt->more() ) {
341     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
342     const SMDS_PositionPtr& aPosition = node->GetPosition();
343     if ( aPosition.get() ) {
344       int aShapeID = aPosition->GetShapeId();
345       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
346       if ( sm ) {
347         if ( sm->Contains( theElem ))
348           return aShapeID;
349         if ( aShape.IsNull() )
350           aShape = aMesh->IndexToShape( aShapeID );
351       }
352       else {
353         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
354       }
355     }
356   }
357
358   // None of nodes is on a proper shape,
359   // find the shape among ancestors of aShape on which a node is
360   if ( aShape.IsNull() ) {
361     //MESSAGE ("::FindShape() - NONE node is on shape")
362     return 0;
363   }
364   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
365   for ( ; ancIt.More(); ancIt.Next() ) {
366     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
367     if ( sm && sm->Contains( theElem ))
368       return aMesh->ShapeToIndex( ancIt.Value() );
369   }
370
371   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
372   return 0;
373 }
374
375 //=======================================================================
376 //function : IsMedium
377 //purpose  :
378 //=======================================================================
379
380 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
381                                 const SMDSAbs_ElementType typeToCheck)
382 {
383   bool isMedium = false;
384   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
385   while (it->more() && !isMedium ) {
386     const SMDS_MeshElement* elem = it->next();
387     isMedium = elem->IsMediumNode(node);
388   }
389   return isMedium;
390 }
391
392 //=======================================================================
393 //function : ShiftNodesQuadTria
394 //purpose  : auxilary
395 //           Shift nodes in the array corresponded to quadratic triangle
396 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
397 //=======================================================================
398 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
399 {
400   const SMDS_MeshNode* nd1 = aNodes[0];
401   aNodes[0] = aNodes[1];
402   aNodes[1] = aNodes[2];
403   aNodes[2] = nd1;
404   const SMDS_MeshNode* nd2 = aNodes[3];
405   aNodes[3] = aNodes[4];
406   aNodes[4] = aNodes[5];
407   aNodes[5] = nd2;
408 }
409
410 //=======================================================================
411 //function : GetNodesFromTwoTria
412 //purpose  : auxilary
413 //           Shift nodes in the array corresponded to quadratic triangle
414 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
415 //=======================================================================
416 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
417                                 const SMDS_MeshElement * theTria2,
418                                 const SMDS_MeshNode* N1[],
419                                 const SMDS_MeshNode* N2[])
420 {
421   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
422   int i=0;
423   while(i<6) {
424     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
425     i++;
426   }
427   if(it->more()) return false;
428   it = theTria2->nodesIterator();
429   i=0;
430   while(i<6) {
431     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
432     i++;
433   }
434   if(it->more()) return false;
435
436   int sames[3] = {-1,-1,-1};
437   int nbsames = 0;
438   int j;
439   for(i=0; i<3; i++) {
440     for(j=0; j<3; j++) {
441       if(N1[i]==N2[j]) {
442         sames[i] = j;
443         nbsames++;
444         break;
445       }
446     }
447   }
448   if(nbsames!=2) return false;
449   if(sames[0]>-1) {
450     ShiftNodesQuadTria(N1);
451     if(sames[1]>-1) {
452       ShiftNodesQuadTria(N1);
453     }
454   }
455   i = sames[0] + sames[1] + sames[2];
456   for(; i<2; i++) {
457     ShiftNodesQuadTria(N2);
458   }
459   // now we receive following N1 and N2 (using numeration as above image)
460   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
461   // i.e. first nodes from both arrays determ new diagonal
462   return true;
463 }
464
465 //=======================================================================
466 //function : InverseDiag
467 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
468 //           but having other common link.
469 //           Return False if args are improper
470 //=======================================================================
471
472 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
473                                     const SMDS_MeshElement * theTria2 )
474 {
475   myLastCreatedElems.Clear();
476   myLastCreatedNodes.Clear();
477
478   if (!theTria1 || !theTria2)
479     return false;
480
481   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
482   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
483   if (F1 && F2) {
484
485     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
486     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
487     //    |/ |                                         | \|
488     //  B +--+ 2                                     B +--+ 2
489
490     // put nodes in array and find out indices of the same ones
491     const SMDS_MeshNode* aNodes [6];
492     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
493     int i = 0;
494     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
495     while ( it->more() ) {
496       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
497
498       if ( i > 2 ) // theTria2
499         // find same node of theTria1
500         for ( int j = 0; j < 3; j++ )
501           if ( aNodes[ i ] == aNodes[ j ]) {
502             sameInd[ j ] = i;
503             sameInd[ i ] = j;
504             break;
505           }
506       // next
507       i++;
508       if ( i == 3 ) {
509         if ( it->more() )
510           return false; // theTria1 is not a triangle
511         it = theTria2->nodesIterator();
512       }
513       if ( i == 6 && it->more() )
514         return false; // theTria2 is not a triangle
515     }
516
517     // find indices of 1,2 and of A,B in theTria1
518     int iA = 0, iB = 0, i1 = 0, i2 = 0;
519     for ( i = 0; i < 6; i++ ) {
520       if ( sameInd [ i ] == 0 )
521         if ( i < 3 ) i1 = i;
522         else         i2 = i;
523       else if (i < 3)
524         if ( iA ) iB = i;
525         else      iA = i;
526     }
527     // nodes 1 and 2 should not be the same
528     if ( aNodes[ i1 ] == aNodes[ i2 ] )
529       return false;
530
531     // theTria1: A->2
532     aNodes[ iA ] = aNodes[ i2 ];
533     // theTria2: B->1
534     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
535
536     //MESSAGE( theTria1 << theTria2 );
537
538     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
539     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
540
541     //MESSAGE( theTria1 << theTria2 );
542
543     return true;
544
545   } // end if(F1 && F2)
546
547   // check case of quadratic faces
548   const SMDS_QuadraticFaceOfNodes* QF1 =
549     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
550   if(!QF1) return false;
551   const SMDS_QuadraticFaceOfNodes* QF2 =
552     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
553   if(!QF2) return false;
554
555   //       5
556   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
557   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
558   //    |   / |
559   //  7 +  +  + 6
560   //    | /9  |
561   //    |/    |
562   //  4 +--+--+ 3
563   //       8
564
565   const SMDS_MeshNode* N1 [6];
566   const SMDS_MeshNode* N2 [6];
567   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
568     return false;
569   // now we receive following N1 and N2 (using numeration as above image)
570   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
571   // i.e. first nodes from both arrays determ new diagonal
572
573   const SMDS_MeshNode* N1new [6];
574   const SMDS_MeshNode* N2new [6];
575   N1new[0] = N1[0];
576   N1new[1] = N2[0];
577   N1new[2] = N2[1];
578   N1new[3] = N1[4];
579   N1new[4] = N2[3];
580   N1new[5] = N1[5];
581   N2new[0] = N1[0];
582   N2new[1] = N1[1];
583   N2new[2] = N2[0];
584   N2new[3] = N1[3];
585   N2new[4] = N2[5];
586   N2new[5] = N1[4];
587   // replaces nodes in faces
588   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
589   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
590
591   return true;
592 }
593
594 //=======================================================================
595 //function : findTriangles
596 //purpose  : find triangles sharing theNode1-theNode2 link
597 //=======================================================================
598
599 static bool findTriangles(const SMDS_MeshNode *    theNode1,
600                           const SMDS_MeshNode *    theNode2,
601                           const SMDS_MeshElement*& theTria1,
602                           const SMDS_MeshElement*& theTria2)
603 {
604   if ( !theNode1 || !theNode2 ) return false;
605
606   theTria1 = theTria2 = 0;
607
608   set< const SMDS_MeshElement* > emap;
609   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
610   while (it->more()) {
611     const SMDS_MeshElement* elem = it->next();
612     if ( elem->NbNodes() == 3 )
613       emap.insert( elem );
614   }
615   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
616   while (it->more()) {
617     const SMDS_MeshElement* elem = it->next();
618     if ( emap.find( elem ) != emap.end() )
619       if ( theTria1 ) {
620         // theTria1 must be element with minimum ID
621         if( theTria1->GetID() < elem->GetID() ) {
622           theTria2 = elem;
623         }
624         else {
625           theTria2 = theTria1;
626           theTria1 = elem;
627         }
628         break;
629       }
630       else {
631         theTria1 = elem;
632       }
633   }
634   return ( theTria1 && theTria2 );
635 }
636
637 //=======================================================================
638 //function : InverseDiag
639 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
640 //           with ones built on the same 4 nodes but having other common link.
641 //           Return false if proper faces not found
642 //=======================================================================
643
644 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
645                                     const SMDS_MeshNode * theNode2)
646 {
647   myLastCreatedElems.Clear();
648   myLastCreatedNodes.Clear();
649
650   MESSAGE( "::InverseDiag()" );
651
652   const SMDS_MeshElement *tr1, *tr2;
653   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
654     return false;
655
656   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
657   //if (!F1) return false;
658   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
659   //if (!F2) return false;
660   if (F1 && F2) {
661
662     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
663     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
664     //    |/ |                                    | \|
665     //  B +--+ 2                                B +--+ 2
666
667     // put nodes in array
668     // and find indices of 1,2 and of A in tr1 and of B in tr2
669     int i, iA1 = 0, i1 = 0;
670     const SMDS_MeshNode* aNodes1 [3];
671     SMDS_ElemIteratorPtr it;
672     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
673       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
674       if ( aNodes1[ i ] == theNode1 )
675         iA1 = i; // node A in tr1
676       else if ( aNodes1[ i ] != theNode2 )
677         i1 = i;  // node 1
678     }
679     int iB2 = 0, i2 = 0;
680     const SMDS_MeshNode* aNodes2 [3];
681     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
682       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
683       if ( aNodes2[ i ] == theNode2 )
684         iB2 = i; // node B in tr2
685       else if ( aNodes2[ i ] != theNode1 )
686         i2 = i;  // node 2
687     }
688
689     // nodes 1 and 2 should not be the same
690     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
691       return false;
692
693     // tr1: A->2
694     aNodes1[ iA1 ] = aNodes2[ i2 ];
695     // tr2: B->1
696     aNodes2[ iB2 ] = aNodes1[ i1 ];
697
698     //MESSAGE( tr1 << tr2 );
699
700     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
701     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
702
703     //MESSAGE( tr1 << tr2 );
704
705     return true;
706   }
707
708   // check case of quadratic faces
709   const SMDS_QuadraticFaceOfNodes* QF1 =
710     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
711   if(!QF1) return false;
712   const SMDS_QuadraticFaceOfNodes* QF2 =
713     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
714   if(!QF2) return false;
715   return InverseDiag(tr1,tr2);
716 }
717
718 //=======================================================================
719 //function : getQuadrangleNodes
720 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
721 //           fusion of triangles tr1 and tr2 having shared link on
722 //           theNode1 and theNode2
723 //=======================================================================
724
725 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
726                         const SMDS_MeshNode *    theNode1,
727                         const SMDS_MeshNode *    theNode2,
728                         const SMDS_MeshElement * tr1,
729                         const SMDS_MeshElement * tr2 )
730 {
731   if( tr1->NbNodes() != tr2->NbNodes() )
732     return false;
733   // find the 4-th node to insert into tr1
734   const SMDS_MeshNode* n4 = 0;
735   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
736   int i=0;
737   while ( !n4 && i<3 ) {
738     const SMDS_MeshNode * n = cast2Node( it->next() );
739     i++;
740     bool isDiag = ( n == theNode1 || n == theNode2 );
741     if ( !isDiag )
742       n4 = n;
743   }
744   // Make an array of nodes to be in a quadrangle
745   int iNode = 0, iFirstDiag = -1;
746   it = tr1->nodesIterator();
747   i=0;
748   while ( i<3 ) {
749     const SMDS_MeshNode * n = cast2Node( it->next() );
750     i++;
751     bool isDiag = ( n == theNode1 || n == theNode2 );
752     if ( isDiag ) {
753       if ( iFirstDiag < 0 )
754         iFirstDiag = iNode;
755       else if ( iNode - iFirstDiag == 1 )
756         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
757     }
758     else if ( n == n4 ) {
759       return false; // tr1 and tr2 should not have all the same nodes
760     }
761     theQuadNodes[ iNode++ ] = n;
762   }
763   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
764     theQuadNodes[ iNode ] = n4;
765
766   return true;
767 }
768
769 //=======================================================================
770 //function : DeleteDiag
771 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
772 //           with a quadrangle built on the same 4 nodes.
773 //           Return false if proper faces not found
774 //=======================================================================
775
776 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
777                                    const SMDS_MeshNode * theNode2)
778 {
779   myLastCreatedElems.Clear();
780   myLastCreatedNodes.Clear();
781
782   MESSAGE( "::DeleteDiag()" );
783
784   const SMDS_MeshElement *tr1, *tr2;
785   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
786     return false;
787
788   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
789   //if (!F1) return false;
790   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
791   //if (!F2) return false;
792   if (F1 && F2) {
793
794     const SMDS_MeshNode* aNodes [ 4 ];
795     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
796       return false;
797
798     //MESSAGE( endl << tr1 << tr2 );
799
800     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
801     myLastCreatedElems.Append(tr1);
802     GetMeshDS()->RemoveElement( tr2 );
803
804     //MESSAGE( endl << tr1 );
805
806     return true;
807   }
808
809   // check case of quadratic faces
810   const SMDS_QuadraticFaceOfNodes* QF1 =
811     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
812   if(!QF1) return false;
813   const SMDS_QuadraticFaceOfNodes* QF2 =
814     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
815   if(!QF2) return false;
816
817   //       5
818   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
819   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
820   //    |   / |
821   //  7 +  +  + 6
822   //    | /9  |
823   //    |/    |
824   //  4 +--+--+ 3
825   //       8
826
827   const SMDS_MeshNode* N1 [6];
828   const SMDS_MeshNode* N2 [6];
829   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
830     return false;
831   // now we receive following N1 and N2 (using numeration as above image)
832   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
833   // i.e. first nodes from both arrays determ new diagonal
834
835   const SMDS_MeshNode* aNodes[8];
836   aNodes[0] = N1[0];
837   aNodes[1] = N1[1];
838   aNodes[2] = N2[0];
839   aNodes[3] = N2[1];
840   aNodes[4] = N1[3];
841   aNodes[5] = N2[5];
842   aNodes[6] = N2[3];
843   aNodes[7] = N1[5];
844
845   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
846   myLastCreatedElems.Append(tr1);
847   GetMeshDS()->RemoveElement( tr2 );
848
849   // remove middle node (9)
850   GetMeshDS()->RemoveNode( N1[4] );
851
852   return true;
853 }
854
855 //=======================================================================
856 //function : Reorient
857 //purpose  : Reverse theElement orientation
858 //=======================================================================
859
860 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
861 {
862   myLastCreatedElems.Clear();
863   myLastCreatedNodes.Clear();
864
865   if (!theElem)
866     return false;
867   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
868   if ( !it || !it->more() )
869     return false;
870
871   switch ( theElem->GetType() ) {
872
873   case SMDSAbs_Edge:
874   case SMDSAbs_Face: {
875     if(!theElem->IsQuadratic()) {
876       int i = theElem->NbNodes();
877       vector<const SMDS_MeshNode*> aNodes( i );
878       while ( it->more() )
879         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
880       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
881     }
882     else {
883       // quadratic elements
884       if(theElem->GetType()==SMDSAbs_Edge) {
885         vector<const SMDS_MeshNode*> aNodes(3);
886         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
887         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
888         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
889         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
890       }
891       else {
892         int nbn = theElem->NbNodes();
893         vector<const SMDS_MeshNode*> aNodes(nbn);
894         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
895         int i=1;
896         for(; i<nbn/2; i++) {
897           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
898         }
899         for(i=0; i<nbn/2; i++) {
900           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
901         }
902         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
903       }
904     }
905   }
906   case SMDSAbs_Volume: {
907     if (theElem->IsPoly()) {
908       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
909         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
910       if (!aPolyedre) {
911         MESSAGE("Warning: bad volumic element");
912         return false;
913       }
914
915       int nbFaces = aPolyedre->NbFaces();
916       vector<const SMDS_MeshNode *> poly_nodes;
917       vector<int> quantities (nbFaces);
918
919       // reverse each face of the polyedre
920       for (int iface = 1; iface <= nbFaces; iface++) {
921         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
922         quantities[iface - 1] = nbFaceNodes;
923
924         for (inode = nbFaceNodes; inode >= 1; inode--) {
925           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
926           poly_nodes.push_back(curNode);
927         }
928       }
929
930       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
931
932     }
933     else {
934       SMDS_VolumeTool vTool;
935       if ( !vTool.Set( theElem ))
936         return false;
937       vTool.Inverse();
938       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
939     }
940   }
941   default:;
942   }
943
944   return false;
945 }
946
947 //=======================================================================
948 //function : getBadRate
949 //purpose  :
950 //=======================================================================
951
952 static double getBadRate (const SMDS_MeshElement*               theElem,
953                           SMESH::Controls::NumericalFunctorPtr& theCrit)
954 {
955   SMESH::Controls::TSequenceOfXYZ P;
956   if ( !theElem || !theCrit->GetPoints( theElem, P ))
957     return 1e100;
958   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
959   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
960 }
961
962 //=======================================================================
963 //function : QuadToTri
964 //purpose  : Cut quadrangles into triangles.
965 //           theCrit is used to select a diagonal to cut
966 //=======================================================================
967
968 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
969                                   SMESH::Controls::NumericalFunctorPtr theCrit)
970 {
971   myLastCreatedElems.Clear();
972   myLastCreatedNodes.Clear();
973
974   MESSAGE( "::QuadToTri()" );
975
976   if ( !theCrit.get() )
977     return false;
978
979   SMESHDS_Mesh * aMesh = GetMeshDS();
980
981   Handle(Geom_Surface) surface;
982   SMESH_MesherHelper   helper( *GetMesh() );
983
984   TIDSortedElemSet::iterator itElem;
985   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
986     const SMDS_MeshElement* elem = *itElem;
987     if ( !elem || elem->GetType() != SMDSAbs_Face )
988       continue;
989     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
990       continue;
991
992     // retrieve element nodes
993     const SMDS_MeshNode* aNodes [8];
994     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
995     int i = 0;
996     while ( itN->more() )
997       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
998
999     // compare two sets of possible triangles
1000     double aBadRate1, aBadRate2; // to what extent a set is bad
1001     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1002     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1003     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1004
1005     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1006     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1007     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1008
1009     int aShapeId = FindShape( elem );
1010     const SMDS_MeshElement* newElem = 0;
1011
1012     if( !elem->IsQuadratic() ) {
1013
1014       // split liner quadrangle
1015
1016       if ( aBadRate1 <= aBadRate2 ) {
1017         // tr1 + tr2 is better
1018         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1019         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1020       }
1021       else {
1022         // tr3 + tr4 is better
1023         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1024         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1025       }
1026     }
1027     else {
1028
1029       // split quadratic quadrangle
1030
1031       // get surface elem is on
1032       if ( aShapeId != helper.GetSubShapeID() ) {
1033         surface.Nullify();
1034         TopoDS_Shape shape;
1035         if ( aShapeId > 0 )
1036           shape = aMesh->IndexToShape( aShapeId );
1037         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1038           TopoDS_Face face = TopoDS::Face( shape );
1039           surface = BRep_Tool::Surface( face );
1040           if ( !surface.IsNull() )
1041             helper.SetSubShape( shape );
1042         }
1043       }
1044       // get elem nodes
1045       const SMDS_MeshNode* aNodes [8];
1046       const SMDS_MeshNode* inFaceNode = 0;
1047       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1048       int i = 0;
1049       while ( itN->more() ) {
1050         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1051         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1052              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1053         {
1054           inFaceNode = aNodes[ i-1 ];
1055         }
1056       }
1057       // find middle point for (0,1,2,3)
1058       // and create a node in this point;
1059       gp_XYZ p( 0,0,0 );
1060       if ( surface.IsNull() ) {
1061         for(i=0; i<4; i++)
1062           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1063         p /= 4;
1064       }
1065       else {
1066         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1067         gp_XY uv( 0,0 );
1068         for(i=0; i<4; i++)
1069           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1070         uv /= 4.;
1071         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1072       }
1073       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1074       myLastCreatedNodes.Append(newN);
1075
1076       // create a new element
1077       const SMDS_MeshNode* N[6];
1078       if ( aBadRate1 <= aBadRate2 ) {
1079         N[0] = aNodes[0];
1080         N[1] = aNodes[1];
1081         N[2] = aNodes[2];
1082         N[3] = aNodes[4];
1083         N[4] = aNodes[5];
1084         N[5] = newN;
1085         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1086                                  aNodes[6], aNodes[7], newN );
1087       }
1088       else {
1089         N[0] = aNodes[1];
1090         N[1] = aNodes[2];
1091         N[2] = aNodes[3];
1092         N[3] = aNodes[5];
1093         N[4] = aNodes[6];
1094         N[5] = newN;
1095         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1096                                  aNodes[7], aNodes[4], newN );
1097       }
1098       aMesh->ChangeElementNodes( elem, N, 6 );
1099
1100     } // quadratic case
1101
1102     // care of a new element
1103
1104     myLastCreatedElems.Append(newElem);
1105     AddToSameGroups( newElem, elem, aMesh );
1106
1107     // put a new triangle on the same shape
1108     if ( aShapeId )
1109       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1110   }
1111   return true;
1112 }
1113
1114 //=======================================================================
1115 //function : BestSplit
1116 //purpose  : Find better diagonal for cutting.
1117 //=======================================================================
1118
1119 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1120                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1121 {
1122   myLastCreatedElems.Clear();
1123   myLastCreatedNodes.Clear();
1124
1125   if (!theCrit.get())
1126     return -1;
1127
1128   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1129     return -1;
1130
1131   if( theQuad->NbNodes()==4 ||
1132       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1133
1134     // retrieve element nodes
1135     const SMDS_MeshNode* aNodes [4];
1136     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1137     int i = 0;
1138     //while (itN->more())
1139     while (i<4) {
1140       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1141     }
1142     // compare two sets of possible triangles
1143     double aBadRate1, aBadRate2; // to what extent a set is bad
1144     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1145     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1146     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1147
1148     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1149     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1150     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1151
1152     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1153       return 1; // diagonal 1-3
1154
1155     return 2; // diagonal 2-4
1156   }
1157   return -1;
1158 }
1159
1160 namespace
1161 {
1162   // Methods of splitting volumes into tetra
1163
1164   const int theHexTo5_1[5*4+1] =
1165     {
1166       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1167     };
1168   const int theHexTo5_2[5*4+1] =
1169     {
1170       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1171     };
1172   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1173
1174   const int theHexTo6_1[6*4+1] =
1175     {
1176       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1177     };
1178   const int theHexTo6_2[6*4+1] =
1179     {
1180       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1181     };
1182   const int theHexTo6_3[6*4+1] =
1183     {
1184       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1185     };
1186   const int theHexTo6_4[6*4+1] =
1187     {
1188       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1189     };
1190   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1191
1192   const int thePyraTo2_1[2*4+1] =
1193     {
1194       0, 1, 2, 4,    0, 2, 3, 4,   -1
1195     };
1196   const int thePyraTo2_2[2*4+1] =
1197     {
1198       1, 2, 3, 4,    1, 3, 0, 4,   -1
1199     };
1200   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1201
1202   const int thePentaTo3_1[3*4+1] =
1203     {
1204       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1205     };
1206   const int thePentaTo3_2[3*4+1] =
1207     {
1208       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1209     };
1210   const int thePentaTo3_3[3*4+1] =
1211     {
1212       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1213     };
1214   const int thePentaTo3_4[3*4+1] =
1215     {
1216       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1217     };
1218   const int thePentaTo3_5[3*4+1] =
1219     {
1220       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1221     };
1222   const int thePentaTo3_6[3*4+1] =
1223     {
1224       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1225     };
1226   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1227                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1228
1229   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1230   {
1231     int _n1, _n2, _n3;
1232     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1233     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1234     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1235   };
1236   struct TSplitMethod
1237   {
1238     int        _nbTetra;
1239     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1240     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1241     bool       _ownConn;      //!< to delete _connectivity in destructor
1242
1243     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1244       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1245     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1246     bool hasFacet( const TTriangleFacet& facet ) const
1247     {
1248       const int* tetConn = _connectivity;
1249       for ( ; tetConn[0] >= 0; tetConn += 4 )
1250         if (( facet.contains( tetConn[0] ) +
1251               facet.contains( tetConn[1] ) +
1252               facet.contains( tetConn[2] ) +
1253               facet.contains( tetConn[3] )) == 3 )
1254           return true;
1255       return false;
1256     }
1257   };
1258
1259   //=======================================================================
1260   /*!
1261    * \brief return TSplitMethod for the given element
1262    */
1263   //=======================================================================
1264
1265   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1266   {
1267     int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1268
1269     // Find out how adjacent volumes are split
1270
1271     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1272     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1273     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1274     {
1275       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1276       maxTetConnSize += 4 * ( nbNodes - 2 );
1277       if ( nbNodes < 4 ) continue;
1278
1279       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1280       const int* nInd = vol.GetFaceNodesIndices( iF );
1281       if ( nbNodes == 4 )
1282       {
1283         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1284         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1285         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1286         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1287       }
1288       else
1289       {
1290         int iCom = 0; // common node of triangle faces to split into
1291         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1292         {
1293           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1294                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1295                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1296           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1297                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1298                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1299           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1300           {
1301             triaSplits.push_back( t012 );
1302             triaSplits.push_back( t023 );
1303             break;
1304           }
1305         }
1306       }
1307       if ( !triaSplits.empty() )
1308         hasAdjacentSplits = true;
1309     }
1310
1311     // Among variants of split method select one compliant with adjacent volumes
1312
1313     TSplitMethod method;
1314     if ( !vol.Element()->IsPoly() )
1315     {
1316       int nbVariants = 2, nbTet = 0;
1317       const int** connVariants = 0;
1318       switch ( vol.Element()->GetEntityType() )
1319       {
1320       case SMDSEntity_Hexa:
1321       case SMDSEntity_Quad_Hexa:
1322         if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1323           connVariants = theHexTo5, nbTet = 5;
1324         else
1325           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1326         break;
1327       case SMDSEntity_Pyramid:
1328       case SMDSEntity_Quad_Pyramid:
1329         connVariants = thePyraTo2;  nbTet = 2;
1330         break;
1331       case SMDSEntity_Penta:
1332       case SMDSEntity_Quad_Penta:
1333         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1334         break;
1335       default:
1336         nbVariants = 0;
1337       }
1338       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1339       {
1340         // check method compliancy with adjacent tetras,
1341         // all found splits must be among facets of tetras described by this method
1342         method = TSplitMethod( nbTet, connVariants[variant] );
1343         if ( hasAdjacentSplits && method._nbTetra > 0 )
1344         {
1345           bool facetCreated = true;
1346           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1347           {
1348             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1349             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1350               facetCreated = method.hasFacet( *facet );
1351           }
1352           if ( !facetCreated )
1353             method = TSplitMethod(0); // incompatible method
1354         }
1355       }
1356     }
1357     if ( method._nbTetra < 1 )
1358     {
1359       // No standard method is applicable, use a generic solution:
1360       // each facet of a volume is split into triangles and
1361       // each of triangles and a volume barycenter form a tetrahedron.
1362
1363       int* connectivity = new int[ maxTetConnSize + 1 ];
1364       method._connectivity = connectivity;
1365       method._ownConn = true;
1366       method._baryNode = true;
1367
1368       int connSize = 0;
1369       int baryCenInd = vol.NbNodes();
1370       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1371       {
1372         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1373         const int*   nInd = vol.GetFaceNodesIndices( iF );
1374         // find common node of triangle facets of tetra to create
1375         int iCommon = 0; // index in linear numeration
1376         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1377         if ( !triaSplits.empty() )
1378         {
1379           // by found facets
1380           const TTriangleFacet* facet = &triaSplits.front();
1381           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1382             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1383                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1384               break;
1385         }
1386         else if ( nbNodes > 3 )
1387         {
1388           // find the best method of splitting into triangles by aspect ratio
1389           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1390           map< double, int > badness2iCommon;
1391           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1392           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1393           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1394             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1395             {
1396               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1397                                       nodes[ iQ*((iLast-1)%nbNodes)],
1398                                       nodes[ iQ*((iLast  )%nbNodes)]);
1399               double badness = getBadRate( &tria, aspectRatio );
1400               badness2iCommon.insert( make_pair( badness, iCommon ));
1401             }
1402           // use iCommon with lowest badness
1403           iCommon = badness2iCommon.begin()->second;
1404         }
1405         if ( iCommon >= nbNodes )
1406           iCommon = 0; // something wrong
1407         // fill connectivity of tetra
1408         int nbTet = nbNodes - 2;
1409         for ( int i = 0; i < nbTet; ++i )
1410         {
1411           int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1412           if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1413           connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1414           connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1415           connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1416           connectivity[ connSize++ ] = baryCenInd;
1417           ++method._nbTetra;
1418         }
1419       }
1420       connectivity[ connSize++ ] = -1;
1421     }
1422     return method;
1423   }
1424   //================================================================================
1425   /*!
1426    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1427    */
1428   //================================================================================
1429
1430   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1431   {
1432     // find the tetrahedron including the three nodes of facet
1433     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1434     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1435     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1436     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1437     while ( volIt1->more() )
1438     {
1439       const SMDS_MeshElement* v = volIt1->next();
1440       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1441         continue;
1442       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1443       while ( volIt2->more() )
1444         if ( v != volIt2->next() )
1445           continue;
1446       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1447       while ( volIt3->more() )
1448         if ( v == volIt3->next() )
1449           return true;
1450     }
1451     return false;
1452   }
1453 } // namespace
1454
1455 //=======================================================================
1456 //function : SplitVolumesIntoTetra
1457 //purpose  : Split volumic elements into tetrahedra.
1458 //=======================================================================
1459
1460 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1461                                               const int                theMethodFlags)
1462 {
1463   // std-like iterator on coordinates of nodes of mesh element
1464   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1465   NXyzIterator xyzEnd;
1466
1467   SMDS_VolumeTool    volTool;
1468   SMESH_MesherHelper helper( *GetMesh());
1469
1470   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1471   SMESHDS_SubMesh* fSubMesh = subMesh;
1472   
1473   SMESH_SequenceOfElemPtr newNodes, newElems;
1474
1475   TIDSortedElemSet::const_iterator elem = theElems.begin();
1476   for ( ; elem != theElems.end(); ++elem )
1477   {
1478     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1479     if ( geomType <= SMDSEntity_Quad_Tetra )
1480       continue; // tetra or face or ...
1481
1482     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1483
1484     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1485     if ( splitMethod._nbTetra < 1 ) continue;
1486
1487     // find submesh to add new tetras in
1488     if ( !subMesh || !subMesh->Contains( *elem ))
1489     {
1490       int shapeID = FindShape( *elem );
1491       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1492       subMesh = GetMeshDS()->MeshElements( shapeID );
1493     }
1494     int iQ;
1495     if ( (*elem)->IsQuadratic() )
1496     {
1497       iQ = 2;
1498       // add quadratic links to the helper
1499       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1500       {
1501         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1502         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1503           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1504       }
1505       helper.SetIsQuadratic( true );
1506     }
1507     else
1508     {
1509       iQ = 1;
1510       helper.SetIsQuadratic( false );
1511     }
1512     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1513     if ( splitMethod._baryNode )
1514     {
1515       // make a node at barycenter
1516       gp_XYZ gc( 0,0,0 );
1517       gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1518       SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1519       nodes.push_back( gcNode );
1520       newNodes.Append( gcNode );
1521     }
1522
1523     // make tetras
1524     helper.SetElementsOnShape( true );
1525     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1526     const int* tetConn = splitMethod._connectivity;
1527     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1528       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1529                                                        nodes[ tetConn[1] ],
1530                                                        nodes[ tetConn[2] ],
1531                                                        nodes[ tetConn[3] ]));
1532
1533     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1534
1535     // Split faces on sides of the split volume
1536
1537     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1538     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1539     {
1540       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1541       if ( nbNodes < 4 ) continue;
1542
1543       // find an existing face
1544       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1545                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1546       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1547       {
1548         // among possible triangles create ones discribed by split method
1549         const int* nInd = volTool.GetFaceNodesIndices( iF );
1550         int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1551         int iCom = 0; // common node of triangle faces to split into
1552         list< TTriangleFacet > facets;
1553         for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1554         {
1555           TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1556                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1557                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1558           TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1559                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1560                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1561           if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1562           {
1563             facets.push_back( t012 );
1564             facets.push_back( t023 );
1565             for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1566               facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1567                                                 nInd[ iQ * ((iLast-1)%nbNodes )],
1568                                                 nInd[ iQ * ((iLast  )%nbNodes )]));
1569             break;
1570           }
1571         }
1572         // find submesh to add new faces in
1573         if ( !fSubMesh || !fSubMesh->Contains( face ))
1574         {
1575           int shapeID = FindShape( face );
1576           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1577         }
1578         // make triangles
1579         helper.SetElementsOnShape( false );
1580         vector< const SMDS_MeshElement* > triangles;
1581         list< TTriangleFacet >::iterator facet = facets.begin();
1582         for ( ; facet != facets.end(); ++facet )
1583         {
1584           if ( !volTool.IsFaceExternal( iF ))
1585             swap( facet->_n2, facet->_n3 );
1586           triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1587                                                volNodes[ facet->_n2 ],
1588                                                volNodes[ facet->_n3 ]));
1589           if ( triangles.back() && fSubMesh )
1590             fSubMesh->AddElement( triangles.back());
1591           newElems.Append( triangles.back() );
1592         }
1593         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1594         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1595       }
1596
1597     } // loop on volume faces to split them into triangles
1598
1599     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1600
1601   } // loop on volumes to split
1602
1603   myLastCreatedNodes = newNodes;
1604   myLastCreatedElems = newElems;
1605 }
1606
1607 //=======================================================================
1608 //function : AddToSameGroups
1609 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1610 //=======================================================================
1611
1612 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1613                                         const SMDS_MeshElement* elemInGroups,
1614                                         SMESHDS_Mesh *          aMesh)
1615 {
1616   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1617   if (!groups.empty()) {
1618     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1619     for ( ; grIt != groups.end(); grIt++ ) {
1620       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1621       if ( group && group->Contains( elemInGroups ))
1622         group->SMDSGroup().Add( elemToAdd );
1623     }
1624   }
1625 }
1626
1627
1628 //=======================================================================
1629 //function : RemoveElemFromGroups
1630 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1631 //=======================================================================
1632 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1633                                              SMESHDS_Mesh *          aMesh)
1634 {
1635   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1636   if (!groups.empty())
1637   {
1638     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1639     for (; GrIt != groups.end(); GrIt++)
1640     {
1641       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1642       if (!grp || grp->IsEmpty()) continue;
1643       grp->SMDSGroup().Remove(removeelem);
1644     }
1645   }
1646 }
1647
1648 //================================================================================
1649 /*!
1650  * \brief Replace elemToRm by elemToAdd in the all groups
1651  */
1652 //================================================================================
1653
1654 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1655                                             const SMDS_MeshElement* elemToAdd,
1656                                             SMESHDS_Mesh *          aMesh)
1657 {
1658   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1659   if (!groups.empty()) {
1660     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1661     for ( ; grIt != groups.end(); grIt++ ) {
1662       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1663       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1664         group->SMDSGroup().Add( elemToAdd );
1665     }
1666   }
1667 }
1668
1669 //================================================================================
1670 /*!
1671  * \brief Replace elemToRm by elemToAdd in the all groups
1672  */
1673 //================================================================================
1674
1675 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1676                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1677                                             SMESHDS_Mesh *                         aMesh)
1678 {
1679   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1680   if (!groups.empty())
1681   {
1682     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1683     for ( ; grIt != groups.end(); grIt++ ) {
1684       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1685       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1686         for ( int i = 0; i < elemToAdd.size(); ++i )
1687           group->SMDSGroup().Add( elemToAdd[ i ] );
1688     }
1689   }
1690 }
1691
1692 //=======================================================================
1693 //function : QuadToTri
1694 //purpose  : Cut quadrangles into triangles.
1695 //           theCrit is used to select a diagonal to cut
1696 //=======================================================================
1697
1698 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1699                                   const bool         the13Diag)
1700 {
1701   myLastCreatedElems.Clear();
1702   myLastCreatedNodes.Clear();
1703
1704   MESSAGE( "::QuadToTri()" );
1705
1706   SMESHDS_Mesh * aMesh = GetMeshDS();
1707
1708   Handle(Geom_Surface) surface;
1709   SMESH_MesherHelper   helper( *GetMesh() );
1710
1711   TIDSortedElemSet::iterator itElem;
1712   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1713     const SMDS_MeshElement* elem = *itElem;
1714     if ( !elem || elem->GetType() != SMDSAbs_Face )
1715       continue;
1716     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1717     if(!isquad) continue;
1718
1719     if(elem->NbNodes()==4) {
1720       // retrieve element nodes
1721       const SMDS_MeshNode* aNodes [4];
1722       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1723       int i = 0;
1724       while ( itN->more() )
1725         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1726
1727       int aShapeId = FindShape( elem );
1728       const SMDS_MeshElement* newElem = 0;
1729       if ( the13Diag ) {
1730         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1731         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1732       }
1733       else {
1734         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1735         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1736       }
1737       myLastCreatedElems.Append(newElem);
1738       // put a new triangle on the same shape and add to the same groups
1739       if ( aShapeId )
1740         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1741       AddToSameGroups( newElem, elem, aMesh );
1742     }
1743
1744     // Quadratic quadrangle
1745
1746     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1747
1748       // get surface elem is on
1749       int aShapeId = FindShape( elem );
1750       if ( aShapeId != helper.GetSubShapeID() ) {
1751         surface.Nullify();
1752         TopoDS_Shape shape;
1753         if ( aShapeId > 0 )
1754           shape = aMesh->IndexToShape( aShapeId );
1755         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1756           TopoDS_Face face = TopoDS::Face( shape );
1757           surface = BRep_Tool::Surface( face );
1758           if ( !surface.IsNull() )
1759             helper.SetSubShape( shape );
1760         }
1761       }
1762
1763       const SMDS_MeshNode* aNodes [8];
1764       const SMDS_MeshNode* inFaceNode = 0;
1765       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1766       int i = 0;
1767       while ( itN->more() ) {
1768         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1769         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1770              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1771         {
1772           inFaceNode = aNodes[ i-1 ];
1773         }
1774       }
1775
1776       // find middle point for (0,1,2,3)
1777       // and create a node in this point;
1778       gp_XYZ p( 0,0,0 );
1779       if ( surface.IsNull() ) {
1780         for(i=0; i<4; i++)
1781           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1782         p /= 4;
1783       }
1784       else {
1785         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1786         gp_XY uv( 0,0 );
1787         for(i=0; i<4; i++)
1788           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1789         uv /= 4.;
1790         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1791       }
1792       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1793       myLastCreatedNodes.Append(newN);
1794
1795       // create a new element
1796       const SMDS_MeshElement* newElem = 0;
1797       const SMDS_MeshNode* N[6];
1798       if ( the13Diag ) {
1799         N[0] = aNodes[0];
1800         N[1] = aNodes[1];
1801         N[2] = aNodes[2];
1802         N[3] = aNodes[4];
1803         N[4] = aNodes[5];
1804         N[5] = newN;
1805         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1806                                  aNodes[6], aNodes[7], newN );
1807       }
1808       else {
1809         N[0] = aNodes[1];
1810         N[1] = aNodes[2];
1811         N[2] = aNodes[3];
1812         N[3] = aNodes[5];
1813         N[4] = aNodes[6];
1814         N[5] = newN;
1815         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1816                                  aNodes[7], aNodes[4], newN );
1817       }
1818       myLastCreatedElems.Append(newElem);
1819       aMesh->ChangeElementNodes( elem, N, 6 );
1820       // put a new triangle on the same shape and add to the same groups
1821       if ( aShapeId )
1822         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1823       AddToSameGroups( newElem, elem, aMesh );
1824     }
1825   }
1826
1827   return true;
1828 }
1829
1830 //=======================================================================
1831 //function : getAngle
1832 //purpose  :
1833 //=======================================================================
1834
1835 double getAngle(const SMDS_MeshElement * tr1,
1836                 const SMDS_MeshElement * tr2,
1837                 const SMDS_MeshNode *    n1,
1838                 const SMDS_MeshNode *    n2)
1839 {
1840   double angle = 2*PI; // bad angle
1841
1842   // get normals
1843   SMESH::Controls::TSequenceOfXYZ P1, P2;
1844   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1845        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1846     return angle;
1847   gp_Vec N1,N2;
1848   if(!tr1->IsQuadratic())
1849     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1850   else
1851     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1852   if ( N1.SquareMagnitude() <= gp::Resolution() )
1853     return angle;
1854   if(!tr2->IsQuadratic())
1855     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1856   else
1857     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1858   if ( N2.SquareMagnitude() <= gp::Resolution() )
1859     return angle;
1860
1861   // find the first diagonal node n1 in the triangles:
1862   // take in account a diagonal link orientation
1863   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1864   for ( int t = 0; t < 2; t++ ) {
1865     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1866     int i = 0, iDiag = -1;
1867     while ( it->more()) {
1868       const SMDS_MeshElement *n = it->next();
1869       if ( n == n1 || n == n2 )
1870         if ( iDiag < 0)
1871           iDiag = i;
1872         else {
1873           if ( i - iDiag == 1 )
1874             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1875           else
1876             nFirst[ t ] = n;
1877           break;
1878         }
1879       i++;
1880     }
1881   }
1882   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1883     N2.Reverse();
1884
1885   angle = N1.Angle( N2 );
1886   //SCRUTE( angle );
1887   return angle;
1888 }
1889
1890 // =================================================
1891 // class generating a unique ID for a pair of nodes
1892 // and able to return nodes by that ID
1893 // =================================================
1894 class LinkID_Gen {
1895 public:
1896
1897   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1898     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1899   {}
1900
1901   long GetLinkID (const SMDS_MeshNode * n1,
1902                   const SMDS_MeshNode * n2) const
1903   {
1904     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1905   }
1906
1907   bool GetNodes (const long             theLinkID,
1908                  const SMDS_MeshNode* & theNode1,
1909                  const SMDS_MeshNode* & theNode2) const
1910   {
1911     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1912     if ( !theNode1 ) return false;
1913     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1914     if ( !theNode2 ) return false;
1915     return true;
1916   }
1917
1918 private:
1919   LinkID_Gen();
1920   const SMESHDS_Mesh* myMesh;
1921   long                myMaxID;
1922 };
1923
1924
1925 //=======================================================================
1926 //function : TriToQuad
1927 //purpose  : Fuse neighbour triangles into quadrangles.
1928 //           theCrit is used to select a neighbour to fuse with.
1929 //           theMaxAngle is a max angle between element normals at which
1930 //           fusion is still performed.
1931 //=======================================================================
1932
1933 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1934                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1935                                   const double                         theMaxAngle)
1936 {
1937   myLastCreatedElems.Clear();
1938   myLastCreatedNodes.Clear();
1939
1940   MESSAGE( "::TriToQuad()" );
1941
1942   if ( !theCrit.get() )
1943     return false;
1944
1945   SMESHDS_Mesh * aMesh = GetMeshDS();
1946
1947   // Prepare data for algo: build
1948   // 1. map of elements with their linkIDs
1949   // 2. map of linkIDs with their elements
1950
1951   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1952   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1953   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
1954   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1955
1956   TIDSortedElemSet::iterator itElem;
1957   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1958     const SMDS_MeshElement* elem = *itElem;
1959     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1960     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1961     if(!IsTria) continue;
1962
1963     // retrieve element nodes
1964     const SMDS_MeshNode* aNodes [4];
1965     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1966     int i = 0;
1967     while ( i<3 )
1968       aNodes[ i++ ] = cast2Node( itN->next() );
1969     aNodes[ 3 ] = aNodes[ 0 ];
1970
1971     // fill maps
1972     for ( i = 0; i < 3; i++ ) {
1973       SMESH_TLink link( aNodes[i], aNodes[i+1] );
1974       // check if elements sharing a link can be fused
1975       itLE = mapLi_listEl.find( link );
1976       if ( itLE != mapLi_listEl.end() ) {
1977         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1978           continue;
1979         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1980         //if ( FindShape( elem ) != FindShape( elem2 ))
1981         //  continue; // do not fuse triangles laying on different shapes
1982         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1983           continue; // avoid making badly shaped quads
1984         (*itLE).second.push_back( elem );
1985       }
1986       else {
1987         mapLi_listEl[ link ].push_back( elem );
1988       }
1989       mapEl_setLi [ elem ].insert( link );
1990     }
1991   }
1992   // Clean the maps from the links shared by a sole element, ie
1993   // links to which only one element is bound in mapLi_listEl
1994
1995   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1996     int nbElems = (*itLE).second.size();
1997     if ( nbElems < 2  ) {
1998       const SMDS_MeshElement* elem = (*itLE).second.front();
1999       SMESH_TLink link = (*itLE).first;
2000       mapEl_setLi[ elem ].erase( link );
2001       if ( mapEl_setLi[ elem ].empty() )
2002         mapEl_setLi.erase( elem );
2003     }
2004   }
2005
2006   // Algo: fuse triangles into quadrangles
2007
2008   while ( ! mapEl_setLi.empty() ) {
2009     // Look for the start element:
2010     // the element having the least nb of shared links
2011     const SMDS_MeshElement* startElem = 0;
2012     int minNbLinks = 4;
2013     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2014       int nbLinks = (*itEL).second.size();
2015       if ( nbLinks < minNbLinks ) {
2016         startElem = (*itEL).first;
2017         minNbLinks = nbLinks;
2018         if ( minNbLinks == 1 )
2019           break;
2020       }
2021     }
2022
2023     // search elements to fuse starting from startElem or links of elements
2024     // fused earlyer - startLinks
2025     list< SMESH_TLink > startLinks;
2026     while ( startElem || !startLinks.empty() ) {
2027       while ( !startElem && !startLinks.empty() ) {
2028         // Get an element to start, by a link
2029         SMESH_TLink linkId = startLinks.front();
2030         startLinks.pop_front();
2031         itLE = mapLi_listEl.find( linkId );
2032         if ( itLE != mapLi_listEl.end() ) {
2033           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2034           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2035           for ( ; itE != listElem.end() ; itE++ )
2036             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2037               startElem = (*itE);
2038           mapLi_listEl.erase( itLE );
2039         }
2040       }
2041
2042       if ( startElem ) {
2043         // Get candidates to be fused
2044         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2045         const SMESH_TLink *link12, *link13;
2046         startElem = 0;
2047         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2048         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2049         ASSERT( !setLi.empty() );
2050         set< SMESH_TLink >::iterator itLi;
2051         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2052         {
2053           const SMESH_TLink & link = (*itLi);
2054           itLE = mapLi_listEl.find( link );
2055           if ( itLE == mapLi_listEl.end() )
2056             continue;
2057
2058           const SMDS_MeshElement* elem = (*itLE).second.front();
2059           if ( elem == tr1 )
2060             elem = (*itLE).second.back();
2061           mapLi_listEl.erase( itLE );
2062           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2063             continue;
2064           if ( tr2 ) {
2065             tr3 = elem;
2066             link13 = &link;
2067           }
2068           else {
2069             tr2 = elem;
2070             link12 = &link;
2071           }
2072
2073           // add other links of elem to list of links to re-start from
2074           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2075           set< SMESH_TLink >::iterator it;
2076           for ( it = links.begin(); it != links.end(); it++ ) {
2077             const SMESH_TLink& link2 = (*it);
2078             if ( link2 != link )
2079               startLinks.push_back( link2 );
2080           }
2081         }
2082
2083         // Get nodes of possible quadrangles
2084         const SMDS_MeshNode *n12 [4], *n13 [4];
2085         bool Ok12 = false, Ok13 = false;
2086         const SMDS_MeshNode *linkNode1, *linkNode2;
2087         if(tr2) {
2088           linkNode1 = link12->first;
2089           linkNode2 = link12->second;
2090           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2091             Ok12 = true;
2092         }
2093         if(tr3) {
2094           linkNode1 = link13->first;
2095           linkNode2 = link13->second;
2096           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2097             Ok13 = true;
2098         }
2099
2100         // Choose a pair to fuse
2101         if ( Ok12 && Ok13 ) {
2102           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2103           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2104           double aBadRate12 = getBadRate( &quad12, theCrit );
2105           double aBadRate13 = getBadRate( &quad13, theCrit );
2106           if (  aBadRate13 < aBadRate12 )
2107             Ok12 = false;
2108           else
2109             Ok13 = false;
2110         }
2111
2112         // Make quadrangles
2113         // and remove fused elems and removed links from the maps
2114         mapEl_setLi.erase( tr1 );
2115         if ( Ok12 ) {
2116           mapEl_setLi.erase( tr2 );
2117           mapLi_listEl.erase( *link12 );
2118           if(tr1->NbNodes()==3) {
2119             if( tr1->GetID() < tr2->GetID() ) {
2120               aMesh->ChangeElementNodes( tr1, n12, 4 );
2121               myLastCreatedElems.Append(tr1);
2122               aMesh->RemoveElement( tr2 );
2123             }
2124             else {
2125               aMesh->ChangeElementNodes( tr2, n12, 4 );
2126               myLastCreatedElems.Append(tr2);
2127               aMesh->RemoveElement( tr1);
2128             }
2129           }
2130           else {
2131             const SMDS_MeshNode* N1 [6];
2132             const SMDS_MeshNode* N2 [6];
2133             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2134             // now we receive following N1 and N2 (using numeration as above image)
2135             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2136             // i.e. first nodes from both arrays determ new diagonal
2137             const SMDS_MeshNode* aNodes[8];
2138             aNodes[0] = N1[0];
2139             aNodes[1] = N1[1];
2140             aNodes[2] = N2[0];
2141             aNodes[3] = N2[1];
2142             aNodes[4] = N1[3];
2143             aNodes[5] = N2[5];
2144             aNodes[6] = N2[3];
2145             aNodes[7] = N1[5];
2146             if( tr1->GetID() < tr2->GetID() ) {
2147               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2148               myLastCreatedElems.Append(tr1);
2149               GetMeshDS()->RemoveElement( tr2 );
2150             }
2151             else {
2152               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2153               myLastCreatedElems.Append(tr2);
2154               GetMeshDS()->RemoveElement( tr1 );
2155             }
2156             // remove middle node (9)
2157             GetMeshDS()->RemoveNode( N1[4] );
2158           }
2159         }
2160         else if ( Ok13 ) {
2161           mapEl_setLi.erase( tr3 );
2162           mapLi_listEl.erase( *link13 );
2163           if(tr1->NbNodes()==3) {
2164             if( tr1->GetID() < tr2->GetID() ) {
2165               aMesh->ChangeElementNodes( tr1, n13, 4 );
2166               myLastCreatedElems.Append(tr1);
2167               aMesh->RemoveElement( tr3 );
2168             }
2169             else {
2170               aMesh->ChangeElementNodes( tr3, n13, 4 );
2171               myLastCreatedElems.Append(tr3);
2172               aMesh->RemoveElement( tr1 );
2173             }
2174           }
2175           else {
2176             const SMDS_MeshNode* N1 [6];
2177             const SMDS_MeshNode* N2 [6];
2178             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2179             // now we receive following N1 and N2 (using numeration as above image)
2180             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2181             // i.e. first nodes from both arrays determ new diagonal
2182             const SMDS_MeshNode* aNodes[8];
2183             aNodes[0] = N1[0];
2184             aNodes[1] = N1[1];
2185             aNodes[2] = N2[0];
2186             aNodes[3] = N2[1];
2187             aNodes[4] = N1[3];
2188             aNodes[5] = N2[5];
2189             aNodes[6] = N2[3];
2190             aNodes[7] = N1[5];
2191             if( tr1->GetID() < tr2->GetID() ) {
2192               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2193               myLastCreatedElems.Append(tr1);
2194               GetMeshDS()->RemoveElement( tr3 );
2195             }
2196             else {
2197               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2198               myLastCreatedElems.Append(tr3);
2199               GetMeshDS()->RemoveElement( tr1 );
2200             }
2201             // remove middle node (9)
2202             GetMeshDS()->RemoveNode( N1[4] );
2203           }
2204         }
2205
2206         // Next element to fuse: the rejected one
2207         if ( tr3 )
2208           startElem = Ok12 ? tr3 : tr2;
2209
2210       } // if ( startElem )
2211     } // while ( startElem || !startLinks.empty() )
2212   } // while ( ! mapEl_setLi.empty() )
2213
2214   return true;
2215 }
2216
2217
2218 /*#define DUMPSO(txt) \
2219 //  cout << txt << endl;
2220 //=============================================================================
2221 //
2222 //
2223 //
2224 //=============================================================================
2225 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2226 {
2227 if ( i1 == i2 )
2228 return;
2229 int tmp = idNodes[ i1 ];
2230 idNodes[ i1 ] = idNodes[ i2 ];
2231 idNodes[ i2 ] = tmp;
2232 gp_Pnt Ptmp = P[ i1 ];
2233 P[ i1 ] = P[ i2 ];
2234 P[ i2 ] = Ptmp;
2235 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2236 }
2237
2238 //=======================================================================
2239 //function : SortQuadNodes
2240 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2241 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2242 //           1 or 2 else 0.
2243 //=======================================================================
2244
2245 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2246 int               idNodes[] )
2247 {
2248   gp_Pnt P[4];
2249   int i;
2250   for ( i = 0; i < 4; i++ ) {
2251     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2252     if ( !n ) return 0;
2253     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2254   }
2255
2256   gp_Vec V1(P[0], P[1]);
2257   gp_Vec V2(P[0], P[2]);
2258   gp_Vec V3(P[0], P[3]);
2259
2260   gp_Vec Cross1 = V1 ^ V2;
2261   gp_Vec Cross2 = V2 ^ V3;
2262
2263   i = 0;
2264   if (Cross1.Dot(Cross2) < 0)
2265   {
2266     Cross1 = V2 ^ V1;
2267     Cross2 = V1 ^ V3;
2268
2269     if (Cross1.Dot(Cross2) < 0)
2270       i = 2;
2271     else
2272       i = 1;
2273     swap ( i, i + 1, idNodes, P );
2274
2275     //     for ( int ii = 0; ii < 4; ii++ ) {
2276     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2277     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2278     //     }
2279   }
2280   return i;
2281 }
2282
2283 //=======================================================================
2284 //function : SortHexaNodes
2285 //purpose  : Set 8 nodes of a hexahedron in a good order.
2286 //           Return success status
2287 //=======================================================================
2288
2289 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2290                                       int               idNodes[] )
2291 {
2292   gp_Pnt P[8];
2293   int i;
2294   DUMPSO( "INPUT: ========================================");
2295   for ( i = 0; i < 8; i++ ) {
2296     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2297     if ( !n ) return false;
2298     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2299     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2300   }
2301   DUMPSO( "========================================");
2302
2303
2304   set<int> faceNodes;  // ids of bottom face nodes, to be found
2305   set<int> checkedId1; // ids of tried 2-nd nodes
2306   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2307   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2308   int iMin, iLoop1 = 0;
2309
2310   // Loop to try the 2-nd nodes
2311
2312   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2313   {
2314     // Find not checked 2-nd node
2315     for ( i = 1; i < 8; i++ )
2316       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2317         int id1 = idNodes[i];
2318         swap ( 1, i, idNodes, P );
2319         checkedId1.insert ( id1 );
2320         break;
2321       }
2322
2323     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2324     // ie that all but meybe one (id3 which is on the same face) nodes
2325     // lay on the same side from the triangle plane.
2326
2327     bool manyInPlane = false; // more than 4 nodes lay in plane
2328     int iLoop2 = 0;
2329     while ( ++iLoop2 < 6 ) {
2330
2331       // get 1-2-3 plane coeffs
2332       Standard_Real A, B, C, D;
2333       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2334       if ( N.SquareMagnitude() > gp::Resolution() )
2335       {
2336         gp_Pln pln ( P[0], N );
2337         pln.Coefficients( A, B, C, D );
2338
2339         // find the node (iMin) closest to pln
2340         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2341         set<int> idInPln;
2342         for ( i = 3; i < 8; i++ ) {
2343           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2344           if ( fabs( dist[i] ) < minDist ) {
2345             minDist = fabs( dist[i] );
2346             iMin = i;
2347           }
2348           if ( fabs( dist[i] ) <= tol )
2349             idInPln.insert( idNodes[i] );
2350         }
2351
2352         // there should not be more than 4 nodes in bottom plane
2353         if ( idInPln.size() > 1 )
2354         {
2355           DUMPSO( "### idInPln.size() = " << idInPln.size());
2356           // idInPlane does not contain the first 3 nodes
2357           if ( manyInPlane || idInPln.size() == 5)
2358             return false; // all nodes in one plane
2359           manyInPlane = true;
2360
2361           // set the 1-st node to be not in plane
2362           for ( i = 3; i < 8; i++ ) {
2363             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2364               DUMPSO( "### Reset 0-th node");
2365               swap( 0, i, idNodes, P );
2366               break;
2367             }
2368           }
2369
2370           // reset to re-check second nodes
2371           leastDist = DBL_MAX;
2372           faceNodes.clear();
2373           checkedId1.clear();
2374           iLoop1 = 0;
2375           break; // from iLoop2;
2376         }
2377
2378         // check that the other 4 nodes are on the same side
2379         bool sameSide = true;
2380         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2381         for ( i = 3; sameSide && i < 8; i++ ) {
2382           if ( i != iMin )
2383             sameSide = ( isNeg == dist[i] <= 0.);
2384         }
2385
2386         // keep best solution
2387         if ( sameSide && minDist < leastDist ) {
2388           leastDist = minDist;
2389           faceNodes.clear();
2390           faceNodes.insert( idNodes[ 1 ] );
2391           faceNodes.insert( idNodes[ 2 ] );
2392           faceNodes.insert( idNodes[ iMin ] );
2393           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2394                   << " leastDist = " << leastDist);
2395           if ( leastDist <= DBL_MIN )
2396             break;
2397         }
2398       }
2399
2400       // set next 3-d node to check
2401       int iNext = 2 + iLoop2;
2402       if ( iNext < 8 ) {
2403         DUMPSO( "Try 2-nd");
2404         swap ( 2, iNext, idNodes, P );
2405       }
2406     } // while ( iLoop2 < 6 )
2407   } // iLoop1
2408
2409   if ( faceNodes.empty() ) return false;
2410
2411   // Put the faceNodes in proper places
2412   for ( i = 4; i < 8; i++ ) {
2413     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2414       // find a place to put
2415       int iTo = 1;
2416       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2417         iTo++;
2418       DUMPSO( "Set faceNodes");
2419       swap ( iTo, i, idNodes, P );
2420     }
2421   }
2422
2423
2424   // Set nodes of the found bottom face in good order
2425   DUMPSO( " Found bottom face: ");
2426   i = SortQuadNodes( theMesh, idNodes );
2427   if ( i ) {
2428     gp_Pnt Ptmp = P[ i ];
2429     P[ i ] = P[ i+1 ];
2430     P[ i+1 ] = Ptmp;
2431   }
2432   //   else
2433   //     for ( int ii = 0; ii < 4; ii++ ) {
2434   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2435   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2436   //    }
2437
2438   // Gravity center of the top and bottom faces
2439   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2440   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2441
2442   // Get direction from the bottom to the top face
2443   gp_Vec upDir ( aGCb, aGCt );
2444   Standard_Real upDirSize = upDir.Magnitude();
2445   if ( upDirSize <= gp::Resolution() ) return false;
2446   upDir / upDirSize;
2447
2448   // Assure that the bottom face normal points up
2449   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2450   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2451   if ( Nb.Dot( upDir ) < 0 ) {
2452     DUMPSO( "Reverse bottom face");
2453     swap( 1, 3, idNodes, P );
2454   }
2455
2456   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2457   Standard_Real minDist = DBL_MAX;
2458   for ( i = 4; i < 8; i++ ) {
2459     // projection of P[i] to the plane defined by P[0] and upDir
2460     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2461     Standard_Real sqDist = P[0].SquareDistance( Pp );
2462     if ( sqDist < minDist ) {
2463       minDist = sqDist;
2464       iMin = i;
2465     }
2466   }
2467   DUMPSO( "Set 4-th");
2468   swap ( 4, iMin, idNodes, P );
2469
2470   // Set nodes of the top face in good order
2471   DUMPSO( "Sort top face");
2472   i = SortQuadNodes( theMesh, &idNodes[4] );
2473   if ( i ) {
2474     i += 4;
2475     gp_Pnt Ptmp = P[ i ];
2476     P[ i ] = P[ i+1 ];
2477     P[ i+1 ] = Ptmp;
2478   }
2479
2480   // Assure that direction of the top face normal is from the bottom face
2481   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2482   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2483   if ( Nt.Dot( upDir ) < 0 ) {
2484     DUMPSO( "Reverse top face");
2485     swap( 5, 7, idNodes, P );
2486   }
2487
2488   //   DUMPSO( "OUTPUT: ========================================");
2489   //   for ( i = 0; i < 8; i++ ) {
2490   //     float *p = ugrid->GetPoint(idNodes[i]);
2491   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2492   //   }
2493
2494   return true;
2495 }*/
2496
2497 //================================================================================
2498 /*!
2499  * \brief Return nodes linked to the given one
2500  * \param theNode - the node
2501  * \param linkedNodes - the found nodes
2502  * \param type - the type of elements to check
2503  *
2504  * Medium nodes are ignored
2505  */
2506 //================================================================================
2507
2508 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2509                                        TIDSortedElemSet &   linkedNodes,
2510                                        SMDSAbs_ElementType  type )
2511 {
2512   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2513   while ( elemIt->more() )
2514   {
2515     const SMDS_MeshElement* elem = elemIt->next();
2516     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2517     if ( elem->GetType() == SMDSAbs_Volume )
2518     {
2519       SMDS_VolumeTool vol( elem );
2520       while ( nodeIt->more() ) {
2521         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2522         if ( theNode != n && vol.IsLinked( theNode, n ))
2523           linkedNodes.insert( n );
2524       }
2525     }
2526     else
2527     {
2528       for ( int i = 0; nodeIt->more(); ++i ) {
2529         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2530         if ( n == theNode ) {
2531           int iBefore = i - 1;
2532           int iAfter  = i + 1;
2533           if ( elem->IsQuadratic() ) {
2534             int nb = elem->NbNodes() / 2;
2535             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2536             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2537           }
2538           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2539           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2540         }
2541       }
2542     }
2543   }
2544 }
2545
2546 //=======================================================================
2547 //function : laplacianSmooth
2548 //purpose  : pulls theNode toward the center of surrounding nodes directly
2549 //           connected to that node along an element edge
2550 //=======================================================================
2551
2552 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2553                      const Handle(Geom_Surface)&          theSurface,
2554                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2555 {
2556   // find surrounding nodes
2557
2558   TIDSortedElemSet nodeSet;
2559   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2560
2561   // compute new coodrs
2562
2563   double coord[] = { 0., 0., 0. };
2564   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2565   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2566     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2567     if ( theSurface.IsNull() ) { // smooth in 3D
2568       coord[0] += node->X();
2569       coord[1] += node->Y();
2570       coord[2] += node->Z();
2571     }
2572     else { // smooth in 2D
2573       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2574       gp_XY* uv = theUVMap[ node ];
2575       coord[0] += uv->X();
2576       coord[1] += uv->Y();
2577     }
2578   }
2579   int nbNodes = nodeSet.size();
2580   if ( !nbNodes )
2581     return;
2582   coord[0] /= nbNodes;
2583   coord[1] /= nbNodes;
2584
2585   if ( !theSurface.IsNull() ) {
2586     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2587     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2588     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2589     coord[0] = p3d.X();
2590     coord[1] = p3d.Y();
2591     coord[2] = p3d.Z();
2592   }
2593   else
2594     coord[2] /= nbNodes;
2595
2596   // move node
2597
2598   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2599 }
2600
2601 //=======================================================================
2602 //function : centroidalSmooth
2603 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2604 //           surrounding elements
2605 //=======================================================================
2606
2607 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2608                       const Handle(Geom_Surface)&          theSurface,
2609                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2610 {
2611   gp_XYZ aNewXYZ(0.,0.,0.);
2612   SMESH::Controls::Area anAreaFunc;
2613   double totalArea = 0.;
2614   int nbElems = 0;
2615
2616   // compute new XYZ
2617
2618   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2619   while ( elemIt->more() )
2620   {
2621     const SMDS_MeshElement* elem = elemIt->next();
2622     nbElems++;
2623
2624     gp_XYZ elemCenter(0.,0.,0.);
2625     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2626     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2627     int nn = elem->NbNodes();
2628     if(elem->IsQuadratic()) nn = nn/2;
2629     int i=0;
2630     //while ( itN->more() ) {
2631     while ( i<nn ) {
2632       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2633       i++;
2634       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2635       aNodePoints.push_back( aP );
2636       if ( !theSurface.IsNull() ) { // smooth in 2D
2637         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2638         gp_XY* uv = theUVMap[ aNode ];
2639         aP.SetCoord( uv->X(), uv->Y(), 0. );
2640       }
2641       elemCenter += aP;
2642     }
2643     double elemArea = anAreaFunc.GetValue( aNodePoints );
2644     totalArea += elemArea;
2645     elemCenter /= nn;
2646     aNewXYZ += elemCenter * elemArea;
2647   }
2648   aNewXYZ /= totalArea;
2649   if ( !theSurface.IsNull() ) {
2650     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2651     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2652   }
2653
2654   // move node
2655
2656   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2657 }
2658
2659 //=======================================================================
2660 //function : getClosestUV
2661 //purpose  : return UV of closest projection
2662 //=======================================================================
2663
2664 static bool getClosestUV (Extrema_GenExtPS& projector,
2665                           const gp_Pnt&     point,
2666                           gp_XY &           result)
2667 {
2668   projector.Perform( point );
2669   if ( projector.IsDone() ) {
2670     double u, v, minVal = DBL_MAX;
2671     for ( int i = projector.NbExt(); i > 0; i-- )
2672       if ( projector.Value( i ) < minVal ) {
2673         minVal = projector.Value( i );
2674         projector.Point( i ).Parameter( u, v );
2675       }
2676     result.SetCoord( u, v );
2677     return true;
2678   }
2679   return false;
2680 }
2681
2682 //=======================================================================
2683 //function : Smooth
2684 //purpose  : Smooth theElements during theNbIterations or until a worst
2685 //           element has aspect ratio <= theTgtAspectRatio.
2686 //           Aspect Ratio varies in range [1.0, inf].
2687 //           If theElements is empty, the whole mesh is smoothed.
2688 //           theFixedNodes contains additionally fixed nodes. Nodes built
2689 //           on edges and boundary nodes are always fixed.
2690 //=======================================================================
2691
2692 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2693                                set<const SMDS_MeshNode*> & theFixedNodes,
2694                                const SmoothMethod          theSmoothMethod,
2695                                const int                   theNbIterations,
2696                                double                      theTgtAspectRatio,
2697                                const bool                  the2D)
2698 {
2699   myLastCreatedElems.Clear();
2700   myLastCreatedNodes.Clear();
2701
2702   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2703
2704   if ( theTgtAspectRatio < 1.0 )
2705     theTgtAspectRatio = 1.0;
2706
2707   const double disttol = 1.e-16;
2708
2709   SMESH::Controls::AspectRatio aQualityFunc;
2710
2711   SMESHDS_Mesh* aMesh = GetMeshDS();
2712
2713   if ( theElems.empty() ) {
2714     // add all faces to theElems
2715     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2716     while ( fIt->more() ) {
2717       const SMDS_MeshElement* face = fIt->next();
2718       theElems.insert( face );
2719     }
2720   }
2721   // get all face ids theElems are on
2722   set< int > faceIdSet;
2723   TIDSortedElemSet::iterator itElem;
2724   if ( the2D )
2725     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2726       int fId = FindShape( *itElem );
2727       // check that corresponding submesh exists and a shape is face
2728       if (fId &&
2729           faceIdSet.find( fId ) == faceIdSet.end() &&
2730           aMesh->MeshElements( fId )) {
2731         TopoDS_Shape F = aMesh->IndexToShape( fId );
2732         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2733           faceIdSet.insert( fId );
2734       }
2735     }
2736   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2737
2738   // ===============================================
2739   // smooth elements on each TopoDS_Face separately
2740   // ===============================================
2741
2742   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2743   for ( ; fId != faceIdSet.rend(); ++fId ) {
2744     // get face surface and submesh
2745     Handle(Geom_Surface) surface;
2746     SMESHDS_SubMesh* faceSubMesh = 0;
2747     TopoDS_Face face;
2748     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2749     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2750     bool isUPeriodic = false, isVPeriodic = false;
2751     if ( *fId ) {
2752       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2753       surface = BRep_Tool::Surface( face );
2754       faceSubMesh = aMesh->MeshElements( *fId );
2755       fToler2 = BRep_Tool::Tolerance( face );
2756       fToler2 *= fToler2 * 10.;
2757       isUPeriodic = surface->IsUPeriodic();
2758       if ( isUPeriodic )
2759         vPeriod = surface->UPeriod();
2760       isVPeriodic = surface->IsVPeriodic();
2761       if ( isVPeriodic )
2762         uPeriod = surface->VPeriod();
2763       surface->Bounds( u1, u2, v1, v2 );
2764     }
2765     // ---------------------------------------------------------
2766     // for elements on a face, find movable and fixed nodes and
2767     // compute UV for them
2768     // ---------------------------------------------------------
2769     bool checkBoundaryNodes = false;
2770     bool isQuadratic = false;
2771     set<const SMDS_MeshNode*> setMovableNodes;
2772     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2773     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2774     list< const SMDS_MeshElement* > elemsOnFace;
2775
2776     Extrema_GenExtPS projector;
2777     GeomAdaptor_Surface surfAdaptor;
2778     if ( !surface.IsNull() ) {
2779       surfAdaptor.Load( surface );
2780       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2781     }
2782     int nbElemOnFace = 0;
2783     itElem = theElems.begin();
2784     // loop on not yet smoothed elements: look for elems on a face
2785     while ( itElem != theElems.end() ) {
2786       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2787         break; // all elements found
2788
2789       const SMDS_MeshElement* elem = *itElem;
2790       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2791            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2792         ++itElem;
2793         continue;
2794       }
2795       elemsOnFace.push_back( elem );
2796       theElems.erase( itElem++ );
2797       nbElemOnFace++;
2798
2799       if ( !isQuadratic )
2800         isQuadratic = elem->IsQuadratic();
2801
2802       // get movable nodes of elem
2803       const SMDS_MeshNode* node;
2804       SMDS_TypeOfPosition posType;
2805       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2806       int nn = 0, nbn =  elem->NbNodes();
2807       if(elem->IsQuadratic())
2808         nbn = nbn/2;
2809       while ( nn++ < nbn ) {
2810         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2811         const SMDS_PositionPtr& pos = node->GetPosition();
2812         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2813         if (posType != SMDS_TOP_EDGE &&
2814             posType != SMDS_TOP_VERTEX &&
2815             theFixedNodes.find( node ) == theFixedNodes.end())
2816         {
2817           // check if all faces around the node are on faceSubMesh
2818           // because a node on edge may be bound to face
2819           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2820           bool all = true;
2821           if ( faceSubMesh ) {
2822             while ( eIt->more() && all ) {
2823               const SMDS_MeshElement* e = eIt->next();
2824               all = faceSubMesh->Contains( e );
2825             }
2826           }
2827           if ( all )
2828             setMovableNodes.insert( node );
2829           else
2830             checkBoundaryNodes = true;
2831         }
2832         if ( posType == SMDS_TOP_3DSPACE )
2833           checkBoundaryNodes = true;
2834       }
2835
2836       if ( surface.IsNull() )
2837         continue;
2838
2839       // get nodes to check UV
2840       list< const SMDS_MeshNode* > uvCheckNodes;
2841       itN = elem->nodesIterator();
2842       nn = 0; nbn =  elem->NbNodes();
2843       if(elem->IsQuadratic())
2844         nbn = nbn/2;
2845       while ( nn++ < nbn ) {
2846         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2847         if ( uvMap.find( node ) == uvMap.end() )
2848           uvCheckNodes.push_back( node );
2849         // add nodes of elems sharing node
2850         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2851         //         while ( eIt->more() ) {
2852         //           const SMDS_MeshElement* e = eIt->next();
2853         //           if ( e != elem ) {
2854         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2855         //             while ( nIt->more() ) {
2856         //               const SMDS_MeshNode* n =
2857         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2858         //               if ( uvMap.find( n ) == uvMap.end() )
2859         //                 uvCheckNodes.push_back( n );
2860         //             }
2861         //           }
2862         //         }
2863       }
2864       // check UV on face
2865       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2866       for ( ; n != uvCheckNodes.end(); ++n ) {
2867         node = *n;
2868         gp_XY uv( 0, 0 );
2869         const SMDS_PositionPtr& pos = node->GetPosition();
2870         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2871         // get existing UV
2872         switch ( posType ) {
2873         case SMDS_TOP_FACE: {
2874           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2875           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2876           break;
2877         }
2878         case SMDS_TOP_EDGE: {
2879           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2880           Handle(Geom2d_Curve) pcurve;
2881           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2882             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2883           if ( !pcurve.IsNull() ) {
2884             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2885             uv = pcurve->Value( u ).XY();
2886           }
2887           break;
2888         }
2889         case SMDS_TOP_VERTEX: {
2890           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2891           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2892             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2893           break;
2894         }
2895         default:;
2896         }
2897         // check existing UV
2898         bool project = true;
2899         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2900         double dist1 = DBL_MAX, dist2 = 0;
2901         if ( posType != SMDS_TOP_3DSPACE ) {
2902           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2903           project = dist1 > fToler2;
2904         }
2905         if ( project ) { // compute new UV
2906           gp_XY newUV;
2907           if ( !getClosestUV( projector, pNode, newUV )) {
2908             MESSAGE("Node Projection Failed " << node);
2909           }
2910           else {
2911             if ( isUPeriodic )
2912               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2913             if ( isVPeriodic )
2914               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2915             // check new UV
2916             if ( posType != SMDS_TOP_3DSPACE )
2917               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2918             if ( dist2 < dist1 )
2919               uv = newUV;
2920           }
2921         }
2922         // store UV in the map
2923         listUV.push_back( uv );
2924         uvMap.insert( make_pair( node, &listUV.back() ));
2925       }
2926     } // loop on not yet smoothed elements
2927
2928     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2929       checkBoundaryNodes = true;
2930
2931     // fix nodes on mesh boundary
2932
2933     if ( checkBoundaryNodes ) {
2934       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2935       map< NLink, int >::iterator link_nb;
2936       // put all elements links to linkNbMap
2937       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2938       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2939         const SMDS_MeshElement* elem = (*elemIt);
2940         int nbn =  elem->NbNodes();
2941         if(elem->IsQuadratic())
2942           nbn = nbn/2;
2943         // loop on elem links: insert them in linkNbMap
2944         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2945         for ( int iN = 0; iN < nbn; ++iN ) {
2946           curNode = elem->GetNode( iN );
2947           NLink link;
2948           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2949           else                      link = make_pair( prevNode , curNode );
2950           prevNode = curNode;
2951           link_nb = linkNbMap.find( link );
2952           if ( link_nb == linkNbMap.end() )
2953             linkNbMap.insert( make_pair ( link, 1 ));
2954           else
2955             link_nb->second++;
2956         }
2957       }
2958       // remove nodes that are in links encountered only once from setMovableNodes
2959       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2960         if ( link_nb->second == 1 ) {
2961           setMovableNodes.erase( link_nb->first.first );
2962           setMovableNodes.erase( link_nb->first.second );
2963         }
2964       }
2965     }
2966
2967     // -----------------------------------------------------
2968     // for nodes on seam edge, compute one more UV ( uvMap2 );
2969     // find movable nodes linked to nodes on seam and which
2970     // are to be smoothed using the second UV ( uvMap2 )
2971     // -----------------------------------------------------
2972
2973     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2974     if ( !surface.IsNull() ) {
2975       TopExp_Explorer eExp( face, TopAbs_EDGE );
2976       for ( ; eExp.More(); eExp.Next() ) {
2977         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2978         if ( !BRep_Tool::IsClosed( edge, face ))
2979           continue;
2980         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2981         if ( !sm ) continue;
2982         // find out which parameter varies for a node on seam
2983         double f,l;
2984         gp_Pnt2d uv1, uv2;
2985         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2986         if ( pcurve.IsNull() ) continue;
2987         uv1 = pcurve->Value( f );
2988         edge.Reverse();
2989         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2990         if ( pcurve.IsNull() ) continue;
2991         uv2 = pcurve->Value( f );
2992         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2993         // assure uv1 < uv2
2994         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2995           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2996         }
2997         // get nodes on seam and its vertices
2998         list< const SMDS_MeshNode* > seamNodes;
2999         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3000         while ( nSeamIt->more() ) {
3001           const SMDS_MeshNode* node = nSeamIt->next();
3002           if ( !isQuadratic || !IsMedium( node ))
3003             seamNodes.push_back( node );
3004         }
3005         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3006         for ( ; vExp.More(); vExp.Next() ) {
3007           sm = aMesh->MeshElements( vExp.Current() );
3008           if ( sm ) {
3009             nSeamIt = sm->GetNodes();
3010             while ( nSeamIt->more() )
3011               seamNodes.push_back( nSeamIt->next() );
3012           }
3013         }
3014         // loop on nodes on seam
3015         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3016         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3017           const SMDS_MeshNode* nSeam = *noSeIt;
3018           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3019           if ( n_uv == uvMap.end() )
3020             continue;
3021           // set the first UV
3022           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3023           // set the second UV
3024           listUV.push_back( *n_uv->second );
3025           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3026           if ( uvMap2.empty() )
3027             uvMap2 = uvMap; // copy the uvMap contents
3028           uvMap2[ nSeam ] = &listUV.back();
3029
3030           // collect movable nodes linked to ones on seam in nodesNearSeam
3031           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3032           while ( eIt->more() ) {
3033             const SMDS_MeshElement* e = eIt->next();
3034             int nbUseMap1 = 0, nbUseMap2 = 0;
3035             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3036             int nn = 0, nbn =  e->NbNodes();
3037             if(e->IsQuadratic()) nbn = nbn/2;
3038             while ( nn++ < nbn )
3039             {
3040               const SMDS_MeshNode* n =
3041                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3042               if (n == nSeam ||
3043                   setMovableNodes.find( n ) == setMovableNodes.end() )
3044                 continue;
3045               // add only nodes being closer to uv2 than to uv1
3046               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3047                            0.5 * ( n->Y() + nSeam->Y() ),
3048                            0.5 * ( n->Z() + nSeam->Z() ));
3049               gp_XY uv;
3050               getClosestUV( projector, pMid, uv );
3051               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3052                 nodesNearSeam.insert( n );
3053                 nbUseMap2++;
3054               }
3055               else
3056                 nbUseMap1++;
3057             }
3058             // for centroidalSmooth all element nodes must
3059             // be on one side of a seam
3060             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3061               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3062               nn = 0;
3063               while ( nn++ < nbn ) {
3064                 const SMDS_MeshNode* n =
3065                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3066                 setMovableNodes.erase( n );
3067               }
3068             }
3069           }
3070         } // loop on nodes on seam
3071       } // loop on edge of a face
3072     } // if ( !face.IsNull() )
3073
3074     if ( setMovableNodes.empty() ) {
3075       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3076       continue; // goto next face
3077     }
3078
3079     // -------------
3080     // SMOOTHING //
3081     // -------------
3082
3083     int it = -1;
3084     double maxRatio = -1., maxDisplacement = -1.;
3085     set<const SMDS_MeshNode*>::iterator nodeToMove;
3086     for ( it = 0; it < theNbIterations; it++ ) {
3087       maxDisplacement = 0.;
3088       nodeToMove = setMovableNodes.begin();
3089       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3090         const SMDS_MeshNode* node = (*nodeToMove);
3091         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3092
3093         // smooth
3094         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3095         if ( theSmoothMethod == LAPLACIAN )
3096           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3097         else
3098           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3099
3100         // node displacement
3101         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3102         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3103         if ( aDispl > maxDisplacement )
3104           maxDisplacement = aDispl;
3105       }
3106       // no node movement => exit
3107       //if ( maxDisplacement < 1.e-16 ) {
3108       if ( maxDisplacement < disttol ) {
3109         MESSAGE("-- no node movement --");
3110         break;
3111       }
3112
3113       // check elements quality
3114       maxRatio  = 0;
3115       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3116       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3117         const SMDS_MeshElement* elem = (*elemIt);
3118         if ( !elem || elem->GetType() != SMDSAbs_Face )
3119           continue;
3120         SMESH::Controls::TSequenceOfXYZ aPoints;
3121         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3122           double aValue = aQualityFunc.GetValue( aPoints );
3123           if ( aValue > maxRatio )
3124             maxRatio = aValue;
3125         }
3126       }
3127       if ( maxRatio <= theTgtAspectRatio ) {
3128         MESSAGE("-- quality achived --");
3129         break;
3130       }
3131       if (it+1 == theNbIterations) {
3132         MESSAGE("-- Iteration limit exceeded --");
3133       }
3134     } // smoothing iterations
3135
3136     MESSAGE(" Face id: " << *fId <<
3137             " Nb iterstions: " << it <<
3138             " Displacement: " << maxDisplacement <<
3139             " Aspect Ratio " << maxRatio);
3140
3141     // ---------------------------------------
3142     // new nodes positions are computed,
3143     // record movement in DS and set new UV
3144     // ---------------------------------------
3145     nodeToMove = setMovableNodes.begin();
3146     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3147       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3148       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3149       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3150       if ( node_uv != uvMap.end() ) {
3151         gp_XY* uv = node_uv->second;
3152         node->SetPosition
3153           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3154       }
3155     }
3156
3157     // move medium nodes of quadratic elements
3158     if ( isQuadratic )
3159     {
3160       SMESH_MesherHelper helper( *GetMesh() );
3161       if ( !face.IsNull() )
3162         helper.SetSubShape( face );
3163       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3164       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3165         const SMDS_QuadraticFaceOfNodes* QF =
3166           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3167         if(QF) {
3168           vector<const SMDS_MeshNode*> Ns;
3169           Ns.reserve(QF->NbNodes()+1);
3170           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3171           while ( anIter->more() )
3172             Ns.push_back( anIter->next() );
3173           Ns.push_back( Ns[0] );
3174           double x, y, z;
3175           for(int i=0; i<QF->NbNodes(); i=i+2) {
3176             if ( !surface.IsNull() ) {
3177               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3178               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3179               gp_XY uv = ( uv1 + uv2 ) / 2.;
3180               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3181               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3182             }
3183             else {
3184               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3185               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3186               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3187             }
3188             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3189                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3190                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3191               // we have to move i+1 node
3192               aMesh->MoveNode( Ns[i+1], x, y, z );
3193             }
3194           }
3195         }
3196       }
3197     }
3198
3199   } // loop on face ids
3200
3201 }
3202
3203 //=======================================================================
3204 //function : isReverse
3205 //purpose  : Return true if normal of prevNodes is not co-directied with
3206 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3207 //           iNotSame is where prevNodes and nextNodes are different
3208 //=======================================================================
3209
3210 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3211                       vector<const SMDS_MeshNode*> nextNodes,
3212                       const int            nbNodes,
3213                       const int            iNotSame)
3214 {
3215   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3216   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3217
3218   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3219   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3220   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3221   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3222
3223   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3224   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3225   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3226   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3227
3228   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3229
3230   return (vA ^ vB) * vN < 0.0;
3231 }
3232
3233 //=======================================================================
3234 /*!
3235  * \brief Create elements by sweeping an element
3236  * \param elem - element to sweep
3237  * \param newNodesItVec - nodes generated from each node of the element
3238  * \param newElems - generated elements
3239  * \param nbSteps - number of sweeping steps
3240  * \param srcElements - to append elem for each generated element
3241  */
3242 //=======================================================================
3243
3244 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3245                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3246                                     list<const SMDS_MeshElement*>&        newElems,
3247                                     const int                             nbSteps,
3248                                     SMESH_SequenceOfElemPtr&              srcElements)
3249 {
3250   SMESHDS_Mesh* aMesh = GetMeshDS();
3251
3252   // Loop on elem nodes:
3253   // find new nodes and detect same nodes indices
3254   int nbNodes = elem->NbNodes();
3255   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3256   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3257   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3258   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3259
3260   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3261   vector<int> sames(nbNodes);
3262   vector<bool> issimple(nbNodes);
3263
3264   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3265     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3266     const SMDS_MeshNode*                 node         = nnIt->first;
3267     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3268     if ( listNewNodes.empty() ) {
3269       return;
3270     }
3271
3272     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3273
3274     itNN[ iNode ] = listNewNodes.begin();
3275     prevNod[ iNode ] = node;
3276     nextNod[ iNode ] = listNewNodes.front();
3277     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3278       if ( prevNod[ iNode ] != nextNod [ iNode ])
3279         iNotSameNode = iNode;
3280       else {
3281         iSameNode = iNode;
3282         //nbSame++;
3283         sames[nbSame++] = iNode;
3284       }
3285     }
3286   }
3287
3288   //cout<<"  nbSame = "<<nbSame<<endl;
3289   if ( nbSame == nbNodes || nbSame > 2) {
3290     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3291     //INFOS( " Too many same nodes of element " << elem->GetID() );
3292     return;
3293   }
3294
3295   //  if( elem->IsQuadratic() && nbSame>0 ) {
3296   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3297   //    return;
3298   //  }
3299
3300   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3301   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3302   if ( nbSame > 0 ) {
3303     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3304     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3305     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3306   }
3307
3308   //if(nbNodes==8)
3309   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3310   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3311   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3312   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3313
3314   // check element orientation
3315   int i0 = 0, i2 = 2;
3316   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3317     //MESSAGE("Reversed elem " << elem );
3318     i0 = 2;
3319     i2 = 0;
3320     if ( nbSame > 0 )
3321       std::swap( iBeforeSame, iAfterSame );
3322   }
3323
3324   // make new elements
3325   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3326     // get next nodes
3327     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3328       if(issimple[iNode]) {
3329         nextNod[ iNode ] = *itNN[ iNode ];
3330         itNN[ iNode ]++;
3331       }
3332       else {
3333         if( elem->GetType()==SMDSAbs_Node ) {
3334           // we have to use two nodes
3335           midlNod[ iNode ] = *itNN[ iNode ];
3336           itNN[ iNode ]++;
3337           nextNod[ iNode ] = *itNN[ iNode ];
3338           itNN[ iNode ]++;
3339         }
3340         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3341           // we have to use each second node
3342           //itNN[ iNode ]++;
3343           nextNod[ iNode ] = *itNN[ iNode ];
3344           itNN[ iNode ]++;
3345         }
3346         else {
3347           // we have to use two nodes
3348           midlNod[ iNode ] = *itNN[ iNode ];
3349           itNN[ iNode ]++;
3350           nextNod[ iNode ] = *itNN[ iNode ];
3351           itNN[ iNode ]++;
3352         }
3353       }
3354     }
3355     SMDS_MeshElement* aNewElem = 0;
3356     if(!elem->IsPoly()) {
3357       switch ( nbNodes ) {
3358       case 0:
3359         return;
3360       case 1: { // NODE
3361         if ( nbSame == 0 ) {
3362           if(issimple[0])
3363             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3364           else
3365             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3366         }
3367         break;
3368       }
3369       case 2: { // EDGE
3370         if ( nbSame == 0 )
3371           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3372                                     nextNod[ 1 ], nextNod[ 0 ] );
3373         else
3374           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3375                                     nextNod[ iNotSameNode ] );
3376         break;
3377       }
3378
3379       case 3: { // TRIANGLE or quadratic edge
3380         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3381
3382           if ( nbSame == 0 )       // --- pentahedron
3383             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3384                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3385
3386           else if ( nbSame == 1 )  // --- pyramid
3387             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3388                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3389                                          nextNod[ iSameNode ]);
3390
3391           else // 2 same nodes:      --- tetrahedron
3392             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3393                                          nextNod[ iNotSameNode ]);
3394         }
3395         else { // quadratic edge
3396           if(nbSame==0) {     // quadratic quadrangle
3397             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3398                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3399           }
3400           else if(nbSame==1) { // quadratic triangle
3401             if(sames[0]==2) {
3402               return; // medium node on axis
3403             }
3404             else if(sames[0]==0) {
3405               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3406                                         nextNod[2], midlNod[1], prevNod[2]);
3407             }
3408             else { // sames[0]==1
3409               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3410                                         midlNod[0], nextNod[2], prevNod[2]);
3411             }
3412           }
3413           else {
3414             return;
3415           }
3416         }
3417         break;
3418       }
3419       case 4: { // QUADRANGLE
3420
3421         if ( nbSame == 0 )       // --- hexahedron
3422           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3423                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3424
3425         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3426           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3427                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3428                                        nextNod[ iSameNode ]);
3429           newElems.push_back( aNewElem );
3430           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3431                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3432                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3433         }
3434         else if ( nbSame == 2 ) { // pentahedron
3435           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3436             // iBeforeSame is same too
3437             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3438                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3439                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3440           else
3441             // iAfterSame is same too
3442             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3443                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3444                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3445         }
3446         break;
3447       }
3448       case 6: { // quadratic triangle
3449         // create pentahedron with 15 nodes
3450         if(nbSame==0) {
3451           if(i0>0) { // reversed case
3452             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3453                                          nextNod[0], nextNod[2], nextNod[1],
3454                                          prevNod[5], prevNod[4], prevNod[3],
3455                                          nextNod[5], nextNod[4], nextNod[3],
3456                                          midlNod[0], midlNod[2], midlNod[1]);
3457           }
3458           else { // not reversed case
3459             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3460                                          nextNod[0], nextNod[1], nextNod[2],
3461                                          prevNod[3], prevNod[4], prevNod[5],
3462                                          nextNod[3], nextNod[4], nextNod[5],
3463                                          midlNod[0], midlNod[1], midlNod[2]);
3464           }
3465         }
3466         else if(nbSame==1) {
3467           // 2d order pyramid of 13 nodes
3468           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3469           //                                 int n12,int n23,int n34,int n41,
3470           //                                 int n15,int n25,int n35,int n45, int ID);
3471           int n5 = iSameNode;
3472           int n1,n4,n41,n15,n45;
3473           if(i0>0) { // reversed case
3474             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3475             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3476             n41 = n1 + 3;
3477             n15 = n5 + 3;
3478             n45 = n4 + 3;
3479           }
3480           else {
3481             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3482             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3483             n41 = n4 + 3;
3484             n15 = n1 + 3;
3485             n45 = n5 + 3;
3486           }
3487           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3488                                       nextNod[n4], prevNod[n4], prevNod[n5],
3489                                       midlNod[n1], nextNod[n41],
3490                                       midlNod[n4], prevNod[n41],
3491                                       prevNod[n15], nextNod[n15],
3492                                       nextNod[n45], prevNod[n45]);
3493         }
3494         else if(nbSame==2) {
3495           // 2d order tetrahedron of 10 nodes
3496           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3497           //                                 int n12,int n23,int n31,
3498           //                                 int n14,int n24,int n34, int ID);
3499           int n1 = iNotSameNode;
3500           int n2,n3,n12,n23,n31;
3501           if(i0>0) { // reversed case
3502             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3503             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3504             n12 = n2 + 3;
3505             n23 = n3 + 3;
3506             n31 = n1 + 3;
3507           }
3508           else {
3509             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3510             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3511             n12 = n1 + 3;
3512             n23 = n2 + 3;
3513             n31 = n3 + 3;
3514           }
3515           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3516                                        prevNod[n12], prevNod[n23], prevNod[n31],
3517                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3518         }
3519         break;
3520       }
3521       case 8: { // quadratic quadrangle
3522         if(nbSame==0) {
3523           // create hexahedron with 20 nodes
3524           if(i0>0) { // reversed case
3525             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3526                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3527                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3528                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3529                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3530           }
3531           else { // not reversed case
3532             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3533                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3534                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3535                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3536                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3537           }
3538         }
3539         else if(nbSame==1) { 
3540           // --- pyramid + pentahedron - can not be created since it is needed 
3541           // additional middle node ot the center of face
3542           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3543           return;
3544         }
3545         else if(nbSame==2) {
3546           // 2d order Pentahedron with 15 nodes
3547           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3548           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3549           //                                 int n14,int n25,int n36, int ID);
3550           int n1,n2,n4,n5;
3551           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3552             // iBeforeSame is same too
3553             n1 = iBeforeSame;
3554             n2 = iOpposSame;
3555             n4 = iSameNode;
3556             n5 = iAfterSame;
3557           }
3558           else {
3559             // iAfterSame is same too
3560             n1 = iSameNode;
3561             n2 = iBeforeSame;
3562             n4 = iAfterSame;
3563             n5 = iOpposSame;
3564           }
3565           int n12,n45,n14,n25;
3566           if(i0>0) { //reversed case
3567             n12 = n1 + 4;
3568             n45 = n5 + 4;
3569             n14 = n4 + 4;
3570             n25 = n2 + 4;
3571           }
3572           else {
3573             n12 = n2 + 4;
3574             n45 = n4 + 4;
3575             n14 = n1 + 4;
3576             n25 = n5 + 4;
3577           }
3578           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3579                                        prevNod[n4], prevNod[n5], nextNod[n5],
3580                                        prevNod[n12], midlNod[n2], nextNod[n12],
3581                                        prevNod[n45], midlNod[n5], nextNod[n45],
3582                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3583         }
3584         break;
3585       }
3586       default: {
3587         // realized for extrusion only
3588         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3589         //vector<int> quantities (nbNodes + 2);
3590
3591         //quantities[0] = nbNodes; // bottom of prism
3592         //for (int inode = 0; inode < nbNodes; inode++) {
3593         //  polyedre_nodes[inode] = prevNod[inode];
3594         //}
3595
3596         //quantities[1] = nbNodes; // top of prism
3597         //for (int inode = 0; inode < nbNodes; inode++) {
3598         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3599         //}
3600
3601         //for (int iface = 0; iface < nbNodes; iface++) {
3602         //  quantities[iface + 2] = 4;
3603         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3604         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3605         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3606         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3607         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3608         //}
3609         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3610         break;
3611       }
3612       }
3613     }
3614
3615     if(!aNewElem) {
3616       // realized for extrusion only
3617       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3618       vector<int> quantities (nbNodes + 2);
3619
3620       quantities[0] = nbNodes; // bottom of prism
3621       for (int inode = 0; inode < nbNodes; inode++) {
3622         polyedre_nodes[inode] = prevNod[inode];
3623       }
3624
3625       quantities[1] = nbNodes; // top of prism
3626       for (int inode = 0; inode < nbNodes; inode++) {
3627         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3628       }
3629
3630       for (int iface = 0; iface < nbNodes; iface++) {
3631         quantities[iface + 2] = 4;
3632         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3633         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3634         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3635         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3636         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3637       }
3638       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3639     }
3640
3641     if ( aNewElem ) {
3642       newElems.push_back( aNewElem );
3643       myLastCreatedElems.Append(aNewElem);
3644       srcElements.Append( elem );
3645     }
3646
3647     // set new prev nodes
3648     for ( iNode = 0; iNode < nbNodes; iNode++ )
3649       prevNod[ iNode ] = nextNod[ iNode ];
3650
3651   } // for steps
3652 }
3653
3654 //=======================================================================
3655 /*!
3656  * \brief Create 1D and 2D elements around swept elements
3657  * \param mapNewNodes - source nodes and ones generated from them
3658  * \param newElemsMap - source elements and ones generated from them
3659  * \param elemNewNodesMap - nodes generated from each node of each element
3660  * \param elemSet - all swept elements
3661  * \param nbSteps - number of sweeping steps
3662  * \param srcElements - to append elem for each generated element
3663  */
3664 //=======================================================================
3665
3666 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3667                                   TElemOfElemListMap &     newElemsMap,
3668                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3669                                   TIDSortedElemSet&        elemSet,
3670                                   const int                nbSteps,
3671                                   SMESH_SequenceOfElemPtr& srcElements)
3672 {
3673   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3674   SMESHDS_Mesh* aMesh = GetMeshDS();
3675
3676   // Find nodes belonging to only one initial element - sweep them to get edges.
3677
3678   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3679   for ( ; nList != mapNewNodes.end(); nList++ ) {
3680     const SMDS_MeshNode* node =
3681       static_cast<const SMDS_MeshNode*>( nList->first );
3682     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3683     int nbInitElems = 0;
3684     const SMDS_MeshElement* el = 0;
3685     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3686     while ( eIt->more() && nbInitElems < 2 ) {
3687       el = eIt->next();
3688       SMDSAbs_ElementType type = el->GetType();
3689       if ( type == SMDSAbs_Volume || type < highType ) continue;
3690       if ( type > highType ) {
3691         nbInitElems = 0;
3692         highType = type;
3693       }
3694       if ( elemSet.find(el) != elemSet.end() )
3695         nbInitElems++;
3696     }
3697     if ( nbInitElems < 2 ) {
3698       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3699       if(!NotCreateEdge) {
3700         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3701         list<const SMDS_MeshElement*> newEdges;
3702         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3703       }
3704     }
3705   }
3706
3707   // Make a ceiling for each element ie an equal element of last new nodes.
3708   // Find free links of faces - make edges and sweep them into faces.
3709
3710   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3711   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3712   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3713     const SMDS_MeshElement* elem = itElem->first;
3714     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3715
3716     if ( elem->GetType() == SMDSAbs_Edge ) {
3717       // create a ceiling edge
3718       if (!elem->IsQuadratic()) {
3719         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3720                                vecNewNodes[ 1 ]->second.back())) {
3721           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3722                                                    vecNewNodes[ 1 ]->second.back()));
3723           srcElements.Append( myLastCreatedElems.Last() );
3724         }
3725       }
3726       else {
3727         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3728                                vecNewNodes[ 1 ]->second.back(),
3729                                vecNewNodes[ 2 ]->second.back())) {
3730           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3731                                                    vecNewNodes[ 1 ]->second.back(),
3732                                                    vecNewNodes[ 2 ]->second.back()));
3733           srcElements.Append( myLastCreatedElems.Last() );
3734         }
3735       }
3736     }
3737     if ( elem->GetType() != SMDSAbs_Face )
3738       continue;
3739
3740     if(itElem->second.size()==0) continue;
3741
3742     bool hasFreeLinks = false;
3743
3744     TIDSortedElemSet avoidSet;
3745     avoidSet.insert( elem );
3746
3747     set<const SMDS_MeshNode*> aFaceLastNodes;
3748     int iNode, nbNodes = vecNewNodes.size();
3749     if(!elem->IsQuadratic()) {
3750       // loop on the face nodes
3751       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3752         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3753         // look for free links of the face
3754         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3755         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3756         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3757         // check if a link is free
3758         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3759           hasFreeLinks = true;
3760           // make an edge and a ceiling for a new edge
3761           if ( !aMesh->FindEdge( n1, n2 )) {
3762             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3763             srcElements.Append( myLastCreatedElems.Last() );
3764           }
3765           n1 = vecNewNodes[ iNode ]->second.back();
3766           n2 = vecNewNodes[ iNext ]->second.back();
3767           if ( !aMesh->FindEdge( n1, n2 )) {
3768             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3769             srcElements.Append( myLastCreatedElems.Last() );
3770           }
3771         }
3772       }
3773     }
3774     else { // elem is quadratic face
3775       int nbn = nbNodes/2;
3776       for ( iNode = 0; iNode < nbn; iNode++ ) {
3777         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3778         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3779         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3780         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3781         // check if a link is free
3782         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3783           hasFreeLinks = true;
3784           // make an edge and a ceiling for a new edge
3785           // find medium node
3786           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3787           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3788             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3789             srcElements.Append( myLastCreatedElems.Last() );
3790           }
3791           n1 = vecNewNodes[ iNode ]->second.back();
3792           n2 = vecNewNodes[ iNext ]->second.back();
3793           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3794           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3795             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3796             srcElements.Append( myLastCreatedElems.Last() );
3797           }
3798         }
3799       }
3800       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3801         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3802       }
3803     }
3804
3805     // sweep free links into faces
3806
3807     if ( hasFreeLinks )  {
3808       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3809       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3810
3811       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3812       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3813         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3814         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3815       }
3816       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3817         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3818         iVol = 0;
3819         while ( iVol++ < volNb ) v++;
3820         // find indices of free faces of a volume and their source edges
3821         list< int > freeInd;
3822         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3823         SMDS_VolumeTool vTool( *v );
3824         int iF, nbF = vTool.NbFaces();
3825         for ( iF = 0; iF < nbF; iF ++ ) {
3826           if (vTool.IsFreeFace( iF ) &&
3827               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3828               initNodeSet != faceNodeSet) // except an initial face
3829           {
3830             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3831               continue;
3832             freeInd.push_back( iF );
3833             // find source edge of a free face iF
3834             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3835             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3836             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3837                                    initNodeSet.begin(), initNodeSet.end(),
3838                                    commonNodes.begin());
3839             if ( (*v)->IsQuadratic() )
3840               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3841             else
3842               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3843 #ifdef _DEBUG_
3844             if ( !srcEdges.back() )
3845             {
3846               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3847                    << iF << " of volume #" << vTool.ID() << endl;
3848             }
3849 #endif
3850           }
3851         }
3852         if ( freeInd.empty() )
3853           continue;
3854
3855         // create faces for all steps;
3856         // if such a face has been already created by sweep of edge,
3857         // assure that its orientation is OK
3858         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3859           vTool.Set( *v );
3860           vTool.SetExternalNormal();
3861           list< int >::iterator ind = freeInd.begin();
3862           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3863           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3864           {
3865             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3866             int nbn = vTool.NbFaceNodes( *ind );
3867             switch ( nbn ) {
3868             case 3: { ///// triangle
3869               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3870               if ( !f )
3871                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3872               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3873                 aMesh->ChangeElementNodes( f, nodes, nbn );
3874               break;
3875             }
3876             case 4: { ///// quadrangle
3877               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3878               if ( !f )
3879                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3880               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3881                 aMesh->ChangeElementNodes( f, nodes, nbn );
3882               break;
3883             }
3884             default:
3885               if( (*v)->IsQuadratic() ) {
3886                 if(nbn==6) { /////// quadratic triangle
3887                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3888                                                              nodes[1], nodes[3], nodes[5] );
3889                   if ( !f ) {
3890                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3891                                                              nodes[1], nodes[3], nodes[5]));
3892                   }
3893                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3894                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3895                     tmpnodes[0] = nodes[0];
3896                     tmpnodes[1] = nodes[2];
3897                     tmpnodes[2] = nodes[4];
3898                     tmpnodes[3] = nodes[1];
3899                     tmpnodes[4] = nodes[3];
3900                     tmpnodes[5] = nodes[5];
3901                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3902                   }
3903                 }
3904                 else {       /////// quadratic quadrangle
3905                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3906                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3907                   if ( !f ) {
3908                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3909                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3910                   }
3911                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3912                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3913                     tmpnodes[0] = nodes[0];
3914                     tmpnodes[1] = nodes[2];
3915                     tmpnodes[2] = nodes[4];
3916                     tmpnodes[3] = nodes[6];
3917                     tmpnodes[4] = nodes[1];
3918                     tmpnodes[5] = nodes[3];
3919                     tmpnodes[6] = nodes[5];
3920                     tmpnodes[7] = nodes[7];
3921                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3922                   }
3923                 }
3924               }
3925               else { //////// polygon
3926                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3927                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3928                 if ( !f )
3929                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3930                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3931                   aMesh->ChangeElementNodes( f, nodes, nbn );
3932               }
3933             }
3934             while ( srcElements.Length() < myLastCreatedElems.Length() )
3935               srcElements.Append( *srcEdge );
3936
3937           }  // loop on free faces
3938
3939           // go to the next volume
3940           iVol = 0;
3941           while ( iVol++ < nbVolumesByStep ) v++;
3942         }
3943       }
3944     } // sweep free links into faces
3945
3946     // Make a ceiling face with a normal external to a volume
3947
3948     SMDS_VolumeTool lastVol( itElem->second.back() );
3949
3950     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3951     if ( iF >= 0 ) {
3952       lastVol.SetExternalNormal();
3953       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3954       int nbn = lastVol.NbFaceNodes( iF );
3955       switch ( nbn ) {
3956       case 3:
3957         if (!hasFreeLinks ||
3958             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3959           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3960         break;
3961       case 4:
3962         if (!hasFreeLinks ||
3963             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3964           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3965         break;
3966       default:
3967         if(itElem->second.back()->IsQuadratic()) {
3968           if(nbn==6) {
3969             if (!hasFreeLinks ||
3970                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3971                                  nodes[1], nodes[3], nodes[5]) ) {
3972               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3973                                                        nodes[1], nodes[3], nodes[5]));
3974             }
3975           }
3976           else { // nbn==8
3977             if (!hasFreeLinks ||
3978                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3979                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3980               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3981                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3982           }
3983         }
3984         else {
3985           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3986           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3987             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3988         }
3989       } // switch
3990
3991       while ( srcElements.Length() < myLastCreatedElems.Length() )
3992         srcElements.Append( myLastCreatedElems.Last() );
3993     }
3994   } // loop on swept elements
3995 }
3996
3997 //=======================================================================
3998 //function : RotationSweep
3999 //purpose  :
4000 //=======================================================================
4001
4002 SMESH_MeshEditor::PGroupIDs
4003 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4004                                 const gp_Ax1&      theAxis,
4005                                 const double       theAngle,
4006                                 const int          theNbSteps,
4007                                 const double       theTol,
4008                                 const bool         theMakeGroups,
4009                                 const bool         theMakeWalls)
4010 {
4011   myLastCreatedElems.Clear();
4012   myLastCreatedNodes.Clear();
4013
4014   // source elements for each generated one
4015   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4016
4017   MESSAGE( "RotationSweep()");
4018   gp_Trsf aTrsf;
4019   aTrsf.SetRotation( theAxis, theAngle );
4020   gp_Trsf aTrsf2;
4021   aTrsf2.SetRotation( theAxis, theAngle/2. );
4022
4023   gp_Lin aLine( theAxis );
4024   double aSqTol = theTol * theTol;
4025
4026   SMESHDS_Mesh* aMesh = GetMeshDS();
4027
4028   TNodeOfNodeListMap mapNewNodes;
4029   TElemOfVecOfNnlmiMap mapElemNewNodes;
4030   TElemOfElemListMap newElemsMap;
4031
4032   // loop on theElems
4033   TIDSortedElemSet::iterator itElem;
4034   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4035     const SMDS_MeshElement* elem = *itElem;
4036     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4037       continue;
4038     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4039     newNodesItVec.reserve( elem->NbNodes() );
4040
4041     // loop on elem nodes
4042     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4043     while ( itN->more() ) {
4044       // check if a node has been already sweeped
4045       const SMDS_MeshNode* node = cast2Node( itN->next() );
4046
4047       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4048       double coord[3];
4049       aXYZ.Coord( coord[0], coord[1], coord[2] );
4050       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4051
4052       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4053       if ( nIt == mapNewNodes.end() ) {
4054         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4055         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4056
4057         // make new nodes
4058         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4059         //double coord[3];
4060         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4061         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4062         const SMDS_MeshNode * newNode = node;
4063         for ( int i = 0; i < theNbSteps; i++ ) {
4064           if ( !isOnAxis ) {
4065             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4066               // create two nodes
4067               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4068               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4069               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4070               myLastCreatedNodes.Append(newNode);
4071               srcNodes.Append( node );
4072               listNewNodes.push_back( newNode );
4073               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4074               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4075             }
4076             else {
4077               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4078             }
4079             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4080             myLastCreatedNodes.Append(newNode);
4081             srcNodes.Append( node );
4082             listNewNodes.push_back( newNode );
4083           }
4084           else {
4085             listNewNodes.push_back( newNode );
4086             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4087               listNewNodes.push_back( newNode );
4088             }
4089           }
4090         }
4091       }
4092       /*
4093         else {
4094         // if current elem is quadratic and current node is not medium
4095         // we have to check - may be it is needed to insert additional nodes
4096         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4097         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4098         if(listNewNodes.size()==theNbSteps) {
4099         listNewNodes.clear();
4100         // make new nodes
4101         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4102         //double coord[3];
4103         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4104         const SMDS_MeshNode * newNode = node;
4105         if ( !isOnAxis ) {
4106         for(int i = 0; i<theNbSteps; i++) {
4107         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4108         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4109         cout<<"    3 AddNode:  "<<newNode;
4110         myLastCreatedNodes.Append(newNode);
4111         listNewNodes.push_back( newNode );
4112         srcNodes.Append( node );
4113         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4114         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4115         cout<<"    4 AddNode:  "<<newNode;
4116         myLastCreatedNodes.Append(newNode);
4117         srcNodes.Append( node );
4118         listNewNodes.push_back( newNode );
4119         }
4120         }
4121         else {
4122         listNewNodes.push_back( newNode );
4123         }
4124         }
4125         }
4126         }
4127       */
4128       newNodesItVec.push_back( nIt );
4129     }
4130     // make new elements
4131     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4132   }
4133
4134   if ( theMakeWalls )
4135     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4136
4137   PGroupIDs newGroupIDs;
4138   if ( theMakeGroups )
4139     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4140
4141   return newGroupIDs;
4142 }
4143
4144
4145 //=======================================================================
4146 //function : CreateNode
4147 //purpose  :
4148 //=======================================================================
4149 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4150                                                   const double y,
4151                                                   const double z,
4152                                                   const double tolnode,
4153                                                   SMESH_SequenceOfNode& aNodes)
4154 {
4155   myLastCreatedElems.Clear();
4156   myLastCreatedNodes.Clear();
4157
4158   gp_Pnt P1(x,y,z);
4159   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4160
4161   // try to search in sequence of existing nodes
4162   // if aNodes.Length()>0 we 'nave to use given sequence
4163   // else - use all nodes of mesh
4164   if(aNodes.Length()>0) {
4165     int i;
4166     for(i=1; i<=aNodes.Length(); i++) {
4167       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4168       if(P1.Distance(P2)<tolnode)
4169         return aNodes.Value(i);
4170     }
4171   }
4172   else {
4173     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4174     while(itn->more()) {
4175       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4176       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4177       if(P1.Distance(P2)<tolnode)
4178         return aN;
4179     }
4180   }
4181
4182   // create new node and return it
4183   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4184   myLastCreatedNodes.Append(NewNode);
4185   return NewNode;
4186 }
4187
4188
4189 //=======================================================================
4190 //function : ExtrusionSweep
4191 //purpose  :
4192 //=======================================================================
4193
4194 SMESH_MeshEditor::PGroupIDs
4195 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4196                                   const gp_Vec&       theStep,
4197                                   const int           theNbSteps,
4198                                   TElemOfElemListMap& newElemsMap,
4199                                   const bool          theMakeGroups,
4200                                   const int           theFlags,
4201                                   const double        theTolerance)
4202 {
4203   ExtrusParam aParams;
4204   aParams.myDir = gp_Dir(theStep);
4205   aParams.myNodes.Clear();
4206   aParams.mySteps = new TColStd_HSequenceOfReal;
4207   int i;
4208   for(i=1; i<=theNbSteps; i++)
4209     aParams.mySteps->Append(theStep.Magnitude());
4210
4211   return
4212     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4213 }
4214
4215
4216 //=======================================================================
4217 //function : ExtrusionSweep
4218 //purpose  :
4219 //=======================================================================
4220
4221 SMESH_MeshEditor::PGroupIDs
4222 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4223                                   ExtrusParam&        theParams,
4224                                   TElemOfElemListMap& newElemsMap,
4225                                   const bool          theMakeGroups,
4226                                   const int           theFlags,
4227                                   const double        theTolerance)
4228 {
4229   myLastCreatedElems.Clear();
4230   myLastCreatedNodes.Clear();
4231
4232   // source elements for each generated one
4233   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4234
4235   SMESHDS_Mesh* aMesh = GetMeshDS();
4236
4237   int nbsteps = theParams.mySteps->Length();
4238
4239   TNodeOfNodeListMap mapNewNodes;
4240   //TNodeOfNodeVecMap mapNewNodes;
4241   TElemOfVecOfNnlmiMap mapElemNewNodes;
4242   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4243
4244   // loop on theElems
4245   TIDSortedElemSet::iterator itElem;
4246   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4247     // check element type
4248     const SMDS_MeshElement* elem = *itElem;
4249     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4250       continue;
4251
4252     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4253     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4254     newNodesItVec.reserve( elem->NbNodes() );
4255
4256     // loop on elem nodes
4257     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4258     while ( itN->more() )
4259     {
4260       // check if a node has been already sweeped
4261       const SMDS_MeshNode* node = cast2Node( itN->next() );
4262       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4263       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4264       if ( nIt == mapNewNodes.end() ) {
4265         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4266         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4267         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4268         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4269         //vecNewNodes.reserve(nbsteps);
4270
4271         // make new nodes
4272         double coord[] = { node->X(), node->Y(), node->Z() };
4273         //int nbsteps = theParams.mySteps->Length();
4274         for ( int i = 0; i < nbsteps; i++ ) {
4275           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4276             // create additional node
4277             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4278             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4279             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4280             if( theFlags & EXTRUSION_FLAG_SEW ) {
4281               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4282                                                          theTolerance, theParams.myNodes);
4283               listNewNodes.push_back( newNode );
4284             }
4285             else {
4286               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4287               myLastCreatedNodes.Append(newNode);
4288               srcNodes.Append( node );
4289               listNewNodes.push_back( newNode );
4290             }
4291           }
4292           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4293           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4294           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4295           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4296           if( theFlags & EXTRUSION_FLAG_SEW ) {
4297             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4298                                                        theTolerance, theParams.myNodes);
4299             listNewNodes.push_back( newNode );
4300             //vecNewNodes[i]=newNode;
4301           }
4302           else {
4303             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4304             myLastCreatedNodes.Append(newNode);
4305             srcNodes.Append( node );
4306             listNewNodes.push_back( newNode );
4307             //vecNewNodes[i]=newNode;
4308           }
4309         }
4310       }
4311       else {
4312         // if current elem is quadratic and current node is not medium
4313         // we have to check - may be it is needed to insert additional nodes
4314         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4315           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4316           if(listNewNodes.size()==nbsteps) {
4317             listNewNodes.clear();
4318             double coord[] = { node->X(), node->Y(), node->Z() };
4319             for ( int i = 0; i < nbsteps; i++ ) {
4320               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4321               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4322               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4323               if( theFlags & EXTRUSION_FLAG_SEW ) {
4324                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4325                                                            theTolerance, theParams.myNodes);
4326                 listNewNodes.push_back( newNode );
4327               }
4328               else {
4329                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4330                 myLastCreatedNodes.Append(newNode);
4331                 srcNodes.Append( node );
4332                 listNewNodes.push_back( newNode );
4333               }
4334               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4335               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4336               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4337               if( theFlags & EXTRUSION_FLAG_SEW ) {
4338                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4339                                                            theTolerance, theParams.myNodes);
4340                 listNewNodes.push_back( newNode );
4341               }
4342               else {
4343                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4344                 myLastCreatedNodes.Append(newNode);
4345                 srcNodes.Append( node );
4346                 listNewNodes.push_back( newNode );
4347               }
4348             }
4349           }
4350         }
4351       }
4352       newNodesItVec.push_back( nIt );
4353     }
4354     // make new elements
4355     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4356   }
4357
4358   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4359     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4360   }
4361   PGroupIDs newGroupIDs;
4362   if ( theMakeGroups )
4363     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4364
4365   return newGroupIDs;
4366 }
4367
4368 /*
4369 //=======================================================================
4370 //class    : SMESH_MeshEditor_PathPoint
4371 //purpose  : auxiliary class
4372 //=======================================================================
4373 class SMESH_MeshEditor_PathPoint {
4374 public:
4375 SMESH_MeshEditor_PathPoint() {
4376 myPnt.SetCoord(99., 99., 99.);
4377 myTgt.SetCoord(1.,0.,0.);
4378 myAngle=0.;
4379 myPrm=0.;
4380 }
4381 void SetPnt(const gp_Pnt& aP3D){
4382 myPnt=aP3D;
4383 }
4384 void SetTangent(const gp_Dir& aTgt){
4385 myTgt=aTgt;
4386 }
4387 void SetAngle(const double& aBeta){
4388 myAngle=aBeta;
4389 }
4390 void SetParameter(const double& aPrm){
4391 myPrm=aPrm;
4392 }
4393 const gp_Pnt& Pnt()const{
4394 return myPnt;
4395 }
4396 const gp_Dir& Tangent()const{
4397 return myTgt;
4398 }
4399 double Angle()const{
4400 return myAngle;
4401 }
4402 double Parameter()const{
4403 return myPrm;
4404 }
4405
4406 protected:
4407 gp_Pnt myPnt;
4408 gp_Dir myTgt;
4409 double myAngle;
4410 double myPrm;
4411 };
4412 */
4413
4414 //=======================================================================
4415 //function : ExtrusionAlongTrack
4416 //purpose  :
4417 //=======================================================================
4418 SMESH_MeshEditor::Extrusion_Error
4419 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4420                                        SMESH_subMesh*       theTrack,
4421                                        const SMDS_MeshNode* theN1,
4422                                        const bool           theHasAngles,
4423                                        list<double>&        theAngles,
4424                                        const bool           theLinearVariation,
4425                                        const bool           theHasRefPoint,
4426                                        const gp_Pnt&        theRefPoint,
4427                                        const bool           theMakeGroups)
4428 {
4429   myLastCreatedElems.Clear();
4430   myLastCreatedNodes.Clear();
4431
4432   int aNbE;
4433   std::list<double> aPrms;
4434   TIDSortedElemSet::iterator itElem;
4435
4436   gp_XYZ aGC;
4437   TopoDS_Edge aTrackEdge;
4438   TopoDS_Vertex aV1, aV2;
4439
4440   SMDS_ElemIteratorPtr aItE;
4441   SMDS_NodeIteratorPtr aItN;
4442   SMDSAbs_ElementType aTypeE;
4443
4444   TNodeOfNodeListMap mapNewNodes;
4445
4446   // 1. Check data
4447   aNbE = theElements.size();
4448   // nothing to do
4449   if ( !aNbE )
4450     return EXTR_NO_ELEMENTS;
4451
4452   // 1.1 Track Pattern
4453   ASSERT( theTrack );
4454
4455   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4456
4457   aItE = pSubMeshDS->GetElements();
4458   while ( aItE->more() ) {
4459     const SMDS_MeshElement* pE = aItE->next();
4460     aTypeE = pE->GetType();
4461     // Pattern must contain links only
4462     if ( aTypeE != SMDSAbs_Edge )
4463       return EXTR_PATH_NOT_EDGE;
4464   }
4465
4466   list<SMESH_MeshEditor_PathPoint> fullList;
4467
4468   const TopoDS_Shape& aS = theTrack->GetSubShape();
4469   // Sub shape for the Pattern must be an Edge or Wire
4470   if( aS.ShapeType() == TopAbs_EDGE ) {
4471     aTrackEdge = TopoDS::Edge( aS );
4472     // the Edge must not be degenerated
4473     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4474       return EXTR_BAD_PATH_SHAPE;
4475     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4476     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4477     const SMDS_MeshNode* aN1 = aItN->next();
4478     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4479     const SMDS_MeshNode* aN2 = aItN->next();
4480     // starting node must be aN1 or aN2
4481     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4482       return EXTR_BAD_STARTING_NODE;
4483     aItN = pSubMeshDS->GetNodes();
4484     while ( aItN->more() ) {
4485       const SMDS_MeshNode* pNode = aItN->next();
4486       const SMDS_EdgePosition* pEPos =
4487         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4488       double aT = pEPos->GetUParameter();
4489       aPrms.push_back( aT );
4490     }
4491     //Extrusion_Error err =
4492     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4493   }
4494   else if( aS.ShapeType() == TopAbs_WIRE ) {
4495     list< SMESH_subMesh* > LSM;
4496     TopTools_SequenceOfShape Edges;
4497     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4498     while(itSM->more()) {
4499       SMESH_subMesh* SM = itSM->next();
4500       LSM.push_back(SM);
4501       const TopoDS_Shape& aS = SM->GetSubShape();
4502       Edges.Append(aS);
4503     }
4504     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4505     int startNid = theN1->GetID();
4506     TColStd_MapOfInteger UsedNums;
4507     int NbEdges = Edges.Length();
4508     int i = 1;
4509     for(; i<=NbEdges; i++) {
4510       int k = 0;
4511       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4512       for(; itLSM!=LSM.end(); itLSM++) {
4513         k++;
4514         if(UsedNums.Contains(k)) continue;
4515         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4516         SMESH_subMesh* locTrack = *itLSM;
4517         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4518         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4519         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4520         const SMDS_MeshNode* aN1 = aItN->next();
4521         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4522         const SMDS_MeshNode* aN2 = aItN->next();
4523         // starting node must be aN1 or aN2
4524         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4525         // 2. Collect parameters on the track edge
4526         aPrms.clear();
4527         aItN = locMeshDS->GetNodes();
4528         while ( aItN->more() ) {
4529           const SMDS_MeshNode* pNode = aItN->next();
4530           const SMDS_EdgePosition* pEPos =
4531             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4532           double aT = pEPos->GetUParameter();
4533           aPrms.push_back( aT );
4534         }
4535         list<SMESH_MeshEditor_PathPoint> LPP;
4536         //Extrusion_Error err =
4537         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4538         LLPPs.push_back(LPP);
4539         UsedNums.Add(k);
4540         // update startN for search following egde
4541         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4542         else startNid = aN1->GetID();
4543         break;
4544       }
4545     }
4546     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4547     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4548     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4549     for(; itPP!=firstList.end(); itPP++) {
4550       fullList.push_back( *itPP );
4551     }
4552     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4553     fullList.pop_back();
4554     itLLPP++;
4555     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4556       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4557       itPP = currList.begin();
4558       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4559       gp_Dir D1 = PP1.Tangent();
4560       gp_Dir D2 = PP2.Tangent();
4561       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4562                            (D1.Z()+D2.Z())/2 ) );
4563       PP1.SetTangent(Dnew);
4564       fullList.push_back(PP1);
4565       itPP++;
4566       for(; itPP!=firstList.end(); itPP++) {
4567         fullList.push_back( *itPP );
4568       }
4569       PP1 = fullList.back();
4570       fullList.pop_back();
4571     }
4572     // if wire not closed
4573     fullList.push_back(PP1);
4574     // else ???
4575   }
4576   else {
4577     return EXTR_BAD_PATH_SHAPE;
4578   }
4579
4580   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4581                           theHasRefPoint, theRefPoint, theMakeGroups);
4582 }
4583
4584
4585 //=======================================================================
4586 //function : ExtrusionAlongTrack
4587 //purpose  :
4588 //=======================================================================
4589 SMESH_MeshEditor::Extrusion_Error
4590 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4591                                        SMESH_Mesh*          theTrack,
4592                                        const SMDS_MeshNode* theN1,
4593                                        const bool           theHasAngles,
4594                                        list<double>&        theAngles,
4595                                        const bool           theLinearVariation,
4596                                        const bool           theHasRefPoint,
4597                                        const gp_Pnt&        theRefPoint,
4598                                        const bool           theMakeGroups)
4599 {
4600   myLastCreatedElems.Clear();
4601   myLastCreatedNodes.Clear();
4602
4603   int aNbE;
4604   std::list<double> aPrms;
4605   TIDSortedElemSet::iterator itElem;
4606
4607   gp_XYZ aGC;
4608   TopoDS_Edge aTrackEdge;
4609   TopoDS_Vertex aV1, aV2;
4610
4611   SMDS_ElemIteratorPtr aItE;
4612   SMDS_NodeIteratorPtr aItN;
4613   SMDSAbs_ElementType aTypeE;
4614
4615   TNodeOfNodeListMap mapNewNodes;
4616
4617   // 1. Check data
4618   aNbE = theElements.size();
4619   // nothing to do
4620   if ( !aNbE )
4621     return EXTR_NO_ELEMENTS;
4622
4623   // 1.1 Track Pattern
4624   ASSERT( theTrack );
4625
4626   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4627
4628   aItE = pMeshDS->elementsIterator();
4629   while ( aItE->more() ) {
4630     const SMDS_MeshElement* pE = aItE->next();
4631     aTypeE = pE->GetType();
4632     // Pattern must contain links only
4633     if ( aTypeE != SMDSAbs_Edge )
4634       return EXTR_PATH_NOT_EDGE;
4635   }
4636
4637   list<SMESH_MeshEditor_PathPoint> fullList;
4638
4639   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4640   // Sub shape for the Pattern must be an Edge or Wire
4641   if( aS.ShapeType() == TopAbs_EDGE ) {
4642     aTrackEdge = TopoDS::Edge( aS );
4643     // the Edge must not be degenerated
4644     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4645       return EXTR_BAD_PATH_SHAPE;
4646     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4647     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4648     const SMDS_MeshNode* aN1 = aItN->next();
4649     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4650     const SMDS_MeshNode* aN2 = aItN->next();
4651     // starting node must be aN1 or aN2
4652     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4653       return EXTR_BAD_STARTING_NODE;
4654     aItN = pMeshDS->nodesIterator();
4655     while ( aItN->more() ) {
4656       const SMDS_MeshNode* pNode = aItN->next();
4657       if( pNode==aN1 || pNode==aN2 ) continue;
4658       const SMDS_EdgePosition* pEPos =
4659         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4660       double aT = pEPos->GetUParameter();
4661       aPrms.push_back( aT );
4662     }
4663     //Extrusion_Error err =
4664     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4665   }
4666   else if( aS.ShapeType() == TopAbs_WIRE ) {
4667     list< SMESH_subMesh* > LSM;
4668     TopTools_SequenceOfShape Edges;
4669     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4670     for(; eExp.More(); eExp.Next()) {
4671       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4672       if( BRep_Tool::Degenerated(E) ) continue;
4673       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4674       if(SM) {
4675         LSM.push_back(SM);
4676         Edges.Append(E);
4677       }
4678     }
4679     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4680     int startNid = theN1->GetID();
4681     TColStd_MapOfInteger UsedNums;
4682     int NbEdges = Edges.Length();
4683     int i = 1;
4684     for(; i<=NbEdges; i++) {
4685       int k = 0;
4686       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4687       for(; itLSM!=LSM.end(); itLSM++) {
4688         k++;
4689         if(UsedNums.Contains(k)) continue;
4690         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4691         SMESH_subMesh* locTrack = *itLSM;
4692         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4693         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4694         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4695         const SMDS_MeshNode* aN1 = aItN->next();
4696         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4697         const SMDS_MeshNode* aN2 = aItN->next();
4698         // starting node must be aN1 or aN2
4699         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4700         // 2. Collect parameters on the track edge
4701         aPrms.clear();
4702         aItN = locMeshDS->GetNodes();
4703         while ( aItN->more() ) {
4704           const SMDS_MeshNode* pNode = aItN->next();
4705           const SMDS_EdgePosition* pEPos =
4706             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4707           double aT = pEPos->GetUParameter();
4708           aPrms.push_back( aT );
4709         }
4710         list<SMESH_MeshEditor_PathPoint> LPP;
4711         //Extrusion_Error err =
4712         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4713         LLPPs.push_back(LPP);
4714         UsedNums.Add(k);
4715         // update startN for search following egde
4716         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4717         else startNid = aN1->GetID();
4718         break;
4719       }
4720     }
4721     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4722     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4723     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4724     for(; itPP!=firstList.end(); itPP++) {
4725       fullList.push_back( *itPP );
4726     }
4727     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4728     fullList.pop_back();
4729     itLLPP++;
4730     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4731       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4732       itPP = currList.begin();
4733       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4734       gp_Pnt P1 = PP1.Pnt();
4735       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4736       gp_Pnt P2 = PP2.Pnt();
4737       gp_Dir D1 = PP1.Tangent();
4738       gp_Dir D2 = PP2.Tangent();
4739       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4740                            (D1.Z()+D2.Z())/2 ) );
4741       PP1.SetTangent(Dnew);
4742       fullList.push_back(PP1);
4743       itPP++;
4744       for(; itPP!=currList.end(); itPP++) {
4745         fullList.push_back( *itPP );
4746       }
4747       PP1 = fullList.back();
4748       fullList.pop_back();
4749     }
4750     // if wire not closed
4751     fullList.push_back(PP1);
4752     // else ???
4753   }
4754   else {
4755     return EXTR_BAD_PATH_SHAPE;
4756   }
4757
4758   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4759                           theHasRefPoint, theRefPoint, theMakeGroups);
4760 }
4761
4762
4763 //=======================================================================
4764 //function : MakeEdgePathPoints
4765 //purpose  : auxilary for ExtrusionAlongTrack
4766 //=======================================================================
4767 SMESH_MeshEditor::Extrusion_Error
4768 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4769                                      const TopoDS_Edge& aTrackEdge,
4770                                      bool FirstIsStart,
4771                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4772 {
4773   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4774   aTolVec=1.e-7;
4775   aTolVec2=aTolVec*aTolVec;
4776   double aT1, aT2;
4777   TopoDS_Vertex aV1, aV2;
4778   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4779   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4780   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4781   // 2. Collect parameters on the track edge
4782   aPrms.push_front( aT1 );
4783   aPrms.push_back( aT2 );
4784   // sort parameters
4785   aPrms.sort();
4786   if( FirstIsStart ) {
4787     if ( aT1 > aT2 ) {
4788       aPrms.reverse();
4789     }
4790   }
4791   else {
4792     if ( aT2 > aT1 ) {
4793       aPrms.reverse();
4794     }
4795   }
4796   // 3. Path Points
4797   SMESH_MeshEditor_PathPoint aPP;
4798   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4799   std::list<double>::iterator aItD = aPrms.begin();
4800   for(; aItD != aPrms.end(); ++aItD) {
4801     double aT = *aItD;
4802     gp_Pnt aP3D;
4803     gp_Vec aVec;
4804     aC3D->D1( aT, aP3D, aVec );
4805     aL2 = aVec.SquareMagnitude();
4806     if ( aL2 < aTolVec2 )
4807       return EXTR_CANT_GET_TANGENT;
4808     gp_Dir aTgt( aVec );
4809     aPP.SetPnt( aP3D );
4810     aPP.SetTangent( aTgt );
4811     aPP.SetParameter( aT );
4812     LPP.push_back(aPP);
4813   }
4814   return EXTR_OK;
4815 }
4816
4817
4818 //=======================================================================
4819 //function : MakeExtrElements
4820 //purpose  : auxilary for ExtrusionAlongTrack
4821 //=======================================================================
4822 SMESH_MeshEditor::Extrusion_Error
4823 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4824                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4825                                    const bool theHasAngles,
4826                                    list<double>& theAngles,
4827                                    const bool theLinearVariation,
4828                                    const bool theHasRefPoint,
4829                                    const gp_Pnt& theRefPoint,
4830                                    const bool theMakeGroups)
4831 {
4832   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4833   int aNbTP = fullList.size();
4834   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4835   // Angles
4836   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4837     LinearAngleVariation(aNbTP-1, theAngles);
4838   }
4839   vector<double> aAngles( aNbTP );
4840   int j = 0;
4841   for(; j<aNbTP; ++j) {
4842     aAngles[j] = 0.;
4843   }
4844   if ( theHasAngles ) {
4845     double anAngle;;
4846     std::list<double>::iterator aItD = theAngles.begin();
4847     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4848       anAngle = *aItD;
4849       aAngles[j] = anAngle;
4850     }
4851   }
4852   // fill vector of path points with angles
4853   //aPPs.resize(fullList.size());
4854   j = -1;
4855   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4856   for(; itPP!=fullList.end(); itPP++) {
4857     j++;
4858     SMESH_MeshEditor_PathPoint PP = *itPP;
4859     PP.SetAngle(aAngles[j]);
4860     aPPs[j] = PP;
4861   }
4862
4863   TNodeOfNodeListMap mapNewNodes;
4864   TElemOfVecOfNnlmiMap mapElemNewNodes;
4865   TElemOfElemListMap newElemsMap;
4866   TIDSortedElemSet::iterator itElem;
4867   double aX, aY, aZ;
4868   int aNb;
4869   SMDSAbs_ElementType aTypeE;
4870   // source elements for each generated one
4871   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4872
4873   // 3. Center of rotation aV0
4874   gp_Pnt aV0 = theRefPoint;
4875   gp_XYZ aGC;
4876   if ( !theHasRefPoint ) {
4877     aNb = 0;
4878     aGC.SetCoord( 0.,0.,0. );
4879
4880     itElem = theElements.begin();
4881     for ( ; itElem != theElements.end(); itElem++ ) {
4882       const SMDS_MeshElement* elem = *itElem;
4883
4884       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4885       while ( itN->more() ) {
4886         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4887         aX = node->X();
4888         aY = node->Y();
4889         aZ = node->Z();
4890
4891         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4892           list<const SMDS_MeshNode*> aLNx;
4893           mapNewNodes[node] = aLNx;
4894           //
4895           gp_XYZ aXYZ( aX, aY, aZ );
4896           aGC += aXYZ;
4897           ++aNb;
4898         }
4899       }
4900     }
4901     aGC /= aNb;
4902     aV0.SetXYZ( aGC );
4903   } // if (!theHasRefPoint) {
4904   mapNewNodes.clear();
4905
4906   // 4. Processing the elements
4907   SMESHDS_Mesh* aMesh = GetMeshDS();
4908
4909   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4910     // check element type
4911     const SMDS_MeshElement* elem = *itElem;
4912     aTypeE = elem->GetType();
4913     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4914       continue;
4915
4916     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4917     newNodesItVec.reserve( elem->NbNodes() );
4918
4919     // loop on elem nodes
4920     int nodeIndex = -1;
4921     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4922     while ( itN->more() )
4923     {
4924       ++nodeIndex;
4925       // check if a node has been already processed
4926       const SMDS_MeshNode* node =
4927         static_cast<const SMDS_MeshNode*>( itN->next() );
4928       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4929       if ( nIt == mapNewNodes.end() ) {
4930         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4931         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4932
4933         // make new nodes
4934         aX = node->X();  aY = node->Y(); aZ = node->Z();
4935
4936         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4937         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4938         gp_Ax1 anAx1, anAxT1T0;
4939         gp_Dir aDT1x, aDT0x, aDT1T0;
4940
4941         aTolAng=1.e-4;
4942
4943         aV0x = aV0;
4944         aPN0.SetCoord(aX, aY, aZ);
4945
4946         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4947         aP0x = aPP0.Pnt();
4948         aDT0x= aPP0.Tangent();
4949         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4950
4951         for ( j = 1; j < aNbTP; ++j ) {
4952           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4953           aP1x = aPP1.Pnt();
4954           aDT1x = aPP1.Tangent();
4955           aAngle1x = aPP1.Angle();
4956
4957           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4958           // Translation
4959           gp_Vec aV01x( aP0x, aP1x );
4960           aTrsf.SetTranslation( aV01x );
4961
4962           // traslated point
4963           aV1x = aV0x.Transformed( aTrsf );
4964           aPN1 = aPN0.Transformed( aTrsf );
4965
4966           // rotation 1 [ T1,T0 ]
4967           aAngleT1T0=-aDT1x.Angle( aDT0x );
4968           if (fabs(aAngleT1T0) > aTolAng) {
4969             aDT1T0=aDT1x^aDT0x;
4970             anAxT1T0.SetLocation( aV1x );
4971             anAxT1T0.SetDirection( aDT1T0 );
4972             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4973
4974             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4975           }
4976
4977           // rotation 2
4978           if ( theHasAngles ) {
4979             anAx1.SetLocation( aV1x );
4980             anAx1.SetDirection( aDT1x );
4981             aTrsfRot.SetRotation( anAx1, aAngle1x );
4982
4983             aPN1 = aPN1.Transformed( aTrsfRot );
4984           }
4985
4986           // make new node
4987           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4988             // create additional node
4989             double x = ( aPN1.X() + aPN0.X() )/2.;
4990             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4991             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4992             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4993             myLastCreatedNodes.Append(newNode);
4994             srcNodes.Append( node );
4995             listNewNodes.push_back( newNode );
4996           }
4997           aX = aPN1.X();
4998           aY = aPN1.Y();
4999           aZ = aPN1.Z();
5000           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5001           myLastCreatedNodes.Append(newNode);
5002           srcNodes.Append( node );
5003           listNewNodes.push_back( newNode );
5004
5005           aPN0 = aPN1;
5006           aP0x = aP1x;
5007           aV0x = aV1x;
5008           aDT0x = aDT1x;
5009         }
5010       }
5011
5012       else {
5013         // if current elem is quadratic and current node is not medium
5014         // we have to check - may be it is needed to insert additional nodes
5015         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5016           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5017           if(listNewNodes.size()==aNbTP-1) {
5018             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5019             gp_XYZ P(node->X(), node->Y(), node->Z());
5020             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5021             int i;
5022             for(i=0; i<aNbTP-1; i++) {
5023               const SMDS_MeshNode* N = *it;
5024               double x = ( N->X() + P.X() )/2.;
5025               double y = ( N->Y() + P.Y() )/2.;
5026               double z = ( N->Z() + P.Z() )/2.;
5027               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5028               srcNodes.Append( node );
5029               myLastCreatedNodes.Append(newN);
5030               aNodes[2*i] = newN;
5031               aNodes[2*i+1] = N;
5032               P = gp_XYZ(N->X(),N->Y(),N->Z());
5033             }
5034             listNewNodes.clear();
5035             for(i=0; i<2*(aNbTP-1); i++) {
5036               listNewNodes.push_back(aNodes[i]);
5037             }
5038           }
5039         }
5040       }
5041
5042       newNodesItVec.push_back( nIt );
5043     }
5044     // make new elements
5045     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5046     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5047     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5048   }
5049
5050   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5051
5052   if ( theMakeGroups )
5053     generateGroups( srcNodes, srcElems, "extruded");
5054
5055   return EXTR_OK;
5056 }
5057
5058
5059 //=======================================================================
5060 //function : LinearAngleVariation
5061 //purpose  : auxilary for ExtrusionAlongTrack
5062 //=======================================================================
5063 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5064                                             list<double>& Angles)
5065 {
5066   int nbAngles = Angles.size();
5067   if( nbSteps > nbAngles ) {
5068     vector<double> theAngles(nbAngles);
5069     list<double>::iterator it = Angles.begin();
5070     int i = -1;
5071     for(; it!=Angles.end(); it++) {
5072       i++;
5073       theAngles[i] = (*it);
5074     }
5075     list<double> res;
5076     double rAn2St = double( nbAngles ) / double( nbSteps );
5077     double angPrev = 0, angle;
5078     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5079       double angCur = rAn2St * ( iSt+1 );
5080       double angCurFloor  = floor( angCur );
5081       double angPrevFloor = floor( angPrev );
5082       if ( angPrevFloor == angCurFloor )
5083         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5084       else {
5085         int iP = int( angPrevFloor );
5086         double angPrevCeil = ceil(angPrev);
5087         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5088
5089         int iC = int( angCurFloor );
5090         if ( iC < nbAngles )
5091           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5092
5093         iP = int( angPrevCeil );
5094         while ( iC-- > iP )
5095           angle += theAngles[ iC ];
5096       }
5097       res.push_back(angle);
5098       angPrev = angCur;
5099     }
5100     Angles.clear();
5101     it = res.begin();
5102     for(; it!=res.end(); it++)
5103       Angles.push_back( *it );
5104   }
5105 }
5106
5107
5108 //=======================================================================
5109 //function : Transform
5110 //purpose  :
5111 //=======================================================================
5112
5113 SMESH_MeshEditor::PGroupIDs
5114 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5115                              const gp_Trsf&     theTrsf,
5116                              const bool         theCopy,
5117                              const bool         theMakeGroups,
5118                              SMESH_Mesh*        theTargetMesh)
5119 {
5120   myLastCreatedElems.Clear();
5121   myLastCreatedNodes.Clear();
5122
5123   bool needReverse = false;
5124   string groupPostfix;
5125   switch ( theTrsf.Form() ) {
5126   case gp_PntMirror:
5127   case gp_Ax1Mirror:
5128   case gp_Ax2Mirror:
5129     needReverse = true;
5130     groupPostfix = "mirrored";
5131     break;
5132   case gp_Rotation:
5133     groupPostfix = "rotated";
5134     break;
5135   case gp_Translation:
5136     groupPostfix = "translated";
5137     break;
5138   case gp_Scale:
5139     groupPostfix = "scaled";
5140     break;
5141   default:
5142     needReverse = false;
5143     groupPostfix = "transformed";
5144   }
5145
5146   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5147   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5148   SMESHDS_Mesh* aMesh    = GetMeshDS();
5149
5150
5151   // map old node to new one
5152   TNodeNodeMap nodeMap;
5153
5154   // elements sharing moved nodes; those of them which have all
5155   // nodes mirrored but are not in theElems are to be reversed
5156   TIDSortedElemSet inverseElemSet;
5157
5158   // source elements for each generated one
5159   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5160
5161   // loop on theElems
5162   TIDSortedElemSet::iterator itElem;
5163   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5164     const SMDS_MeshElement* elem = *itElem;
5165     if ( !elem )
5166       continue;
5167
5168     // loop on elem nodes
5169     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5170     while ( itN->more() ) {
5171
5172       // check if a node has been already transformed
5173       const SMDS_MeshNode* node = cast2Node( itN->next() );
5174       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5175         nodeMap.insert( make_pair ( node, node ));
5176       if ( !n2n_isnew.second )
5177         continue;
5178
5179       double coord[3];
5180       coord[0] = node->X();
5181       coord[1] = node->Y();
5182       coord[2] = node->Z();
5183       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5184       if ( theTargetMesh ) {
5185         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5186         n2n_isnew.first->second = newNode;
5187         myLastCreatedNodes.Append(newNode);
5188         srcNodes.Append( node );
5189       }
5190       else if ( theCopy ) {
5191         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5192         n2n_isnew.first->second = newNode;
5193         myLastCreatedNodes.Append(newNode);
5194         srcNodes.Append( node );
5195       }
5196       else {
5197         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5198         // node position on shape becomes invalid
5199         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5200           ( SMDS_SpacePosition::originSpacePosition() );
5201       }
5202
5203       // keep inverse elements
5204       if ( !theCopy && !theTargetMesh && needReverse ) {
5205         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5206         while ( invElemIt->more() ) {
5207           const SMDS_MeshElement* iel = invElemIt->next();
5208           inverseElemSet.insert( iel );
5209         }
5210       }
5211     }
5212   }
5213
5214   // either create new elements or reverse mirrored ones
5215   if ( !theCopy && !needReverse && !theTargetMesh )
5216     return PGroupIDs();
5217
5218   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5219   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5220     theElems.insert( *invElemIt );
5221
5222   // replicate or reverse elements
5223
5224   enum {
5225     REV_TETRA   = 0,  //  = nbNodes - 4
5226     REV_PYRAMID = 1,  //  = nbNodes - 4
5227     REV_PENTA   = 2,  //  = nbNodes - 4
5228     REV_FACE    = 3,
5229     REV_HEXA    = 4,  //  = nbNodes - 4
5230     FORWARD     = 5
5231   };
5232   int index[][8] = {
5233     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5234     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5235     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5236     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5237     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5238     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5239   };
5240
5241   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5242   {
5243     const SMDS_MeshElement* elem = *itElem;
5244     if ( !elem || elem->GetType() == SMDSAbs_Node )
5245       continue;
5246
5247     int nbNodes = elem->NbNodes();
5248     int elemType = elem->GetType();
5249
5250     if (elem->IsPoly()) {
5251       // Polygon or Polyhedral Volume
5252       switch ( elemType ) {
5253       case SMDSAbs_Face:
5254         {
5255           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5256           int iNode = 0;
5257           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5258           while (itN->more()) {
5259             const SMDS_MeshNode* node =
5260               static_cast<const SMDS_MeshNode*>(itN->next());
5261             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5262             if (nodeMapIt == nodeMap.end())
5263               break; // not all nodes transformed
5264             if (needReverse) {
5265               // reverse mirrored faces and volumes
5266               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5267             } else {
5268               poly_nodes[iNode] = (*nodeMapIt).second;
5269             }
5270             iNode++;
5271           }
5272           if ( iNode != nbNodes )
5273             continue; // not all nodes transformed
5274
5275           if ( theTargetMesh ) {
5276             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5277             srcElems.Append( elem );
5278           }
5279           else if ( theCopy ) {
5280             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5281             srcElems.Append( elem );
5282           }
5283           else {
5284             aMesh->ChangePolygonNodes(elem, poly_nodes);
5285           }
5286         }
5287         break;
5288       case SMDSAbs_Volume:
5289         {
5290           // ATTENTION: Reversing is not yet done!!!
5291           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5292             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5293           if (!aPolyedre) {
5294             MESSAGE("Warning: bad volumic element");
5295             continue;
5296           }
5297
5298           vector<const SMDS_MeshNode*> poly_nodes;
5299           vector<int> quantities;
5300
5301           bool allTransformed = true;
5302           int nbFaces = aPolyedre->NbFaces();
5303           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5304             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5305             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5306               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5307               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5308               if (nodeMapIt == nodeMap.end()) {
5309                 allTransformed = false; // not all nodes transformed
5310               } else {
5311                 poly_nodes.push_back((*nodeMapIt).second);
5312               }
5313             }
5314             quantities.push_back(nbFaceNodes);
5315           }
5316           if ( !allTransformed )
5317             continue; // not all nodes transformed
5318
5319           if ( theTargetMesh ) {
5320             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5321             srcElems.Append( elem );
5322           }
5323           else if ( theCopy ) {
5324             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5325             srcElems.Append( elem );
5326           }
5327           else {
5328             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5329           }
5330         }
5331         break;
5332       default:;
5333       }
5334       continue;
5335     }
5336
5337     // Regular elements
5338     int* i = index[ FORWARD ];
5339     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5340       if ( elemType == SMDSAbs_Face )
5341         i = index[ REV_FACE ];
5342       else
5343         i = index[ nbNodes - 4 ];
5344
5345     if(elem->IsQuadratic()) {
5346       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5347       i = anIds;
5348       if(needReverse) {
5349         if(nbNodes==3) { // quadratic edge
5350           static int anIds[] = {1,0,2};
5351           i = anIds;
5352         }
5353         else if(nbNodes==6) { // quadratic triangle
5354           static int anIds[] = {0,2,1,5,4,3};
5355           i = anIds;
5356         }
5357         else if(nbNodes==8) { // quadratic quadrangle
5358           static int anIds[] = {0,3,2,1,7,6,5,4};
5359           i = anIds;
5360         }
5361         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5362           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5363           i = anIds;
5364         }
5365         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5366           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5367           i = anIds;
5368         }
5369         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5370           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5371           i = anIds;
5372         }
5373         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5374           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5375           i = anIds;
5376         }
5377       }
5378     }
5379
5380     // find transformed nodes
5381     vector<const SMDS_MeshNode*> nodes(nbNodes);
5382     int iNode = 0;
5383     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5384     while ( itN->more() ) {
5385       const SMDS_MeshNode* node =
5386         static_cast<const SMDS_MeshNode*>( itN->next() );
5387       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5388       if ( nodeMapIt == nodeMap.end() )
5389         break; // not all nodes transformed
5390       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5391     }
5392     if ( iNode != nbNodes )
5393       continue; // not all nodes transformed
5394
5395     if ( theTargetMesh ) {
5396       if ( SMDS_MeshElement* copy =
5397            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5398         myLastCreatedElems.Append( copy );
5399         srcElems.Append( elem );
5400       }
5401     }
5402     else if ( theCopy ) {
5403       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5404         myLastCreatedElems.Append( copy );
5405         srcElems.Append( elem );
5406       }
5407     }
5408     else {
5409       // reverse element as it was reversed by transformation
5410       if ( nbNodes > 2 )
5411         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5412     }
5413   }
5414
5415   PGroupIDs newGroupIDs;
5416
5417   if ( theMakeGroups && theCopy ||
5418        theMakeGroups && theTargetMesh )
5419     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5420
5421   return newGroupIDs;
5422 }
5423
5424
5425 //=======================================================================
5426 //function : Scale
5427 //purpose  :
5428 //=======================================================================
5429
5430 SMESH_MeshEditor::PGroupIDs
5431 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5432                          const gp_Pnt&            thePoint,
5433                          const std::list<double>& theScaleFact,
5434                          const bool         theCopy,
5435                          const bool         theMakeGroups,
5436                          SMESH_Mesh*        theTargetMesh)
5437 {
5438   myLastCreatedElems.Clear();
5439   myLastCreatedNodes.Clear();
5440
5441   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5442   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5443   SMESHDS_Mesh* aMesh    = GetMeshDS();
5444
5445   double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5446   std::list<double>::const_iterator itS = theScaleFact.begin();
5447   scaleX = (*itS);
5448   if(theScaleFact.size()==1) {
5449     scaleY = (*itS);
5450     scaleZ= (*itS);
5451   }
5452   if(theScaleFact.size()==2) {
5453     itS++;
5454     scaleY = (*itS);
5455     scaleZ= (*itS);
5456   }
5457   if(theScaleFact.size()>2) {
5458     itS++;
5459     scaleY = (*itS);
5460     itS++;
5461     scaleZ= (*itS);
5462   }
5463   
5464   // map old node to new one
5465   TNodeNodeMap nodeMap;
5466
5467   // elements sharing moved nodes; those of them which have all
5468   // nodes mirrored but are not in theElems are to be reversed
5469   TIDSortedElemSet inverseElemSet;
5470
5471   // source elements for each generated one
5472   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5473
5474   // loop on theElems
5475   TIDSortedElemSet::iterator itElem;
5476   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5477     const SMDS_MeshElement* elem = *itElem;
5478     if ( !elem )
5479       continue;
5480
5481     // loop on elem nodes
5482     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5483     while ( itN->more() ) {
5484
5485       // check if a node has been already transformed
5486       const SMDS_MeshNode* node = cast2Node( itN->next() );
5487       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5488         nodeMap.insert( make_pair ( node, node ));
5489       if ( !n2n_isnew.second )
5490         continue;
5491
5492       //double coord[3];
5493       //coord[0] = node->X();
5494       //coord[1] = node->Y();
5495       //coord[2] = node->Z();
5496       //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5497       double dx = (node->X() - thePoint.X()) * scaleX;
5498       double dy = (node->Y() - thePoint.Y()) * scaleY;
5499       double dz = (node->Z() - thePoint.Z()) * scaleZ;
5500       if ( theTargetMesh ) {
5501         //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5502         const SMDS_MeshNode * newNode =
5503           aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5504         n2n_isnew.first->second = newNode;
5505         myLastCreatedNodes.Append(newNode);
5506         srcNodes.Append( node );
5507       }
5508       else if ( theCopy ) {
5509         //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5510         const SMDS_MeshNode * newNode =
5511           aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5512         n2n_isnew.first->second = newNode;
5513         myLastCreatedNodes.Append(newNode);
5514         srcNodes.Append( node );
5515       }
5516       else {
5517         //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5518         aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5519         // node position on shape becomes invalid
5520         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5521           ( SMDS_SpacePosition::originSpacePosition() );
5522       }
5523
5524       // keep inverse elements
5525       //if ( !theCopy && !theTargetMesh && needReverse ) {
5526       //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5527       //  while ( invElemIt->more() ) {
5528       //    const SMDS_MeshElement* iel = invElemIt->next();
5529       //    inverseElemSet.insert( iel );
5530       //  }
5531       //}
5532     }
5533   }
5534
5535   // either create new elements or reverse mirrored ones
5536   //if ( !theCopy && !needReverse && !theTargetMesh )
5537   if ( !theCopy && !theTargetMesh )
5538     return PGroupIDs();
5539
5540   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5541   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5542     theElems.insert( *invElemIt );
5543
5544   // replicate or reverse elements
5545
5546   enum {
5547     REV_TETRA   = 0,  //  = nbNodes - 4
5548     REV_PYRAMID = 1,  //  = nbNodes - 4
5549     REV_PENTA   = 2,  //  = nbNodes - 4
5550     REV_FACE    = 3,
5551     REV_HEXA    = 4,  //  = nbNodes - 4
5552     FORWARD     = 5
5553   };
5554   int index[][8] = {
5555     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5556     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5557     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5558     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5559     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5560     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5561   };
5562
5563   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5564   {
5565     const SMDS_MeshElement* elem = *itElem;
5566     if ( !elem || elem->GetType() == SMDSAbs_Node )
5567       continue;
5568
5569     int nbNodes = elem->NbNodes();
5570     int elemType = elem->GetType();
5571
5572     if (elem->IsPoly()) {
5573       // Polygon or Polyhedral Volume
5574       switch ( elemType ) {
5575       case SMDSAbs_Face:
5576         {
5577           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5578           int iNode = 0;
5579           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5580           while (itN->more()) {
5581             const SMDS_MeshNode* node =
5582               static_cast<const SMDS_MeshNode*>(itN->next());
5583             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5584             if (nodeMapIt == nodeMap.end())
5585               break; // not all nodes transformed
5586             //if (needReverse) {
5587             //  // reverse mirrored faces and volumes
5588             //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5589             //} else {
5590             poly_nodes[iNode] = (*nodeMapIt).second;
5591             //}
5592             iNode++;
5593           }
5594           if ( iNode != nbNodes )
5595             continue; // not all nodes transformed
5596
5597           if ( theTargetMesh ) {
5598             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5599             srcElems.Append( elem );
5600           }
5601           else if ( theCopy ) {
5602             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5603             srcElems.Append( elem );
5604           }
5605           else {
5606             aMesh->ChangePolygonNodes(elem, poly_nodes);
5607           }
5608         }
5609         break;
5610       case SMDSAbs_Volume:
5611         {
5612           // ATTENTION: Reversing is not yet done!!!
5613           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5614             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5615           if (!aPolyedre) {
5616             MESSAGE("Warning: bad volumic element");
5617             continue;
5618           }
5619
5620           vector<const SMDS_MeshNode*> poly_nodes;
5621           vector<int> quantities;
5622
5623           bool allTransformed = true;
5624           int nbFaces = aPolyedre->NbFaces();
5625           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5626             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5627             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5628               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5629               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5630               if (nodeMapIt == nodeMap.end()) {
5631                 allTransformed = false; // not all nodes transformed
5632               } else {
5633                 poly_nodes.push_back((*nodeMapIt).second);
5634               }
5635             }
5636             quantities.push_back(nbFaceNodes);
5637           }
5638           if ( !allTransformed )
5639             continue; // not all nodes transformed
5640
5641           if ( theTargetMesh ) {
5642             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5643             srcElems.Append( elem );
5644           }
5645           else if ( theCopy ) {
5646             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5647             srcElems.Append( elem );
5648           }
5649           else {
5650             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5651           }
5652         }
5653         break;
5654       default:;
5655       }
5656       continue;
5657     }
5658
5659     // Regular elements
5660     int* i = index[ FORWARD ];
5661     //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5662     //  if ( elemType == SMDSAbs_Face )
5663     //    i = index[ REV_FACE ];
5664     //  else
5665     //    i = index[ nbNodes - 4 ];
5666
5667     if(elem->IsQuadratic()) {
5668       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5669       i = anIds;
5670       //if(needReverse) {
5671       //  if(nbNodes==3) { // quadratic edge
5672       //    static int anIds[] = {1,0,2};
5673       //    i = anIds;
5674       //  }
5675       //  else if(nbNodes==6) { // quadratic triangle
5676       //    static int anIds[] = {0,2,1,5,4,3};
5677       //    i = anIds;
5678       //  }
5679       //  else if(nbNodes==8) { // quadratic quadrangle
5680       //    static int anIds[] = {0,3,2,1,7,6,5,4};
5681       //    i = anIds;
5682       //  }
5683       //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5684       //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5685       //    i = anIds;
5686       //  }
5687       //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5688       //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5689       //    i = anIds;
5690       //  }
5691       //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5692       //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5693       //    i = anIds;
5694       //  }
5695       //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5696       //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5697       //    i = anIds;
5698       //  }
5699       //}
5700     }
5701
5702     // find transformed nodes
5703     vector<const SMDS_MeshNode*> nodes(nbNodes);
5704     int iNode = 0;
5705     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5706     while ( itN->more() ) {
5707       const SMDS_MeshNode* node =
5708         static_cast<const SMDS_MeshNode*>( itN->next() );
5709       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5710       if ( nodeMapIt == nodeMap.end() )
5711         break; // not all nodes transformed
5712       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5713     }
5714     if ( iNode != nbNodes )
5715       continue; // not all nodes transformed
5716
5717     if ( theTargetMesh ) {
5718       if ( SMDS_MeshElement* copy =
5719            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5720         myLastCreatedElems.Append( copy );
5721         srcElems.Append( elem );
5722       }
5723     }
5724     else if ( theCopy ) {
5725       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5726         myLastCreatedElems.Append( copy );
5727         srcElems.Append( elem );
5728       }
5729     }
5730     else {
5731       // reverse element as it was reversed by transformation
5732       if ( nbNodes > 2 )
5733         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5734     }
5735   }
5736
5737   PGroupIDs newGroupIDs;
5738
5739   if ( theMakeGroups && theCopy ||
5740        theMakeGroups && theTargetMesh ) {
5741     string groupPostfix = "scaled";
5742     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5743   }
5744
5745   return newGroupIDs;
5746 }
5747
5748
5749 //=======================================================================
5750 /*!
5751  * \brief Create groups of elements made during transformation
5752  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5753  * \param elemGens - elements making corresponding myLastCreatedElems
5754  * \param postfix - to append to names of new groups
5755  */
5756 //=======================================================================
5757
5758 SMESH_MeshEditor::PGroupIDs
5759 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5760                                  const SMESH_SequenceOfElemPtr& elemGens,
5761                                  const std::string&             postfix,
5762                                  SMESH_Mesh*                    targetMesh)
5763 {
5764   PGroupIDs newGroupIDs( new list<int> );
5765   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5766
5767   // Sort existing groups by types and collect their names
5768
5769   // to store an old group and a generated new one
5770   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5771   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5772   // group names
5773   set< string > groupNames;
5774   //
5775   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5776   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5777   while ( groupIt->more() ) {
5778     SMESH_Group * group = groupIt->next();
5779     if ( !group ) continue;
5780     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5781     if ( !groupDS || groupDS->IsEmpty() ) continue;
5782     groupNames.insert( group->GetName() );
5783     groupDS->SetStoreName( group->GetName() );
5784     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5785   }
5786
5787   // Groups creation
5788
5789   // loop on nodes and elements
5790   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5791   {
5792     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5793     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5794     if ( gens.Length() != elems.Length() )
5795       throw SALOME_Exception(LOCALIZED("invalid args"));
5796
5797     // loop on created elements
5798     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5799     {
5800       const SMDS_MeshElement* sourceElem = gens( iElem );
5801       if ( !sourceElem ) {
5802         MESSAGE("generateGroups(): NULL source element");
5803         continue;
5804       }
5805       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5806       if ( groupsOldNew.empty() ) {
5807         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5808           ++iElem; // skip all elements made by sourceElem
5809         continue;
5810       }
5811       // collect all elements made by sourceElem
5812       list< const SMDS_MeshElement* > resultElems;
5813       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5814         if ( resElem != sourceElem )
5815           resultElems.push_back( resElem );
5816       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5817         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5818           if ( resElem != sourceElem )
5819             resultElems.push_back( resElem );
5820       // do not generate element groups from node ones
5821       if ( sourceElem->GetType() == SMDSAbs_Node &&
5822            elems( iElem )->GetType() != SMDSAbs_Node )
5823         continue;
5824
5825       // add resultElems to groups made by ones the sourceElem belongs to
5826       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5827       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5828       {
5829         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5830         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5831         {
5832           SMDS_MeshGroup* & newGroup = gOldNew->second;
5833           if ( !newGroup )// create a new group
5834           {
5835             // make a name
5836             string name = oldGroup->GetStoreName();
5837             if ( !targetMesh ) {
5838               name += "_";
5839               name += postfix;
5840               int nb = 0;
5841               while ( !groupNames.insert( name ).second ) // name exists
5842               {
5843                 if ( nb == 0 ) {
5844                   name += "_1";
5845                 }
5846                 else {
5847                   TCollection_AsciiString nbStr(nb+1);
5848                   name.resize( name.rfind('_')+1 );
5849                   name += nbStr.ToCString();
5850                 }
5851                 ++nb;
5852               }
5853             }
5854             // make a group
5855             int id;
5856             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5857                                                  name.c_str(), id );
5858             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5859             newGroup = & groupDS->SMDSGroup();
5860             newGroupIDs->push_back( id );
5861           }
5862
5863           // fill in a new group
5864           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5865           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5866             newGroup->Add( *resElemIt );
5867         }
5868       }
5869     } // loop on created elements
5870   }// loop on nodes and elements
5871
5872   return newGroupIDs;
5873 }
5874
5875 //================================================================================
5876 /*!
5877  * \brief Return list of group of nodes close to each other within theTolerance
5878  *        Search among theNodes or in the whole mesh if theNodes is empty using
5879  *        an Octree algorithm
5880  */
5881 //================================================================================
5882
5883 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5884                                             const double                theTolerance,
5885                                             TListOfListOfNodes &        theGroupsOfNodes)
5886 {
5887   myLastCreatedElems.Clear();
5888   myLastCreatedNodes.Clear();
5889
5890   set<const SMDS_MeshNode*> nodes;
5891   if ( theNodes.empty() )
5892   { // get all nodes in the mesh
5893     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5894     while ( nIt->more() )
5895       nodes.insert( nodes.end(),nIt->next());
5896   }
5897   else
5898     nodes=theNodes;
5899
5900   SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5901 }
5902
5903
5904 //=======================================================================
5905 /*!
5906  * \brief Implementation of search for the node closest to point
5907  */
5908 //=======================================================================
5909
5910 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5911 {
5912   //---------------------------------------------------------------------
5913   /*!
5914    * \brief Constructor
5915    */
5916   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5917   {
5918     myMesh = ( SMESHDS_Mesh* ) theMesh;
5919
5920     set<const SMDS_MeshNode*> nodes;
5921     if ( theMesh ) {
5922       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5923       while ( nIt->more() )
5924         nodes.insert( nodes.end(), nIt->next() );
5925     }
5926     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5927
5928     // get max size of a leaf box
5929     SMESH_OctreeNode* tree = myOctreeNode;
5930     while ( !tree->isLeaf() )
5931     {
5932       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5933       if ( cIt->more() )
5934         tree = cIt->next();
5935     }
5936     myHalfLeafSize = tree->maxSize() / 2.;
5937   }
5938
5939   //---------------------------------------------------------------------
5940   /*!
5941    * \brief Move node and update myOctreeNode accordingly
5942    */
5943   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5944   {
5945     myOctreeNode->UpdateByMoveNode( node, toPnt );
5946     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5947   }
5948
5949   //---------------------------------------------------------------------
5950   /*!
5951    * \brief Do it's job
5952    */
5953   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5954   {
5955     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5956     map<double, const SMDS_MeshNode*> dist2Nodes;
5957     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5958     if ( !dist2Nodes.empty() )
5959       return dist2Nodes.begin()->second;
5960     list<const SMDS_MeshNode*> nodes;
5961     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5962
5963     double minSqDist = DBL_MAX;
5964     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5965     {
5966       // sort leafs by their distance from thePnt
5967       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5968       TDistTreeMap treeMap;
5969       list< SMESH_OctreeNode* > treeList;
5970       list< SMESH_OctreeNode* >::iterator trIt;
5971       treeList.push_back( myOctreeNode );
5972
5973       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5974       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5975       {
5976         SMESH_OctreeNode* tree = *trIt;
5977         if ( !tree->isLeaf() ) // put children to the queue
5978         {
5979           if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5980           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5981           while ( cIt->more() )
5982             treeList.push_back( cIt->next() );
5983         }
5984         else if ( tree->NbNodes() ) // put a tree to the treeMap
5985         {
5986           const Bnd_B3d& box = tree->getBox();
5987           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5988           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5989           if ( !it_in.second ) // not unique distance to box center
5990             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5991         }
5992       }
5993       // find distance after which there is no sense to check tree's
5994       double sqLimit = DBL_MAX;
5995       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5996       if ( treeMap.size() > 5 ) {
5997         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5998         const Bnd_B3d& box = closestTree->getBox();
5999         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6000         sqLimit = limit * limit;
6001       }
6002       // get all nodes from trees
6003       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6004         if ( sqDist_tree->first > sqLimit )
6005           break;
6006         SMESH_OctreeNode* tree = sqDist_tree->second;
6007         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6008       }
6009     }
6010     // find closest among nodes
6011     minSqDist = DBL_MAX;
6012     const SMDS_MeshNode* closestNode = 0;
6013     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6014     for ( ; nIt != nodes.end(); ++nIt ) {
6015       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6016       if ( minSqDist > sqDist ) {
6017         closestNode = *nIt;
6018         minSqDist = sqDist;
6019       }
6020     }
6021     return closestNode;
6022   }
6023
6024   //---------------------------------------------------------------------
6025   /*!
6026    * \brief Destructor
6027    */
6028   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6029
6030   //---------------------------------------------------------------------
6031   /*!
6032    * \brief Return the node tree
6033    */
6034   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6035
6036 private:
6037   SMESH_OctreeNode* myOctreeNode;
6038   SMESHDS_Mesh*     myMesh;
6039   double            myHalfLeafSize; // max size of a leaf box
6040 };
6041
6042 //=======================================================================
6043 /*!
6044  * \brief Return SMESH_NodeSearcher
6045  */
6046 //=======================================================================
6047
6048 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6049 {
6050   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6051 }
6052
6053 // ========================================================================
6054 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6055 {
6056   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6057   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6058   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6059
6060   //=======================================================================
6061   /*!
6062    * \brief Octal tree of bounding boxes of elements
6063    */
6064   //=======================================================================
6065
6066   class ElementBndBoxTree : public SMESH_Octree
6067   {
6068   public:
6069
6070     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
6071     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6072     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6073     ~ElementBndBoxTree();
6074
6075   protected:
6076     ElementBndBoxTree() {}
6077     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6078     void buildChildrenData();
6079     Bnd_B3d* buildRootBox();
6080   private:
6081     //!< Bounding box of element
6082     struct ElementBox : public Bnd_B3d
6083     {
6084       const SMDS_MeshElement* _element;
6085       int                     _refCount; // an ElementBox can be included in several tree branches
6086       ElementBox(const SMDS_MeshElement* elem);
6087     };
6088     vector< ElementBox* > _elements;
6089   };
6090
6091   //================================================================================
6092   /*!
6093    * \brief ElementBndBoxTree creation
6094    */
6095   //================================================================================
6096
6097   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
6098     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6099   {
6100     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6101     _elements.reserve( nbElems );
6102
6103     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6104     while ( elemIt->more() )
6105       _elements.push_back( new ElementBox( elemIt->next() ));
6106
6107     if ( _elements.size() > MaxNbElemsInLeaf )
6108       compute();
6109     else
6110       myIsLeaf = true;
6111   }
6112
6113   //================================================================================
6114   /*!
6115    * \brief Destructor
6116    */
6117   //================================================================================
6118
6119   ElementBndBoxTree::~ElementBndBoxTree()
6120   {
6121     for ( int i = 0; i < _elements.size(); ++i )
6122       if ( --_elements[i]->_refCount <= 0 )
6123         delete _elements[i];
6124   }
6125
6126   //================================================================================
6127   /*!
6128    * \brief Return the maximal box
6129    */
6130   //================================================================================
6131
6132   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6133   {
6134     Bnd_B3d* box = new Bnd_B3d;
6135     for ( int i = 0; i < _elements.size(); ++i )
6136       box->Add( *_elements[i] );
6137     return box;
6138   }
6139
6140   //================================================================================
6141   /*!
6142    * \brief Redistrubute element boxes among children
6143    */
6144   //================================================================================
6145
6146   void ElementBndBoxTree::buildChildrenData()
6147   {
6148     for ( int i = 0; i < _elements.size(); ++i )
6149     {
6150       for (int j = 0; j < 8; j++)
6151       {
6152         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6153         {
6154           _elements[i]->_refCount++;
6155           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6156         }
6157       }
6158       _elements[i]->_refCount--;
6159     }
6160     _elements.clear();
6161
6162     for (int j = 0; j < 8; j++)
6163     {
6164       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6165       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6166         child->myIsLeaf = true;
6167
6168       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6169         child->_elements.resize( child->_elements.size() ); // compact
6170     }
6171   }
6172
6173   //================================================================================
6174   /*!
6175    * \brief Return elements which can include the point
6176    */
6177   //================================================================================
6178
6179   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6180                                                 TIDSortedElemSet& foundElems)
6181   {
6182     if ( level() && getBox().IsOut( point.XYZ() ))
6183       return;
6184
6185     if ( isLeaf() )
6186     {
6187       for ( int i = 0; i < _elements.size(); ++i )
6188         if ( !_elements[i]->IsOut( point.XYZ() ))
6189           foundElems.insert( _elements[i]->_element );
6190     }
6191     else
6192     {
6193       for (int i = 0; i < 8; i++)
6194         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6195     }
6196   }
6197
6198   //================================================================================
6199   /*!
6200    * \brief Return elements which can be intersected by the line
6201    */
6202   //================================================================================
6203
6204   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6205                                                TIDSortedElemSet& foundElems)
6206   {
6207     if ( level() && getBox().IsOut( line ))
6208       return;
6209
6210     if ( isLeaf() )
6211     {
6212       for ( int i = 0; i < _elements.size(); ++i )
6213         if ( !_elements[i]->IsOut( line ))
6214           foundElems.insert( _elements[i]->_element );
6215     }
6216     else
6217     {
6218       for (int i = 0; i < 8; i++)
6219         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6220     }
6221   }
6222
6223   //================================================================================
6224   /*!
6225    * \brief Construct the element box
6226    */
6227   //================================================================================
6228
6229   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
6230   {
6231     _element  = elem;
6232     _refCount = 1;
6233     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6234     while ( nIt->more() )
6235       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6236     Enlarge( NodeRadius );
6237   }
6238
6239 } // namespace
6240
6241 //=======================================================================
6242 /*!
6243  * \brief Implementation of search for the elements by point and
6244  *        of classification of point in 2D mesh
6245  */
6246 //=======================================================================
6247
6248 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6249 {
6250   SMESHDS_Mesh*                _mesh;
6251   ElementBndBoxTree*           _ebbTree;
6252   SMESH_NodeSearcherImpl*      _nodeSearcher;
6253   SMDSAbs_ElementType          _elementType;
6254   double                       _tolerance;
6255   bool                         _outerFacesFound;
6256   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6257
6258   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6259     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6260   ~SMESH_ElementSearcherImpl()
6261   {
6262     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6263     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6264   }
6265   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6266                                   SMDSAbs_ElementType                type,
6267                                   vector< const SMDS_MeshElement* >& foundElements);
6268   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6269
6270   double getTolerance();
6271   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6272                             const double tolerance, double & param);
6273   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6274   bool isOuterBoundary(const SMDS_MeshElement* face) const
6275   {
6276     return _outerFaces.empty() || _outerFaces.count(face);
6277   }
6278   struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
6279   {
6280     const SMDS_MeshElement* _face;
6281     gp_Vec                  _faceNorm;
6282     bool                    _coincides; //!< the line lays in face plane
6283     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6284       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6285   };
6286   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6287   {
6288     SMESH_TLink      _link;
6289     TIDSortedElemSet _faces;
6290     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6291       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6292   };
6293 };
6294
6295 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6296 {
6297   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6298              << ", _coincides="<<i._coincides << ")";
6299 }
6300
6301 //=======================================================================
6302 /*!
6303  * \brief define tolerance for search
6304  */
6305 //=======================================================================
6306
6307 double SMESH_ElementSearcherImpl::getTolerance()
6308 {
6309   if ( _tolerance < 0 )
6310   {
6311     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6312
6313     _tolerance = 0;
6314     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6315     {
6316       double boxSize = _nodeSearcher->getTree()->maxSize();
6317       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6318     }
6319     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6320     {
6321       double boxSize = _ebbTree->maxSize();
6322       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6323     }
6324     if ( _tolerance == 0 )
6325     {
6326       // define tolerance by size of a most complex element
6327       int complexType = SMDSAbs_Volume;
6328       while ( complexType > SMDSAbs_All &&
6329               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6330         --complexType;
6331       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6332
6333       double elemSize;
6334       if ( complexType == int( SMDSAbs_Node ))
6335       {
6336         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6337         elemSize = 1;
6338         if ( meshInfo.NbNodes() > 2 )
6339           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6340       }
6341       else
6342       {
6343         const SMDS_MeshElement* elem =
6344           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6345         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6346         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6347         while ( nodeIt->more() )
6348         {
6349           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6350           elemSize = max( dist, elemSize );
6351         }
6352       }
6353       _tolerance = 1e-6 * elemSize;
6354     }
6355   }
6356   return _tolerance;
6357 }
6358
6359 //================================================================================
6360 /*!
6361  * \brief Find intersection of the line and an edge of face and return parameter on line
6362  */
6363 //================================================================================
6364
6365 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6366                                                      const SMDS_MeshElement* face,
6367                                                      const double            tol,
6368                                                      double &                param)
6369 {
6370   int nbInts = 0;
6371   param = 0;
6372
6373   GeomAPI_ExtremaCurveCurve anExtCC;
6374   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6375   
6376   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6377   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6378   {
6379     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6380                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6381     anExtCC.Init( lineCurve, edge);
6382     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6383     {
6384       Quantity_Parameter pl, pe;
6385       anExtCC.LowerDistanceParameters( pl, pe );
6386       param += pl;
6387       if ( ++nbInts == 2 )
6388         break;
6389     }
6390   }
6391   if ( nbInts > 0 ) param /= nbInts;
6392   return nbInts > 0;
6393 }
6394 //================================================================================
6395 /*!
6396  * \brief Find all faces belonging to the outer boundary of mesh
6397  */
6398 //================================================================================
6399
6400 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6401 {
6402   if ( _outerFacesFound ) return;
6403
6404   // Collect all outer faces by passing from one outer face to another via their links
6405   // and BTW find out if there are internal faces at all.
6406
6407   // checked links and links where outer boundary meets internal one
6408   set< SMESH_TLink > visitedLinks, seamLinks;
6409
6410   // links to treat with already visited faces sharing them
6411   list < TFaceLink > startLinks;
6412
6413   // load startLinks with the first outerFace
6414   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6415   _outerFaces.insert( outerFace );
6416
6417   TIDSortedElemSet emptySet;
6418   while ( !startLinks.empty() )
6419   {
6420     const SMESH_TLink& link  = startLinks.front()._link;
6421     TIDSortedElemSet&  faces = startLinks.front()._faces;
6422
6423     outerFace = *faces.begin();
6424     // find other faces sharing the link
6425     const SMDS_MeshElement* f;
6426     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6427       faces.insert( f );
6428
6429     // select another outer face among the found 
6430     const SMDS_MeshElement* outerFace2 = 0;
6431     if ( faces.size() == 2 )
6432     {
6433       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6434     }
6435     else if ( faces.size() > 2 )
6436     {
6437       seamLinks.insert( link );
6438
6439       // link direction within the outerFace
6440       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6441                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6442       int i1 = outerFace->GetNodeIndex( link.node1() );
6443       int i2 = outerFace->GetNodeIndex( link.node2() );
6444       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6445       if ( rev ) n1n2.Reverse();
6446       // outerFace normal
6447       gp_XYZ ofNorm, fNorm;
6448       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6449       {
6450         // direction from the link inside outerFace
6451         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6452         // sort all other faces by angle with the dirInOF
6453         map< double, const SMDS_MeshElement* > angle2Face;
6454         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6455         for ( ; face != faces.end(); ++face )
6456         {
6457           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6458             continue;
6459           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6460           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6461           if ( angle < 0 ) angle += 2*PI;
6462           angle2Face.insert( make_pair( angle, *face ));
6463         }
6464         if ( !angle2Face.empty() )
6465           outerFace2 = angle2Face.begin()->second;
6466       }
6467     }
6468     // store the found outer face and add its links to continue seaching from
6469     if ( outerFace2 )
6470     {
6471       _outerFaces.insert( outerFace );
6472       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6473       for ( int i = 0; i < nbNodes; ++i )
6474       {
6475         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6476         if ( visitedLinks.insert( link2 ).second )
6477           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6478       }
6479     }
6480     startLinks.pop_front();
6481   }
6482   _outerFacesFound = true;
6483
6484   if ( !seamLinks.empty() )
6485   {
6486     // There are internal boundaries touching the outher one,
6487     // find all faces of internal boundaries in order to find
6488     // faces of boundaries of holes, if any.
6489     
6490   }
6491   else
6492   {
6493     _outerFaces.clear();
6494   }
6495 }
6496
6497 //=======================================================================
6498 /*!
6499  * \brief Find elements of given type where the given point is IN or ON.
6500  *        Returns nb of found elements and elements them-selves.
6501  *
6502  * 'ALL' type means elements of any type excluding nodes and 0D elements
6503  */
6504 //=======================================================================
6505
6506 int SMESH_ElementSearcherImpl::
6507 FindElementsByPoint(const gp_Pnt&                      point,
6508                     SMDSAbs_ElementType                type,
6509                     vector< const SMDS_MeshElement* >& foundElements)
6510 {
6511   foundElements.clear();
6512
6513   double tolerance = getTolerance();
6514
6515   // =================================================================================
6516   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6517   {
6518     if ( !_nodeSearcher )
6519       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6520
6521     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6522     if ( !closeNode ) return foundElements.size();
6523
6524     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6525       return foundElements.size(); // to far from any node
6526
6527     if ( type == SMDSAbs_Node )
6528     {
6529       foundElements.push_back( closeNode );
6530     }
6531     else
6532     {
6533       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6534       while ( elemIt->more() )
6535         foundElements.push_back( elemIt->next() );
6536     }
6537   }
6538   // =================================================================================
6539   else // elements more complex than 0D
6540   {
6541     if ( !_ebbTree || _elementType != type )
6542     {
6543       if ( _ebbTree ) delete _ebbTree;
6544       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6545     }
6546     TIDSortedElemSet suspectElems;
6547     _ebbTree->getElementsNearPoint( point, suspectElems );
6548     TIDSortedElemSet::iterator elem = suspectElems.begin();
6549     for ( ; elem != suspectElems.end(); ++elem )
6550       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6551         foundElements.push_back( *elem );
6552   }
6553   return foundElements.size();
6554 }
6555
6556 //================================================================================
6557 /*!
6558  * \brief Classify the given point in the closed 2D mesh
6559  */
6560 //================================================================================
6561
6562 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6563 {
6564   double tolerance = getTolerance();
6565   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6566   {
6567     if ( _ebbTree ) delete _ebbTree;
6568     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6569   }
6570   // Algo: analyse transition of a line starting at the point through mesh boundary;
6571   // try three lines parallel to axis of the coordinate system and perform rough
6572   // analysis. If solution is not clear perform thorough analysis.
6573
6574   const int nbAxes = 3;
6575   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6576   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6577   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6578   multimap< int, int > nbInt2Axis; // to find the simplest case
6579   for ( int axis = 0; axis < nbAxes; ++axis )
6580   {
6581     gp_Ax1 lineAxis( point, axisDir[axis]);
6582     gp_Lin line    ( lineAxis );
6583
6584     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6585     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6586
6587     // Intersect faces with the line
6588
6589     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6590     TIDSortedElemSet::iterator face = suspectFaces.begin();
6591     for ( ; face != suspectFaces.end(); ++face )
6592     {
6593       // get face plane
6594       gp_XYZ fNorm;
6595       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6596       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6597
6598       // perform intersection
6599       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6600       if ( !intersection.IsDone() )
6601         continue;
6602       if ( intersection.IsInQuadric() )
6603       {
6604         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6605       }
6606       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6607       {
6608         gp_Pnt intersectionPoint = intersection.Point(1);
6609         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6610           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6611       }
6612     }
6613     // Analyse intersections roughly
6614
6615     int nbInter = u2inters.size();
6616     if ( nbInter == 0 )
6617       return TopAbs_OUT; 
6618
6619     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6620     if ( nbInter == 1 ) // not closed mesh
6621       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6622
6623     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6624       return TopAbs_ON;
6625
6626     if ( (f<0) == (l<0) )
6627       return TopAbs_OUT;
6628
6629     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6630     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6631     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6632       return TopAbs_IN;
6633
6634     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6635
6636     if ( _outerFacesFound ) break; // pass to thorough analysis
6637
6638   } // three attempts - loop on CS axes
6639
6640   // Analyse intersections thoroughly.
6641   // We make two loops maximum, on the first one we only exclude touching intersections,
6642   // on the second, if situation is still unclear, we gather and use information on
6643   // position of faces (internal or outer). If faces position is already gathered,
6644   // we make the second loop right away.
6645
6646   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6647   {
6648     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6649     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6650     {
6651       int axis = nb_axis->second;
6652       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6653
6654       gp_Ax1 lineAxis( point, axisDir[axis]);
6655       gp_Lin line    ( lineAxis );
6656
6657       // add tangent intersections to u2inters
6658       double param;
6659       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6660       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6661         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6662           u2inters.insert(make_pair( param, *tgtInt ));
6663       tangentInters[ axis ].clear();
6664
6665       // Count intersections before and after the point excluding touching ones.
6666       // If hasPositionInfo we count intersections of outer boundary only
6667
6668       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6669       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6670       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6671       bool ok = ! u_int1->second._coincides;
6672       while ( ok && u_int1 != u2inters.end() )
6673       {
6674         double u = u_int1->first;
6675         bool touchingInt = false;
6676         if ( ++u_int2 != u2inters.end() )
6677         {
6678           // skip intersections at the same point (if the line passes through edge or node)
6679           int nbSamePnt = 0;
6680           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6681           {
6682             ++nbSamePnt;
6683             ++u_int2;
6684           }
6685
6686           // skip tangent intersections
6687           int nbTgt = 0;
6688           const SMDS_MeshElement* prevFace = u_int1->second._face;
6689           while ( ok && u_int2->second._coincides )
6690           {
6691             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6692               ok = false;
6693             else
6694             {
6695               nbTgt++;
6696               u_int2++;
6697               ok = ( u_int2 != u2inters.end() );
6698             }
6699           }
6700           if ( !ok ) break;
6701
6702           // skip intersections at the same point after tangent intersections
6703           if ( nbTgt > 0 )
6704           {
6705             double u2 = u_int2->first;
6706             ++u_int2;
6707             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6708             {
6709               ++nbSamePnt;
6710               ++u_int2;
6711             }
6712           }
6713           // decide if we skipped a touching intersection
6714           if ( nbSamePnt + nbTgt > 0 )
6715           {
6716             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6717             map< double, TInters >::iterator u_int = u_int1;
6718             for ( ; u_int != u_int2; ++u_int )
6719             {
6720               if ( u_int->second._coincides ) continue;
6721               double dot = u_int->second._faceNorm * line.Direction();
6722               if ( dot > maxDot ) maxDot = dot;
6723               if ( dot < minDot ) minDot = dot;
6724             }
6725             touchingInt = ( minDot*maxDot < 0 );
6726           }
6727         }
6728         if ( !touchingInt )
6729         {
6730           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6731           {
6732             if ( u < 0 )
6733               ++nbIntBeforePoint;
6734             else
6735               ++nbIntAfterPoint;
6736           }
6737           if ( u < f ) f = u;
6738           if ( u > l ) l = u;
6739         }
6740
6741         u_int1 = u_int2; // to next intersection
6742
6743       } // loop on intersections with one line
6744
6745       if ( ok )
6746       {
6747         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6748           return TopAbs_ON;
6749
6750         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6751           return TopAbs_OUT; 
6752
6753         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6754           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6755
6756         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6757           return TopAbs_IN;
6758
6759         if ( (f<0) == (l<0) )
6760           return TopAbs_OUT;
6761
6762         if ( hasPositionInfo )
6763           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6764       }
6765     } // loop on intersections of the tree lines - thorough analysis
6766
6767     if ( !hasPositionInfo )
6768     {
6769       // gather info on faces position - is face in the outer boundary or not
6770       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6771       findOuterBoundary( u2inters.begin()->second._face );
6772     }
6773
6774   } // two attempts - with and w/o faces position info in the mesh
6775
6776   return TopAbs_UNKNOWN;
6777 }
6778
6779 //=======================================================================
6780 /*!
6781  * \brief Return SMESH_ElementSearcher
6782  */
6783 //=======================================================================
6784
6785 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6786 {
6787   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6788 }
6789
6790 //=======================================================================
6791 /*!
6792  * \brief Return true if the point is IN or ON of the element
6793  */
6794 //=======================================================================
6795
6796 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6797 {
6798   if ( element->GetType() == SMDSAbs_Volume)
6799   {
6800     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6801   }
6802
6803   // get ordered nodes
6804
6805   vector< gp_XYZ > xyz;
6806
6807   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6808   if ( element->IsQuadratic() )
6809     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6810       nodeIt = f->interlacedNodesElemIterator();
6811     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6812       nodeIt = e->interlacedNodesElemIterator();
6813
6814   while ( nodeIt->more() )
6815     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6816
6817   int i, nbNodes = element->NbNodes();
6818
6819   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6820   {
6821     // compute face normal
6822     gp_Vec faceNorm(0,0,0);
6823     xyz.push_back( xyz.front() );
6824     for ( i = 0; i < nbNodes; ++i )
6825     {
6826       gp_Vec edge1( xyz[i+1], xyz[i]);
6827       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6828       faceNorm += edge1 ^ edge2;
6829     }
6830     double normSize = faceNorm.Magnitude();
6831     if ( normSize <= tol )
6832     {
6833       // degenerated face: point is out if it is out of all face edges
6834       for ( i = 0; i < nbNodes; ++i )
6835       {
6836         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6837         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6838         SMDS_MeshEdge edge( &n1, &n2 );
6839         if ( !isOut( &edge, point, tol ))
6840           return false;
6841       }
6842       return true;
6843     }
6844     faceNorm /= normSize;
6845
6846     // check if the point lays on face plane
6847     gp_Vec n2p( xyz[0], point );
6848     if ( fabs( n2p * faceNorm ) > tol )
6849       return true; // not on face plane
6850
6851     // check if point is out of face boundary:
6852     // define it by closest transition of a ray point->infinity through face boundary
6853     // on the face plane.
6854     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6855     // to find intersections of the ray with the boundary.
6856     gp_Vec ray = n2p;
6857     gp_Vec plnNorm = ray ^ faceNorm;
6858     normSize = plnNorm.Magnitude();
6859     if ( normSize <= tol ) return false; // point coincides with the first node
6860     plnNorm /= normSize;
6861     // for each node of the face, compute its signed distance to the plane
6862     vector<double> dist( nbNodes + 1);
6863     for ( i = 0; i < nbNodes; ++i )
6864     {
6865       gp_Vec n2p( xyz[i], point );
6866       dist[i] = n2p * plnNorm;
6867     }
6868     dist.back() = dist.front();
6869     // find the closest intersection
6870     int    iClosest = -1;
6871     double rClosest, distClosest = 1e100;;
6872     gp_Pnt pClosest;
6873     for ( i = 0; i < nbNodes; ++i )
6874     {
6875       double r;
6876       if ( fabs( dist[i]) < tol )
6877         r = 0.;
6878       else if ( fabs( dist[i+1]) < tol )
6879         r = 1.;
6880       else if ( dist[i] * dist[i+1] < 0 )
6881         r = dist[i] / ( dist[i] - dist[i+1] );
6882       else
6883         continue; // no intersection
6884       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6885       gp_Vec p2int ( point, pInt);
6886       if ( p2int * ray > -tol ) // right half-space
6887       {
6888         double intDist = p2int.SquareMagnitude();
6889         if ( intDist < distClosest )
6890         {
6891           iClosest = i;
6892           rClosest = r;
6893           pClosest = pInt;
6894           distClosest = intDist;
6895         }
6896       }
6897     }
6898     if ( iClosest < 0 )
6899       return true; // no intesections - out
6900
6901     // analyse transition
6902     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6903     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6904     gp_Vec p2int ( point, pClosest );
6905     bool out = (edgeNorm * p2int) < -tol;
6906     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6907       return out;
6908
6909     // ray pass through a face node; analyze transition through an adjacent edge
6910     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6911     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6912     gp_Vec edgeAdjacent( p1, p2 );
6913     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6914     bool out2 = (edgeNorm2 * p2int) < -tol;
6915
6916     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6917     return covexCorner ? (out || out2) : (out && out2);
6918   }
6919   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6920   {
6921     // point is out of edge if it is NOT ON any straight part of edge
6922     // (we consider quadratic edge as being composed of two straight parts)
6923     for ( i = 1; i < nbNodes; ++i )
6924     {
6925       gp_Vec edge( xyz[i-1], xyz[i]);
6926       gp_Vec n1p ( xyz[i-1], point);
6927       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6928       if ( dist > tol )
6929         continue;
6930       gp_Vec n2p( xyz[i], point );
6931       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6932         continue;
6933       return false; // point is ON this part
6934     }
6935     return true;
6936   }
6937   // Node or 0D element -------------------------------------------------------------------------
6938   {
6939     gp_Vec n2p ( xyz[0], point );
6940     return n2p.Magnitude() <= tol;
6941   }
6942   return true;
6943 }
6944
6945 //=======================================================================
6946 //function : SimplifyFace
6947 //purpose  :
6948 //=======================================================================
6949 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6950                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6951                                     vector<int>&                        quantities) const
6952 {
6953   int nbNodes = faceNodes.size();
6954
6955   if (nbNodes < 3)
6956     return 0;
6957
6958   set<const SMDS_MeshNode*> nodeSet;
6959
6960   // get simple seq of nodes
6961   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6962   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6963   int iSimple = 0, nbUnique = 0;
6964
6965   simpleNodes[iSimple++] = faceNodes[0];
6966   nbUnique++;
6967   for (int iCur = 1; iCur < nbNodes; iCur++) {
6968     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6969       simpleNodes[iSimple++] = faceNodes[iCur];
6970       if (nodeSet.insert( faceNodes[iCur] ).second)
6971         nbUnique++;
6972     }
6973   }
6974   int nbSimple = iSimple;
6975   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6976     nbSimple--;
6977     iSimple--;
6978   }
6979
6980   if (nbUnique < 3)
6981     return 0;
6982
6983   // separate loops
6984   int nbNew = 0;
6985   bool foundLoop = (nbSimple > nbUnique);
6986   while (foundLoop) {
6987     foundLoop = false;
6988     set<const SMDS_MeshNode*> loopSet;
6989     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6990       const SMDS_MeshNode* n = simpleNodes[iSimple];
6991       if (!loopSet.insert( n ).second) {
6992         foundLoop = true;
6993
6994         // separate loop
6995         int iC = 0, curLast = iSimple;
6996         for (; iC < curLast; iC++) {
6997           if (simpleNodes[iC] == n) break;
6998         }
6999         int loopLen = curLast - iC;
7000         if (loopLen > 2) {
7001           // create sub-element
7002           nbNew++;
7003           quantities.push_back(loopLen);
7004           for (; iC < curLast; iC++) {
7005             poly_nodes.push_back(simpleNodes[iC]);
7006           }
7007         }
7008         // shift the rest nodes (place from the first loop position)
7009         for (iC = curLast + 1; iC < nbSimple; iC++) {
7010           simpleNodes[iC - loopLen] = simpleNodes[iC];
7011         }
7012         nbSimple -= loopLen;
7013         iSimple -= loopLen;
7014       }
7015     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7016   } // while (foundLoop)
7017
7018   if (iSimple > 2) {
7019     nbNew++;
7020     quantities.push_back(iSimple);
7021     for (int i = 0; i < iSimple; i++)
7022       poly_nodes.push_back(simpleNodes[i]);
7023   }
7024
7025   return nbNew;
7026 }
7027
7028 //=======================================================================
7029 //function : MergeNodes
7030 //purpose  : In each group, the cdr of nodes are substituted by the first one
7031 //           in all elements.
7032 //=======================================================================
7033
7034 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7035 {
7036   myLastCreatedElems.Clear();
7037   myLastCreatedNodes.Clear();
7038
7039   SMESHDS_Mesh* aMesh = GetMeshDS();
7040
7041   TNodeNodeMap nodeNodeMap; // node to replace - new node
7042   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7043   list< int > rmElemIds, rmNodeIds;
7044
7045   // Fill nodeNodeMap and elems
7046
7047   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7048   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7049     list<const SMDS_MeshNode*>& nodes = *grIt;
7050     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7051     const SMDS_MeshNode* nToKeep = *nIt;
7052     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7053       const SMDS_MeshNode* nToRemove = *nIt;
7054       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7055       if ( nToRemove != nToKeep ) {
7056         rmNodeIds.push_back( nToRemove->GetID() );
7057         AddToSameGroups( nToKeep, nToRemove, aMesh );
7058       }
7059
7060       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7061       while ( invElemIt->more() ) {
7062         const SMDS_MeshElement* elem = invElemIt->next();
7063         elems.insert(elem);
7064       }
7065     }
7066   }
7067   // Change element nodes or remove an element
7068
7069   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7070   for ( ; eIt != elems.end(); eIt++ ) {
7071     const SMDS_MeshElement* elem = *eIt;
7072     int nbNodes = elem->NbNodes();
7073     int aShapeId = FindShape( elem );
7074
7075     set<const SMDS_MeshNode*> nodeSet;
7076     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7077     int iUnique = 0, iCur = 0, nbRepl = 0;
7078     vector<int> iRepl( nbNodes );
7079
7080     // get new seq of nodes
7081     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7082     while ( itN->more() ) {
7083       const SMDS_MeshNode* n =
7084         static_cast<const SMDS_MeshNode*>( itN->next() );
7085
7086       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7087       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7088         n = (*nnIt).second;
7089         // BUG 0020185: begin
7090         {
7091           bool stopRecur = false;
7092           set<const SMDS_MeshNode*> nodesRecur;
7093           nodesRecur.insert(n);
7094           while (!stopRecur) {
7095             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7096             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7097               n = (*nnIt_i).second;
7098               if (!nodesRecur.insert(n).second) {
7099                 // error: recursive dependancy
7100                 stopRecur = true;
7101               }
7102             }
7103             else
7104               stopRecur = true;
7105           }
7106         }
7107         // BUG 0020185: end
7108         iRepl[ nbRepl++ ] = iCur;
7109       }
7110       curNodes[ iCur ] = n;
7111       bool isUnique = nodeSet.insert( n ).second;
7112       if ( isUnique )
7113         uniqueNodes[ iUnique++ ] = n;
7114       iCur++;
7115     }
7116
7117     // Analyse element topology after replacement
7118
7119     bool isOk = true;
7120     int nbUniqueNodes = nodeSet.size();
7121     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7122       // Polygons and Polyhedral volumes
7123       if (elem->IsPoly()) {
7124
7125         if (elem->GetType() == SMDSAbs_Face) {
7126           // Polygon
7127           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7128           int inode = 0;
7129           for (; inode < nbNodes; inode++) {
7130             face_nodes[inode] = curNodes[inode];
7131           }
7132
7133           vector<const SMDS_MeshNode *> polygons_nodes;
7134           vector<int> quantities;
7135           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7136
7137           if (nbNew > 0) {
7138             inode = 0;
7139             for (int iface = 0; iface < nbNew - 1; iface++) {
7140               int nbNodes = quantities[iface];
7141               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7142               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7143                 poly_nodes[ii] = polygons_nodes[inode];
7144               }
7145               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7146               myLastCreatedElems.Append(newElem);
7147               if (aShapeId)
7148                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7149             }
7150             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7151           }
7152           else {
7153             rmElemIds.push_back(elem->GetID());
7154           }
7155
7156         }
7157         else if (elem->GetType() == SMDSAbs_Volume) {
7158           // Polyhedral volume
7159           if (nbUniqueNodes < 4) {
7160             rmElemIds.push_back(elem->GetID());
7161           }
7162           else {
7163             // each face has to be analized in order to check volume validity
7164             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7165               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7166             if (aPolyedre) {
7167               int nbFaces = aPolyedre->NbFaces();
7168
7169               vector<const SMDS_MeshNode *> poly_nodes;
7170               vector<int> quantities;
7171
7172               for (int iface = 1; iface <= nbFaces; iface++) {
7173                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7174                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7175
7176                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7177                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7178                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7179                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7180                     faceNode = (*nnIt).second;
7181                   }
7182                   faceNodes[inode - 1] = faceNode;
7183                 }
7184
7185                 SimplifyFace(faceNodes, poly_nodes, quantities);
7186               }
7187
7188               if (quantities.size() > 3) {
7189                 // to be done: remove coincident faces
7190               }
7191
7192               if (quantities.size() > 3)
7193                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7194               else
7195                 rmElemIds.push_back(elem->GetID());
7196
7197             }
7198             else {
7199               rmElemIds.push_back(elem->GetID());
7200             }
7201           }
7202         }
7203         else {
7204         }
7205
7206         continue;
7207       }
7208
7209       // Regular elements
7210       switch ( nbNodes ) {
7211       case 2: ///////////////////////////////////// EDGE
7212         isOk = false; break;
7213       case 3: ///////////////////////////////////// TRIANGLE
7214         isOk = false; break;
7215       case 4:
7216         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7217           isOk = false;
7218         else { //////////////////////////////////// QUADRANGLE
7219           if ( nbUniqueNodes < 3 )
7220             isOk = false;
7221           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7222             isOk = false; // opposite nodes stick
7223         }
7224         break;
7225       case 6: ///////////////////////////////////// PENTAHEDRON
7226         if ( nbUniqueNodes == 4 ) {
7227           // ---------------------------------> tetrahedron
7228           if (nbRepl == 3 &&
7229               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7230             // all top nodes stick: reverse a bottom
7231             uniqueNodes[ 0 ] = curNodes [ 1 ];
7232             uniqueNodes[ 1 ] = curNodes [ 0 ];
7233           }
7234           else if (nbRepl == 3 &&
7235                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7236             // all bottom nodes stick: set a top before
7237             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7238             uniqueNodes[ 0 ] = curNodes [ 3 ];
7239             uniqueNodes[ 1 ] = curNodes [ 4 ];
7240             uniqueNodes[ 2 ] = curNodes [ 5 ];
7241           }
7242           else if (nbRepl == 4 &&
7243                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7244             // a lateral face turns into a line: reverse a bottom
7245             uniqueNodes[ 0 ] = curNodes [ 1 ];
7246             uniqueNodes[ 1 ] = curNodes [ 0 ];
7247           }
7248           else
7249             isOk = false;
7250         }
7251         else if ( nbUniqueNodes == 5 ) {
7252           // PENTAHEDRON --------------------> 2 tetrahedrons
7253           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7254             // a bottom node sticks with a linked top one
7255             // 1.
7256             SMDS_MeshElement* newElem =
7257               aMesh->AddVolume(curNodes[ 3 ],
7258                                curNodes[ 4 ],
7259                                curNodes[ 5 ],
7260                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7261             myLastCreatedElems.Append(newElem);
7262             if ( aShapeId )
7263               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7264             // 2. : reverse a bottom
7265             uniqueNodes[ 0 ] = curNodes [ 1 ];
7266             uniqueNodes[ 1 ] = curNodes [ 0 ];
7267             nbUniqueNodes = 4;
7268           }
7269           else
7270             isOk = false;
7271         }
7272         else
7273           isOk = false;
7274         break;
7275       case 8: {
7276         if(elem->IsQuadratic()) { // Quadratic quadrangle
7277           //   1    5    2
7278           //    +---+---+
7279           //    |       |
7280           //    |       |
7281           //   4+       +6
7282           //    |       |
7283           //    |       |
7284           //    +---+---+
7285           //   0    7    3
7286           isOk = false;
7287           if(nbRepl==3) {
7288             nbUniqueNodes = 6;
7289             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7290               uniqueNodes[0] = curNodes[0];
7291               uniqueNodes[1] = curNodes[2];
7292               uniqueNodes[2] = curNodes[3];
7293               uniqueNodes[3] = curNodes[5];
7294               uniqueNodes[4] = curNodes[6];
7295               uniqueNodes[5] = curNodes[7];
7296               isOk = true;
7297             }
7298             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7299               uniqueNodes[0] = curNodes[0];
7300               uniqueNodes[1] = curNodes[1];
7301               uniqueNodes[2] = curNodes[2];
7302               uniqueNodes[3] = curNodes[4];
7303               uniqueNodes[4] = curNodes[5];
7304               uniqueNodes[5] = curNodes[6];
7305               isOk = true;
7306             }
7307             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7308               uniqueNodes[0] = curNodes[1];
7309               uniqueNodes[1] = curNodes[2];
7310               uniqueNodes[2] = curNodes[3];
7311               uniqueNodes[3] = curNodes[5];
7312               uniqueNodes[4] = curNodes[6];
7313               uniqueNodes[5] = curNodes[0];
7314               isOk = true;
7315             }
7316             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7317               uniqueNodes[0] = curNodes[0];
7318               uniqueNodes[1] = curNodes[1];
7319               uniqueNodes[2] = curNodes[3];
7320               uniqueNodes[3] = curNodes[4];
7321               uniqueNodes[4] = curNodes[6];
7322               uniqueNodes[5] = curNodes[7];
7323               isOk = true;
7324             }
7325             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7326               uniqueNodes[0] = curNodes[0];
7327               uniqueNodes[1] = curNodes[2];
7328               uniqueNodes[2] = curNodes[3];
7329               uniqueNodes[3] = curNodes[1];
7330               uniqueNodes[4] = curNodes[6];
7331               uniqueNodes[5] = curNodes[7];
7332               isOk = true;
7333             }
7334             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7335               uniqueNodes[0] = curNodes[0];
7336               uniqueNodes[1] = curNodes[1];
7337               uniqueNodes[2] = curNodes[2];
7338               uniqueNodes[3] = curNodes[4];
7339               uniqueNodes[4] = curNodes[5];
7340               uniqueNodes[5] = curNodes[7];
7341               isOk = true;
7342             }
7343             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7344               uniqueNodes[0] = curNodes[0];
7345               uniqueNodes[1] = curNodes[1];
7346               uniqueNodes[2] = curNodes[3];
7347               uniqueNodes[3] = curNodes[4];
7348               uniqueNodes[4] = curNodes[2];
7349               uniqueNodes[5] = curNodes[7];
7350               isOk = true;
7351             }
7352             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7353               uniqueNodes[0] = curNodes[0];
7354               uniqueNodes[1] = curNodes[1];
7355               uniqueNodes[2] = curNodes[2];
7356               uniqueNodes[3] = curNodes[4];
7357               uniqueNodes[4] = curNodes[5];
7358               uniqueNodes[5] = curNodes[3];
7359               isOk = true;
7360             }
7361           }
7362           break;
7363         }
7364         //////////////////////////////////// HEXAHEDRON
7365         isOk = false;
7366         SMDS_VolumeTool hexa (elem);
7367         hexa.SetExternalNormal();
7368         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7369           //////////////////////// ---> tetrahedron
7370           for ( int iFace = 0; iFace < 6; iFace++ ) {
7371             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7372             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7373                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7374                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7375               // one face turns into a point ...
7376               int iOppFace = hexa.GetOppFaceIndex( iFace );
7377               ind = hexa.GetFaceNodesIndices( iOppFace );
7378               int nbStick = 0;
7379               iUnique = 2; // reverse a tetrahedron bottom
7380               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7381                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7382                   nbStick++;
7383                 else if ( iUnique >= 0 )
7384                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7385               }
7386               if ( nbStick == 1 ) {
7387                 // ... and the opposite one - into a triangle.
7388                 // set a top node
7389                 ind = hexa.GetFaceNodesIndices( iFace );
7390                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7391                 isOk = true;
7392               }
7393               break;
7394             }
7395           }
7396         }
7397         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7398           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7399           for ( int iFace = 0; iFace < 6; iFace++ ) {
7400             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7401             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7402                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7403                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7404               // one face turns into a point ...
7405               int iOppFace = hexa.GetOppFaceIndex( iFace );
7406               ind = hexa.GetFaceNodesIndices( iOppFace );
7407               int nbStick = 0;
7408               iUnique = 2;  // reverse a tetrahedron 1 bottom
7409               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7410                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7411                   nbStick++;
7412                 else if ( iUnique >= 0 )
7413                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7414               }
7415               if ( nbStick == 0 ) {
7416                 // ... and the opposite one is a quadrangle
7417                 // set a top node
7418                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7419                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7420                 nbUniqueNodes = 4;
7421                 // tetrahedron 2
7422                 SMDS_MeshElement* newElem =
7423                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7424                                    curNodes[ind[ 3 ]],
7425                                    curNodes[ind[ 2 ]],
7426                                    curNodes[indTop[ 0 ]]);
7427                 myLastCreatedElems.Append(newElem);
7428                 if ( aShapeId )
7429                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7430                 isOk = true;
7431               }
7432               break;
7433             }
7434           }
7435         }
7436         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7437           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7438           // find indices of quad and tri faces
7439           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7440           for ( iFace = 0; iFace < 6; iFace++ ) {
7441             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7442             nodeSet.clear();
7443             for ( iCur = 0; iCur < 4; iCur++ )
7444               nodeSet.insert( curNodes[ind[ iCur ]] );
7445             nbUniqueNodes = nodeSet.size();
7446             if ( nbUniqueNodes == 3 )
7447               iTriFace[ nbTri++ ] = iFace;
7448             else if ( nbUniqueNodes == 4 )
7449               iQuadFace[ nbQuad++ ] = iFace;
7450           }
7451           if (nbQuad == 2 && nbTri == 4 &&
7452               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7453             // 2 opposite quadrangles stuck with a diagonal;
7454             // sample groups of merged indices: (0-4)(2-6)
7455             // --------------------------------------------> 2 tetrahedrons
7456             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7457             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7458             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7459             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7460                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7461               // stuck with 0-2 diagonal
7462               i0  = ind1[ 3 ];
7463               i1d = ind1[ 0 ];
7464               i2  = ind1[ 1 ];
7465               i3d = ind1[ 2 ];
7466               i0t = ind2[ 1 ];
7467               i2t = ind2[ 3 ];
7468             }
7469             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7470                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7471               // stuck with 1-3 diagonal
7472               i0  = ind1[ 0 ];
7473               i1d = ind1[ 1 ];
7474               i2  = ind1[ 2 ];
7475               i3d = ind1[ 3 ];
7476               i0t = ind2[ 0 ];
7477               i2t = ind2[ 1 ];
7478             }
7479             else {
7480               ASSERT(0);
7481             }
7482             // tetrahedron 1
7483             uniqueNodes[ 0 ] = curNodes [ i0 ];
7484             uniqueNodes[ 1 ] = curNodes [ i1d ];
7485             uniqueNodes[ 2 ] = curNodes [ i3d ];
7486             uniqueNodes[ 3 ] = curNodes [ i0t ];
7487             nbUniqueNodes = 4;
7488             // tetrahedron 2
7489             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7490                                                          curNodes[ i2 ],
7491                                                          curNodes[ i3d ],
7492                                                          curNodes[ i2t ]);
7493             myLastCreatedElems.Append(newElem);
7494             if ( aShapeId )
7495               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7496             isOk = true;
7497           }
7498           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7499                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7500             // --------------------------------------------> prism
7501             // find 2 opposite triangles
7502             nbUniqueNodes = 6;
7503             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7504               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7505                 // find indices of kept and replaced nodes
7506                 // and fill unique nodes of 2 opposite triangles
7507                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7508                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7509                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7510                 // fill unique nodes
7511                 iUnique = 0;
7512                 isOk = true;
7513                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7514                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7515                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7516                   if ( n == nInit ) {
7517                     // iCur of a linked node of the opposite face (make normals co-directed):
7518                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7519                     // check that correspondent corners of triangles are linked
7520                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7521                       isOk = false;
7522                     else {
7523                       uniqueNodes[ iUnique ] = n;
7524                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7525                       iUnique++;
7526                     }
7527                   }
7528                 }
7529                 break;
7530               }
7531             }
7532           }
7533         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7534         break;
7535       } // HEXAHEDRON
7536
7537       default:
7538         isOk = false;
7539       } // switch ( nbNodes )
7540
7541     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7542
7543     if ( isOk ) {
7544       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7545         // Change nodes of polyedre
7546         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7547           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7548         if (aPolyedre) {
7549           int nbFaces = aPolyedre->NbFaces();
7550
7551           vector<const SMDS_MeshNode *> poly_nodes;
7552           vector<int> quantities (nbFaces);
7553
7554           for (int iface = 1; iface <= nbFaces; iface++) {
7555             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7556             quantities[iface - 1] = nbFaceNodes;
7557
7558             for (inode = 1; inode <= nbFaceNodes; inode++) {
7559               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7560
7561               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7562               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7563                 curNode = (*nnIt).second;
7564               }
7565               poly_nodes.push_back(curNode);
7566             }
7567           }
7568           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7569         }
7570       }
7571       else {
7572         // Change regular element or polygon
7573         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7574       }
7575     }
7576     else {
7577       // Remove invalid regular element or invalid polygon
7578       rmElemIds.push_back( elem->GetID() );
7579     }
7580
7581   } // loop on elements
7582
7583   // Remove equal nodes and bad elements
7584
7585   Remove( rmNodeIds, true );
7586   Remove( rmElemIds, false );
7587
7588 }
7589
7590
7591 // ========================================================
7592 // class   : SortableElement
7593 // purpose : allow sorting elements basing on their nodes
7594 // ========================================================
7595 class SortableElement : public set <const SMDS_MeshElement*>
7596 {
7597 public:
7598
7599   SortableElement( const SMDS_MeshElement* theElem )
7600   {
7601     myElem = theElem;
7602     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7603     while ( nodeIt->more() )
7604       this->insert( nodeIt->next() );
7605   }
7606
7607   const SMDS_MeshElement* Get() const
7608   { return myElem; }
7609
7610   void Set(const SMDS_MeshElement* e) const
7611   { myElem = e; }
7612
7613
7614 private:
7615   mutable const SMDS_MeshElement* myElem;
7616 };
7617
7618 //=======================================================================
7619 //function : FindEqualElements
7620 //purpose  : Return list of group of elements built on the same nodes.
7621 //           Search among theElements or in the whole mesh if theElements is empty
7622 //=======================================================================
7623 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7624                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7625 {
7626   myLastCreatedElems.Clear();
7627   myLastCreatedNodes.Clear();
7628
7629   typedef set<const SMDS_MeshElement*> TElemsSet;
7630   typedef map< SortableElement, int > TMapOfNodeSet;
7631   typedef list<int> TGroupOfElems;
7632
7633   TElemsSet elems;
7634   if ( theElements.empty() )
7635   { // get all elements in the mesh
7636     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7637     while ( eIt->more() )
7638       elems.insert( elems.end(), eIt->next());
7639   }
7640   else
7641     elems = theElements;
7642
7643   vector< TGroupOfElems > arrayOfGroups;
7644   TGroupOfElems groupOfElems;
7645   TMapOfNodeSet mapOfNodeSet;
7646
7647   TElemsSet::iterator elemIt = elems.begin();
7648   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7649     const SMDS_MeshElement* curElem = *elemIt;
7650     SortableElement SE(curElem);
7651     int ind = -1;
7652     // check uniqueness
7653     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7654     if( !(pp.second) ) {
7655       TMapOfNodeSet::iterator& itSE = pp.first;
7656       ind = (*itSE).second;
7657       arrayOfGroups[ind].push_back(curElem->GetID());
7658     }
7659     else {
7660       groupOfElems.clear();
7661       groupOfElems.push_back(curElem->GetID());
7662       arrayOfGroups.push_back(groupOfElems);
7663       i++;
7664     }
7665   }
7666
7667   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7668   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7669     groupOfElems = *groupIt;
7670     if ( groupOfElems.size() > 1 ) {
7671       groupOfElems.sort();
7672       theGroupsOfElementsID.push_back(groupOfElems);
7673     }
7674   }
7675 }
7676
7677 //=======================================================================
7678 //function : MergeElements
7679 //purpose  : In each given group, substitute all elements by the first one.
7680 //=======================================================================
7681
7682 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7683 {
7684   myLastCreatedElems.Clear();
7685   myLastCreatedNodes.Clear();
7686
7687   typedef list<int> TListOfIDs;
7688   TListOfIDs rmElemIds; // IDs of elems to remove
7689
7690   SMESHDS_Mesh* aMesh = GetMeshDS();
7691
7692   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7693   while ( groupsIt != theGroupsOfElementsID.end() ) {
7694     TListOfIDs& aGroupOfElemID = *groupsIt;
7695     aGroupOfElemID.sort();
7696     int elemIDToKeep = aGroupOfElemID.front();
7697     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7698     aGroupOfElemID.pop_front();
7699     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7700     while ( idIt != aGroupOfElemID.end() ) {
7701       int elemIDToRemove = *idIt;
7702       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7703       // add the kept element in groups of removed one (PAL15188)
7704       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7705       rmElemIds.push_back( elemIDToRemove );
7706       ++idIt;
7707     }
7708     ++groupsIt;
7709   }
7710
7711   Remove( rmElemIds, false );
7712 }
7713
7714 //=======================================================================
7715 //function : MergeEqualElements
7716 //purpose  : Remove all but one of elements built on the same nodes.
7717 //=======================================================================
7718
7719 void SMESH_MeshEditor::MergeEqualElements()
7720 {
7721   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7722                                                  to merge equal elements in the whole mesh */
7723   TListOfListOfElementsID aGroupsOfElementsID;
7724   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7725   MergeElements(aGroupsOfElementsID);
7726 }
7727
7728 //=======================================================================
7729 //function : FindFaceInSet
7730 //purpose  : Return a face having linked nodes n1 and n2 and which is
7731 //           - not in avoidSet,
7732 //           - in elemSet provided that !elemSet.empty()
7733 //           i1 and i2 optionally returns indices of n1 and n2
7734 //=======================================================================
7735
7736 const SMDS_MeshElement*
7737 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7738                                 const SMDS_MeshNode*    n2,
7739                                 const TIDSortedElemSet& elemSet,
7740                                 const TIDSortedElemSet& avoidSet,
7741                                 int*                    n1ind,
7742                                 int*                    n2ind)
7743
7744 {
7745   int i1, i2;
7746   const SMDS_MeshElement* face = 0;
7747
7748   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7749   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7750   {
7751     const SMDS_MeshElement* elem = invElemIt->next();
7752     if (avoidSet.count( elem ))
7753       continue;
7754     if ( !elemSet.empty() && !elemSet.count( elem ))
7755       continue;
7756     // index of n1
7757     i1 = elem->GetNodeIndex( n1 );
7758     // find a n2 linked to n1
7759     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7760     for ( int di = -1; di < 2 && !face; di += 2 )
7761     {
7762       i2 = (i1+di+nbN) % nbN;
7763       if ( elem->GetNode( i2 ) == n2 )
7764         face = elem;
7765     }
7766     if ( !face && elem->IsQuadratic())
7767     {
7768       // analysis for quadratic elements using all nodes
7769       const SMDS_QuadraticFaceOfNodes* F =
7770         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7771       // use special nodes iterator
7772       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7773       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7774       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7775       {
7776         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7777         if ( n1 == prevN && n2 == n )
7778         {
7779           face = elem;
7780         }
7781         else if ( n2 == prevN && n1 == n )
7782         {
7783           face = elem; swap( i1, i2 );
7784         }
7785         prevN = n;
7786       }
7787     }
7788   }
7789   if ( n1ind ) *n1ind = i1;
7790   if ( n2ind ) *n2ind = i2;
7791   return face;
7792 }
7793
7794 //=======================================================================
7795 //function : findAdjacentFace
7796 //purpose  :
7797 //=======================================================================
7798
7799 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7800                                                 const SMDS_MeshNode* n2,
7801                                                 const SMDS_MeshElement* elem)
7802 {
7803   TIDSortedElemSet elemSet, avoidSet;
7804   if ( elem )
7805     avoidSet.insert ( elem );
7806   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7807 }
7808
7809 //=======================================================================
7810 //function : FindFreeBorder
7811 //purpose  :
7812 //=======================================================================
7813
7814 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7815
7816 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7817                                        const SMDS_MeshNode*             theSecondNode,
7818                                        const SMDS_MeshNode*             theLastNode,
7819                                        list< const SMDS_MeshNode* > &   theNodes,
7820                                        list< const SMDS_MeshElement* >& theFaces)
7821 {
7822   if ( !theFirstNode || !theSecondNode )
7823     return false;
7824   // find border face between theFirstNode and theSecondNode
7825   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7826   if ( !curElem )
7827     return false;
7828
7829   theFaces.push_back( curElem );
7830   theNodes.push_back( theFirstNode );
7831   theNodes.push_back( theSecondNode );
7832
7833   //vector<const SMDS_MeshNode*> nodes;
7834   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7835   TIDSortedElemSet foundElems;
7836   bool needTheLast = ( theLastNode != 0 );
7837
7838   while ( nStart != theLastNode ) {
7839     if ( nStart == theFirstNode )
7840       return !needTheLast;
7841
7842     // find all free border faces sharing form nStart
7843
7844     list< const SMDS_MeshElement* > curElemList;
7845     list< const SMDS_MeshNode* > nStartList;
7846     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7847     while ( invElemIt->more() ) {
7848       const SMDS_MeshElement* e = invElemIt->next();
7849       if ( e == curElem || foundElems.insert( e ).second ) {
7850         // get nodes
7851         int iNode = 0, nbNodes = e->NbNodes();
7852         //const SMDS_MeshNode* nodes[nbNodes+1];
7853         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7854
7855         if(e->IsQuadratic()) {
7856           const SMDS_QuadraticFaceOfNodes* F =
7857             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7858           // use special nodes iterator
7859           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7860           while( anIter->more() ) {
7861             nodes[ iNode++ ] = anIter->next();
7862           }
7863         }
7864         else {
7865           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7866           while ( nIt->more() )
7867             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7868         }
7869         nodes[ iNode ] = nodes[ 0 ];
7870         // check 2 links
7871         for ( iNode = 0; iNode < nbNodes; iNode++ )
7872           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7873                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7874               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7875           {
7876             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7877             curElemList.push_back( e );
7878           }
7879       }
7880     }
7881     // analyse the found
7882
7883     int nbNewBorders = curElemList.size();
7884     if ( nbNewBorders == 0 ) {
7885       // no free border furthermore
7886       return !needTheLast;
7887     }
7888     else if ( nbNewBorders == 1 ) {
7889       // one more element found
7890       nIgnore = nStart;
7891       nStart = nStartList.front();
7892       curElem = curElemList.front();
7893       theFaces.push_back( curElem );
7894       theNodes.push_back( nStart );
7895     }
7896     else {
7897       // several continuations found
7898       list< const SMDS_MeshElement* >::iterator curElemIt;
7899       list< const SMDS_MeshNode* >::iterator nStartIt;
7900       // check if one of them reached the last node
7901       if ( needTheLast ) {
7902         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7903              curElemIt!= curElemList.end();
7904              curElemIt++, nStartIt++ )
7905           if ( *nStartIt == theLastNode ) {
7906             theFaces.push_back( *curElemIt );
7907             theNodes.push_back( *nStartIt );
7908             return true;
7909           }
7910       }
7911       // find the best free border by the continuations
7912       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7913       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7914       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7915            curElemIt!= curElemList.end();
7916            curElemIt++, nStartIt++ )
7917       {
7918         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7919         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7920         // find one more free border
7921         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7922           cNL->clear();
7923           cFL->clear();
7924         }
7925         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7926           // choice: clear a worse one
7927           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7928           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7929           contNodes[ iWorse ].clear();
7930           contFaces[ iWorse ].clear();
7931         }
7932       }
7933       if ( contNodes[0].empty() && contNodes[1].empty() )
7934         return false;
7935
7936       // append the best free border
7937       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7938       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7939       theNodes.pop_back(); // remove nIgnore
7940       theNodes.pop_back(); // remove nStart
7941       theFaces.pop_back(); // remove curElem
7942       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7943       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7944       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7945       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7946       return true;
7947
7948     } // several continuations found
7949   } // while ( nStart != theLastNode )
7950
7951   return true;
7952 }
7953
7954 //=======================================================================
7955 //function : CheckFreeBorderNodes
7956 //purpose  : Return true if the tree nodes are on a free border
7957 //=======================================================================
7958
7959 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7960                                             const SMDS_MeshNode* theNode2,
7961                                             const SMDS_MeshNode* theNode3)
7962 {
7963   list< const SMDS_MeshNode* > nodes;
7964   list< const SMDS_MeshElement* > faces;
7965   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7966 }
7967
7968 //=======================================================================
7969 //function : SewFreeBorder
7970 //purpose  :
7971 //=======================================================================
7972
7973 SMESH_MeshEditor::Sew_Error
7974 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7975                                  const SMDS_MeshNode* theBordSecondNode,
7976                                  const SMDS_MeshNode* theBordLastNode,
7977                                  const SMDS_MeshNode* theSideFirstNode,
7978                                  const SMDS_MeshNode* theSideSecondNode,
7979                                  const SMDS_MeshNode* theSideThirdNode,
7980                                  const bool           theSideIsFreeBorder,
7981                                  const bool           toCreatePolygons,
7982                                  const bool           toCreatePolyedrs)
7983 {
7984   myLastCreatedElems.Clear();
7985   myLastCreatedNodes.Clear();
7986
7987   MESSAGE("::SewFreeBorder()");
7988   Sew_Error aResult = SEW_OK;
7989
7990   // ====================================
7991   //    find side nodes and elements
7992   // ====================================
7993
7994   list< const SMDS_MeshNode* > nSide[ 2 ];
7995   list< const SMDS_MeshElement* > eSide[ 2 ];
7996   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7997   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7998
7999   // Free border 1
8000   // --------------
8001   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8002                       nSide[0], eSide[0])) {
8003     MESSAGE(" Free Border 1 not found " );
8004     aResult = SEW_BORDER1_NOT_FOUND;
8005   }
8006   if (theSideIsFreeBorder) {
8007     // Free border 2
8008     // --------------
8009     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8010                         nSide[1], eSide[1])) {
8011       MESSAGE(" Free Border 2 not found " );
8012       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8013     }
8014   }
8015   if ( aResult != SEW_OK )
8016     return aResult;
8017
8018   if (!theSideIsFreeBorder) {
8019     // Side 2
8020     // --------------
8021
8022     // -------------------------------------------------------------------------
8023     // Algo:
8024     // 1. If nodes to merge are not coincident, move nodes of the free border
8025     //    from the coord sys defined by the direction from the first to last
8026     //    nodes of the border to the correspondent sys of the side 2
8027     // 2. On the side 2, find the links most co-directed with the correspondent
8028     //    links of the free border
8029     // -------------------------------------------------------------------------
8030
8031     // 1. Since sewing may brake if there are volumes to split on the side 2,
8032     //    we wont move nodes but just compute new coordinates for them
8033     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8034     TNodeXYZMap nBordXYZ;
8035     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8036     list< const SMDS_MeshNode* >::iterator nBordIt;
8037
8038     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8039     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8040     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8041     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8042     double tol2 = 1.e-8;
8043     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8044     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8045       // Need node movement.
8046
8047       // find X and Z axes to create trsf
8048       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8049       gp_Vec X = Zs ^ Zb;
8050       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8051         // Zb || Zs
8052         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8053
8054       // coord systems
8055       gp_Ax3 toBordAx( Pb1, Zb, X );
8056       gp_Ax3 fromSideAx( Ps1, Zs, X );
8057       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8058       // set trsf
8059       gp_Trsf toBordSys, fromSide2Sys;
8060       toBordSys.SetTransformation( toBordAx );
8061       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8062       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8063
8064       // move
8065       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8066         const SMDS_MeshNode* n = *nBordIt;
8067         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8068         toBordSys.Transforms( xyz );
8069         fromSide2Sys.Transforms( xyz );
8070         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8071       }
8072     }
8073     else {
8074       // just insert nodes XYZ in the nBordXYZ map
8075       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8076         const SMDS_MeshNode* n = *nBordIt;
8077         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8078       }
8079     }
8080
8081     // 2. On the side 2, find the links most co-directed with the correspondent
8082     //    links of the free border
8083
8084     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8085     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8086     sideNodes.push_back( theSideFirstNode );
8087
8088     bool hasVolumes = false;
8089     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8090     set<long> foundSideLinkIDs, checkedLinkIDs;
8091     SMDS_VolumeTool volume;
8092     //const SMDS_MeshNode* faceNodes[ 4 ];
8093
8094     const SMDS_MeshNode*    sideNode;
8095     const SMDS_MeshElement* sideElem;
8096     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8097     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8098     nBordIt = bordNodes.begin();
8099     nBordIt++;
8100     // border node position and border link direction to compare with
8101     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8102     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8103     // choose next side node by link direction or by closeness to
8104     // the current border node:
8105     bool searchByDir = ( *nBordIt != theBordLastNode );
8106     do {
8107       // find the next node on the Side 2
8108       sideNode = 0;
8109       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8110       long linkID;
8111       checkedLinkIDs.clear();
8112       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8113
8114       // loop on inverse elements of current node (prevSideNode) on the Side 2
8115       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8116       while ( invElemIt->more() )
8117       {
8118         const SMDS_MeshElement* elem = invElemIt->next();
8119         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8120         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8121         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8122         bool isVolume = volume.Set( elem );
8123         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8124         if ( isVolume ) // --volume
8125           hasVolumes = true;
8126         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8127           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8128           if(elem->IsQuadratic()) {
8129             const SMDS_QuadraticFaceOfNodes* F =
8130               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8131             // use special nodes iterator
8132             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8133             while( anIter->more() ) {
8134               nodes[ iNode ] = anIter->next();
8135               if ( nodes[ iNode++ ] == prevSideNode )
8136                 iPrevNode = iNode - 1;
8137             }
8138           }
8139           else {
8140             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8141             while ( nIt->more() ) {
8142               nodes[ iNode ] = cast2Node( nIt->next() );
8143               if ( nodes[ iNode++ ] == prevSideNode )
8144                 iPrevNode = iNode - 1;
8145             }
8146           }
8147           // there are 2 links to check
8148           nbNodes = 2;
8149         }
8150         else // --edge
8151           continue;
8152         // loop on links, to be precise, on the second node of links
8153         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8154           const SMDS_MeshNode* n = nodes[ iNode ];
8155           if ( isVolume ) {
8156             if ( !volume.IsLinked( n, prevSideNode ))
8157               continue;
8158           }
8159           else {
8160             if ( iNode ) // a node before prevSideNode
8161               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8162             else         // a node after prevSideNode
8163               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8164           }
8165           // check if this link was already used
8166           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8167           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8168           if (!isJustChecked &&
8169               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8170           {
8171             // test a link geometrically
8172             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8173             bool linkIsBetter = false;
8174             double dot = 0.0, dist = 0.0;
8175             if ( searchByDir ) { // choose most co-directed link
8176               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8177               linkIsBetter = ( dot > maxDot );
8178             }
8179             else { // choose link with the node closest to bordPos
8180               dist = ( nextXYZ - bordPos ).SquareModulus();
8181               linkIsBetter = ( dist < minDist );
8182             }
8183             if ( linkIsBetter ) {
8184               maxDot = dot;
8185               minDist = dist;
8186               linkID = iLink;
8187               sideNode = n;
8188               sideElem = elem;
8189             }
8190           }
8191         }
8192       } // loop on inverse elements of prevSideNode
8193
8194       if ( !sideNode ) {
8195         MESSAGE(" Cant find path by links of the Side 2 ");
8196         return SEW_BAD_SIDE_NODES;
8197       }
8198       sideNodes.push_back( sideNode );
8199       sideElems.push_back( sideElem );
8200       foundSideLinkIDs.insert ( linkID );
8201       prevSideNode = sideNode;
8202
8203       if ( *nBordIt == theBordLastNode )
8204         searchByDir = false;
8205       else {
8206         // find the next border link to compare with
8207         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8208         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8209         // move to next border node if sideNode is before forward border node (bordPos)
8210         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8211           prevBordNode = *nBordIt;
8212           nBordIt++;
8213           bordPos = nBordXYZ[ *nBordIt ];
8214           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8215           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8216         }
8217       }
8218     }
8219     while ( sideNode != theSideSecondNode );
8220
8221     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8222       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8223       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8224     }
8225   } // end nodes search on the side 2
8226
8227   // ============================
8228   // sew the border to the side 2
8229   // ============================
8230
8231   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8232   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8233
8234   TListOfListOfNodes nodeGroupsToMerge;
8235   if ( nbNodes[0] == nbNodes[1] ||
8236        ( theSideIsFreeBorder && !theSideThirdNode)) {
8237
8238     // all nodes are to be merged
8239
8240     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8241          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8242          nIt[0]++, nIt[1]++ )
8243     {
8244       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8245       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8246       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8247     }
8248   }
8249   else {
8250
8251     // insert new nodes into the border and the side to get equal nb of segments
8252
8253     // get normalized parameters of nodes on the borders
8254     //double param[ 2 ][ maxNbNodes ];
8255     double* param[ 2 ];
8256     param[0] = new double [ maxNbNodes ];
8257     param[1] = new double [ maxNbNodes ];
8258     int iNode, iBord;
8259     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8260       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8261       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8262       const SMDS_MeshNode* nPrev = *nIt;
8263       double bordLength = 0;
8264       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8265         const SMDS_MeshNode* nCur = *nIt;
8266         gp_XYZ segment (nCur->X() - nPrev->X(),
8267                         nCur->Y() - nPrev->Y(),
8268                         nCur->Z() - nPrev->Z());
8269         double segmentLen = segment.Modulus();
8270         bordLength += segmentLen;
8271         param[ iBord ][ iNode ] = bordLength;
8272         nPrev = nCur;
8273       }
8274       // normalize within [0,1]
8275       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8276         param[ iBord ][ iNode ] /= bordLength;
8277       }
8278     }
8279
8280     // loop on border segments
8281     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8282     int i[ 2 ] = { 0, 0 };
8283     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8284     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8285
8286     TElemOfNodeListMap insertMap;
8287     TElemOfNodeListMap::iterator insertMapIt;
8288     // insertMap is
8289     // key:   elem to insert nodes into
8290     // value: 2 nodes to insert between + nodes to be inserted
8291     do {
8292       bool next[ 2 ] = { false, false };
8293
8294       // find min adjacent segment length after sewing
8295       double nextParam = 10., prevParam = 0;
8296       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8297         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8298           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8299         if ( i[ iBord ] > 0 )
8300           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8301       }
8302       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8303       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8304       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8305
8306       // choose to insert or to merge nodes
8307       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8308       if ( Abs( du ) <= minSegLen * 0.2 ) {
8309         // merge
8310         // ------
8311         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8312         const SMDS_MeshNode* n0 = *nIt[0];
8313         const SMDS_MeshNode* n1 = *nIt[1];
8314         nodeGroupsToMerge.back().push_back( n1 );
8315         nodeGroupsToMerge.back().push_back( n0 );
8316         // position of node of the border changes due to merge
8317         param[ 0 ][ i[0] ] += du;
8318         // move n1 for the sake of elem shape evaluation during insertion.
8319         // n1 will be removed by MergeNodes() anyway
8320         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8321         next[0] = next[1] = true;
8322       }
8323       else {
8324         // insert
8325         // ------
8326         int intoBord = ( du < 0 ) ? 0 : 1;
8327         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8328         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8329         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8330         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8331         if ( intoBord == 1 ) {
8332           // move node of the border to be on a link of elem of the side
8333           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8334           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8335           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8336           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8337           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8338         }
8339         insertMapIt = insertMap.find( elem );
8340         bool notFound = ( insertMapIt == insertMap.end() );
8341         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8342         if ( otherLink ) {
8343           // insert into another link of the same element:
8344           // 1. perform insertion into the other link of the elem
8345           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8346           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8347           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8348           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8349           // 2. perform insertion into the link of adjacent faces
8350           while (true) {
8351             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8352             if ( adjElem )
8353               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8354             else
8355               break;
8356           }
8357           if (toCreatePolyedrs) {
8358             // perform insertion into the links of adjacent volumes
8359             UpdateVolumes(n12, n22, nodeList);
8360           }
8361           // 3. find an element appeared on n1 and n2 after the insertion
8362           insertMap.erase( elem );
8363           elem = findAdjacentFace( n1, n2, 0 );
8364         }
8365         if ( notFound || otherLink ) {
8366           // add element and nodes of the side into the insertMap
8367           insertMapIt = insertMap.insert
8368             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8369           (*insertMapIt).second.push_back( n1 );
8370           (*insertMapIt).second.push_back( n2 );
8371         }
8372         // add node to be inserted into elem
8373         (*insertMapIt).second.push_back( nIns );
8374         next[ 1 - intoBord ] = true;
8375       }
8376
8377       // go to the next segment
8378       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8379         if ( next[ iBord ] ) {
8380           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8381             eIt[ iBord ]++;
8382           nPrev[ iBord ] = *nIt[ iBord ];
8383           nIt[ iBord ]++; i[ iBord ]++;
8384         }
8385       }
8386     }
8387     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8388
8389     // perform insertion of nodes into elements
8390
8391     for (insertMapIt = insertMap.begin();
8392          insertMapIt != insertMap.end();
8393          insertMapIt++ )
8394     {
8395       const SMDS_MeshElement* elem = (*insertMapIt).first;
8396       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8397       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8398       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8399
8400       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8401
8402       if ( !theSideIsFreeBorder ) {
8403         // look for and insert nodes into the faces adjacent to elem
8404         while (true) {
8405           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8406           if ( adjElem )
8407             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8408           else
8409             break;
8410         }
8411       }
8412       if (toCreatePolyedrs) {
8413         // perform insertion into the links of adjacent volumes
8414         UpdateVolumes(n1, n2, nodeList);
8415       }
8416     }
8417
8418     delete param[0];
8419     delete param[1];
8420   } // end: insert new nodes
8421
8422   MergeNodes ( nodeGroupsToMerge );
8423
8424   return aResult;
8425 }
8426
8427 //=======================================================================
8428 //function : InsertNodesIntoLink
8429 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8430 //           and theBetweenNode2 and split theElement
8431 //=======================================================================
8432
8433 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8434                                            const SMDS_MeshNode*        theBetweenNode1,
8435                                            const SMDS_MeshNode*        theBetweenNode2,
8436                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8437                                            const bool                  toCreatePoly)
8438 {
8439   if ( theFace->GetType() != SMDSAbs_Face ) return;
8440
8441   // find indices of 2 link nodes and of the rest nodes
8442   int iNode = 0, il1, il2, i3, i4;
8443   il1 = il2 = i3 = i4 = -1;
8444   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8445   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8446
8447   if(theFace->IsQuadratic()) {
8448     const SMDS_QuadraticFaceOfNodes* F =
8449       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8450     // use special nodes iterator
8451     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8452     while( anIter->more() ) {
8453       const SMDS_MeshNode* n = anIter->next();
8454       if ( n == theBetweenNode1 )
8455         il1 = iNode;
8456       else if ( n == theBetweenNode2 )
8457         il2 = iNode;
8458       else if ( i3 < 0 )
8459         i3 = iNode;
8460       else
8461         i4 = iNode;
8462       nodes[ iNode++ ] = n;
8463     }
8464   }
8465   else {
8466     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8467     while ( nodeIt->more() ) {
8468       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8469       if ( n == theBetweenNode1 )
8470         il1 = iNode;
8471       else if ( n == theBetweenNode2 )
8472         il2 = iNode;
8473       else if ( i3 < 0 )
8474         i3 = iNode;
8475       else
8476         i4 = iNode;
8477       nodes[ iNode++ ] = n;
8478     }
8479   }
8480   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8481     return ;
8482
8483   // arrange link nodes to go one after another regarding the face orientation
8484   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8485   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8486   if ( reverse ) {
8487     iNode = il1;
8488     il1 = il2;
8489     il2 = iNode;
8490     aNodesToInsert.reverse();
8491   }
8492   // check that not link nodes of a quadrangles are in good order
8493   int nbFaceNodes = theFace->NbNodes();
8494   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8495     iNode = i3;
8496     i3 = i4;
8497     i4 = iNode;
8498   }
8499
8500   if (toCreatePoly || theFace->IsPoly()) {
8501
8502     iNode = 0;
8503     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8504
8505     // add nodes of face up to first node of link
8506     bool isFLN = false;
8507
8508     if(theFace->IsQuadratic()) {
8509       const SMDS_QuadraticFaceOfNodes* F =
8510         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8511       // use special nodes iterator
8512       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8513       while( anIter->more()  && !isFLN ) {
8514         const SMDS_MeshNode* n = anIter->next();
8515         poly_nodes[iNode++] = n;
8516         if (n == nodes[il1]) {
8517           isFLN = true;
8518         }
8519       }
8520       // add nodes to insert
8521       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8522       for (; nIt != aNodesToInsert.end(); nIt++) {
8523         poly_nodes[iNode++] = *nIt;
8524       }
8525       // add nodes of face starting from last node of link
8526       while ( anIter->more() ) {
8527         poly_nodes[iNode++] = anIter->next();
8528       }
8529     }
8530     else {
8531       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8532       while ( nodeIt->more() && !isFLN ) {
8533         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8534         poly_nodes[iNode++] = n;
8535         if (n == nodes[il1]) {
8536           isFLN = true;
8537         }
8538       }
8539       // add nodes to insert
8540       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8541       for (; nIt != aNodesToInsert.end(); nIt++) {
8542         poly_nodes[iNode++] = *nIt;
8543       }
8544       // add nodes of face starting from last node of link
8545       while ( nodeIt->more() ) {
8546         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8547         poly_nodes[iNode++] = n;
8548       }
8549     }
8550
8551     // edit or replace the face
8552     SMESHDS_Mesh *aMesh = GetMeshDS();
8553
8554     if (theFace->IsPoly()) {
8555       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8556     }
8557     else {
8558       int aShapeId = FindShape( theFace );
8559
8560       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8561       myLastCreatedElems.Append(newElem);
8562       if ( aShapeId && newElem )
8563         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8564
8565       aMesh->RemoveElement(theFace);
8566     }
8567     return;
8568   }
8569
8570   if( !theFace->IsQuadratic() ) {
8571
8572     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8573     int nbLinkNodes = 2 + aNodesToInsert.size();
8574     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8575     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8576     linkNodes[ 0 ] = nodes[ il1 ];
8577     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8578     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8579     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8580       linkNodes[ iNode++ ] = *nIt;
8581     }
8582     // decide how to split a quadrangle: compare possible variants
8583     // and choose which of splits to be a quadrangle
8584     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8585     if ( nbFaceNodes == 3 ) {
8586       iBestQuad = nbSplits;
8587       i4 = i3;
8588     }
8589     else if ( nbFaceNodes == 4 ) {
8590       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8591       double aBestRate = DBL_MAX;
8592       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8593         i1 = 0; i2 = 1;
8594         double aBadRate = 0;
8595         // evaluate elements quality
8596         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8597           if ( iSplit == iQuad ) {
8598             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8599                                    linkNodes[ i2++ ],
8600                                    nodes[ i3 ],
8601                                    nodes[ i4 ]);
8602             aBadRate += getBadRate( &quad, aCrit );
8603           }
8604           else {
8605             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8606                                    linkNodes[ i2++ ],
8607                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8608             aBadRate += getBadRate( &tria, aCrit );
8609           }
8610         }
8611         // choice
8612         if ( aBadRate < aBestRate ) {
8613           iBestQuad = iQuad;
8614           aBestRate = aBadRate;
8615         }
8616       }
8617     }
8618
8619     // create new elements
8620     SMESHDS_Mesh *aMesh = GetMeshDS();
8621     int aShapeId = FindShape( theFace );
8622
8623     i1 = 0; i2 = 1;
8624     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8625       SMDS_MeshElement* newElem = 0;
8626       if ( iSplit == iBestQuad )
8627         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8628                                   linkNodes[ i2++ ],
8629                                   nodes[ i3 ],
8630                                   nodes[ i4 ]);
8631       else
8632         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8633                                   linkNodes[ i2++ ],
8634                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8635       myLastCreatedElems.Append(newElem);
8636       if ( aShapeId && newElem )
8637         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8638     }
8639
8640     // change nodes of theFace
8641     const SMDS_MeshNode* newNodes[ 4 ];
8642     newNodes[ 0 ] = linkNodes[ i1 ];
8643     newNodes[ 1 ] = linkNodes[ i2 ];
8644     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8645     newNodes[ 3 ] = nodes[ i4 ];
8646     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8647   } // end if(!theFace->IsQuadratic())
8648   else { // theFace is quadratic
8649     // we have to split theFace on simple triangles and one simple quadrangle
8650     int tmp = il1/2;
8651     int nbshift = tmp*2;
8652     // shift nodes in nodes[] by nbshift
8653     int i,j;
8654     for(i=0; i<nbshift; i++) {
8655       const SMDS_MeshNode* n = nodes[0];
8656       for(j=0; j<nbFaceNodes-1; j++) {
8657         nodes[j] = nodes[j+1];
8658       }
8659       nodes[nbFaceNodes-1] = n;
8660     }
8661     il1 = il1 - nbshift;
8662     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8663     //   n0      n1     n2    n0      n1     n2
8664     //     +-----+-----+        +-----+-----+
8665     //      \         /         |           |
8666     //       \       /          |           |
8667     //      n5+     +n3       n7+           +n3
8668     //         \   /            |           |
8669     //          \ /             |           |
8670     //           +              +-----+-----+
8671     //           n4           n6      n5     n4
8672
8673     // create new elements
8674     SMESHDS_Mesh *aMesh = GetMeshDS();
8675     int aShapeId = FindShape( theFace );
8676
8677     int n1,n2,n3;
8678     if(nbFaceNodes==6) { // quadratic triangle
8679       SMDS_MeshElement* newElem =
8680         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8681       myLastCreatedElems.Append(newElem);
8682       if ( aShapeId && newElem )
8683         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8684       if(theFace->IsMediumNode(nodes[il1])) {
8685         // create quadrangle
8686         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8687         myLastCreatedElems.Append(newElem);
8688         if ( aShapeId && newElem )
8689           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8690         n1 = 1;
8691         n2 = 2;
8692         n3 = 3;
8693       }
8694       else {
8695         // create quadrangle
8696         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8697         myLastCreatedElems.Append(newElem);
8698         if ( aShapeId && newElem )
8699           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8700         n1 = 0;
8701         n2 = 1;
8702         n3 = 5;
8703       }
8704     }
8705     else { // nbFaceNodes==8 - quadratic quadrangle
8706       SMDS_MeshElement* newElem =
8707         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8708       myLastCreatedElems.Append(newElem);
8709       if ( aShapeId && newElem )
8710         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8711       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8712       myLastCreatedElems.Append(newElem);
8713       if ( aShapeId && newElem )
8714         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8715       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8716       myLastCreatedElems.Append(newElem);
8717       if ( aShapeId && newElem )
8718         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8719       if(theFace->IsMediumNode(nodes[il1])) {
8720         // create quadrangle
8721         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8722         myLastCreatedElems.Append(newElem);
8723         if ( aShapeId && newElem )
8724           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8725         n1 = 1;
8726         n2 = 2;
8727         n3 = 3;
8728       }
8729       else {
8730         // create quadrangle
8731         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8732         myLastCreatedElems.Append(newElem);
8733         if ( aShapeId && newElem )
8734           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8735         n1 = 0;
8736         n2 = 1;
8737         n3 = 7;
8738       }
8739     }
8740     // create needed triangles using n1,n2,n3 and inserted nodes
8741     int nbn = 2 + aNodesToInsert.size();
8742     //const SMDS_MeshNode* aNodes[nbn];
8743     vector<const SMDS_MeshNode*> aNodes(nbn);
8744     aNodes[0] = nodes[n1];
8745     aNodes[nbn-1] = nodes[n2];
8746     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8747     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8748       aNodes[iNode++] = *nIt;
8749     }
8750     for(i=1; i<nbn; i++) {
8751       SMDS_MeshElement* newElem =
8752         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8753       myLastCreatedElems.Append(newElem);
8754       if ( aShapeId && newElem )
8755         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8756     }
8757     // remove old quadratic face
8758     aMesh->RemoveElement(theFace);
8759   }
8760 }
8761
8762 //=======================================================================
8763 //function : UpdateVolumes
8764 //purpose  :
8765 //=======================================================================
8766 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8767                                       const SMDS_MeshNode*        theBetweenNode2,
8768                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8769 {
8770   myLastCreatedElems.Clear();
8771   myLastCreatedNodes.Clear();
8772
8773   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8774   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8775     const SMDS_MeshElement* elem = invElemIt->next();
8776
8777     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8778     SMDS_VolumeTool aVolume (elem);
8779     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8780       continue;
8781
8782     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8783     int iface, nbFaces = aVolume.NbFaces();
8784     vector<const SMDS_MeshNode *> poly_nodes;
8785     vector<int> quantities (nbFaces);
8786
8787     for (iface = 0; iface < nbFaces; iface++) {
8788       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8789       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8790       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8791
8792       for (int inode = 0; inode < nbFaceNodes; inode++) {
8793         poly_nodes.push_back(faceNodes[inode]);
8794
8795         if (nbInserted == 0) {
8796           if (faceNodes[inode] == theBetweenNode1) {
8797             if (faceNodes[inode + 1] == theBetweenNode2) {
8798               nbInserted = theNodesToInsert.size();
8799
8800               // add nodes to insert
8801               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8802               for (; nIt != theNodesToInsert.end(); nIt++) {
8803                 poly_nodes.push_back(*nIt);
8804               }
8805             }
8806           }
8807           else if (faceNodes[inode] == theBetweenNode2) {
8808             if (faceNodes[inode + 1] == theBetweenNode1) {
8809               nbInserted = theNodesToInsert.size();
8810
8811               // add nodes to insert in reversed order
8812               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8813               nIt--;
8814               for (; nIt != theNodesToInsert.begin(); nIt--) {
8815                 poly_nodes.push_back(*nIt);
8816               }
8817               poly_nodes.push_back(*nIt);
8818             }
8819           }
8820           else {
8821           }
8822         }
8823       }
8824       quantities[iface] = nbFaceNodes + nbInserted;
8825     }
8826
8827     // Replace or update the volume
8828     SMESHDS_Mesh *aMesh = GetMeshDS();
8829
8830     if (elem->IsPoly()) {
8831       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8832
8833     }
8834     else {
8835       int aShapeId = FindShape( elem );
8836
8837       SMDS_MeshElement* newElem =
8838         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8839       myLastCreatedElems.Append(newElem);
8840       if (aShapeId && newElem)
8841         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8842
8843       aMesh->RemoveElement(elem);
8844     }
8845   }
8846 }
8847
8848 //=======================================================================
8849 /*!
8850  * \brief Convert elements contained in a submesh to quadratic
8851  * \retval int - nb of checked elements
8852  */
8853 //=======================================================================
8854
8855 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8856                                              SMESH_MesherHelper& theHelper,
8857                                              const bool          theForce3d)
8858 {
8859   int nbElem = 0;
8860   if( !theSm ) return nbElem;
8861
8862   const bool notFromGroups = false;
8863   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8864   while(ElemItr->more())
8865   {
8866     nbElem++;
8867     const SMDS_MeshElement* elem = ElemItr->next();
8868     if( !elem || elem->IsQuadratic() ) continue;
8869
8870     int id = elem->GetID();
8871     int nbNodes = elem->NbNodes();
8872     vector<const SMDS_MeshNode *> aNds (nbNodes);
8873
8874     for(int i = 0; i < nbNodes; i++)
8875     {
8876       aNds[i] = elem->GetNode(i);
8877     }
8878     SMDSAbs_ElementType aType = elem->GetType();
8879
8880     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8881
8882     const SMDS_MeshElement* NewElem = 0;
8883
8884     switch( aType )
8885     {
8886     case SMDSAbs_Edge :
8887       {
8888         NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8889         break;
8890       }
8891     case SMDSAbs_Face :
8892       {
8893         switch(nbNodes)
8894         {
8895         case 3:
8896           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8897           break;
8898         case 4:
8899           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8900           break;
8901         default:
8902           continue;
8903         }
8904         break;
8905       }
8906     case SMDSAbs_Volume :
8907       {
8908         switch(nbNodes)
8909         {
8910         case 4:
8911           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8912           break;
8913         case 5:
8914           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8915           break;
8916         case 6:
8917           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8918           break;
8919         case 8:
8920           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8921                                         aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8922           break;
8923         default:
8924           continue;
8925         }
8926         break;
8927       }
8928     default :
8929       continue;
8930     }
8931     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8932     if( NewElem )
8933       theSm->AddElement( NewElem );
8934   }
8935   return nbElem;
8936 }
8937
8938 //=======================================================================
8939 //function : ConvertToQuadratic
8940 //purpose  :
8941 //=======================================================================
8942 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8943 {
8944   SMESHDS_Mesh* meshDS = GetMeshDS();
8945
8946   SMESH_MesherHelper aHelper(*myMesh);
8947   aHelper.SetIsQuadratic( true );
8948   const bool notFromGroups = false;
8949
8950   int nbCheckedElems = 0;
8951   if ( myMesh->HasShapeToMesh() )
8952   {
8953     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8954     {
8955       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8956       while ( smIt->more() ) {
8957         SMESH_subMesh* sm = smIt->next();
8958         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8959           aHelper.SetSubShape( sm->GetSubShape() );
8960           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8961         }
8962       }
8963     }
8964   }
8965   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8966   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8967   {
8968     SMESHDS_SubMesh *smDS = 0;
8969     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8970     while(aEdgeItr->more())
8971     {
8972       const SMDS_MeshEdge* edge = aEdgeItr->next();
8973       if(edge && !edge->IsQuadratic())
8974       {
8975         int id = edge->GetID();
8976         const SMDS_MeshNode* n1 = edge->GetNode(0);
8977         const SMDS_MeshNode* n2 = edge->GetNode(1);
8978
8979         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8980
8981         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8982         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8983       }
8984     }
8985     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8986     while(aFaceItr->more())
8987     {
8988       const SMDS_MeshFace* face = aFaceItr->next();
8989       if(!face || face->IsQuadratic() ) continue;
8990
8991       int id = face->GetID();
8992       int nbNodes = face->NbNodes();
8993       vector<const SMDS_MeshNode *> aNds (nbNodes);
8994
8995       for(int i = 0; i < nbNodes; i++)
8996       {
8997         aNds[i] = face->GetNode(i);
8998       }
8999
9000       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9001
9002       SMDS_MeshFace * NewFace = 0;
9003       switch(nbNodes)
9004       {
9005       case 3:
9006         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9007         break;
9008       case 4:
9009         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9010         break;
9011       default:
9012         continue;
9013       }
9014       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9015     }
9016     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9017     while(aVolumeItr->more())
9018     {
9019       const SMDS_MeshVolume* volume = aVolumeItr->next();
9020       if(!volume || volume->IsQuadratic() ) continue;
9021
9022       int id = volume->GetID();
9023       int nbNodes = volume->NbNodes();
9024       vector<const SMDS_MeshNode *> aNds (nbNodes);
9025
9026       for(int i = 0; i < nbNodes; i++)
9027       {
9028         aNds[i] = volume->GetNode(i);
9029       }
9030
9031       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9032
9033       SMDS_MeshVolume * NewVolume = 0;
9034       switch(nbNodes)
9035       {
9036       case 4:
9037         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9038                                       aNds[3], id, theForce3d );
9039         break;
9040       case 5:
9041         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9042                                       aNds[3], aNds[4], id, theForce3d);
9043         break;
9044       case 6:
9045         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9046                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
9047         break;
9048       case 8:
9049         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9050                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9051         break;
9052       default:
9053         continue;
9054       }
9055       ReplaceElemInGroups(volume, NewVolume, meshDS);
9056     }
9057   }
9058   if ( !theForce3d ) {
9059     aHelper.SetSubShape(0); // apply to the whole mesh
9060     aHelper.FixQuadraticElements();
9061   }
9062 }
9063
9064 //=======================================================================
9065 /*!
9066  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9067  * \retval int - nb of checked elements
9068  */
9069 //=======================================================================
9070
9071 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9072                                      SMDS_ElemIteratorPtr theItr,
9073                                      const int            theShapeID)
9074 {
9075   int nbElem = 0;
9076   SMESHDS_Mesh* meshDS = GetMeshDS();
9077   const bool notFromGroups = false;
9078
9079   while( theItr->more() )
9080   {
9081     const SMDS_MeshElement* elem = theItr->next();
9082     nbElem++;
9083     if( elem && elem->IsQuadratic())
9084     {
9085       int id = elem->GetID();
9086       int nbNodes = elem->NbNodes();
9087       vector<const SMDS_MeshNode *> aNds, mediumNodes;
9088       aNds.reserve( nbNodes );
9089       mediumNodes.reserve( nbNodes );
9090
9091       for(int i = 0; i < nbNodes; i++)
9092       {
9093         const SMDS_MeshNode* n = elem->GetNode(i);
9094
9095         if( elem->IsMediumNode( n ) )
9096           mediumNodes.push_back( n );
9097         else
9098           aNds.push_back( n );
9099       }
9100       if( aNds.empty() ) continue;
9101       SMDSAbs_ElementType aType = elem->GetType();
9102
9103       //remove old quadratic element
9104       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9105
9106       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9107       ReplaceElemInGroups(elem, NewElem, meshDS);
9108       if( theSm && NewElem )
9109         theSm->AddElement( NewElem );
9110
9111       // remove medium nodes
9112       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9113       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9114         const SMDS_MeshNode* n = *nIt;
9115         if ( n->NbInverseElements() == 0 ) {
9116           if ( n->GetPosition()->GetShapeId() != theShapeID )
9117             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9118                                     ( n->GetPosition()->GetShapeId() ));
9119           else
9120             meshDS->RemoveFreeNode( n, theSm );
9121         }
9122       }
9123     }
9124   }
9125   return nbElem;
9126 }
9127
9128 //=======================================================================
9129 //function : ConvertFromQuadratic
9130 //purpose  :
9131 //=======================================================================
9132 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9133 {
9134   int nbCheckedElems = 0;
9135   if ( myMesh->HasShapeToMesh() )
9136   {
9137     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9138     {
9139       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9140       while ( smIt->more() ) {
9141         SMESH_subMesh* sm = smIt->next();
9142         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9143           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9144       }
9145     }
9146   }
9147
9148   int totalNbElems =
9149     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9150   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9151   {
9152     SMESHDS_SubMesh *aSM = 0;
9153     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9154   }
9155
9156   return true;
9157 }
9158
9159 //=======================================================================
9160 //function : SewSideElements
9161 //purpose  :
9162 //=======================================================================
9163
9164 SMESH_MeshEditor::Sew_Error
9165 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9166                                    TIDSortedElemSet&    theSide2,
9167                                    const SMDS_MeshNode* theFirstNode1,
9168                                    const SMDS_MeshNode* theFirstNode2,
9169                                    const SMDS_MeshNode* theSecondNode1,
9170                                    const SMDS_MeshNode* theSecondNode2)
9171 {
9172   myLastCreatedElems.Clear();
9173   myLastCreatedNodes.Clear();
9174
9175   MESSAGE ("::::SewSideElements()");
9176   if ( theSide1.size() != theSide2.size() )
9177     return SEW_DIFF_NB_OF_ELEMENTS;
9178
9179   Sew_Error aResult = SEW_OK;
9180   // Algo:
9181   // 1. Build set of faces representing each side
9182   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9183   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9184
9185   // =======================================================================
9186   // 1. Build set of faces representing each side:
9187   // =======================================================================
9188   // a. build set of nodes belonging to faces
9189   // b. complete set of faces: find missing fices whose nodes are in set of nodes
9190   // c. create temporary faces representing side of volumes if correspondent
9191   //    face does not exist
9192
9193   SMESHDS_Mesh* aMesh = GetMeshDS();
9194   SMDS_Mesh aTmpFacesMesh;
9195   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9196   set<const SMDS_MeshElement*> volSet1,  volSet2;
9197   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9198   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9199   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9200   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9201   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9202   int iSide, iFace, iNode;
9203
9204   for ( iSide = 0; iSide < 2; iSide++ ) {
9205     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9206     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9207     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9208     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9209     set<const SMDS_MeshElement*>::iterator vIt;
9210     TIDSortedElemSet::iterator eIt;
9211     set<const SMDS_MeshNode*>::iterator    nIt;
9212
9213     // check that given nodes belong to given elements
9214     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9215     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9216     int firstIndex = -1, secondIndex = -1;
9217     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9218       const SMDS_MeshElement* elem = *eIt;
9219       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9220       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9221       if ( firstIndex > -1 && secondIndex > -1 ) break;
9222     }
9223     if ( firstIndex < 0 || secondIndex < 0 ) {
9224       // we can simply return until temporary faces created
9225       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9226     }
9227
9228     // -----------------------------------------------------------
9229     // 1a. Collect nodes of existing faces
9230     //     and build set of face nodes in order to detect missing
9231     //     faces corresponing to sides of volumes
9232     // -----------------------------------------------------------
9233
9234     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9235
9236     // loop on the given element of a side
9237     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9238       //const SMDS_MeshElement* elem = *eIt;
9239       const SMDS_MeshElement* elem = *eIt;
9240       if ( elem->GetType() == SMDSAbs_Face ) {
9241         faceSet->insert( elem );
9242         set <const SMDS_MeshNode*> faceNodeSet;
9243         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9244         while ( nodeIt->more() ) {
9245           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9246           nodeSet->insert( n );
9247           faceNodeSet.insert( n );
9248         }
9249         setOfFaceNodeSet.insert( faceNodeSet );
9250       }
9251       else if ( elem->GetType() == SMDSAbs_Volume )
9252         volSet->insert( elem );
9253     }
9254     // ------------------------------------------------------------------------------
9255     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9256     // ------------------------------------------------------------------------------
9257
9258     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9259       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9260       while ( fIt->more() ) { // loop on faces sharing a node
9261         const SMDS_MeshElement* f = fIt->next();
9262         if ( faceSet->find( f ) == faceSet->end() ) {
9263           // check if all nodes are in nodeSet and
9264           // complete setOfFaceNodeSet if they are
9265           set <const SMDS_MeshNode*> faceNodeSet;
9266           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9267           bool allInSet = true;
9268           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9269             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9270             if ( nodeSet->find( n ) == nodeSet->end() )
9271               allInSet = false;
9272             else
9273               faceNodeSet.insert( n );
9274           }
9275           if ( allInSet ) {
9276             faceSet->insert( f );
9277             setOfFaceNodeSet.insert( faceNodeSet );
9278           }
9279         }
9280       }
9281     }
9282
9283     // -------------------------------------------------------------------------
9284     // 1c. Create temporary faces representing sides of volumes if correspondent
9285     //     face does not exist
9286     // -------------------------------------------------------------------------
9287
9288     if ( !volSet->empty() ) {
9289       //int nodeSetSize = nodeSet->size();
9290
9291       // loop on given volumes
9292       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9293         SMDS_VolumeTool vol (*vIt);
9294         // loop on volume faces: find free faces
9295         // --------------------------------------
9296         list<const SMDS_MeshElement* > freeFaceList;
9297         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9298           if ( !vol.IsFreeFace( iFace ))
9299             continue;
9300           // check if there is already a face with same nodes in a face set
9301           const SMDS_MeshElement* aFreeFace = 0;
9302           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9303           int nbNodes = vol.NbFaceNodes( iFace );
9304           set <const SMDS_MeshNode*> faceNodeSet;
9305           vol.GetFaceNodes( iFace, faceNodeSet );
9306           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9307           if ( isNewFace ) {
9308             // no such a face is given but it still can exist, check it
9309             if ( nbNodes == 3 ) {
9310               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9311             }
9312             else if ( nbNodes == 4 ) {
9313               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9314             }
9315             else {
9316               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9317               aFreeFace = aMesh->FindFace(poly_nodes);
9318             }
9319           }
9320           if ( !aFreeFace ) {
9321             // create a temporary face
9322             if ( nbNodes == 3 ) {
9323               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9324             }
9325             else if ( nbNodes == 4 ) {
9326               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9327             }
9328             else {
9329               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9330               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9331             }
9332           }
9333           if ( aFreeFace )
9334             freeFaceList.push_back( aFreeFace );
9335
9336         } // loop on faces of a volume
9337
9338         // choose one of several free faces
9339         // --------------------------------------
9340         if ( freeFaceList.size() > 1 ) {
9341           // choose a face having max nb of nodes shared by other elems of a side
9342           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9343           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9344           while ( fIt != freeFaceList.end() ) { // loop on free faces
9345             int nbSharedNodes = 0;
9346             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9347             while ( nodeIt->more() ) { // loop on free face nodes
9348               const SMDS_MeshNode* n =
9349                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9350               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9351               while ( invElemIt->more() ) {
9352                 const SMDS_MeshElement* e = invElemIt->next();
9353                 if ( faceSet->find( e ) != faceSet->end() )
9354                   nbSharedNodes++;
9355                 if ( elemSet->find( e ) != elemSet->end() )
9356                   nbSharedNodes++;
9357               }
9358             }
9359             if ( nbSharedNodes >= maxNbNodes ) {
9360               maxNbNodes = nbSharedNodes;
9361               fIt++;
9362             }
9363             else
9364               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9365           }
9366           if ( freeFaceList.size() > 1 )
9367           {
9368             // could not choose one face, use another way
9369             // choose a face most close to the bary center of the opposite side
9370             gp_XYZ aBC( 0., 0., 0. );
9371             set <const SMDS_MeshNode*> addedNodes;
9372             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9373             eIt = elemSet2->begin();
9374             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9375               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9376               while ( nodeIt->more() ) { // loop on free face nodes
9377                 const SMDS_MeshNode* n =
9378                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9379                 if ( addedNodes.insert( n ).second )
9380                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9381               }
9382             }
9383             aBC /= addedNodes.size();
9384             double minDist = DBL_MAX;
9385             fIt = freeFaceList.begin();
9386             while ( fIt != freeFaceList.end() ) { // loop on free faces
9387               double dist = 0;
9388               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9389               while ( nodeIt->more() ) { // loop on free face nodes
9390                 const SMDS_MeshNode* n =
9391                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9392                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9393                 dist += ( aBC - p ).SquareModulus();
9394               }
9395               if ( dist < minDist ) {
9396                 minDist = dist;
9397                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9398               }
9399               else
9400                 fIt = freeFaceList.erase( fIt++ );
9401             }
9402           }
9403         } // choose one of several free faces of a volume
9404
9405         if ( freeFaceList.size() == 1 ) {
9406           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9407           faceSet->insert( aFreeFace );
9408           // complete a node set with nodes of a found free face
9409           //           for ( iNode = 0; iNode < ; iNode++ )
9410           //             nodeSet->insert( fNodes[ iNode ] );
9411         }
9412
9413       } // loop on volumes of a side
9414
9415       //       // complete a set of faces if new nodes in a nodeSet appeared
9416       //       // ----------------------------------------------------------
9417       //       if ( nodeSetSize != nodeSet->size() ) {
9418       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9419       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9420       //           while ( fIt->more() ) { // loop on faces sharing a node
9421       //             const SMDS_MeshElement* f = fIt->next();
9422       //             if ( faceSet->find( f ) == faceSet->end() ) {
9423       //               // check if all nodes are in nodeSet and
9424       //               // complete setOfFaceNodeSet if they are
9425       //               set <const SMDS_MeshNode*> faceNodeSet;
9426       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9427       //               bool allInSet = true;
9428       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9429       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9430       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9431       //                   allInSet = false;
9432       //                 else
9433       //                   faceNodeSet.insert( n );
9434       //               }
9435       //               if ( allInSet ) {
9436       //                 faceSet->insert( f );
9437       //                 setOfFaceNodeSet.insert( faceNodeSet );
9438       //               }
9439       //             }
9440       //           }
9441       //         }
9442       //       }
9443     } // Create temporary faces, if there are volumes given
9444   } // loop on sides
9445
9446   if ( faceSet1.size() != faceSet2.size() ) {
9447     // delete temporary faces: they are in reverseElements of actual nodes
9448     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9449     while ( tmpFaceIt->more() )
9450       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9451     MESSAGE("Diff nb of faces");
9452     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9453   }
9454
9455   // ============================================================
9456   // 2. Find nodes to merge:
9457   //              bind a node to remove to a node to put instead
9458   // ============================================================
9459
9460   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9461   if ( theFirstNode1 != theFirstNode2 )
9462     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9463   if ( theSecondNode1 != theSecondNode2 )
9464     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9465
9466   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9467   set< long > linkIdSet; // links to process
9468   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9469
9470   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9471   list< NLink > linkList[2];
9472   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9473   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9474   // loop on links in linkList; find faces by links and append links
9475   // of the found faces to linkList
9476   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9477   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9478     NLink link[] = { *linkIt[0], *linkIt[1] };
9479     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9480     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9481       continue;
9482
9483     // by links, find faces in the face sets,
9484     // and find indices of link nodes in the found faces;
9485     // in a face set, there is only one or no face sharing a link
9486     // ---------------------------------------------------------------
9487
9488     const SMDS_MeshElement* face[] = { 0, 0 };
9489     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9490     vector<const SMDS_MeshNode*> fnodes1(9);
9491     vector<const SMDS_MeshNode*> fnodes2(9);
9492     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9493     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9494     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9495     int iLinkNode[2][2];
9496     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9497       const SMDS_MeshNode* n1 = link[iSide].first;
9498       const SMDS_MeshNode* n2 = link[iSide].second;
9499       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9500       set< const SMDS_MeshElement* > fMap;
9501       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9502         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9503         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9504         while ( fIt->more() ) { // loop on faces sharing a node
9505           const SMDS_MeshElement* f = fIt->next();
9506           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9507               ! fMap.insert( f ).second ) // f encounters twice
9508           {
9509             if ( face[ iSide ] ) {
9510               MESSAGE( "2 faces per link " );
9511               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9512               break;
9513             }
9514             face[ iSide ] = f;
9515             faceSet->erase( f );
9516             // get face nodes and find ones of a link
9517             iNode = 0;
9518             int nbl = -1;
9519             if(f->IsPoly()) {
9520               if(iSide==0) {
9521                 fnodes1.resize(f->NbNodes()+1);
9522                 notLinkNodes1.resize(f->NbNodes()-2);
9523               }
9524               else {
9525                 fnodes2.resize(f->NbNodes()+1);
9526                 notLinkNodes2.resize(f->NbNodes()-2);
9527               }
9528             }
9529             if(!f->IsQuadratic()) {
9530               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9531               while ( nIt->more() ) {
9532                 const SMDS_MeshNode* n =
9533                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9534                 if ( n == n1 ) {
9535                   iLinkNode[ iSide ][ 0 ] = iNode;
9536                 }
9537                 else if ( n == n2 ) {
9538                   iLinkNode[ iSide ][ 1 ] = iNode;
9539                 }
9540                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9541                 //  notLinkNodes[ iSide ][ 1 ] = n;
9542                 //else
9543                 //  notLinkNodes[ iSide ][ 0 ] = n;
9544                 else {
9545                   nbl++;
9546                   if(iSide==0)
9547                     notLinkNodes1[nbl] = n;
9548                   //notLinkNodes1.push_back(n);
9549                   else
9550                     notLinkNodes2[nbl] = n;
9551                   //notLinkNodes2.push_back(n);
9552                 }
9553                 //faceNodes[ iSide ][ iNode++ ] = n;
9554                 if(iSide==0) {
9555                   fnodes1[iNode++] = n;
9556                 }
9557                 else {
9558                   fnodes2[iNode++] = n;
9559                 }
9560               }
9561             }
9562             else { // f->IsQuadratic()
9563               const SMDS_QuadraticFaceOfNodes* F =
9564                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9565               // use special nodes iterator
9566               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9567               while ( anIter->more() ) {
9568                 const SMDS_MeshNode* n =
9569                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9570                 if ( n == n1 ) {
9571                   iLinkNode[ iSide ][ 0 ] = iNode;
9572                 }
9573                 else if ( n == n2 ) {
9574                   iLinkNode[ iSide ][ 1 ] = iNode;
9575                 }
9576                 else {
9577                   nbl++;
9578                   if(iSide==0) {
9579                     notLinkNodes1[nbl] = n;
9580                   }
9581                   else {
9582                     notLinkNodes2[nbl] = n;
9583                   }
9584                 }
9585                 if(iSide==0) {
9586                   fnodes1[iNode++] = n;
9587                 }
9588                 else {
9589                   fnodes2[iNode++] = n;
9590                 }
9591               }
9592             }
9593             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9594             if(iSide==0) {
9595               fnodes1[iNode] = fnodes1[0];
9596             }
9597             else {
9598               fnodes2[iNode] = fnodes1[0];
9599             }
9600           }
9601         }
9602       }
9603     }
9604
9605     // check similarity of elements of the sides
9606     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9607       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9608       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9609         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9610       }
9611       else {
9612         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9613       }
9614       break; // do not return because it s necessary to remove tmp faces
9615     }
9616
9617     // set nodes to merge
9618     // -------------------
9619
9620     if ( face[0] && face[1] )  {
9621       int nbNodes = face[0]->NbNodes();
9622       if ( nbNodes != face[1]->NbNodes() ) {
9623         MESSAGE("Diff nb of face nodes");
9624         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9625         break; // do not return because it s necessary to remove tmp faces
9626       }
9627       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9628       if ( nbNodes == 3 ) {
9629         //nReplaceMap.insert( TNodeNodeMap::value_type
9630         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9631         nReplaceMap.insert( TNodeNodeMap::value_type
9632                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9633       }
9634       else {
9635         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9636           // analyse link orientation in faces
9637           int i1 = iLinkNode[ iSide ][ 0 ];
9638           int i2 = iLinkNode[ iSide ][ 1 ];
9639           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9640           // if notLinkNodes are the first and the last ones, then
9641           // their order does not correspond to the link orientation
9642           if (( i1 == 1 && i2 == 2 ) ||
9643               ( i1 == 2 && i2 == 1 ))
9644             reverse[ iSide ] = !reverse[ iSide ];
9645         }
9646         if ( reverse[0] == reverse[1] ) {
9647           //nReplaceMap.insert( TNodeNodeMap::value_type
9648           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9649           //nReplaceMap.insert( TNodeNodeMap::value_type
9650           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9651           for(int nn=0; nn<nbNodes-2; nn++) {
9652             nReplaceMap.insert( TNodeNodeMap::value_type
9653                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9654           }
9655         }
9656         else {
9657           //nReplaceMap.insert( TNodeNodeMap::value_type
9658           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9659           //nReplaceMap.insert( TNodeNodeMap::value_type
9660           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9661           for(int nn=0; nn<nbNodes-2; nn++) {
9662             nReplaceMap.insert( TNodeNodeMap::value_type
9663                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9664           }
9665         }
9666       }
9667
9668       // add other links of the faces to linkList
9669       // -----------------------------------------
9670
9671       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9672       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9673         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9674         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9675         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9676         if ( !iter_isnew.second ) { // already in a set: no need to process
9677           linkIdSet.erase( iter_isnew.first );
9678         }
9679         else // new in set == encountered for the first time: add
9680         {
9681           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9682           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9683           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9684           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9685           linkList[0].push_back ( NLink( n1, n2 ));
9686           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9687         }
9688       }
9689     } // 2 faces found
9690   } // loop on link lists
9691
9692   if ( aResult == SEW_OK &&
9693        ( linkIt[0] != linkList[0].end() ||
9694          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9695     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9696              " " << (faceSetPtr[1]->empty()));
9697     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9698   }
9699
9700   // ====================================================================
9701   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9702   // ====================================================================
9703
9704   // delete temporary faces: they are in reverseElements of actual nodes
9705   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9706   while ( tmpFaceIt->more() )
9707     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9708
9709   if ( aResult != SEW_OK)
9710     return aResult;
9711
9712   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9713   // loop on nodes replacement map
9714   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9715   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9716     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9717       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9718       nodeIDsToRemove.push_back( nToRemove->GetID() );
9719       // loop on elements sharing nToRemove
9720       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9721       while ( invElemIt->more() ) {
9722         const SMDS_MeshElement* e = invElemIt->next();
9723         // get a new suite of nodes: make replacement
9724         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9725         vector< const SMDS_MeshNode*> nodes( nbNodes );
9726         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9727         while ( nIt->more() ) {
9728           const SMDS_MeshNode* n =
9729             static_cast<const SMDS_MeshNode*>( nIt->next() );
9730           nnIt = nReplaceMap.find( n );
9731           if ( nnIt != nReplaceMap.end() ) {
9732             nbReplaced++;
9733             n = (*nnIt).second;
9734           }
9735           nodes[ i++ ] = n;
9736         }
9737         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9738         //         elemIDsToRemove.push_back( e->GetID() );
9739         //       else
9740         if ( nbReplaced )
9741           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9742       }
9743     }
9744
9745   Remove( nodeIDsToRemove, true );
9746
9747   return aResult;
9748 }
9749
9750 //================================================================================
9751 /*!
9752  * \brief Find corresponding nodes in two sets of faces
9753  * \param theSide1 - first face set
9754  * \param theSide2 - second first face
9755  * \param theFirstNode1 - a boundary node of set 1
9756  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9757  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9758  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9759  * \param nReplaceMap - output map of corresponding nodes
9760  * \retval bool  - is a success or not
9761  */
9762 //================================================================================
9763
9764 #ifdef _DEBUG_
9765 //#define DEBUG_MATCHING_NODES
9766 #endif
9767
9768 SMESH_MeshEditor::Sew_Error
9769 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9770                                     set<const SMDS_MeshElement*>& theSide2,
9771                                     const SMDS_MeshNode*          theFirstNode1,
9772                                     const SMDS_MeshNode*          theFirstNode2,
9773                                     const SMDS_MeshNode*          theSecondNode1,
9774                                     const SMDS_MeshNode*          theSecondNode2,
9775                                     TNodeNodeMap &                nReplaceMap)
9776 {
9777   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9778
9779   nReplaceMap.clear();
9780   if ( theFirstNode1 != theFirstNode2 )
9781     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9782   if ( theSecondNode1 != theSecondNode2 )
9783     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9784
9785   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9786   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9787
9788   list< NLink > linkList[2];
9789   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9790   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9791
9792   // loop on links in linkList; find faces by links and append links
9793   // of the found faces to linkList
9794   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9795   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9796     NLink link[] = { *linkIt[0], *linkIt[1] };
9797     if ( linkSet.find( link[0] ) == linkSet.end() )
9798       continue;
9799
9800     // by links, find faces in the face sets,
9801     // and find indices of link nodes in the found faces;
9802     // in a face set, there is only one or no face sharing a link
9803     // ---------------------------------------------------------------
9804
9805     const SMDS_MeshElement* face[] = { 0, 0 };
9806     list<const SMDS_MeshNode*> notLinkNodes[2];
9807     //bool reverse[] = { false, false }; // order of notLinkNodes
9808     int nbNodes[2];
9809     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9810     {
9811       const SMDS_MeshNode* n1 = link[iSide].first;
9812       const SMDS_MeshNode* n2 = link[iSide].second;
9813       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9814       set< const SMDS_MeshElement* > facesOfNode1;
9815       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9816       {
9817         // during a loop of the first node, we find all faces around n1,
9818         // during a loop of the second node, we find one face sharing both n1 and n2
9819         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9820         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9821         while ( fIt->more() ) { // loop on faces sharing a node
9822           const SMDS_MeshElement* f = fIt->next();
9823           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9824               ! facesOfNode1.insert( f ).second ) // f encounters twice
9825           {
9826             if ( face[ iSide ] ) {
9827               MESSAGE( "2 faces per link " );
9828               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9829             }
9830             face[ iSide ] = f;
9831             faceSet->erase( f );
9832
9833             // get not link nodes
9834             int nbN = f->NbNodes();
9835             if ( f->IsQuadratic() )
9836               nbN /= 2;
9837             nbNodes[ iSide ] = nbN;
9838             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9839             int i1 = f->GetNodeIndex( n1 );
9840             int i2 = f->GetNodeIndex( n2 );
9841             int iEnd = nbN, iBeg = -1, iDelta = 1;
9842             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9843             if ( reverse ) {
9844               std::swap( iEnd, iBeg ); iDelta = -1;
9845             }
9846             int i = i2;
9847             while ( true ) {
9848               i += iDelta;
9849               if ( i == iEnd ) i = iBeg + iDelta;
9850               if ( i == i1 ) break;
9851               nodes.push_back ( f->GetNode( i ) );
9852             }
9853           }
9854         }
9855       }
9856     }
9857     // check similarity of elements of the sides
9858     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9859       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9860       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9861         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9862       }
9863       else {
9864         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9865       }
9866     }
9867
9868     // set nodes to merge
9869     // -------------------
9870
9871     if ( face[0] && face[1] )  {
9872       if ( nbNodes[0] != nbNodes[1] ) {
9873         MESSAGE("Diff nb of face nodes");
9874         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9875       }
9876 #ifdef DEBUG_MATCHING_NODES
9877       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9878                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9879                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9880 #endif
9881       int nbN = nbNodes[0];
9882       {
9883         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9884         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9885         for ( int i = 0 ; i < nbN - 2; ++i ) {
9886 #ifdef DEBUG_MATCHING_NODES
9887           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9888 #endif
9889           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9890         }
9891       }
9892
9893       // add other links of the face 1 to linkList
9894       // -----------------------------------------
9895
9896       const SMDS_MeshElement* f0 = face[0];
9897       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9898       for ( int i = 0; i < nbN; i++ )
9899       {
9900         const SMDS_MeshNode* n2 = f0->GetNode( i );
9901         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9902           linkSet.insert( SMESH_TLink( n1, n2 ));
9903         if ( !iter_isnew.second ) { // already in a set: no need to process
9904           linkSet.erase( iter_isnew.first );
9905         }
9906         else // new in set == encountered for the first time: add
9907         {
9908 #ifdef DEBUG_MATCHING_NODES
9909           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9910                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9911 #endif
9912           linkList[0].push_back ( NLink( n1, n2 ));
9913           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9914         }
9915         n1 = n2;
9916       }
9917     } // 2 faces found
9918   } // loop on link lists
9919
9920   return SEW_OK;
9921 }
9922
9923 //================================================================================
9924 /*!
9925   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9926   \param theElems - the list of elements (edges or faces) to be replicated
9927   The nodes for duplication could be found from these elements
9928   \param theNodesNot - list of nodes to NOT replicate
9929   \param theAffectedElems - the list of elements (cells and edges) to which the 
9930   replicated nodes should be associated to.
9931   \return TRUE if operation has been completed successfully, FALSE otherwise
9932 */
9933 //================================================================================
9934
9935 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9936                                     const TIDSortedElemSet& theNodesNot,
9937                                     const TIDSortedElemSet& theAffectedElems )
9938 {
9939   myLastCreatedElems.Clear();
9940   myLastCreatedNodes.Clear();
9941
9942   if ( theElems.size() == 0 )
9943     return false;
9944
9945   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9946   if ( !aMeshDS )
9947     return false;
9948
9949   bool res = false;
9950   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9951   // duplicate elements and nodes
9952   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9953   // replce nodes by duplications
9954   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9955   return res;
9956 }
9957
9958 //================================================================================
9959 /*!
9960   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9961   \param theMeshDS - mesh instance
9962   \param theElems - the elements replicated or modified (nodes should be changed)
9963   \param theNodesNot - nodes to NOT replicate
9964   \param theNodeNodeMap - relation of old node to new created node
9965   \param theIsDoubleElem - flag os to replicate element or modify
9966   \return TRUE if operation has been completed successfully, FALSE otherwise
9967 */
9968 //================================================================================
9969
9970 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9971                                     const TIDSortedElemSet& theElems,
9972                                     const TIDSortedElemSet& theNodesNot,
9973                                     std::map< const SMDS_MeshNode*,
9974                                     const SMDS_MeshNode* >& theNodeNodeMap,
9975                                     const bool theIsDoubleElem )
9976 {
9977   // iterate on through element and duplicate them (by nodes duplication)
9978   bool res = false;
9979   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9980   for ( ;  elemItr != theElems.end(); ++elemItr )
9981   {
9982     const SMDS_MeshElement* anElem = *elemItr;
9983     if (!anElem)
9984       continue;
9985
9986     bool isDuplicate = false;
9987     // duplicate nodes to duplicate element
9988     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9989     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9990     int ind = 0;
9991     while ( anIter->more() ) 
9992     { 
9993
9994       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9995       SMDS_MeshNode* aNewNode = aCurrNode;
9996       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9997         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9998       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9999       {
10000         // duplicate node
10001         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10002         theNodeNodeMap[ aCurrNode ] = aNewNode;
10003         myLastCreatedNodes.Append( aNewNode );
10004       }
10005       isDuplicate |= (aCurrNode != aNewNode);
10006       newNodes[ ind++ ] = aNewNode;
10007     }
10008     if ( !isDuplicate )
10009       continue;
10010
10011     if ( theIsDoubleElem )
10012       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10013     else
10014       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10015
10016     res = true;
10017   }
10018   return res;
10019 }
10020
10021 //================================================================================
10022 /*!
10023   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10024   \param theNodes - identifiers of nodes to be doubled
10025   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10026          nodes. If list of element identifiers is empty then nodes are doubled but 
10027          they not assigned to elements
10028   \return TRUE if operation has been completed successfully, FALSE otherwise
10029 */
10030 //================================================================================
10031
10032 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10033                                     const std::list< int >& theListOfModifiedElems )
10034 {
10035   myLastCreatedElems.Clear();
10036   myLastCreatedNodes.Clear();
10037
10038   if ( theListOfNodes.size() == 0 )
10039     return false;
10040
10041   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10042   if ( !aMeshDS )
10043     return false;
10044
10045   // iterate through nodes and duplicate them
10046
10047   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10048
10049   std::list< int >::const_iterator aNodeIter;
10050   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10051   {
10052     int aCurr = *aNodeIter;
10053     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10054     if ( !aNode )
10055       continue;
10056
10057     // duplicate node
10058
10059     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10060     if ( aNewNode )
10061     {
10062       anOldNodeToNewNode[ aNode ] = aNewNode;
10063       myLastCreatedNodes.Append( aNewNode );
10064     }
10065   }
10066
10067   // Create map of new nodes for modified elements
10068
10069   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10070
10071   std::list< int >::const_iterator anElemIter;
10072   for ( anElemIter = theListOfModifiedElems.begin(); 
10073         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10074   {
10075     int aCurr = *anElemIter;
10076     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10077     if ( !anElem )
10078       continue;
10079
10080     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10081
10082     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10083     int ind = 0;
10084     while ( anIter->more() ) 
10085     { 
10086       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10087       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10088       {
10089         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10090         aNodeArr[ ind++ ] = aNewNode;
10091       }
10092       else
10093         aNodeArr[ ind++ ] = aCurrNode;
10094     }
10095     anElemToNodes[ anElem ] = aNodeArr;
10096   }
10097
10098   // Change nodes of elements  
10099
10100   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10101     anElemToNodesIter = anElemToNodes.begin();
10102   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10103   {
10104     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10105     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10106     if ( anElem )
10107       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10108   }
10109
10110   return true;
10111 }
10112
10113 namespace {
10114
10115   //================================================================================
10116   /*!
10117   \brief Check if element located inside shape
10118   \return TRUE if IN or ON shape, FALSE otherwise
10119   */
10120   //================================================================================
10121
10122   template<class Classifier>
10123   bool isInside(const SMDS_MeshElement* theElem,
10124                 Classifier&             theClassifier,
10125                 const double            theTol)
10126   {
10127     gp_XYZ centerXYZ (0, 0, 0);
10128     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10129     while (aNodeItr->more())
10130       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10131
10132     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10133     theClassifier.Perform(aPnt, theTol);
10134     TopAbs_State aState = theClassifier.State();
10135     return (aState == TopAbs_IN || aState == TopAbs_ON );
10136   }
10137
10138   //================================================================================
10139   /*!
10140    * \brief Classifier of the 3D point on the TopoDS_Face
10141    *        with interaface suitable for isInside()
10142    */
10143   //================================================================================
10144
10145   struct _FaceClassifier
10146   {
10147     Extrema_ExtPS       _extremum;
10148     BRepAdaptor_Surface _surface;
10149     TopAbs_State        _state;
10150
10151     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10152     {
10153       _extremum.Initialize( _surface,
10154                             _surface.FirstUParameter(), _surface.LastUParameter(),
10155                             _surface.FirstVParameter(), _surface.LastVParameter(),
10156                             _surface.Tolerance(), _surface.Tolerance() );
10157     }
10158     void Perform(const gp_Pnt& aPnt, double theTol)
10159     {
10160       _state = TopAbs_OUT;
10161       _extremum.Perform(aPnt);
10162       if ( _extremum.IsDone() )
10163         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10164           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10165     }
10166     TopAbs_State State() const
10167     {
10168       return _state;
10169     }
10170   };
10171 }
10172
10173 //================================================================================
10174 /*!
10175   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10176   \param theElems - group of of elements (edges or faces) to be replicated
10177   \param theNodesNot - group of nodes not to replicate
10178   \param theShape - shape to detect affected elements (element which geometric center
10179   located on or inside shape).
10180   The replicated nodes should be associated to affected elements.
10181   \return TRUE if operation has been completed successfully, FALSE otherwise
10182 */
10183 //================================================================================
10184
10185 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10186                                             const TIDSortedElemSet& theNodesNot,
10187                                             const TopoDS_Shape&     theShape )
10188 {
10189   if ( theShape.IsNull() )
10190     return false;
10191
10192   const double aTol = Precision::Confusion();
10193   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10194   auto_ptr<_FaceClassifier>              aFaceClassifier;
10195   if ( theShape.ShapeType() == TopAbs_SOLID )
10196   {
10197     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10198     bsc3d->PerformInfinitePoint(aTol);
10199   }
10200   else if (theShape.ShapeType() == TopAbs_FACE )
10201   {
10202     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10203   }
10204
10205   // iterates on indicated elements and get elements by back references from their nodes
10206   TIDSortedElemSet anAffected;
10207   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10208   for ( ;  elemItr != theElems.end(); ++elemItr )
10209   {
10210     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10211     if (!anElem)
10212       continue;
10213
10214     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10215     while ( nodeItr->more() )
10216     {
10217       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10218       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10219         continue;
10220       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10221       while ( backElemItr->more() )
10222       {
10223         const SMDS_MeshElement* curElem = backElemItr->next();
10224         if ( curElem && theElems.find(curElem) == theElems.end() &&
10225              ( bsc3d.get() ?
10226                isInside( curElem, *bsc3d, aTol ) :
10227                isInside( curElem, *aFaceClassifier, aTol )))
10228           anAffected.insert( curElem );
10229       }
10230     }
10231   }
10232   return DoubleNodes( theElems, theNodesNot, anAffected );
10233 }
10234
10235 //================================================================================
10236 /*!
10237  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10238  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10239  * \return TRUE if operation has been completed successfully, FALSE otherwise
10240  */
10241 //================================================================================
10242
10243 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10244 {
10245   // iterates on volume elements and detect all free faces on them
10246   SMESHDS_Mesh* aMesh = GetMeshDS();
10247   if (!aMesh)
10248     return false;
10249   //bool res = false;
10250   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10251   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10252   while(vIt->more())
10253   {
10254     const SMDS_MeshVolume* volume = vIt->next();
10255     SMDS_VolumeTool vTool( volume );
10256     vTool.SetExternalNormal();
10257     const bool isPoly = volume->IsPoly();
10258     const bool isQuad = volume->IsQuadratic();
10259     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10260     {
10261       if (!vTool.IsFreeFace(iface))
10262         continue;
10263       nbFree++;
10264       vector<const SMDS_MeshNode *> nodes;
10265       int nbFaceNodes = vTool.NbFaceNodes(iface);
10266       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10267       int inode = 0;
10268       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10269         nodes.push_back(faceNodes[inode]);
10270       if (isQuad)
10271         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10272           nodes.push_back(faceNodes[inode]);
10273
10274       // add new face based on volume nodes
10275       if (aMesh->FindFace( nodes ) ) {
10276         nbExisted++;
10277         continue; // face already exsist
10278       }
10279       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10280       nbCreated++;
10281     }
10282   }
10283   return ( nbFree==(nbExisted+nbCreated) );
10284 }