Salome HOME
0020982: EDF 1547 SMESH: Creation of non-conformal quadratic pyramids
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
48
49 #include "utilities.h"
50
51 #include <BRepAdaptor_Surface.hxx>
52 #include <BRepClass3d_SolidClassifier.hxx>
53 #include <BRep_Tool.hxx>
54 #include <ElCLib.hxx>
55 #include <Extrema_GenExtPS.hxx>
56 #include <Extrema_POnCurv.hxx>
57 #include <Extrema_POnSurf.hxx>
58 #include <GC_MakeSegment.hxx>
59 #include <Geom2d_Curve.hxx>
60 #include <GeomAPI_ExtremaCurveCurve.hxx>
61 #include <GeomAdaptor_Surface.hxx>
62 #include <Geom_Curve.hxx>
63 #include <Geom_Line.hxx>
64 #include <Geom_Surface.hxx>
65 #include <IntAna_IntConicQuad.hxx>
66 #include <IntAna_Quadric.hxx>
67 #include <Precision.hxx>
68 #include <TColStd_ListOfInteger.hxx>
69 #include <TopAbs_State.hxx>
70 #include <TopExp.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopTools_ListIteratorOfListOfShape.hxx>
73 #include <TopTools_ListOfShape.hxx>
74 #include <TopTools_SequenceOfShape.hxx>
75 #include <TopoDS.hxx>
76 #include <TopoDS_Face.hxx>
77 #include <gp.hxx>
78 #include <gp_Ax1.hxx>
79 #include <gp_Dir.hxx>
80 #include <gp_Lin.hxx>
81 #include <gp_Pln.hxx>
82 #include <gp_Trsf.hxx>
83 #include <gp_Vec.hxx>
84 #include <gp_XY.hxx>
85 #include <gp_XYZ.hxx>
86
87 #include <math.h>
88
89 #include <map>
90 #include <set>
91 #include <numeric>
92 #include <limits>
93
94 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
95
96 using namespace std;
97 using namespace SMESH::Controls;
98
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
101
102 //=======================================================================
103 //function : SMESH_MeshEditor
104 //purpose  :
105 //=======================================================================
106
107 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
108   :myMesh( theMesh ) // theMesh may be NULL
109 {
110 }
111
112 //=======================================================================
113 /*!
114  * \brief Add element
115  */
116 //=======================================================================
117
118 SMDS_MeshElement*
119 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
120                              const SMDSAbs_ElementType            type,
121                              const bool                           isPoly,
122                              const int                            ID)
123 {
124   SMDS_MeshElement* e = 0;
125   int nbnode = node.size();
126   SMESHDS_Mesh* mesh = GetMeshDS();
127   switch ( type ) {
128   case SMDSAbs_0DElement:
129     if ( nbnode == 1 )
130       if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
131       else      e = mesh->Add0DElement      (node[0] );
132     break;
133   case SMDSAbs_Edge:
134     if ( nbnode == 2 )
135       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
136       else      e = mesh->AddEdge      (node[0], node[1] );
137     else if ( nbnode == 3 )
138       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
139       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
140     break;
141   case SMDSAbs_Face:
142     if ( !isPoly ) {
143       if      (nbnode == 3)
144         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
145         else      e = mesh->AddFace      (node[0], node[1], node[2] );
146       else if (nbnode == 4) 
147         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
148         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
149       else if (nbnode == 6)
150         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
151                                           node[4], node[5], ID);
152         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
153                                           node[4], node[5] );
154       else if (nbnode == 8)
155         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
156                                           node[4], node[5], node[6], node[7], ID);
157         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
158                                           node[4], node[5], node[6], node[7] );
159     } else {
160       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
161       else      e = mesh->AddPolygonalFace      (node    );
162     }
163     break;
164   case SMDSAbs_Volume:
165     if ( !isPoly ) {
166       if      (nbnode == 4)
167         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
168         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
169       else if (nbnode == 5)
170         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171                                             node[4], ID);
172         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
173                                             node[4] );
174       else if (nbnode == 6)
175         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
176                                             node[4], node[5], ID);
177         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
178                                             node[4], node[5] );
179       else if (nbnode == 8)
180         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
181                                             node[4], node[5], node[6], node[7], ID);
182         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
183                                             node[4], node[5], node[6], node[7] );
184       else if (nbnode == 10)
185         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
186                                             node[4], node[5], node[6], node[7],
187                                             node[8], node[9], ID);
188         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
189                                             node[4], node[5], node[6], node[7],
190                                             node[8], node[9] );
191       else if (nbnode == 13)
192         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193                                             node[4], node[5], node[6], node[7],
194                                             node[8], node[9], node[10],node[11],
195                                             node[12],ID);
196         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
197                                             node[4], node[5], node[6], node[7],
198                                             node[8], node[9], node[10],node[11],
199                                             node[12] );
200       else if (nbnode == 15)
201         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
202                                             node[4], node[5], node[6], node[7],
203                                             node[8], node[9], node[10],node[11],
204                                             node[12],node[13],node[14],ID);
205         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
206                                             node[4], node[5], node[6], node[7],
207                                             node[8], node[9], node[10],node[11],
208                                             node[12],node[13],node[14] );
209       else if (nbnode == 20)
210         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
211                                             node[4], node[5], node[6], node[7],
212                                             node[8], node[9], node[10],node[11],
213                                             node[12],node[13],node[14],node[15],
214                                             node[16],node[17],node[18],node[19],ID);
215         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
216                                             node[4], node[5], node[6], node[7],
217                                             node[8], node[9], node[10],node[11],
218                                             node[12],node[13],node[14],node[15],
219                                             node[16],node[17],node[18],node[19] );
220     }
221   }
222   return e;
223 }
224
225 //=======================================================================
226 /*!
227  * \brief Add element
228  */
229 //=======================================================================
230
231 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
232                                                const SMDSAbs_ElementType type,
233                                                const bool                isPoly,
234                                                const int                 ID)
235 {
236   vector<const SMDS_MeshNode*> nodes;
237   nodes.reserve( nodeIDs.size() );
238   vector<int>::const_iterator id = nodeIDs.begin();
239   while ( id != nodeIDs.end() ) {
240     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
241       nodes.push_back( node );
242     else
243       return 0;
244   }
245   return AddElement( nodes, type, isPoly, ID );
246 }
247
248 //=======================================================================
249 //function : Remove
250 //purpose  : Remove a node or an element.
251 //           Modify a compute state of sub-meshes which become empty
252 //=======================================================================
253
254 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
255                               const bool         isNodes )
256 {
257   myLastCreatedElems.Clear();
258   myLastCreatedNodes.Clear();
259
260   SMESHDS_Mesh* aMesh = GetMeshDS();
261   set< SMESH_subMesh *> smmap;
262
263   int removed = 0;
264   list<int>::const_iterator it = theIDs.begin();
265   for ( ; it != theIDs.end(); it++ ) {
266     const SMDS_MeshElement * elem;
267     if ( isNodes )
268       elem = aMesh->FindNode( *it );
269     else
270       elem = aMesh->FindElement( *it );
271     if ( !elem )
272       continue;
273
274     // Notify VERTEX sub-meshes about modification
275     if ( isNodes ) {
276       const SMDS_MeshNode* node = cast2Node( elem );
277       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
278         if ( int aShapeID = node->GetPosition()->GetShapeId() )
279           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
280             smmap.insert( sm );
281     }
282     // Find sub-meshes to notify about modification
283     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
284     //     while ( nodeIt->more() ) {
285     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
286     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
287     //       if ( aPosition.get() ) {
288     //         if ( int aShapeID = aPosition->GetShapeId() ) {
289     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
290     //             smmap.insert( sm );
291     //         }
292     //       }
293     //     }
294
295     // Do remove
296     if ( isNodes )
297       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
298     else
299       aMesh->RemoveElement( elem );
300     removed++;
301   }
302
303   // Notify sub-meshes about modification
304   if ( !smmap.empty() ) {
305     set< SMESH_subMesh *>::iterator smIt;
306     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
307       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
308   }
309
310   //   // Check if the whole mesh becomes empty
311   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
312   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
313
314   return removed;
315 }
316
317 //=======================================================================
318 //function : FindShape
319 //purpose  : Return an index of the shape theElem is on
320 //           or zero if a shape not found
321 //=======================================================================
322
323 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
324 {
325   myLastCreatedElems.Clear();
326   myLastCreatedNodes.Clear();
327
328   SMESHDS_Mesh * aMesh = GetMeshDS();
329   if ( aMesh->ShapeToMesh().IsNull() )
330     return 0;
331
332   if ( theElem->GetType() == SMDSAbs_Node ) {
333     const SMDS_PositionPtr& aPosition =
334       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
335     if ( aPosition.get() )
336       return aPosition->GetShapeId();
337     else
338       return 0;
339   }
340
341   TopoDS_Shape aShape; // the shape a node is on
342   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
343   while ( nodeIt->more() ) {
344     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
345     const SMDS_PositionPtr& aPosition = node->GetPosition();
346     if ( aPosition.get() ) {
347       int aShapeID = aPosition->GetShapeId();
348       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
349       if ( sm ) {
350         if ( sm->Contains( theElem ))
351           return aShapeID;
352         if ( aShape.IsNull() )
353           aShape = aMesh->IndexToShape( aShapeID );
354       }
355       else {
356         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
357       }
358     }
359   }
360
361   // None of nodes is on a proper shape,
362   // find the shape among ancestors of aShape on which a node is
363   if ( aShape.IsNull() ) {
364     //MESSAGE ("::FindShape() - NONE node is on shape")
365     return 0;
366   }
367   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
368   for ( ; ancIt.More(); ancIt.Next() ) {
369     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
370     if ( sm && sm->Contains( theElem ))
371       return aMesh->ShapeToIndex( ancIt.Value() );
372   }
373
374   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
375   return 0;
376 }
377
378 //=======================================================================
379 //function : IsMedium
380 //purpose  :
381 //=======================================================================
382
383 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
384                                 const SMDSAbs_ElementType typeToCheck)
385 {
386   bool isMedium = false;
387   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
388   while (it->more() && !isMedium ) {
389     const SMDS_MeshElement* elem = it->next();
390     isMedium = elem->IsMediumNode(node);
391   }
392   return isMedium;
393 }
394
395 //=======================================================================
396 //function : ShiftNodesQuadTria
397 //purpose  : auxilary
398 //           Shift nodes in the array corresponded to quadratic triangle
399 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
400 //=======================================================================
401 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
402 {
403   const SMDS_MeshNode* nd1 = aNodes[0];
404   aNodes[0] = aNodes[1];
405   aNodes[1] = aNodes[2];
406   aNodes[2] = nd1;
407   const SMDS_MeshNode* nd2 = aNodes[3];
408   aNodes[3] = aNodes[4];
409   aNodes[4] = aNodes[5];
410   aNodes[5] = nd2;
411 }
412
413 //=======================================================================
414 //function : GetNodesFromTwoTria
415 //purpose  : auxilary
416 //           Shift nodes in the array corresponded to quadratic triangle
417 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
418 //=======================================================================
419 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
420                                 const SMDS_MeshElement * theTria2,
421                                 const SMDS_MeshNode* N1[],
422                                 const SMDS_MeshNode* N2[])
423 {
424   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
425   int i=0;
426   while(i<6) {
427     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
428     i++;
429   }
430   if(it->more()) return false;
431   it = theTria2->nodesIterator();
432   i=0;
433   while(i<6) {
434     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
435     i++;
436   }
437   if(it->more()) return false;
438
439   int sames[3] = {-1,-1,-1};
440   int nbsames = 0;
441   int j;
442   for(i=0; i<3; i++) {
443     for(j=0; j<3; j++) {
444       if(N1[i]==N2[j]) {
445         sames[i] = j;
446         nbsames++;
447         break;
448       }
449     }
450   }
451   if(nbsames!=2) return false;
452   if(sames[0]>-1) {
453     ShiftNodesQuadTria(N1);
454     if(sames[1]>-1) {
455       ShiftNodesQuadTria(N1);
456     }
457   }
458   i = sames[0] + sames[1] + sames[2];
459   for(; i<2; i++) {
460     ShiftNodesQuadTria(N2);
461   }
462   // now we receive following N1 and N2 (using numeration as above image)
463   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
464   // i.e. first nodes from both arrays determ new diagonal
465   return true;
466 }
467
468 //=======================================================================
469 //function : InverseDiag
470 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
471 //           but having other common link.
472 //           Return False if args are improper
473 //=======================================================================
474
475 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
476                                     const SMDS_MeshElement * theTria2 )
477 {
478   myLastCreatedElems.Clear();
479   myLastCreatedNodes.Clear();
480
481   if (!theTria1 || !theTria2)
482     return false;
483
484   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
485   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
486   if (F1 && F2) {
487
488     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
489     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
490     //    |/ |                                         | \|
491     //  B +--+ 2                                     B +--+ 2
492
493     // put nodes in array and find out indices of the same ones
494     const SMDS_MeshNode* aNodes [6];
495     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
496     int i = 0;
497     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
498     while ( it->more() ) {
499       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
500
501       if ( i > 2 ) // theTria2
502         // find same node of theTria1
503         for ( int j = 0; j < 3; j++ )
504           if ( aNodes[ i ] == aNodes[ j ]) {
505             sameInd[ j ] = i;
506             sameInd[ i ] = j;
507             break;
508           }
509       // next
510       i++;
511       if ( i == 3 ) {
512         if ( it->more() )
513           return false; // theTria1 is not a triangle
514         it = theTria2->nodesIterator();
515       }
516       if ( i == 6 && it->more() )
517         return false; // theTria2 is not a triangle
518     }
519
520     // find indices of 1,2 and of A,B in theTria1
521     int iA = 0, iB = 0, i1 = 0, i2 = 0;
522     for ( i = 0; i < 6; i++ ) {
523       if ( sameInd [ i ] == 0 )
524         if ( i < 3 ) i1 = i;
525         else         i2 = i;
526       else if (i < 3)
527         if ( iA ) iB = i;
528         else      iA = i;
529     }
530     // nodes 1 and 2 should not be the same
531     if ( aNodes[ i1 ] == aNodes[ i2 ] )
532       return false;
533
534     // theTria1: A->2
535     aNodes[ iA ] = aNodes[ i2 ];
536     // theTria2: B->1
537     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
538
539     //MESSAGE( theTria1 << theTria2 );
540
541     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
542     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
543
544     //MESSAGE( theTria1 << theTria2 );
545
546     return true;
547
548   } // end if(F1 && F2)
549
550   // check case of quadratic faces
551   const SMDS_QuadraticFaceOfNodes* QF1 =
552     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
553   if(!QF1) return false;
554   const SMDS_QuadraticFaceOfNodes* QF2 =
555     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
556   if(!QF2) return false;
557
558   //       5
559   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
560   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
561   //    |   / |
562   //  7 +  +  + 6
563   //    | /9  |
564   //    |/    |
565   //  4 +--+--+ 3
566   //       8
567
568   const SMDS_MeshNode* N1 [6];
569   const SMDS_MeshNode* N2 [6];
570   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
571     return false;
572   // now we receive following N1 and N2 (using numeration as above image)
573   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
574   // i.e. first nodes from both arrays determ new diagonal
575
576   const SMDS_MeshNode* N1new [6];
577   const SMDS_MeshNode* N2new [6];
578   N1new[0] = N1[0];
579   N1new[1] = N2[0];
580   N1new[2] = N2[1];
581   N1new[3] = N1[4];
582   N1new[4] = N2[3];
583   N1new[5] = N1[5];
584   N2new[0] = N1[0];
585   N2new[1] = N1[1];
586   N2new[2] = N2[0];
587   N2new[3] = N1[3];
588   N2new[4] = N2[5];
589   N2new[5] = N1[4];
590   // replaces nodes in faces
591   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
592   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
593
594   return true;
595 }
596
597 //=======================================================================
598 //function : findTriangles
599 //purpose  : find triangles sharing theNode1-theNode2 link
600 //=======================================================================
601
602 static bool findTriangles(const SMDS_MeshNode *    theNode1,
603                           const SMDS_MeshNode *    theNode2,
604                           const SMDS_MeshElement*& theTria1,
605                           const SMDS_MeshElement*& theTria2)
606 {
607   if ( !theNode1 || !theNode2 ) return false;
608
609   theTria1 = theTria2 = 0;
610
611   set< const SMDS_MeshElement* > emap;
612   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
613   while (it->more()) {
614     const SMDS_MeshElement* elem = it->next();
615     if ( elem->NbNodes() == 3 )
616       emap.insert( elem );
617   }
618   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
619   while (it->more()) {
620     const SMDS_MeshElement* elem = it->next();
621     if ( emap.find( elem ) != emap.end() )
622       if ( theTria1 ) {
623         // theTria1 must be element with minimum ID
624         if( theTria1->GetID() < elem->GetID() ) {
625           theTria2 = elem;
626         }
627         else {
628           theTria2 = theTria1;
629           theTria1 = elem;
630         }
631         break;
632       }
633       else {
634         theTria1 = elem;
635       }
636   }
637   return ( theTria1 && theTria2 );
638 }
639
640 //=======================================================================
641 //function : InverseDiag
642 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
643 //           with ones built on the same 4 nodes but having other common link.
644 //           Return false if proper faces not found
645 //=======================================================================
646
647 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
648                                     const SMDS_MeshNode * theNode2)
649 {
650   myLastCreatedElems.Clear();
651   myLastCreatedNodes.Clear();
652
653   MESSAGE( "::InverseDiag()" );
654
655   const SMDS_MeshElement *tr1, *tr2;
656   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
657     return false;
658
659   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
660   //if (!F1) return false;
661   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
662   //if (!F2) return false;
663   if (F1 && F2) {
664
665     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
666     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
667     //    |/ |                                    | \|
668     //  B +--+ 2                                B +--+ 2
669
670     // put nodes in array
671     // and find indices of 1,2 and of A in tr1 and of B in tr2
672     int i, iA1 = 0, i1 = 0;
673     const SMDS_MeshNode* aNodes1 [3];
674     SMDS_ElemIteratorPtr it;
675     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
676       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
677       if ( aNodes1[ i ] == theNode1 )
678         iA1 = i; // node A in tr1
679       else if ( aNodes1[ i ] != theNode2 )
680         i1 = i;  // node 1
681     }
682     int iB2 = 0, i2 = 0;
683     const SMDS_MeshNode* aNodes2 [3];
684     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
685       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
686       if ( aNodes2[ i ] == theNode2 )
687         iB2 = i; // node B in tr2
688       else if ( aNodes2[ i ] != theNode1 )
689         i2 = i;  // node 2
690     }
691
692     // nodes 1 and 2 should not be the same
693     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
694       return false;
695
696     // tr1: A->2
697     aNodes1[ iA1 ] = aNodes2[ i2 ];
698     // tr2: B->1
699     aNodes2[ iB2 ] = aNodes1[ i1 ];
700
701     //MESSAGE( tr1 << tr2 );
702
703     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
704     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
705
706     //MESSAGE( tr1 << tr2 );
707
708     return true;
709   }
710
711   // check case of quadratic faces
712   const SMDS_QuadraticFaceOfNodes* QF1 =
713     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
714   if(!QF1) return false;
715   const SMDS_QuadraticFaceOfNodes* QF2 =
716     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
717   if(!QF2) return false;
718   return InverseDiag(tr1,tr2);
719 }
720
721 //=======================================================================
722 //function : getQuadrangleNodes
723 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
724 //           fusion of triangles tr1 and tr2 having shared link on
725 //           theNode1 and theNode2
726 //=======================================================================
727
728 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
729                         const SMDS_MeshNode *    theNode1,
730                         const SMDS_MeshNode *    theNode2,
731                         const SMDS_MeshElement * tr1,
732                         const SMDS_MeshElement * tr2 )
733 {
734   if( tr1->NbNodes() != tr2->NbNodes() )
735     return false;
736   // find the 4-th node to insert into tr1
737   const SMDS_MeshNode* n4 = 0;
738   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
739   int i=0;
740   while ( !n4 && i<3 ) {
741     const SMDS_MeshNode * n = cast2Node( it->next() );
742     i++;
743     bool isDiag = ( n == theNode1 || n == theNode2 );
744     if ( !isDiag )
745       n4 = n;
746   }
747   // Make an array of nodes to be in a quadrangle
748   int iNode = 0, iFirstDiag = -1;
749   it = tr1->nodesIterator();
750   i=0;
751   while ( i<3 ) {
752     const SMDS_MeshNode * n = cast2Node( it->next() );
753     i++;
754     bool isDiag = ( n == theNode1 || n == theNode2 );
755     if ( isDiag ) {
756       if ( iFirstDiag < 0 )
757         iFirstDiag = iNode;
758       else if ( iNode - iFirstDiag == 1 )
759         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
760     }
761     else if ( n == n4 ) {
762       return false; // tr1 and tr2 should not have all the same nodes
763     }
764     theQuadNodes[ iNode++ ] = n;
765   }
766   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
767     theQuadNodes[ iNode ] = n4;
768
769   return true;
770 }
771
772 //=======================================================================
773 //function : DeleteDiag
774 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
775 //           with a quadrangle built on the same 4 nodes.
776 //           Return false if proper faces not found
777 //=======================================================================
778
779 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
780                                    const SMDS_MeshNode * theNode2)
781 {
782   myLastCreatedElems.Clear();
783   myLastCreatedNodes.Clear();
784
785   MESSAGE( "::DeleteDiag()" );
786
787   const SMDS_MeshElement *tr1, *tr2;
788   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
789     return false;
790
791   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
792   //if (!F1) return false;
793   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
794   //if (!F2) return false;
795   if (F1 && F2) {
796
797     const SMDS_MeshNode* aNodes [ 4 ];
798     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
799       return false;
800
801     //MESSAGE( endl << tr1 << tr2 );
802
803     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
804     myLastCreatedElems.Append(tr1);
805     GetMeshDS()->RemoveElement( tr2 );
806
807     //MESSAGE( endl << tr1 );
808
809     return true;
810   }
811
812   // check case of quadratic faces
813   const SMDS_QuadraticFaceOfNodes* QF1 =
814     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
815   if(!QF1) return false;
816   const SMDS_QuadraticFaceOfNodes* QF2 =
817     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
818   if(!QF2) return false;
819
820   //       5
821   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
822   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
823   //    |   / |
824   //  7 +  +  + 6
825   //    | /9  |
826   //    |/    |
827   //  4 +--+--+ 3
828   //       8
829
830   const SMDS_MeshNode* N1 [6];
831   const SMDS_MeshNode* N2 [6];
832   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
833     return false;
834   // now we receive following N1 and N2 (using numeration as above image)
835   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
836   // i.e. first nodes from both arrays determ new diagonal
837
838   const SMDS_MeshNode* aNodes[8];
839   aNodes[0] = N1[0];
840   aNodes[1] = N1[1];
841   aNodes[2] = N2[0];
842   aNodes[3] = N2[1];
843   aNodes[4] = N1[3];
844   aNodes[5] = N2[5];
845   aNodes[6] = N2[3];
846   aNodes[7] = N1[5];
847
848   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
849   myLastCreatedElems.Append(tr1);
850   GetMeshDS()->RemoveElement( tr2 );
851
852   // remove middle node (9)
853   GetMeshDS()->RemoveNode( N1[4] );
854
855   return true;
856 }
857
858 //=======================================================================
859 //function : Reorient
860 //purpose  : Reverse theElement orientation
861 //=======================================================================
862
863 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
864 {
865   myLastCreatedElems.Clear();
866   myLastCreatedNodes.Clear();
867
868   if (!theElem)
869     return false;
870   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
871   if ( !it || !it->more() )
872     return false;
873
874   switch ( theElem->GetType() ) {
875
876   case SMDSAbs_Edge:
877   case SMDSAbs_Face: {
878     if(!theElem->IsQuadratic()) {
879       int i = theElem->NbNodes();
880       vector<const SMDS_MeshNode*> aNodes( i );
881       while ( it->more() )
882         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
883       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
884     }
885     else {
886       // quadratic elements
887       if(theElem->GetType()==SMDSAbs_Edge) {
888         vector<const SMDS_MeshNode*> aNodes(3);
889         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
890         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
891         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
892         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
893       }
894       else {
895         int nbn = theElem->NbNodes();
896         vector<const SMDS_MeshNode*> aNodes(nbn);
897         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
898         int i=1;
899         for(; i<nbn/2; i++) {
900           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
901         }
902         for(i=0; i<nbn/2; i++) {
903           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
904         }
905         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
906       }
907     }
908   }
909   case SMDSAbs_Volume: {
910     if (theElem->IsPoly()) {
911       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
912         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
913       if (!aPolyedre) {
914         MESSAGE("Warning: bad volumic element");
915         return false;
916       }
917
918       int nbFaces = aPolyedre->NbFaces();
919       vector<const SMDS_MeshNode *> poly_nodes;
920       vector<int> quantities (nbFaces);
921
922       // reverse each face of the polyedre
923       for (int iface = 1; iface <= nbFaces; iface++) {
924         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
925         quantities[iface - 1] = nbFaceNodes;
926
927         for (inode = nbFaceNodes; inode >= 1; inode--) {
928           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
929           poly_nodes.push_back(curNode);
930         }
931       }
932
933       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
934
935     }
936     else {
937       SMDS_VolumeTool vTool;
938       if ( !vTool.Set( theElem ))
939         return false;
940       vTool.Inverse();
941       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
942     }
943   }
944   default:;
945   }
946
947   return false;
948 }
949
950 //=======================================================================
951 //function : getBadRate
952 //purpose  :
953 //=======================================================================
954
955 static double getBadRate (const SMDS_MeshElement*               theElem,
956                           SMESH::Controls::NumericalFunctorPtr& theCrit)
957 {
958   SMESH::Controls::TSequenceOfXYZ P;
959   if ( !theElem || !theCrit->GetPoints( theElem, P ))
960     return 1e100;
961   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
962   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
963 }
964
965 //=======================================================================
966 //function : QuadToTri
967 //purpose  : Cut quadrangles into triangles.
968 //           theCrit is used to select a diagonal to cut
969 //=======================================================================
970
971 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
972                                   SMESH::Controls::NumericalFunctorPtr theCrit)
973 {
974   myLastCreatedElems.Clear();
975   myLastCreatedNodes.Clear();
976
977   MESSAGE( "::QuadToTri()" );
978
979   if ( !theCrit.get() )
980     return false;
981
982   SMESHDS_Mesh * aMesh = GetMeshDS();
983
984   Handle(Geom_Surface) surface;
985   SMESH_MesherHelper   helper( *GetMesh() );
986
987   TIDSortedElemSet::iterator itElem;
988   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
989     const SMDS_MeshElement* elem = *itElem;
990     if ( !elem || elem->GetType() != SMDSAbs_Face )
991       continue;
992     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
993       continue;
994
995     // retrieve element nodes
996     const SMDS_MeshNode* aNodes [8];
997     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
998     int i = 0;
999     while ( itN->more() )
1000       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1001
1002     // compare two sets of possible triangles
1003     double aBadRate1, aBadRate2; // to what extent a set is bad
1004     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1005     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1006     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1007
1008     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1009     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1010     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1011
1012     int aShapeId = FindShape( elem );
1013     const SMDS_MeshElement* newElem = 0;
1014
1015     if( !elem->IsQuadratic() ) {
1016
1017       // split liner quadrangle
1018
1019       if ( aBadRate1 <= aBadRate2 ) {
1020         // tr1 + tr2 is better
1021         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1022         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1023       }
1024       else {
1025         // tr3 + tr4 is better
1026         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1027         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1028       }
1029     }
1030     else {
1031
1032       // split quadratic quadrangle
1033
1034       // get surface elem is on
1035       if ( aShapeId != helper.GetSubShapeID() ) {
1036         surface.Nullify();
1037         TopoDS_Shape shape;
1038         if ( aShapeId > 0 )
1039           shape = aMesh->IndexToShape( aShapeId );
1040         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1041           TopoDS_Face face = TopoDS::Face( shape );
1042           surface = BRep_Tool::Surface( face );
1043           if ( !surface.IsNull() )
1044             helper.SetSubShape( shape );
1045         }
1046       }
1047       // get elem nodes
1048       const SMDS_MeshNode* aNodes [8];
1049       const SMDS_MeshNode* inFaceNode = 0;
1050       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1051       int i = 0;
1052       while ( itN->more() ) {
1053         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1054         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1055              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1056         {
1057           inFaceNode = aNodes[ i-1 ];
1058         }
1059       }
1060       // find middle point for (0,1,2,3)
1061       // and create a node in this point;
1062       gp_XYZ p( 0,0,0 );
1063       if ( surface.IsNull() ) {
1064         for(i=0; i<4; i++)
1065           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1066         p /= 4;
1067       }
1068       else {
1069         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1070         gp_XY uv( 0,0 );
1071         for(i=0; i<4; i++)
1072           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1073         uv /= 4.;
1074         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1075       }
1076       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1077       myLastCreatedNodes.Append(newN);
1078
1079       // create a new element
1080       const SMDS_MeshNode* N[6];
1081       if ( aBadRate1 <= aBadRate2 ) {
1082         N[0] = aNodes[0];
1083         N[1] = aNodes[1];
1084         N[2] = aNodes[2];
1085         N[3] = aNodes[4];
1086         N[4] = aNodes[5];
1087         N[5] = newN;
1088         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1089                                  aNodes[6], aNodes[7], newN );
1090       }
1091       else {
1092         N[0] = aNodes[1];
1093         N[1] = aNodes[2];
1094         N[2] = aNodes[3];
1095         N[3] = aNodes[5];
1096         N[4] = aNodes[6];
1097         N[5] = newN;
1098         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1099                                  aNodes[7], aNodes[4], newN );
1100       }
1101       aMesh->ChangeElementNodes( elem, N, 6 );
1102
1103     } // quadratic case
1104
1105     // care of a new element
1106
1107     myLastCreatedElems.Append(newElem);
1108     AddToSameGroups( newElem, elem, aMesh );
1109
1110     // put a new triangle on the same shape
1111     if ( aShapeId )
1112       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1113   }
1114   return true;
1115 }
1116
1117 //=======================================================================
1118 //function : BestSplit
1119 //purpose  : Find better diagonal for cutting.
1120 //=======================================================================
1121
1122 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1123                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1124 {
1125   myLastCreatedElems.Clear();
1126   myLastCreatedNodes.Clear();
1127
1128   if (!theCrit.get())
1129     return -1;
1130
1131   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1132     return -1;
1133
1134   if( theQuad->NbNodes()==4 ||
1135       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1136
1137     // retrieve element nodes
1138     const SMDS_MeshNode* aNodes [4];
1139     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1140     int i = 0;
1141     //while (itN->more())
1142     while (i<4) {
1143       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1144     }
1145     // compare two sets of possible triangles
1146     double aBadRate1, aBadRate2; // to what extent a set is bad
1147     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1148     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1149     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1150
1151     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1152     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1153     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1154
1155     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1156       return 1; // diagonal 1-3
1157
1158     return 2; // diagonal 2-4
1159   }
1160   return -1;
1161 }
1162
1163 namespace
1164 {
1165   // Methods of splitting volumes into tetra
1166
1167   const int theHexTo5_1[5*4+1] =
1168     {
1169       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1170     };
1171   const int theHexTo5_2[5*4+1] =
1172     {
1173       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1174     };
1175   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1176
1177   const int theHexTo6_1[6*4+1] =
1178     {
1179       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1180     };
1181   const int theHexTo6_2[6*4+1] =
1182     {
1183       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1184     };
1185   const int theHexTo6_3[6*4+1] =
1186     {
1187       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1188     };
1189   const int theHexTo6_4[6*4+1] =
1190     {
1191       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1192     };
1193   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1194
1195   const int thePyraTo2_1[2*4+1] =
1196     {
1197       0, 1, 2, 4,    0, 2, 3, 4,   -1
1198     };
1199   const int thePyraTo2_2[2*4+1] =
1200     {
1201       1, 2, 3, 4,    1, 3, 0, 4,   -1
1202     };
1203   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1204
1205   const int thePentaTo3_1[3*4+1] =
1206     {
1207       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1208     };
1209   const int thePentaTo3_2[3*4+1] =
1210     {
1211       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1212     };
1213   const int thePentaTo3_3[3*4+1] =
1214     {
1215       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1216     };
1217   const int thePentaTo3_4[3*4+1] =
1218     {
1219       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1220     };
1221   const int thePentaTo3_5[3*4+1] =
1222     {
1223       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1224     };
1225   const int thePentaTo3_6[3*4+1] =
1226     {
1227       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1228     };
1229   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1230                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1231
1232   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1233   {
1234     int _n1, _n2, _n3;
1235     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1236     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1237     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1238   };
1239   struct TSplitMethod
1240   {
1241     int        _nbTetra;
1242     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1243     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1244     bool       _ownConn;      //!< to delete _connectivity in destructor
1245
1246     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1247       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1248     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1249     bool hasFacet( const TTriangleFacet& facet ) const
1250     {
1251       const int* tetConn = _connectivity;
1252       for ( ; tetConn[0] >= 0; tetConn += 4 )
1253         if (( facet.contains( tetConn[0] ) +
1254               facet.contains( tetConn[1] ) +
1255               facet.contains( tetConn[2] ) +
1256               facet.contains( tetConn[3] )) == 3 )
1257           return true;
1258       return false;
1259     }
1260   };
1261
1262   //=======================================================================
1263   /*!
1264    * \brief return TSplitMethod for the given element
1265    */
1266   //=======================================================================
1267
1268   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1269   {
1270     int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1271
1272     // Find out how adjacent volumes are split
1273
1274     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1275     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1276     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1277     {
1278       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1279       maxTetConnSize += 4 * ( nbNodes - 2 );
1280       if ( nbNodes < 4 ) continue;
1281
1282       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1283       const int* nInd = vol.GetFaceNodesIndices( iF );
1284       if ( nbNodes == 4 )
1285       {
1286         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1287         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1288         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1289         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1290       }
1291       else
1292       {
1293         int iCom = 0; // common node of triangle faces to split into
1294         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1295         {
1296           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1297                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1298                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1299           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1300                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1301                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1302           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1303           {
1304             triaSplits.push_back( t012 );
1305             triaSplits.push_back( t023 );
1306             break;
1307           }
1308         }
1309       }
1310       if ( !triaSplits.empty() )
1311         hasAdjacentSplits = true;
1312     }
1313
1314     // Among variants of split method select one compliant with adjacent volumes
1315
1316     TSplitMethod method;
1317     if ( !vol.Element()->IsPoly() )
1318     {
1319       int nbVariants = 2, nbTet = 0;
1320       const int** connVariants = 0;
1321       switch ( vol.Element()->GetEntityType() )
1322       {
1323       case SMDSEntity_Hexa:
1324       case SMDSEntity_Quad_Hexa:
1325         if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1326           connVariants = theHexTo5, nbTet = 5;
1327         else
1328           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1329         break;
1330       case SMDSEntity_Pyramid:
1331       case SMDSEntity_Quad_Pyramid:
1332         connVariants = thePyraTo2;  nbTet = 2;
1333         break;
1334       case SMDSEntity_Penta:
1335       case SMDSEntity_Quad_Penta:
1336         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1337         break;
1338       default:
1339         nbVariants = 0;
1340       }
1341       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1342       {
1343         // check method compliancy with adjacent tetras,
1344         // all found splits must be among facets of tetras described by this method
1345         method = TSplitMethod( nbTet, connVariants[variant] );
1346         if ( hasAdjacentSplits && method._nbTetra > 0 )
1347         {
1348           bool facetCreated = true;
1349           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1350           {
1351             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1352             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1353               facetCreated = method.hasFacet( *facet );
1354           }
1355           if ( !facetCreated )
1356             method = TSplitMethod(0); // incompatible method
1357         }
1358       }
1359     }
1360     if ( method._nbTetra < 1 )
1361     {
1362       // No standard method is applicable, use a generic solution:
1363       // each facet of a volume is split into triangles and
1364       // each of triangles and a volume barycenter form a tetrahedron.
1365
1366       int* connectivity = new int[ maxTetConnSize + 1 ];
1367       method._connectivity = connectivity;
1368       method._ownConn = true;
1369       method._baryNode = true;
1370
1371       int connSize = 0;
1372       int baryCenInd = vol.NbNodes();
1373       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1374       {
1375         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1376         const int*   nInd = vol.GetFaceNodesIndices( iF );
1377         // find common node of triangle facets of tetra to create
1378         int iCommon = 0; // index in linear numeration
1379         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1380         if ( !triaSplits.empty() )
1381         {
1382           // by found facets
1383           const TTriangleFacet* facet = &triaSplits.front();
1384           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1385             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1386                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1387               break;
1388         }
1389         else if ( nbNodes > 3 )
1390         {
1391           // find the best method of splitting into triangles by aspect ratio
1392           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1393           map< double, int > badness2iCommon;
1394           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1395           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1396           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1397             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1398             {
1399               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1400                                       nodes[ iQ*((iLast-1)%nbNodes)],
1401                                       nodes[ iQ*((iLast  )%nbNodes)]);
1402               double badness = getBadRate( &tria, aspectRatio );
1403               badness2iCommon.insert( make_pair( badness, iCommon ));
1404             }
1405           // use iCommon with lowest badness
1406           iCommon = badness2iCommon.begin()->second;
1407         }
1408         if ( iCommon >= nbNodes )
1409           iCommon = 0; // something wrong
1410         // fill connectivity of tetra
1411         int nbTet = nbNodes - 2;
1412         for ( int i = 0; i < nbTet; ++i )
1413         {
1414           int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1415           if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1416           connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1417           connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1418           connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1419           connectivity[ connSize++ ] = baryCenInd;
1420           ++method._nbTetra;
1421         }
1422       }
1423       connectivity[ connSize++ ] = -1;
1424     }
1425     return method;
1426   }
1427   //================================================================================
1428   /*!
1429    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1430    */
1431   //================================================================================
1432
1433   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1434   {
1435     // find the tetrahedron including the three nodes of facet
1436     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1437     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1438     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1439     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1440     while ( volIt1->more() )
1441     {
1442       const SMDS_MeshElement* v = volIt1->next();
1443       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1444         continue;
1445       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1446       while ( volIt2->more() )
1447         if ( v != volIt2->next() )
1448           continue;
1449       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1450       while ( volIt3->more() )
1451         if ( v == volIt3->next() )
1452           return true;
1453     }
1454     return false;
1455   }
1456 } // namespace
1457
1458 //=======================================================================
1459 //function : SplitVolumesIntoTetra
1460 //purpose  : Split volumic elements into tetrahedra.
1461 //=======================================================================
1462
1463 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1464                                               const int                theMethodFlags)
1465 {
1466   // std-like iterator on coordinates of nodes of mesh element
1467   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1468   NXyzIterator xyzEnd;
1469
1470   SMDS_VolumeTool    volTool;
1471   SMESH_MesherHelper helper( *GetMesh());
1472
1473   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1474   SMESHDS_SubMesh* fSubMesh = subMesh;
1475   
1476   SMESH_SequenceOfElemPtr newNodes, newElems;
1477
1478   TIDSortedElemSet::const_iterator elem = theElems.begin();
1479   for ( ; elem != theElems.end(); ++elem )
1480   {
1481     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1482     if ( geomType <= SMDSEntity_Quad_Tetra )
1483       continue; // tetra or face or ...
1484
1485     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1486
1487     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1488     if ( splitMethod._nbTetra < 1 ) continue;
1489
1490     // find submesh to add new tetras in
1491     if ( !subMesh || !subMesh->Contains( *elem ))
1492     {
1493       int shapeID = FindShape( *elem );
1494       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1495       subMesh = GetMeshDS()->MeshElements( shapeID );
1496     }
1497     int iQ;
1498     if ( (*elem)->IsQuadratic() )
1499     {
1500       iQ = 2;
1501       // add quadratic links to the helper
1502       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1503       {
1504         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1505         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1506           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1507       }
1508       helper.SetIsQuadratic( true );
1509     }
1510     else
1511     {
1512       iQ = 1;
1513       helper.SetIsQuadratic( false );
1514     }
1515     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1516     if ( splitMethod._baryNode )
1517     {
1518       // make a node at barycenter
1519       gp_XYZ gc( 0,0,0 );
1520       gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1521       SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1522       nodes.push_back( gcNode );
1523       newNodes.Append( gcNode );
1524     }
1525
1526     // make tetras
1527     helper.SetElementsOnShape( true );
1528     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1529     const int* tetConn = splitMethod._connectivity;
1530     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1531       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1532                                                        nodes[ tetConn[1] ],
1533                                                        nodes[ tetConn[2] ],
1534                                                        nodes[ tetConn[3] ]));
1535
1536     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1537
1538     // Split faces on sides of the split volume
1539
1540     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1541     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1542     {
1543       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1544       if ( nbNodes < 4 ) continue;
1545
1546       // find an existing face
1547       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1548                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1549       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1550       {
1551         // among possible triangles create ones discribed by split method
1552         const int* nInd = volTool.GetFaceNodesIndices( iF );
1553         int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1554         int iCom = 0; // common node of triangle faces to split into
1555         list< TTriangleFacet > facets;
1556         for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1557         {
1558           TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1559                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1560                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1561           TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1562                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1563                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1564           if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1565           {
1566             facets.push_back( t012 );
1567             facets.push_back( t023 );
1568             for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1569               facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1570                                                 nInd[ iQ * ((iLast-1)%nbNodes )],
1571                                                 nInd[ iQ * ((iLast  )%nbNodes )]));
1572             break;
1573           }
1574         }
1575         // find submesh to add new faces in
1576         if ( !fSubMesh || !fSubMesh->Contains( face ))
1577         {
1578           int shapeID = FindShape( face );
1579           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1580         }
1581         // make triangles
1582         helper.SetElementsOnShape( false );
1583         vector< const SMDS_MeshElement* > triangles;
1584         list< TTriangleFacet >::iterator facet = facets.begin();
1585         for ( ; facet != facets.end(); ++facet )
1586         {
1587           if ( !volTool.IsFaceExternal( iF ))
1588             swap( facet->_n2, facet->_n3 );
1589           triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1590                                                volNodes[ facet->_n2 ],
1591                                                volNodes[ facet->_n3 ]));
1592           if ( triangles.back() && fSubMesh )
1593             fSubMesh->AddElement( triangles.back());
1594           newElems.Append( triangles.back() );
1595         }
1596         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1597         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1598       }
1599
1600     } // loop on volume faces to split them into triangles
1601
1602     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1603
1604   } // loop on volumes to split
1605
1606   myLastCreatedNodes = newNodes;
1607   myLastCreatedElems = newElems;
1608 }
1609
1610 //=======================================================================
1611 //function : AddToSameGroups
1612 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1613 //=======================================================================
1614
1615 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1616                                         const SMDS_MeshElement* elemInGroups,
1617                                         SMESHDS_Mesh *          aMesh)
1618 {
1619   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1620   if (!groups.empty()) {
1621     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1622     for ( ; grIt != groups.end(); grIt++ ) {
1623       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1624       if ( group && group->Contains( elemInGroups ))
1625         group->SMDSGroup().Add( elemToAdd );
1626     }
1627   }
1628 }
1629
1630
1631 //=======================================================================
1632 //function : RemoveElemFromGroups
1633 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1634 //=======================================================================
1635 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1636                                              SMESHDS_Mesh *          aMesh)
1637 {
1638   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1639   if (!groups.empty())
1640   {
1641     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1642     for (; GrIt != groups.end(); GrIt++)
1643     {
1644       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1645       if (!grp || grp->IsEmpty()) continue;
1646       grp->SMDSGroup().Remove(removeelem);
1647     }
1648   }
1649 }
1650
1651 //================================================================================
1652 /*!
1653  * \brief Replace elemToRm by elemToAdd in the all groups
1654  */
1655 //================================================================================
1656
1657 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1658                                             const SMDS_MeshElement* elemToAdd,
1659                                             SMESHDS_Mesh *          aMesh)
1660 {
1661   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1662   if (!groups.empty()) {
1663     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1664     for ( ; grIt != groups.end(); grIt++ ) {
1665       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1666       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1667         group->SMDSGroup().Add( elemToAdd );
1668     }
1669   }
1670 }
1671
1672 //================================================================================
1673 /*!
1674  * \brief Replace elemToRm by elemToAdd in the all groups
1675  */
1676 //================================================================================
1677
1678 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1679                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1680                                             SMESHDS_Mesh *                         aMesh)
1681 {
1682   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1683   if (!groups.empty())
1684   {
1685     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1686     for ( ; grIt != groups.end(); grIt++ ) {
1687       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1688       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1689         for ( int i = 0; i < elemToAdd.size(); ++i )
1690           group->SMDSGroup().Add( elemToAdd[ i ] );
1691     }
1692   }
1693 }
1694
1695 //=======================================================================
1696 //function : QuadToTri
1697 //purpose  : Cut quadrangles into triangles.
1698 //           theCrit is used to select a diagonal to cut
1699 //=======================================================================
1700
1701 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1702                                   const bool         the13Diag)
1703 {
1704   myLastCreatedElems.Clear();
1705   myLastCreatedNodes.Clear();
1706
1707   MESSAGE( "::QuadToTri()" );
1708
1709   SMESHDS_Mesh * aMesh = GetMeshDS();
1710
1711   Handle(Geom_Surface) surface;
1712   SMESH_MesherHelper   helper( *GetMesh() );
1713
1714   TIDSortedElemSet::iterator itElem;
1715   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1716     const SMDS_MeshElement* elem = *itElem;
1717     if ( !elem || elem->GetType() != SMDSAbs_Face )
1718       continue;
1719     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1720     if(!isquad) continue;
1721
1722     if(elem->NbNodes()==4) {
1723       // retrieve element nodes
1724       const SMDS_MeshNode* aNodes [4];
1725       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1726       int i = 0;
1727       while ( itN->more() )
1728         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1729
1730       int aShapeId = FindShape( elem );
1731       const SMDS_MeshElement* newElem = 0;
1732       if ( the13Diag ) {
1733         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1734         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1735       }
1736       else {
1737         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1738         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1739       }
1740       myLastCreatedElems.Append(newElem);
1741       // put a new triangle on the same shape and add to the same groups
1742       if ( aShapeId )
1743         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1744       AddToSameGroups( newElem, elem, aMesh );
1745     }
1746
1747     // Quadratic quadrangle
1748
1749     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1750
1751       // get surface elem is on
1752       int aShapeId = FindShape( elem );
1753       if ( aShapeId != helper.GetSubShapeID() ) {
1754         surface.Nullify();
1755         TopoDS_Shape shape;
1756         if ( aShapeId > 0 )
1757           shape = aMesh->IndexToShape( aShapeId );
1758         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1759           TopoDS_Face face = TopoDS::Face( shape );
1760           surface = BRep_Tool::Surface( face );
1761           if ( !surface.IsNull() )
1762             helper.SetSubShape( shape );
1763         }
1764       }
1765
1766       const SMDS_MeshNode* aNodes [8];
1767       const SMDS_MeshNode* inFaceNode = 0;
1768       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1769       int i = 0;
1770       while ( itN->more() ) {
1771         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1772         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1773              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1774         {
1775           inFaceNode = aNodes[ i-1 ];
1776         }
1777       }
1778
1779       // find middle point for (0,1,2,3)
1780       // and create a node in this point;
1781       gp_XYZ p( 0,0,0 );
1782       if ( surface.IsNull() ) {
1783         for(i=0; i<4; i++)
1784           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1785         p /= 4;
1786       }
1787       else {
1788         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1789         gp_XY uv( 0,0 );
1790         for(i=0; i<4; i++)
1791           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1792         uv /= 4.;
1793         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1794       }
1795       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1796       myLastCreatedNodes.Append(newN);
1797
1798       // create a new element
1799       const SMDS_MeshElement* newElem = 0;
1800       const SMDS_MeshNode* N[6];
1801       if ( the13Diag ) {
1802         N[0] = aNodes[0];
1803         N[1] = aNodes[1];
1804         N[2] = aNodes[2];
1805         N[3] = aNodes[4];
1806         N[4] = aNodes[5];
1807         N[5] = newN;
1808         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1809                                  aNodes[6], aNodes[7], newN );
1810       }
1811       else {
1812         N[0] = aNodes[1];
1813         N[1] = aNodes[2];
1814         N[2] = aNodes[3];
1815         N[3] = aNodes[5];
1816         N[4] = aNodes[6];
1817         N[5] = newN;
1818         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1819                                  aNodes[7], aNodes[4], newN );
1820       }
1821       myLastCreatedElems.Append(newElem);
1822       aMesh->ChangeElementNodes( elem, N, 6 );
1823       // put a new triangle on the same shape and add to the same groups
1824       if ( aShapeId )
1825         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1826       AddToSameGroups( newElem, elem, aMesh );
1827     }
1828   }
1829
1830   return true;
1831 }
1832
1833 //=======================================================================
1834 //function : getAngle
1835 //purpose  :
1836 //=======================================================================
1837
1838 double getAngle(const SMDS_MeshElement * tr1,
1839                 const SMDS_MeshElement * tr2,
1840                 const SMDS_MeshNode *    n1,
1841                 const SMDS_MeshNode *    n2)
1842 {
1843   double angle = 2*PI; // bad angle
1844
1845   // get normals
1846   SMESH::Controls::TSequenceOfXYZ P1, P2;
1847   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1848        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1849     return angle;
1850   gp_Vec N1,N2;
1851   if(!tr1->IsQuadratic())
1852     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1853   else
1854     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1855   if ( N1.SquareMagnitude() <= gp::Resolution() )
1856     return angle;
1857   if(!tr2->IsQuadratic())
1858     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1859   else
1860     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1861   if ( N2.SquareMagnitude() <= gp::Resolution() )
1862     return angle;
1863
1864   // find the first diagonal node n1 in the triangles:
1865   // take in account a diagonal link orientation
1866   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1867   for ( int t = 0; t < 2; t++ ) {
1868     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1869     int i = 0, iDiag = -1;
1870     while ( it->more()) {
1871       const SMDS_MeshElement *n = it->next();
1872       if ( n == n1 || n == n2 )
1873         if ( iDiag < 0)
1874           iDiag = i;
1875         else {
1876           if ( i - iDiag == 1 )
1877             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1878           else
1879             nFirst[ t ] = n;
1880           break;
1881         }
1882       i++;
1883     }
1884   }
1885   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1886     N2.Reverse();
1887
1888   angle = N1.Angle( N2 );
1889   //SCRUTE( angle );
1890   return angle;
1891 }
1892
1893 // =================================================
1894 // class generating a unique ID for a pair of nodes
1895 // and able to return nodes by that ID
1896 // =================================================
1897 class LinkID_Gen {
1898 public:
1899
1900   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1901     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1902   {}
1903
1904   long GetLinkID (const SMDS_MeshNode * n1,
1905                   const SMDS_MeshNode * n2) const
1906   {
1907     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1908   }
1909
1910   bool GetNodes (const long             theLinkID,
1911                  const SMDS_MeshNode* & theNode1,
1912                  const SMDS_MeshNode* & theNode2) const
1913   {
1914     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1915     if ( !theNode1 ) return false;
1916     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1917     if ( !theNode2 ) return false;
1918     return true;
1919   }
1920
1921 private:
1922   LinkID_Gen();
1923   const SMESHDS_Mesh* myMesh;
1924   long                myMaxID;
1925 };
1926
1927
1928 //=======================================================================
1929 //function : TriToQuad
1930 //purpose  : Fuse neighbour triangles into quadrangles.
1931 //           theCrit is used to select a neighbour to fuse with.
1932 //           theMaxAngle is a max angle between element normals at which
1933 //           fusion is still performed.
1934 //=======================================================================
1935
1936 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1937                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1938                                   const double                         theMaxAngle)
1939 {
1940   myLastCreatedElems.Clear();
1941   myLastCreatedNodes.Clear();
1942
1943   MESSAGE( "::TriToQuad()" );
1944
1945   if ( !theCrit.get() )
1946     return false;
1947
1948   SMESHDS_Mesh * aMesh = GetMeshDS();
1949
1950   // Prepare data for algo: build
1951   // 1. map of elements with their linkIDs
1952   // 2. map of linkIDs with their elements
1953
1954   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1955   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1956   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
1957   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1958
1959   TIDSortedElemSet::iterator itElem;
1960   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1961     const SMDS_MeshElement* elem = *itElem;
1962     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1963     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1964     if(!IsTria) continue;
1965
1966     // retrieve element nodes
1967     const SMDS_MeshNode* aNodes [4];
1968     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1969     int i = 0;
1970     while ( i<3 )
1971       aNodes[ i++ ] = cast2Node( itN->next() );
1972     aNodes[ 3 ] = aNodes[ 0 ];
1973
1974     // fill maps
1975     for ( i = 0; i < 3; i++ ) {
1976       SMESH_TLink link( aNodes[i], aNodes[i+1] );
1977       // check if elements sharing a link can be fused
1978       itLE = mapLi_listEl.find( link );
1979       if ( itLE != mapLi_listEl.end() ) {
1980         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1981           continue;
1982         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1983         //if ( FindShape( elem ) != FindShape( elem2 ))
1984         //  continue; // do not fuse triangles laying on different shapes
1985         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1986           continue; // avoid making badly shaped quads
1987         (*itLE).second.push_back( elem );
1988       }
1989       else {
1990         mapLi_listEl[ link ].push_back( elem );
1991       }
1992       mapEl_setLi [ elem ].insert( link );
1993     }
1994   }
1995   // Clean the maps from the links shared by a sole element, ie
1996   // links to which only one element is bound in mapLi_listEl
1997
1998   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1999     int nbElems = (*itLE).second.size();
2000     if ( nbElems < 2  ) {
2001       const SMDS_MeshElement* elem = (*itLE).second.front();
2002       SMESH_TLink link = (*itLE).first;
2003       mapEl_setLi[ elem ].erase( link );
2004       if ( mapEl_setLi[ elem ].empty() )
2005         mapEl_setLi.erase( elem );
2006     }
2007   }
2008
2009   // Algo: fuse triangles into quadrangles
2010
2011   while ( ! mapEl_setLi.empty() ) {
2012     // Look for the start element:
2013     // the element having the least nb of shared links
2014     const SMDS_MeshElement* startElem = 0;
2015     int minNbLinks = 4;
2016     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2017       int nbLinks = (*itEL).second.size();
2018       if ( nbLinks < minNbLinks ) {
2019         startElem = (*itEL).first;
2020         minNbLinks = nbLinks;
2021         if ( minNbLinks == 1 )
2022           break;
2023       }
2024     }
2025
2026     // search elements to fuse starting from startElem or links of elements
2027     // fused earlyer - startLinks
2028     list< SMESH_TLink > startLinks;
2029     while ( startElem || !startLinks.empty() ) {
2030       while ( !startElem && !startLinks.empty() ) {
2031         // Get an element to start, by a link
2032         SMESH_TLink linkId = startLinks.front();
2033         startLinks.pop_front();
2034         itLE = mapLi_listEl.find( linkId );
2035         if ( itLE != mapLi_listEl.end() ) {
2036           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2037           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2038           for ( ; itE != listElem.end() ; itE++ )
2039             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2040               startElem = (*itE);
2041           mapLi_listEl.erase( itLE );
2042         }
2043       }
2044
2045       if ( startElem ) {
2046         // Get candidates to be fused
2047         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2048         const SMESH_TLink *link12, *link13;
2049         startElem = 0;
2050         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2051         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2052         ASSERT( !setLi.empty() );
2053         set< SMESH_TLink >::iterator itLi;
2054         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2055         {
2056           const SMESH_TLink & link = (*itLi);
2057           itLE = mapLi_listEl.find( link );
2058           if ( itLE == mapLi_listEl.end() )
2059             continue;
2060
2061           const SMDS_MeshElement* elem = (*itLE).second.front();
2062           if ( elem == tr1 )
2063             elem = (*itLE).second.back();
2064           mapLi_listEl.erase( itLE );
2065           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2066             continue;
2067           if ( tr2 ) {
2068             tr3 = elem;
2069             link13 = &link;
2070           }
2071           else {
2072             tr2 = elem;
2073             link12 = &link;
2074           }
2075
2076           // add other links of elem to list of links to re-start from
2077           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2078           set< SMESH_TLink >::iterator it;
2079           for ( it = links.begin(); it != links.end(); it++ ) {
2080             const SMESH_TLink& link2 = (*it);
2081             if ( link2 != link )
2082               startLinks.push_back( link2 );
2083           }
2084         }
2085
2086         // Get nodes of possible quadrangles
2087         const SMDS_MeshNode *n12 [4], *n13 [4];
2088         bool Ok12 = false, Ok13 = false;
2089         const SMDS_MeshNode *linkNode1, *linkNode2;
2090         if(tr2) {
2091           linkNode1 = link12->first;
2092           linkNode2 = link12->second;
2093           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2094             Ok12 = true;
2095         }
2096         if(tr3) {
2097           linkNode1 = link13->first;
2098           linkNode2 = link13->second;
2099           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2100             Ok13 = true;
2101         }
2102
2103         // Choose a pair to fuse
2104         if ( Ok12 && Ok13 ) {
2105           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2106           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2107           double aBadRate12 = getBadRate( &quad12, theCrit );
2108           double aBadRate13 = getBadRate( &quad13, theCrit );
2109           if (  aBadRate13 < aBadRate12 )
2110             Ok12 = false;
2111           else
2112             Ok13 = false;
2113         }
2114
2115         // Make quadrangles
2116         // and remove fused elems and removed links from the maps
2117         mapEl_setLi.erase( tr1 );
2118         if ( Ok12 ) {
2119           mapEl_setLi.erase( tr2 );
2120           mapLi_listEl.erase( *link12 );
2121           if(tr1->NbNodes()==3) {
2122             if( tr1->GetID() < tr2->GetID() ) {
2123               aMesh->ChangeElementNodes( tr1, n12, 4 );
2124               myLastCreatedElems.Append(tr1);
2125               aMesh->RemoveElement( tr2 );
2126             }
2127             else {
2128               aMesh->ChangeElementNodes( tr2, n12, 4 );
2129               myLastCreatedElems.Append(tr2);
2130               aMesh->RemoveElement( tr1);
2131             }
2132           }
2133           else {
2134             const SMDS_MeshNode* N1 [6];
2135             const SMDS_MeshNode* N2 [6];
2136             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2137             // now we receive following N1 and N2 (using numeration as above image)
2138             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2139             // i.e. first nodes from both arrays determ new diagonal
2140             const SMDS_MeshNode* aNodes[8];
2141             aNodes[0] = N1[0];
2142             aNodes[1] = N1[1];
2143             aNodes[2] = N2[0];
2144             aNodes[3] = N2[1];
2145             aNodes[4] = N1[3];
2146             aNodes[5] = N2[5];
2147             aNodes[6] = N2[3];
2148             aNodes[7] = N1[5];
2149             if( tr1->GetID() < tr2->GetID() ) {
2150               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2151               myLastCreatedElems.Append(tr1);
2152               GetMeshDS()->RemoveElement( tr2 );
2153             }
2154             else {
2155               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2156               myLastCreatedElems.Append(tr2);
2157               GetMeshDS()->RemoveElement( tr1 );
2158             }
2159             // remove middle node (9)
2160             GetMeshDS()->RemoveNode( N1[4] );
2161           }
2162         }
2163         else if ( Ok13 ) {
2164           mapEl_setLi.erase( tr3 );
2165           mapLi_listEl.erase( *link13 );
2166           if(tr1->NbNodes()==3) {
2167             if( tr1->GetID() < tr2->GetID() ) {
2168               aMesh->ChangeElementNodes( tr1, n13, 4 );
2169               myLastCreatedElems.Append(tr1);
2170               aMesh->RemoveElement( tr3 );
2171             }
2172             else {
2173               aMesh->ChangeElementNodes( tr3, n13, 4 );
2174               myLastCreatedElems.Append(tr3);
2175               aMesh->RemoveElement( tr1 );
2176             }
2177           }
2178           else {
2179             const SMDS_MeshNode* N1 [6];
2180             const SMDS_MeshNode* N2 [6];
2181             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2182             // now we receive following N1 and N2 (using numeration as above image)
2183             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2184             // i.e. first nodes from both arrays determ new diagonal
2185             const SMDS_MeshNode* aNodes[8];
2186             aNodes[0] = N1[0];
2187             aNodes[1] = N1[1];
2188             aNodes[2] = N2[0];
2189             aNodes[3] = N2[1];
2190             aNodes[4] = N1[3];
2191             aNodes[5] = N2[5];
2192             aNodes[6] = N2[3];
2193             aNodes[7] = N1[5];
2194             if( tr1->GetID() < tr2->GetID() ) {
2195               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2196               myLastCreatedElems.Append(tr1);
2197               GetMeshDS()->RemoveElement( tr3 );
2198             }
2199             else {
2200               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2201               myLastCreatedElems.Append(tr3);
2202               GetMeshDS()->RemoveElement( tr1 );
2203             }
2204             // remove middle node (9)
2205             GetMeshDS()->RemoveNode( N1[4] );
2206           }
2207         }
2208
2209         // Next element to fuse: the rejected one
2210         if ( tr3 )
2211           startElem = Ok12 ? tr3 : tr2;
2212
2213       } // if ( startElem )
2214     } // while ( startElem || !startLinks.empty() )
2215   } // while ( ! mapEl_setLi.empty() )
2216
2217   return true;
2218 }
2219
2220
2221 /*#define DUMPSO(txt) \
2222 //  cout << txt << endl;
2223 //=============================================================================
2224 //
2225 //
2226 //
2227 //=============================================================================
2228 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2229 {
2230 if ( i1 == i2 )
2231 return;
2232 int tmp = idNodes[ i1 ];
2233 idNodes[ i1 ] = idNodes[ i2 ];
2234 idNodes[ i2 ] = tmp;
2235 gp_Pnt Ptmp = P[ i1 ];
2236 P[ i1 ] = P[ i2 ];
2237 P[ i2 ] = Ptmp;
2238 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2239 }
2240
2241 //=======================================================================
2242 //function : SortQuadNodes
2243 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2244 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2245 //           1 or 2 else 0.
2246 //=======================================================================
2247
2248 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2249 int               idNodes[] )
2250 {
2251   gp_Pnt P[4];
2252   int i;
2253   for ( i = 0; i < 4; i++ ) {
2254     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2255     if ( !n ) return 0;
2256     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2257   }
2258
2259   gp_Vec V1(P[0], P[1]);
2260   gp_Vec V2(P[0], P[2]);
2261   gp_Vec V3(P[0], P[3]);
2262
2263   gp_Vec Cross1 = V1 ^ V2;
2264   gp_Vec Cross2 = V2 ^ V3;
2265
2266   i = 0;
2267   if (Cross1.Dot(Cross2) < 0)
2268   {
2269     Cross1 = V2 ^ V1;
2270     Cross2 = V1 ^ V3;
2271
2272     if (Cross1.Dot(Cross2) < 0)
2273       i = 2;
2274     else
2275       i = 1;
2276     swap ( i, i + 1, idNodes, P );
2277
2278     //     for ( int ii = 0; ii < 4; ii++ ) {
2279     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2280     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2281     //     }
2282   }
2283   return i;
2284 }
2285
2286 //=======================================================================
2287 //function : SortHexaNodes
2288 //purpose  : Set 8 nodes of a hexahedron in a good order.
2289 //           Return success status
2290 //=======================================================================
2291
2292 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2293                                       int               idNodes[] )
2294 {
2295   gp_Pnt P[8];
2296   int i;
2297   DUMPSO( "INPUT: ========================================");
2298   for ( i = 0; i < 8; i++ ) {
2299     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2300     if ( !n ) return false;
2301     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2302     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2303   }
2304   DUMPSO( "========================================");
2305
2306
2307   set<int> faceNodes;  // ids of bottom face nodes, to be found
2308   set<int> checkedId1; // ids of tried 2-nd nodes
2309   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2310   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2311   int iMin, iLoop1 = 0;
2312
2313   // Loop to try the 2-nd nodes
2314
2315   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2316   {
2317     // Find not checked 2-nd node
2318     for ( i = 1; i < 8; i++ )
2319       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2320         int id1 = idNodes[i];
2321         swap ( 1, i, idNodes, P );
2322         checkedId1.insert ( id1 );
2323         break;
2324       }
2325
2326     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2327     // ie that all but meybe one (id3 which is on the same face) nodes
2328     // lay on the same side from the triangle plane.
2329
2330     bool manyInPlane = false; // more than 4 nodes lay in plane
2331     int iLoop2 = 0;
2332     while ( ++iLoop2 < 6 ) {
2333
2334       // get 1-2-3 plane coeffs
2335       Standard_Real A, B, C, D;
2336       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2337       if ( N.SquareMagnitude() > gp::Resolution() )
2338       {
2339         gp_Pln pln ( P[0], N );
2340         pln.Coefficients( A, B, C, D );
2341
2342         // find the node (iMin) closest to pln
2343         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2344         set<int> idInPln;
2345         for ( i = 3; i < 8; i++ ) {
2346           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2347           if ( fabs( dist[i] ) < minDist ) {
2348             minDist = fabs( dist[i] );
2349             iMin = i;
2350           }
2351           if ( fabs( dist[i] ) <= tol )
2352             idInPln.insert( idNodes[i] );
2353         }
2354
2355         // there should not be more than 4 nodes in bottom plane
2356         if ( idInPln.size() > 1 )
2357         {
2358           DUMPSO( "### idInPln.size() = " << idInPln.size());
2359           // idInPlane does not contain the first 3 nodes
2360           if ( manyInPlane || idInPln.size() == 5)
2361             return false; // all nodes in one plane
2362           manyInPlane = true;
2363
2364           // set the 1-st node to be not in plane
2365           for ( i = 3; i < 8; i++ ) {
2366             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2367               DUMPSO( "### Reset 0-th node");
2368               swap( 0, i, idNodes, P );
2369               break;
2370             }
2371           }
2372
2373           // reset to re-check second nodes
2374           leastDist = DBL_MAX;
2375           faceNodes.clear();
2376           checkedId1.clear();
2377           iLoop1 = 0;
2378           break; // from iLoop2;
2379         }
2380
2381         // check that the other 4 nodes are on the same side
2382         bool sameSide = true;
2383         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2384         for ( i = 3; sameSide && i < 8; i++ ) {
2385           if ( i != iMin )
2386             sameSide = ( isNeg == dist[i] <= 0.);
2387         }
2388
2389         // keep best solution
2390         if ( sameSide && minDist < leastDist ) {
2391           leastDist = minDist;
2392           faceNodes.clear();
2393           faceNodes.insert( idNodes[ 1 ] );
2394           faceNodes.insert( idNodes[ 2 ] );
2395           faceNodes.insert( idNodes[ iMin ] );
2396           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2397                   << " leastDist = " << leastDist);
2398           if ( leastDist <= DBL_MIN )
2399             break;
2400         }
2401       }
2402
2403       // set next 3-d node to check
2404       int iNext = 2 + iLoop2;
2405       if ( iNext < 8 ) {
2406         DUMPSO( "Try 2-nd");
2407         swap ( 2, iNext, idNodes, P );
2408       }
2409     } // while ( iLoop2 < 6 )
2410   } // iLoop1
2411
2412   if ( faceNodes.empty() ) return false;
2413
2414   // Put the faceNodes in proper places
2415   for ( i = 4; i < 8; i++ ) {
2416     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2417       // find a place to put
2418       int iTo = 1;
2419       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2420         iTo++;
2421       DUMPSO( "Set faceNodes");
2422       swap ( iTo, i, idNodes, P );
2423     }
2424   }
2425
2426
2427   // Set nodes of the found bottom face in good order
2428   DUMPSO( " Found bottom face: ");
2429   i = SortQuadNodes( theMesh, idNodes );
2430   if ( i ) {
2431     gp_Pnt Ptmp = P[ i ];
2432     P[ i ] = P[ i+1 ];
2433     P[ i+1 ] = Ptmp;
2434   }
2435   //   else
2436   //     for ( int ii = 0; ii < 4; ii++ ) {
2437   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2438   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2439   //    }
2440
2441   // Gravity center of the top and bottom faces
2442   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2443   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2444
2445   // Get direction from the bottom to the top face
2446   gp_Vec upDir ( aGCb, aGCt );
2447   Standard_Real upDirSize = upDir.Magnitude();
2448   if ( upDirSize <= gp::Resolution() ) return false;
2449   upDir / upDirSize;
2450
2451   // Assure that the bottom face normal points up
2452   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2453   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2454   if ( Nb.Dot( upDir ) < 0 ) {
2455     DUMPSO( "Reverse bottom face");
2456     swap( 1, 3, idNodes, P );
2457   }
2458
2459   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2460   Standard_Real minDist = DBL_MAX;
2461   for ( i = 4; i < 8; i++ ) {
2462     // projection of P[i] to the plane defined by P[0] and upDir
2463     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2464     Standard_Real sqDist = P[0].SquareDistance( Pp );
2465     if ( sqDist < minDist ) {
2466       minDist = sqDist;
2467       iMin = i;
2468     }
2469   }
2470   DUMPSO( "Set 4-th");
2471   swap ( 4, iMin, idNodes, P );
2472
2473   // Set nodes of the top face in good order
2474   DUMPSO( "Sort top face");
2475   i = SortQuadNodes( theMesh, &idNodes[4] );
2476   if ( i ) {
2477     i += 4;
2478     gp_Pnt Ptmp = P[ i ];
2479     P[ i ] = P[ i+1 ];
2480     P[ i+1 ] = Ptmp;
2481   }
2482
2483   // Assure that direction of the top face normal is from the bottom face
2484   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2485   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2486   if ( Nt.Dot( upDir ) < 0 ) {
2487     DUMPSO( "Reverse top face");
2488     swap( 5, 7, idNodes, P );
2489   }
2490
2491   //   DUMPSO( "OUTPUT: ========================================");
2492   //   for ( i = 0; i < 8; i++ ) {
2493   //     float *p = ugrid->GetPoint(idNodes[i]);
2494   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2495   //   }
2496
2497   return true;
2498 }*/
2499
2500 //================================================================================
2501 /*!
2502  * \brief Return nodes linked to the given one
2503  * \param theNode - the node
2504  * \param linkedNodes - the found nodes
2505  * \param type - the type of elements to check
2506  *
2507  * Medium nodes are ignored
2508  */
2509 //================================================================================
2510
2511 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2512                                        TIDSortedElemSet &   linkedNodes,
2513                                        SMDSAbs_ElementType  type )
2514 {
2515   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2516   while ( elemIt->more() )
2517   {
2518     const SMDS_MeshElement* elem = elemIt->next();
2519     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2520     if ( elem->GetType() == SMDSAbs_Volume )
2521     {
2522       SMDS_VolumeTool vol( elem );
2523       while ( nodeIt->more() ) {
2524         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2525         if ( theNode != n && vol.IsLinked( theNode, n ))
2526           linkedNodes.insert( n );
2527       }
2528     }
2529     else
2530     {
2531       for ( int i = 0; nodeIt->more(); ++i ) {
2532         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2533         if ( n == theNode ) {
2534           int iBefore = i - 1;
2535           int iAfter  = i + 1;
2536           if ( elem->IsQuadratic() ) {
2537             int nb = elem->NbNodes() / 2;
2538             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2539             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2540           }
2541           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2542           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2543         }
2544       }
2545     }
2546   }
2547 }
2548
2549 //=======================================================================
2550 //function : laplacianSmooth
2551 //purpose  : pulls theNode toward the center of surrounding nodes directly
2552 //           connected to that node along an element edge
2553 //=======================================================================
2554
2555 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2556                      const Handle(Geom_Surface)&          theSurface,
2557                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2558 {
2559   // find surrounding nodes
2560
2561   TIDSortedElemSet nodeSet;
2562   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2563
2564   // compute new coodrs
2565
2566   double coord[] = { 0., 0., 0. };
2567   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2568   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2569     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2570     if ( theSurface.IsNull() ) { // smooth in 3D
2571       coord[0] += node->X();
2572       coord[1] += node->Y();
2573       coord[2] += node->Z();
2574     }
2575     else { // smooth in 2D
2576       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2577       gp_XY* uv = theUVMap[ node ];
2578       coord[0] += uv->X();
2579       coord[1] += uv->Y();
2580     }
2581   }
2582   int nbNodes = nodeSet.size();
2583   if ( !nbNodes )
2584     return;
2585   coord[0] /= nbNodes;
2586   coord[1] /= nbNodes;
2587
2588   if ( !theSurface.IsNull() ) {
2589     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2590     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2591     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2592     coord[0] = p3d.X();
2593     coord[1] = p3d.Y();
2594     coord[2] = p3d.Z();
2595   }
2596   else
2597     coord[2] /= nbNodes;
2598
2599   // move node
2600
2601   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2602 }
2603
2604 //=======================================================================
2605 //function : centroidalSmooth
2606 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2607 //           surrounding elements
2608 //=======================================================================
2609
2610 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2611                       const Handle(Geom_Surface)&          theSurface,
2612                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2613 {
2614   gp_XYZ aNewXYZ(0.,0.,0.);
2615   SMESH::Controls::Area anAreaFunc;
2616   double totalArea = 0.;
2617   int nbElems = 0;
2618
2619   // compute new XYZ
2620
2621   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2622   while ( elemIt->more() )
2623   {
2624     const SMDS_MeshElement* elem = elemIt->next();
2625     nbElems++;
2626
2627     gp_XYZ elemCenter(0.,0.,0.);
2628     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2629     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2630     int nn = elem->NbNodes();
2631     if(elem->IsQuadratic()) nn = nn/2;
2632     int i=0;
2633     //while ( itN->more() ) {
2634     while ( i<nn ) {
2635       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2636       i++;
2637       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2638       aNodePoints.push_back( aP );
2639       if ( !theSurface.IsNull() ) { // smooth in 2D
2640         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2641         gp_XY* uv = theUVMap[ aNode ];
2642         aP.SetCoord( uv->X(), uv->Y(), 0. );
2643       }
2644       elemCenter += aP;
2645     }
2646     double elemArea = anAreaFunc.GetValue( aNodePoints );
2647     totalArea += elemArea;
2648     elemCenter /= nn;
2649     aNewXYZ += elemCenter * elemArea;
2650   }
2651   aNewXYZ /= totalArea;
2652   if ( !theSurface.IsNull() ) {
2653     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2654     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2655   }
2656
2657   // move node
2658
2659   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2660 }
2661
2662 //=======================================================================
2663 //function : getClosestUV
2664 //purpose  : return UV of closest projection
2665 //=======================================================================
2666
2667 static bool getClosestUV (Extrema_GenExtPS& projector,
2668                           const gp_Pnt&     point,
2669                           gp_XY &           result)
2670 {
2671   projector.Perform( point );
2672   if ( projector.IsDone() ) {
2673     double u, v, minVal = DBL_MAX;
2674     for ( int i = projector.NbExt(); i > 0; i-- )
2675       if ( projector.Value( i ) < minVal ) {
2676         minVal = projector.Value( i );
2677         projector.Point( i ).Parameter( u, v );
2678       }
2679     result.SetCoord( u, v );
2680     return true;
2681   }
2682   return false;
2683 }
2684
2685 //=======================================================================
2686 //function : Smooth
2687 //purpose  : Smooth theElements during theNbIterations or until a worst
2688 //           element has aspect ratio <= theTgtAspectRatio.
2689 //           Aspect Ratio varies in range [1.0, inf].
2690 //           If theElements is empty, the whole mesh is smoothed.
2691 //           theFixedNodes contains additionally fixed nodes. Nodes built
2692 //           on edges and boundary nodes are always fixed.
2693 //=======================================================================
2694
2695 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2696                                set<const SMDS_MeshNode*> & theFixedNodes,
2697                                const SmoothMethod          theSmoothMethod,
2698                                const int                   theNbIterations,
2699                                double                      theTgtAspectRatio,
2700                                const bool                  the2D)
2701 {
2702   myLastCreatedElems.Clear();
2703   myLastCreatedNodes.Clear();
2704
2705   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2706
2707   if ( theTgtAspectRatio < 1.0 )
2708     theTgtAspectRatio = 1.0;
2709
2710   const double disttol = 1.e-16;
2711
2712   SMESH::Controls::AspectRatio aQualityFunc;
2713
2714   SMESHDS_Mesh* aMesh = GetMeshDS();
2715
2716   if ( theElems.empty() ) {
2717     // add all faces to theElems
2718     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2719     while ( fIt->more() ) {
2720       const SMDS_MeshElement* face = fIt->next();
2721       theElems.insert( face );
2722     }
2723   }
2724   // get all face ids theElems are on
2725   set< int > faceIdSet;
2726   TIDSortedElemSet::iterator itElem;
2727   if ( the2D )
2728     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2729       int fId = FindShape( *itElem );
2730       // check that corresponding submesh exists and a shape is face
2731       if (fId &&
2732           faceIdSet.find( fId ) == faceIdSet.end() &&
2733           aMesh->MeshElements( fId )) {
2734         TopoDS_Shape F = aMesh->IndexToShape( fId );
2735         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2736           faceIdSet.insert( fId );
2737       }
2738     }
2739   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2740
2741   // ===============================================
2742   // smooth elements on each TopoDS_Face separately
2743   // ===============================================
2744
2745   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2746   for ( ; fId != faceIdSet.rend(); ++fId ) {
2747     // get face surface and submesh
2748     Handle(Geom_Surface) surface;
2749     SMESHDS_SubMesh* faceSubMesh = 0;
2750     TopoDS_Face face;
2751     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2752     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2753     bool isUPeriodic = false, isVPeriodic = false;
2754     if ( *fId ) {
2755       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2756       surface = BRep_Tool::Surface( face );
2757       faceSubMesh = aMesh->MeshElements( *fId );
2758       fToler2 = BRep_Tool::Tolerance( face );
2759       fToler2 *= fToler2 * 10.;
2760       isUPeriodic = surface->IsUPeriodic();
2761       if ( isUPeriodic )
2762         vPeriod = surface->UPeriod();
2763       isVPeriodic = surface->IsVPeriodic();
2764       if ( isVPeriodic )
2765         uPeriod = surface->VPeriod();
2766       surface->Bounds( u1, u2, v1, v2 );
2767     }
2768     // ---------------------------------------------------------
2769     // for elements on a face, find movable and fixed nodes and
2770     // compute UV for them
2771     // ---------------------------------------------------------
2772     bool checkBoundaryNodes = false;
2773     bool isQuadratic = false;
2774     set<const SMDS_MeshNode*> setMovableNodes;
2775     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2776     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2777     list< const SMDS_MeshElement* > elemsOnFace;
2778
2779     Extrema_GenExtPS projector;
2780     GeomAdaptor_Surface surfAdaptor;
2781     if ( !surface.IsNull() ) {
2782       surfAdaptor.Load( surface );
2783       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2784     }
2785     int nbElemOnFace = 0;
2786     itElem = theElems.begin();
2787     // loop on not yet smoothed elements: look for elems on a face
2788     while ( itElem != theElems.end() ) {
2789       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2790         break; // all elements found
2791
2792       const SMDS_MeshElement* elem = *itElem;
2793       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2794            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2795         ++itElem;
2796         continue;
2797       }
2798       elemsOnFace.push_back( elem );
2799       theElems.erase( itElem++ );
2800       nbElemOnFace++;
2801
2802       if ( !isQuadratic )
2803         isQuadratic = elem->IsQuadratic();
2804
2805       // get movable nodes of elem
2806       const SMDS_MeshNode* node;
2807       SMDS_TypeOfPosition posType;
2808       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2809       int nn = 0, nbn =  elem->NbNodes();
2810       if(elem->IsQuadratic())
2811         nbn = nbn/2;
2812       while ( nn++ < nbn ) {
2813         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2814         const SMDS_PositionPtr& pos = node->GetPosition();
2815         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2816         if (posType != SMDS_TOP_EDGE &&
2817             posType != SMDS_TOP_VERTEX &&
2818             theFixedNodes.find( node ) == theFixedNodes.end())
2819         {
2820           // check if all faces around the node are on faceSubMesh
2821           // because a node on edge may be bound to face
2822           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2823           bool all = true;
2824           if ( faceSubMesh ) {
2825             while ( eIt->more() && all ) {
2826               const SMDS_MeshElement* e = eIt->next();
2827               all = faceSubMesh->Contains( e );
2828             }
2829           }
2830           if ( all )
2831             setMovableNodes.insert( node );
2832           else
2833             checkBoundaryNodes = true;
2834         }
2835         if ( posType == SMDS_TOP_3DSPACE )
2836           checkBoundaryNodes = true;
2837       }
2838
2839       if ( surface.IsNull() )
2840         continue;
2841
2842       // get nodes to check UV
2843       list< const SMDS_MeshNode* > uvCheckNodes;
2844       itN = elem->nodesIterator();
2845       nn = 0; nbn =  elem->NbNodes();
2846       if(elem->IsQuadratic())
2847         nbn = nbn/2;
2848       while ( nn++ < nbn ) {
2849         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2850         if ( uvMap.find( node ) == uvMap.end() )
2851           uvCheckNodes.push_back( node );
2852         // add nodes of elems sharing node
2853         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2854         //         while ( eIt->more() ) {
2855         //           const SMDS_MeshElement* e = eIt->next();
2856         //           if ( e != elem ) {
2857         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2858         //             while ( nIt->more() ) {
2859         //               const SMDS_MeshNode* n =
2860         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2861         //               if ( uvMap.find( n ) == uvMap.end() )
2862         //                 uvCheckNodes.push_back( n );
2863         //             }
2864         //           }
2865         //         }
2866       }
2867       // check UV on face
2868       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2869       for ( ; n != uvCheckNodes.end(); ++n ) {
2870         node = *n;
2871         gp_XY uv( 0, 0 );
2872         const SMDS_PositionPtr& pos = node->GetPosition();
2873         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2874         // get existing UV
2875         switch ( posType ) {
2876         case SMDS_TOP_FACE: {
2877           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2878           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2879           break;
2880         }
2881         case SMDS_TOP_EDGE: {
2882           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2883           Handle(Geom2d_Curve) pcurve;
2884           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2885             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2886           if ( !pcurve.IsNull() ) {
2887             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2888             uv = pcurve->Value( u ).XY();
2889           }
2890           break;
2891         }
2892         case SMDS_TOP_VERTEX: {
2893           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2894           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2895             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2896           break;
2897         }
2898         default:;
2899         }
2900         // check existing UV
2901         bool project = true;
2902         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2903         double dist1 = DBL_MAX, dist2 = 0;
2904         if ( posType != SMDS_TOP_3DSPACE ) {
2905           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2906           project = dist1 > fToler2;
2907         }
2908         if ( project ) { // compute new UV
2909           gp_XY newUV;
2910           if ( !getClosestUV( projector, pNode, newUV )) {
2911             MESSAGE("Node Projection Failed " << node);
2912           }
2913           else {
2914             if ( isUPeriodic )
2915               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2916             if ( isVPeriodic )
2917               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2918             // check new UV
2919             if ( posType != SMDS_TOP_3DSPACE )
2920               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2921             if ( dist2 < dist1 )
2922               uv = newUV;
2923           }
2924         }
2925         // store UV in the map
2926         listUV.push_back( uv );
2927         uvMap.insert( make_pair( node, &listUV.back() ));
2928       }
2929     } // loop on not yet smoothed elements
2930
2931     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2932       checkBoundaryNodes = true;
2933
2934     // fix nodes on mesh boundary
2935
2936     if ( checkBoundaryNodes ) {
2937       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2938       map< NLink, int >::iterator link_nb;
2939       // put all elements links to linkNbMap
2940       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2941       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2942         const SMDS_MeshElement* elem = (*elemIt);
2943         int nbn =  elem->NbNodes();
2944         if(elem->IsQuadratic())
2945           nbn = nbn/2;
2946         // loop on elem links: insert them in linkNbMap
2947         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2948         for ( int iN = 0; iN < nbn; ++iN ) {
2949           curNode = elem->GetNode( iN );
2950           NLink link;
2951           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2952           else                      link = make_pair( prevNode , curNode );
2953           prevNode = curNode;
2954           link_nb = linkNbMap.find( link );
2955           if ( link_nb == linkNbMap.end() )
2956             linkNbMap.insert( make_pair ( link, 1 ));
2957           else
2958             link_nb->second++;
2959         }
2960       }
2961       // remove nodes that are in links encountered only once from setMovableNodes
2962       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2963         if ( link_nb->second == 1 ) {
2964           setMovableNodes.erase( link_nb->first.first );
2965           setMovableNodes.erase( link_nb->first.second );
2966         }
2967       }
2968     }
2969
2970     // -----------------------------------------------------
2971     // for nodes on seam edge, compute one more UV ( uvMap2 );
2972     // find movable nodes linked to nodes on seam and which
2973     // are to be smoothed using the second UV ( uvMap2 )
2974     // -----------------------------------------------------
2975
2976     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2977     if ( !surface.IsNull() ) {
2978       TopExp_Explorer eExp( face, TopAbs_EDGE );
2979       for ( ; eExp.More(); eExp.Next() ) {
2980         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2981         if ( !BRep_Tool::IsClosed( edge, face ))
2982           continue;
2983         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2984         if ( !sm ) continue;
2985         // find out which parameter varies for a node on seam
2986         double f,l;
2987         gp_Pnt2d uv1, uv2;
2988         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2989         if ( pcurve.IsNull() ) continue;
2990         uv1 = pcurve->Value( f );
2991         edge.Reverse();
2992         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2993         if ( pcurve.IsNull() ) continue;
2994         uv2 = pcurve->Value( f );
2995         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2996         // assure uv1 < uv2
2997         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2998           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2999         }
3000         // get nodes on seam and its vertices
3001         list< const SMDS_MeshNode* > seamNodes;
3002         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3003         while ( nSeamIt->more() ) {
3004           const SMDS_MeshNode* node = nSeamIt->next();
3005           if ( !isQuadratic || !IsMedium( node ))
3006             seamNodes.push_back( node );
3007         }
3008         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3009         for ( ; vExp.More(); vExp.Next() ) {
3010           sm = aMesh->MeshElements( vExp.Current() );
3011           if ( sm ) {
3012             nSeamIt = sm->GetNodes();
3013             while ( nSeamIt->more() )
3014               seamNodes.push_back( nSeamIt->next() );
3015           }
3016         }
3017         // loop on nodes on seam
3018         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3019         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3020           const SMDS_MeshNode* nSeam = *noSeIt;
3021           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3022           if ( n_uv == uvMap.end() )
3023             continue;
3024           // set the first UV
3025           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3026           // set the second UV
3027           listUV.push_back( *n_uv->second );
3028           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3029           if ( uvMap2.empty() )
3030             uvMap2 = uvMap; // copy the uvMap contents
3031           uvMap2[ nSeam ] = &listUV.back();
3032
3033           // collect movable nodes linked to ones on seam in nodesNearSeam
3034           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3035           while ( eIt->more() ) {
3036             const SMDS_MeshElement* e = eIt->next();
3037             int nbUseMap1 = 0, nbUseMap2 = 0;
3038             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3039             int nn = 0, nbn =  e->NbNodes();
3040             if(e->IsQuadratic()) nbn = nbn/2;
3041             while ( nn++ < nbn )
3042             {
3043               const SMDS_MeshNode* n =
3044                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3045               if (n == nSeam ||
3046                   setMovableNodes.find( n ) == setMovableNodes.end() )
3047                 continue;
3048               // add only nodes being closer to uv2 than to uv1
3049               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3050                            0.5 * ( n->Y() + nSeam->Y() ),
3051                            0.5 * ( n->Z() + nSeam->Z() ));
3052               gp_XY uv;
3053               getClosestUV( projector, pMid, uv );
3054               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3055                 nodesNearSeam.insert( n );
3056                 nbUseMap2++;
3057               }
3058               else
3059                 nbUseMap1++;
3060             }
3061             // for centroidalSmooth all element nodes must
3062             // be on one side of a seam
3063             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3064               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3065               nn = 0;
3066               while ( nn++ < nbn ) {
3067                 const SMDS_MeshNode* n =
3068                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3069                 setMovableNodes.erase( n );
3070               }
3071             }
3072           }
3073         } // loop on nodes on seam
3074       } // loop on edge of a face
3075     } // if ( !face.IsNull() )
3076
3077     if ( setMovableNodes.empty() ) {
3078       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3079       continue; // goto next face
3080     }
3081
3082     // -------------
3083     // SMOOTHING //
3084     // -------------
3085
3086     int it = -1;
3087     double maxRatio = -1., maxDisplacement = -1.;
3088     set<const SMDS_MeshNode*>::iterator nodeToMove;
3089     for ( it = 0; it < theNbIterations; it++ ) {
3090       maxDisplacement = 0.;
3091       nodeToMove = setMovableNodes.begin();
3092       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3093         const SMDS_MeshNode* node = (*nodeToMove);
3094         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3095
3096         // smooth
3097         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3098         if ( theSmoothMethod == LAPLACIAN )
3099           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3100         else
3101           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3102
3103         // node displacement
3104         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3105         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3106         if ( aDispl > maxDisplacement )
3107           maxDisplacement = aDispl;
3108       }
3109       // no node movement => exit
3110       //if ( maxDisplacement < 1.e-16 ) {
3111       if ( maxDisplacement < disttol ) {
3112         MESSAGE("-- no node movement --");
3113         break;
3114       }
3115
3116       // check elements quality
3117       maxRatio  = 0;
3118       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3119       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3120         const SMDS_MeshElement* elem = (*elemIt);
3121         if ( !elem || elem->GetType() != SMDSAbs_Face )
3122           continue;
3123         SMESH::Controls::TSequenceOfXYZ aPoints;
3124         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3125           double aValue = aQualityFunc.GetValue( aPoints );
3126           if ( aValue > maxRatio )
3127             maxRatio = aValue;
3128         }
3129       }
3130       if ( maxRatio <= theTgtAspectRatio ) {
3131         MESSAGE("-- quality achived --");
3132         break;
3133       }
3134       if (it+1 == theNbIterations) {
3135         MESSAGE("-- Iteration limit exceeded --");
3136       }
3137     } // smoothing iterations
3138
3139     MESSAGE(" Face id: " << *fId <<
3140             " Nb iterstions: " << it <<
3141             " Displacement: " << maxDisplacement <<
3142             " Aspect Ratio " << maxRatio);
3143
3144     // ---------------------------------------
3145     // new nodes positions are computed,
3146     // record movement in DS and set new UV
3147     // ---------------------------------------
3148     nodeToMove = setMovableNodes.begin();
3149     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3150       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3151       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3152       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3153       if ( node_uv != uvMap.end() ) {
3154         gp_XY* uv = node_uv->second;
3155         node->SetPosition
3156           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3157       }
3158     }
3159
3160     // move medium nodes of quadratic elements
3161     if ( isQuadratic )
3162     {
3163       SMESH_MesherHelper helper( *GetMesh() );
3164       if ( !face.IsNull() )
3165         helper.SetSubShape( face );
3166       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3167       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3168         const SMDS_QuadraticFaceOfNodes* QF =
3169           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3170         if(QF) {
3171           vector<const SMDS_MeshNode*> Ns;
3172           Ns.reserve(QF->NbNodes()+1);
3173           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3174           while ( anIter->more() )
3175             Ns.push_back( anIter->next() );
3176           Ns.push_back( Ns[0] );
3177           double x, y, z;
3178           for(int i=0; i<QF->NbNodes(); i=i+2) {
3179             if ( !surface.IsNull() ) {
3180               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3181               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3182               gp_XY uv = ( uv1 + uv2 ) / 2.;
3183               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3184               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3185             }
3186             else {
3187               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3188               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3189               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3190             }
3191             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3192                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3193                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3194               // we have to move i+1 node
3195               aMesh->MoveNode( Ns[i+1], x, y, z );
3196             }
3197           }
3198         }
3199       }
3200     }
3201
3202   } // loop on face ids
3203
3204 }
3205
3206 //=======================================================================
3207 //function : isReverse
3208 //purpose  : Return true if normal of prevNodes is not co-directied with
3209 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3210 //           iNotSame is where prevNodes and nextNodes are different
3211 //=======================================================================
3212
3213 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3214                       vector<const SMDS_MeshNode*> nextNodes,
3215                       const int            nbNodes,
3216                       const int            iNotSame)
3217 {
3218   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3219   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3220
3221   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3222   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3223   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3224   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3225
3226   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3227   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3228   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3229   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3230
3231   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3232
3233   return (vA ^ vB) * vN < 0.0;
3234 }
3235
3236 //=======================================================================
3237 /*!
3238  * \brief Create elements by sweeping an element
3239  * \param elem - element to sweep
3240  * \param newNodesItVec - nodes generated from each node of the element
3241  * \param newElems - generated elements
3242  * \param nbSteps - number of sweeping steps
3243  * \param srcElements - to append elem for each generated element
3244  */
3245 //=======================================================================
3246
3247 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3248                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3249                                     list<const SMDS_MeshElement*>&        newElems,
3250                                     const int                             nbSteps,
3251                                     SMESH_SequenceOfElemPtr&              srcElements)
3252 {
3253   SMESHDS_Mesh* aMesh = GetMeshDS();
3254
3255   // Loop on elem nodes:
3256   // find new nodes and detect same nodes indices
3257   int nbNodes = elem->NbNodes();
3258   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3259   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3260   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3261   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3262
3263   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3264   vector<int> sames(nbNodes);
3265   vector<bool> issimple(nbNodes);
3266
3267   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3268     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3269     const SMDS_MeshNode*                 node         = nnIt->first;
3270     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3271     if ( listNewNodes.empty() ) {
3272       return;
3273     }
3274
3275     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3276
3277     itNN[ iNode ] = listNewNodes.begin();
3278     prevNod[ iNode ] = node;
3279     nextNod[ iNode ] = listNewNodes.front();
3280     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3281       if ( prevNod[ iNode ] != nextNod [ iNode ])
3282         iNotSameNode = iNode;
3283       else {
3284         iSameNode = iNode;
3285         //nbSame++;
3286         sames[nbSame++] = iNode;
3287       }
3288     }
3289   }
3290
3291   //cout<<"  nbSame = "<<nbSame<<endl;
3292   if ( nbSame == nbNodes || nbSame > 2) {
3293     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3294     //INFOS( " Too many same nodes of element " << elem->GetID() );
3295     return;
3296   }
3297
3298   //  if( elem->IsQuadratic() && nbSame>0 ) {
3299   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3300   //    return;
3301   //  }
3302
3303   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3304   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3305   if ( nbSame > 0 ) {
3306     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3307     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3308     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3309   }
3310
3311   //if(nbNodes==8)
3312   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3313   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3314   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3315   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3316
3317   // check element orientation
3318   int i0 = 0, i2 = 2;
3319   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3320     //MESSAGE("Reversed elem " << elem );
3321     i0 = 2;
3322     i2 = 0;
3323     if ( nbSame > 0 )
3324       std::swap( iBeforeSame, iAfterSame );
3325   }
3326
3327   // make new elements
3328   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3329     // get next nodes
3330     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3331       if(issimple[iNode]) {
3332         nextNod[ iNode ] = *itNN[ iNode ];
3333         itNN[ iNode ]++;
3334       }
3335       else {
3336         if( elem->GetType()==SMDSAbs_Node ) {
3337           // we have to use two nodes
3338           midlNod[ iNode ] = *itNN[ iNode ];
3339           itNN[ iNode ]++;
3340           nextNod[ iNode ] = *itNN[ iNode ];
3341           itNN[ iNode ]++;
3342         }
3343         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3344           // we have to use each second node
3345           //itNN[ iNode ]++;
3346           nextNod[ iNode ] = *itNN[ iNode ];
3347           itNN[ iNode ]++;
3348         }
3349         else {
3350           // we have to use two nodes
3351           midlNod[ iNode ] = *itNN[ iNode ];
3352           itNN[ iNode ]++;
3353           nextNod[ iNode ] = *itNN[ iNode ];
3354           itNN[ iNode ]++;
3355         }
3356       }
3357     }
3358     SMDS_MeshElement* aNewElem = 0;
3359     if(!elem->IsPoly()) {
3360       switch ( nbNodes ) {
3361       case 0:
3362         return;
3363       case 1: { // NODE
3364         if ( nbSame == 0 ) {
3365           if(issimple[0])
3366             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3367           else
3368             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3369         }
3370         break;
3371       }
3372       case 2: { // EDGE
3373         if ( nbSame == 0 )
3374           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3375                                     nextNod[ 1 ], nextNod[ 0 ] );
3376         else
3377           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3378                                     nextNod[ iNotSameNode ] );
3379         break;
3380       }
3381
3382       case 3: { // TRIANGLE or quadratic edge
3383         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3384
3385           if ( nbSame == 0 )       // --- pentahedron
3386             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3387                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3388
3389           else if ( nbSame == 1 )  // --- pyramid
3390             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3391                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3392                                          nextNod[ iSameNode ]);
3393
3394           else // 2 same nodes:      --- tetrahedron
3395             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3396                                          nextNod[ iNotSameNode ]);
3397         }
3398         else { // quadratic edge
3399           if(nbSame==0) {     // quadratic quadrangle
3400             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3401                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3402           }
3403           else if(nbSame==1) { // quadratic triangle
3404             if(sames[0]==2) {
3405               return; // medium node on axis
3406             }
3407             else if(sames[0]==0) {
3408               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3409                                         nextNod[2], midlNod[1], prevNod[2]);
3410             }
3411             else { // sames[0]==1
3412               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3413                                         midlNod[0], nextNod[2], prevNod[2]);
3414             }
3415           }
3416           else {
3417             return;
3418           }
3419         }
3420         break;
3421       }
3422       case 4: { // QUADRANGLE
3423
3424         if ( nbSame == 0 )       // --- hexahedron
3425           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3426                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3427
3428         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3429           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3430                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3431                                        nextNod[ iSameNode ]);
3432           newElems.push_back( aNewElem );
3433           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3434                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3435                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3436         }
3437         else if ( nbSame == 2 ) { // pentahedron
3438           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3439             // iBeforeSame is same too
3440             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3441                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3442                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3443           else
3444             // iAfterSame is same too
3445             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3446                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3447                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3448         }
3449         break;
3450       }
3451       case 6: { // quadratic triangle
3452         // create pentahedron with 15 nodes
3453         if(nbSame==0) {
3454           if(i0>0) { // reversed case
3455             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3456                                          nextNod[0], nextNod[2], nextNod[1],
3457                                          prevNod[5], prevNod[4], prevNod[3],
3458                                          nextNod[5], nextNod[4], nextNod[3],
3459                                          midlNod[0], midlNod[2], midlNod[1]);
3460           }
3461           else { // not reversed case
3462             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3463                                          nextNod[0], nextNod[1], nextNod[2],
3464                                          prevNod[3], prevNod[4], prevNod[5],
3465                                          nextNod[3], nextNod[4], nextNod[5],
3466                                          midlNod[0], midlNod[1], midlNod[2]);
3467           }
3468         }
3469         else if(nbSame==1) {
3470           // 2d order pyramid of 13 nodes
3471           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3472           //                                 int n12,int n23,int n34,int n41,
3473           //                                 int n15,int n25,int n35,int n45, int ID);
3474           int n5 = iSameNode;
3475           int n1,n4,n41,n15,n45;
3476           if(i0>0) { // reversed case
3477             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3478             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3479             n41 = n1 + 3;
3480             n15 = n5 + 3;
3481             n45 = n4 + 3;
3482           }
3483           else {
3484             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3485             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3486             n41 = n4 + 3;
3487             n15 = n1 + 3;
3488             n45 = n5 + 3;
3489           }
3490           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3491                                       nextNod[n4], prevNod[n4], prevNod[n5],
3492                                       midlNod[n1], nextNod[n41],
3493                                       midlNod[n4], prevNod[n41],
3494                                       prevNod[n15], nextNod[n15],
3495                                       nextNod[n45], prevNod[n45]);
3496         }
3497         else if(nbSame==2) {
3498           // 2d order tetrahedron of 10 nodes
3499           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3500           //                                 int n12,int n23,int n31,
3501           //                                 int n14,int n24,int n34, int ID);
3502           int n1 = iNotSameNode;
3503           int n2,n3,n12,n23,n31;
3504           if(i0>0) { // reversed case
3505             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3506             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3507             n12 = n2 + 3;
3508             n23 = n3 + 3;
3509             n31 = n1 + 3;
3510           }
3511           else {
3512             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3513             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3514             n12 = n1 + 3;
3515             n23 = n2 + 3;
3516             n31 = n3 + 3;
3517           }
3518           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3519                                        prevNod[n12], prevNod[n23], prevNod[n31],
3520                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3521         }
3522         break;
3523       }
3524       case 8: { // quadratic quadrangle
3525         if(nbSame==0) {
3526           // create hexahedron with 20 nodes
3527           if(i0>0) { // reversed case
3528             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3529                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3530                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3531                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3532                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3533           }
3534           else { // not reversed case
3535             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3536                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3537                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3538                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3539                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3540           }
3541         }
3542         else if(nbSame==1) { 
3543           // --- pyramid + pentahedron - can not be created since it is needed 
3544           // additional middle node ot the center of face
3545           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3546           return;
3547         }
3548         else if(nbSame==2) {
3549           // 2d order Pentahedron with 15 nodes
3550           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3551           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3552           //                                 int n14,int n25,int n36, int ID);
3553           int n1,n2,n4,n5;
3554           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3555             // iBeforeSame is same too
3556             n1 = iBeforeSame;
3557             n2 = iOpposSame;
3558             n4 = iSameNode;
3559             n5 = iAfterSame;
3560           }
3561           else {
3562             // iAfterSame is same too
3563             n1 = iSameNode;
3564             n2 = iBeforeSame;
3565             n4 = iAfterSame;
3566             n5 = iOpposSame;
3567           }
3568           int n12,n45,n14,n25;
3569           if(i0>0) { //reversed case
3570             n12 = n1 + 4;
3571             n45 = n5 + 4;
3572             n14 = n4 + 4;
3573             n25 = n2 + 4;
3574           }
3575           else {
3576             n12 = n2 + 4;
3577             n45 = n4 + 4;
3578             n14 = n1 + 4;
3579             n25 = n5 + 4;
3580           }
3581           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3582                                        prevNod[n4], prevNod[n5], nextNod[n5],
3583                                        prevNod[n12], midlNod[n2], nextNod[n12],
3584                                        prevNod[n45], midlNod[n5], nextNod[n45],
3585                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3586         }
3587         break;
3588       }
3589       default: {
3590         // realized for extrusion only
3591         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3592         //vector<int> quantities (nbNodes + 2);
3593
3594         //quantities[0] = nbNodes; // bottom of prism
3595         //for (int inode = 0; inode < nbNodes; inode++) {
3596         //  polyedre_nodes[inode] = prevNod[inode];
3597         //}
3598
3599         //quantities[1] = nbNodes; // top of prism
3600         //for (int inode = 0; inode < nbNodes; inode++) {
3601         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3602         //}
3603
3604         //for (int iface = 0; iface < nbNodes; iface++) {
3605         //  quantities[iface + 2] = 4;
3606         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3607         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3608         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3609         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3610         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3611         //}
3612         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3613         break;
3614       }
3615       }
3616     }
3617
3618     if(!aNewElem) {
3619       // realized for extrusion only
3620       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3621       vector<int> quantities (nbNodes + 2);
3622
3623       quantities[0] = nbNodes; // bottom of prism
3624       for (int inode = 0; inode < nbNodes; inode++) {
3625         polyedre_nodes[inode] = prevNod[inode];
3626       }
3627
3628       quantities[1] = nbNodes; // top of prism
3629       for (int inode = 0; inode < nbNodes; inode++) {
3630         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3631       }
3632
3633       for (int iface = 0; iface < nbNodes; iface++) {
3634         quantities[iface + 2] = 4;
3635         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3636         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3637         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3638         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3639         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3640       }
3641       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3642     }
3643
3644     if ( aNewElem ) {
3645       newElems.push_back( aNewElem );
3646       myLastCreatedElems.Append(aNewElem);
3647       srcElements.Append( elem );
3648     }
3649
3650     // set new prev nodes
3651     for ( iNode = 0; iNode < nbNodes; iNode++ )
3652       prevNod[ iNode ] = nextNod[ iNode ];
3653
3654   } // for steps
3655 }
3656
3657 //=======================================================================
3658 /*!
3659  * \brief Create 1D and 2D elements around swept elements
3660  * \param mapNewNodes - source nodes and ones generated from them
3661  * \param newElemsMap - source elements and ones generated from them
3662  * \param elemNewNodesMap - nodes generated from each node of each element
3663  * \param elemSet - all swept elements
3664  * \param nbSteps - number of sweeping steps
3665  * \param srcElements - to append elem for each generated element
3666  */
3667 //=======================================================================
3668
3669 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3670                                   TElemOfElemListMap &     newElemsMap,
3671                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3672                                   TIDSortedElemSet&        elemSet,
3673                                   const int                nbSteps,
3674                                   SMESH_SequenceOfElemPtr& srcElements)
3675 {
3676   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3677   SMESHDS_Mesh* aMesh = GetMeshDS();
3678
3679   // Find nodes belonging to only one initial element - sweep them to get edges.
3680
3681   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3682   for ( ; nList != mapNewNodes.end(); nList++ ) {
3683     const SMDS_MeshNode* node =
3684       static_cast<const SMDS_MeshNode*>( nList->first );
3685     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3686     int nbInitElems = 0;
3687     const SMDS_MeshElement* el = 0;
3688     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3689     while ( eIt->more() && nbInitElems < 2 ) {
3690       el = eIt->next();
3691       SMDSAbs_ElementType type = el->GetType();
3692       if ( type == SMDSAbs_Volume || type < highType ) continue;
3693       if ( type > highType ) {
3694         nbInitElems = 0;
3695         highType = type;
3696       }
3697       if ( elemSet.find(el) != elemSet.end() )
3698         nbInitElems++;
3699     }
3700     if ( nbInitElems < 2 ) {
3701       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3702       if(!NotCreateEdge) {
3703         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3704         list<const SMDS_MeshElement*> newEdges;
3705         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3706       }
3707     }
3708   }
3709
3710   // Make a ceiling for each element ie an equal element of last new nodes.
3711   // Find free links of faces - make edges and sweep them into faces.
3712
3713   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3714   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3715   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3716     const SMDS_MeshElement* elem = itElem->first;
3717     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3718
3719     if ( elem->GetType() == SMDSAbs_Edge ) {
3720       // create a ceiling edge
3721       if (!elem->IsQuadratic()) {
3722         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3723                                vecNewNodes[ 1 ]->second.back())) {
3724           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3725                                                    vecNewNodes[ 1 ]->second.back()));
3726           srcElements.Append( myLastCreatedElems.Last() );
3727         }
3728       }
3729       else {
3730         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3731                                vecNewNodes[ 1 ]->second.back(),
3732                                vecNewNodes[ 2 ]->second.back())) {
3733           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3734                                                    vecNewNodes[ 1 ]->second.back(),
3735                                                    vecNewNodes[ 2 ]->second.back()));
3736           srcElements.Append( myLastCreatedElems.Last() );
3737         }
3738       }
3739     }
3740     if ( elem->GetType() != SMDSAbs_Face )
3741       continue;
3742
3743     if(itElem->second.size()==0) continue;
3744
3745     bool hasFreeLinks = false;
3746
3747     TIDSortedElemSet avoidSet;
3748     avoidSet.insert( elem );
3749
3750     set<const SMDS_MeshNode*> aFaceLastNodes;
3751     int iNode, nbNodes = vecNewNodes.size();
3752     if(!elem->IsQuadratic()) {
3753       // loop on the face nodes
3754       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3755         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3756         // look for free links of the face
3757         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3758         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3759         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3760         // check if a link is free
3761         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3762           hasFreeLinks = true;
3763           // make an edge and a ceiling for a new edge
3764           if ( !aMesh->FindEdge( n1, n2 )) {
3765             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3766             srcElements.Append( myLastCreatedElems.Last() );
3767           }
3768           n1 = vecNewNodes[ iNode ]->second.back();
3769           n2 = vecNewNodes[ iNext ]->second.back();
3770           if ( !aMesh->FindEdge( n1, n2 )) {
3771             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3772             srcElements.Append( myLastCreatedElems.Last() );
3773           }
3774         }
3775       }
3776     }
3777     else { // elem is quadratic face
3778       int nbn = nbNodes/2;
3779       for ( iNode = 0; iNode < nbn; iNode++ ) {
3780         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3781         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3782         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3783         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3784         // check if a link is free
3785         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3786           hasFreeLinks = true;
3787           // make an edge and a ceiling for a new edge
3788           // find medium node
3789           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3790           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3791             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3792             srcElements.Append( myLastCreatedElems.Last() );
3793           }
3794           n1 = vecNewNodes[ iNode ]->second.back();
3795           n2 = vecNewNodes[ iNext ]->second.back();
3796           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3797           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3798             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3799             srcElements.Append( myLastCreatedElems.Last() );
3800           }
3801         }
3802       }
3803       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3804         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3805       }
3806     }
3807
3808     // sweep free links into faces
3809
3810     if ( hasFreeLinks )  {
3811       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3812       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3813
3814       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3815       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3816         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3817         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3818       }
3819       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3820         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3821         iVol = 0;
3822         while ( iVol++ < volNb ) v++;
3823         // find indices of free faces of a volume and their source edges
3824         list< int > freeInd;
3825         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3826         SMDS_VolumeTool vTool( *v );
3827         int iF, nbF = vTool.NbFaces();
3828         for ( iF = 0; iF < nbF; iF ++ ) {
3829           if (vTool.IsFreeFace( iF ) &&
3830               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3831               initNodeSet != faceNodeSet) // except an initial face
3832           {
3833             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3834               continue;
3835             freeInd.push_back( iF );
3836             // find source edge of a free face iF
3837             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3838             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3839             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3840                                    initNodeSet.begin(), initNodeSet.end(),
3841                                    commonNodes.begin());
3842             if ( (*v)->IsQuadratic() )
3843               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3844             else
3845               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3846 #ifdef _DEBUG_
3847             if ( !srcEdges.back() )
3848             {
3849               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3850                    << iF << " of volume #" << vTool.ID() << endl;
3851             }
3852 #endif
3853           }
3854         }
3855         if ( freeInd.empty() )
3856           continue;
3857
3858         // create faces for all steps;
3859         // if such a face has been already created by sweep of edge,
3860         // assure that its orientation is OK
3861         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3862           vTool.Set( *v );
3863           vTool.SetExternalNormal();
3864           list< int >::iterator ind = freeInd.begin();
3865           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3866           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3867           {
3868             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3869             int nbn = vTool.NbFaceNodes( *ind );
3870             switch ( nbn ) {
3871             case 3: { ///// triangle
3872               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3873               if ( !f )
3874                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3875               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3876                 aMesh->ChangeElementNodes( f, nodes, nbn );
3877               break;
3878             }
3879             case 4: { ///// quadrangle
3880               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3881               if ( !f )
3882                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3883               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3884                 aMesh->ChangeElementNodes( f, nodes, nbn );
3885               break;
3886             }
3887             default:
3888               if( (*v)->IsQuadratic() ) {
3889                 if(nbn==6) { /////// quadratic triangle
3890                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3891                                                              nodes[1], nodes[3], nodes[5] );
3892                   if ( !f ) {
3893                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3894                                                              nodes[1], nodes[3], nodes[5]));
3895                   }
3896                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3897                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3898                     tmpnodes[0] = nodes[0];
3899                     tmpnodes[1] = nodes[2];
3900                     tmpnodes[2] = nodes[4];
3901                     tmpnodes[3] = nodes[1];
3902                     tmpnodes[4] = nodes[3];
3903                     tmpnodes[5] = nodes[5];
3904                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3905                   }
3906                 }
3907                 else {       /////// quadratic quadrangle
3908                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3909                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3910                   if ( !f ) {
3911                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3912                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3913                   }
3914                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3915                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3916                     tmpnodes[0] = nodes[0];
3917                     tmpnodes[1] = nodes[2];
3918                     tmpnodes[2] = nodes[4];
3919                     tmpnodes[3] = nodes[6];
3920                     tmpnodes[4] = nodes[1];
3921                     tmpnodes[5] = nodes[3];
3922                     tmpnodes[6] = nodes[5];
3923                     tmpnodes[7] = nodes[7];
3924                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3925                   }
3926                 }
3927               }
3928               else { //////// polygon
3929                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3930                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3931                 if ( !f )
3932                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3933                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3934                   aMesh->ChangeElementNodes( f, nodes, nbn );
3935               }
3936             }
3937             while ( srcElements.Length() < myLastCreatedElems.Length() )
3938               srcElements.Append( *srcEdge );
3939
3940           }  // loop on free faces
3941
3942           // go to the next volume
3943           iVol = 0;
3944           while ( iVol++ < nbVolumesByStep ) v++;
3945         }
3946       }
3947     } // sweep free links into faces
3948
3949     // Make a ceiling face with a normal external to a volume
3950
3951     SMDS_VolumeTool lastVol( itElem->second.back() );
3952
3953     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3954     if ( iF >= 0 ) {
3955       lastVol.SetExternalNormal();
3956       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3957       int nbn = lastVol.NbFaceNodes( iF );
3958       switch ( nbn ) {
3959       case 3:
3960         if (!hasFreeLinks ||
3961             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3962           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3963         break;
3964       case 4:
3965         if (!hasFreeLinks ||
3966             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3967           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3968         break;
3969       default:
3970         if(itElem->second.back()->IsQuadratic()) {
3971           if(nbn==6) {
3972             if (!hasFreeLinks ||
3973                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3974                                  nodes[1], nodes[3], nodes[5]) ) {
3975               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3976                                                        nodes[1], nodes[3], nodes[5]));
3977             }
3978           }
3979           else { // nbn==8
3980             if (!hasFreeLinks ||
3981                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3982                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3983               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3984                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3985           }
3986         }
3987         else {
3988           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3989           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3990             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3991         }
3992       } // switch
3993
3994       while ( srcElements.Length() < myLastCreatedElems.Length() )
3995         srcElements.Append( myLastCreatedElems.Last() );
3996     }
3997   } // loop on swept elements
3998 }
3999
4000 //=======================================================================
4001 //function : RotationSweep
4002 //purpose  :
4003 //=======================================================================
4004
4005 SMESH_MeshEditor::PGroupIDs
4006 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4007                                 const gp_Ax1&      theAxis,
4008                                 const double       theAngle,
4009                                 const int          theNbSteps,
4010                                 const double       theTol,
4011                                 const bool         theMakeGroups,
4012                                 const bool         theMakeWalls)
4013 {
4014   myLastCreatedElems.Clear();
4015   myLastCreatedNodes.Clear();
4016
4017   // source elements for each generated one
4018   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4019
4020   MESSAGE( "RotationSweep()");
4021   gp_Trsf aTrsf;
4022   aTrsf.SetRotation( theAxis, theAngle );
4023   gp_Trsf aTrsf2;
4024   aTrsf2.SetRotation( theAxis, theAngle/2. );
4025
4026   gp_Lin aLine( theAxis );
4027   double aSqTol = theTol * theTol;
4028
4029   SMESHDS_Mesh* aMesh = GetMeshDS();
4030
4031   TNodeOfNodeListMap mapNewNodes;
4032   TElemOfVecOfNnlmiMap mapElemNewNodes;
4033   TElemOfElemListMap newElemsMap;
4034
4035   // loop on theElems
4036   TIDSortedElemSet::iterator itElem;
4037   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4038     const SMDS_MeshElement* elem = *itElem;
4039     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4040       continue;
4041     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4042     newNodesItVec.reserve( elem->NbNodes() );
4043
4044     // loop on elem nodes
4045     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4046     while ( itN->more() ) {
4047       // check if a node has been already sweeped
4048       const SMDS_MeshNode* node = cast2Node( itN->next() );
4049
4050       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4051       double coord[3];
4052       aXYZ.Coord( coord[0], coord[1], coord[2] );
4053       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4054
4055       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4056       if ( nIt == mapNewNodes.end() ) {
4057         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4058         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4059
4060         // make new nodes
4061         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4062         //double coord[3];
4063         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4064         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4065         const SMDS_MeshNode * newNode = node;
4066         for ( int i = 0; i < theNbSteps; i++ ) {
4067           if ( !isOnAxis ) {
4068             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4069               // create two nodes
4070               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4071               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4072               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4073               myLastCreatedNodes.Append(newNode);
4074               srcNodes.Append( node );
4075               listNewNodes.push_back( newNode );
4076               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4077               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4078             }
4079             else {
4080               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4081             }
4082             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4083             myLastCreatedNodes.Append(newNode);
4084             srcNodes.Append( node );
4085             listNewNodes.push_back( newNode );
4086           }
4087           else {
4088             listNewNodes.push_back( newNode );
4089             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4090               listNewNodes.push_back( newNode );
4091             }
4092           }
4093         }
4094       }
4095       /*
4096         else {
4097         // if current elem is quadratic and current node is not medium
4098         // we have to check - may be it is needed to insert additional nodes
4099         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4100         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4101         if(listNewNodes.size()==theNbSteps) {
4102         listNewNodes.clear();
4103         // make new nodes
4104         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4105         //double coord[3];
4106         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4107         const SMDS_MeshNode * newNode = node;
4108         if ( !isOnAxis ) {
4109         for(int i = 0; i<theNbSteps; i++) {
4110         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4111         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4112         cout<<"    3 AddNode:  "<<newNode;
4113         myLastCreatedNodes.Append(newNode);
4114         listNewNodes.push_back( newNode );
4115         srcNodes.Append( node );
4116         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4117         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4118         cout<<"    4 AddNode:  "<<newNode;
4119         myLastCreatedNodes.Append(newNode);
4120         srcNodes.Append( node );
4121         listNewNodes.push_back( newNode );
4122         }
4123         }
4124         else {
4125         listNewNodes.push_back( newNode );
4126         }
4127         }
4128         }
4129         }
4130       */
4131       newNodesItVec.push_back( nIt );
4132     }
4133     // make new elements
4134     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4135   }
4136
4137   if ( theMakeWalls )
4138     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4139
4140   PGroupIDs newGroupIDs;
4141   if ( theMakeGroups )
4142     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4143
4144   return newGroupIDs;
4145 }
4146
4147
4148 //=======================================================================
4149 //function : CreateNode
4150 //purpose  :
4151 //=======================================================================
4152 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4153                                                   const double y,
4154                                                   const double z,
4155                                                   const double tolnode,
4156                                                   SMESH_SequenceOfNode& aNodes)
4157 {
4158   myLastCreatedElems.Clear();
4159   myLastCreatedNodes.Clear();
4160
4161   gp_Pnt P1(x,y,z);
4162   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4163
4164   // try to search in sequence of existing nodes
4165   // if aNodes.Length()>0 we 'nave to use given sequence
4166   // else - use all nodes of mesh
4167   if(aNodes.Length()>0) {
4168     int i;
4169     for(i=1; i<=aNodes.Length(); i++) {
4170       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4171       if(P1.Distance(P2)<tolnode)
4172         return aNodes.Value(i);
4173     }
4174   }
4175   else {
4176     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4177     while(itn->more()) {
4178       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4179       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4180       if(P1.Distance(P2)<tolnode)
4181         return aN;
4182     }
4183   }
4184
4185   // create new node and return it
4186   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4187   myLastCreatedNodes.Append(NewNode);
4188   return NewNode;
4189 }
4190
4191
4192 //=======================================================================
4193 //function : ExtrusionSweep
4194 //purpose  :
4195 //=======================================================================
4196
4197 SMESH_MeshEditor::PGroupIDs
4198 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4199                                   const gp_Vec&       theStep,
4200                                   const int           theNbSteps,
4201                                   TElemOfElemListMap& newElemsMap,
4202                                   const bool          theMakeGroups,
4203                                   const int           theFlags,
4204                                   const double        theTolerance)
4205 {
4206   ExtrusParam aParams;
4207   aParams.myDir = gp_Dir(theStep);
4208   aParams.myNodes.Clear();
4209   aParams.mySteps = new TColStd_HSequenceOfReal;
4210   int i;
4211   for(i=1; i<=theNbSteps; i++)
4212     aParams.mySteps->Append(theStep.Magnitude());
4213
4214   return
4215     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4216 }
4217
4218
4219 //=======================================================================
4220 //function : ExtrusionSweep
4221 //purpose  :
4222 //=======================================================================
4223
4224 SMESH_MeshEditor::PGroupIDs
4225 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4226                                   ExtrusParam&        theParams,
4227                                   TElemOfElemListMap& newElemsMap,
4228                                   const bool          theMakeGroups,
4229                                   const int           theFlags,
4230                                   const double        theTolerance)
4231 {
4232   myLastCreatedElems.Clear();
4233   myLastCreatedNodes.Clear();
4234
4235   // source elements for each generated one
4236   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4237
4238   SMESHDS_Mesh* aMesh = GetMeshDS();
4239
4240   int nbsteps = theParams.mySteps->Length();
4241
4242   TNodeOfNodeListMap mapNewNodes;
4243   //TNodeOfNodeVecMap mapNewNodes;
4244   TElemOfVecOfNnlmiMap mapElemNewNodes;
4245   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4246
4247   // loop on theElems
4248   TIDSortedElemSet::iterator itElem;
4249   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4250     // check element type
4251     const SMDS_MeshElement* elem = *itElem;
4252     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4253       continue;
4254
4255     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4256     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4257     newNodesItVec.reserve( elem->NbNodes() );
4258
4259     // loop on elem nodes
4260     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4261     while ( itN->more() )
4262     {
4263       // check if a node has been already sweeped
4264       const SMDS_MeshNode* node = cast2Node( itN->next() );
4265       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4266       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4267       if ( nIt == mapNewNodes.end() ) {
4268         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4269         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4270         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4271         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4272         //vecNewNodes.reserve(nbsteps);
4273
4274         // make new nodes
4275         double coord[] = { node->X(), node->Y(), node->Z() };
4276         //int nbsteps = theParams.mySteps->Length();
4277         for ( int i = 0; i < nbsteps; i++ ) {
4278           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4279             // create additional node
4280             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4281             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4282             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4283             if( theFlags & EXTRUSION_FLAG_SEW ) {
4284               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4285                                                          theTolerance, theParams.myNodes);
4286               listNewNodes.push_back( newNode );
4287             }
4288             else {
4289               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4290               myLastCreatedNodes.Append(newNode);
4291               srcNodes.Append( node );
4292               listNewNodes.push_back( newNode );
4293             }
4294           }
4295           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4296           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4297           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4298           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4299           if( theFlags & EXTRUSION_FLAG_SEW ) {
4300             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4301                                                        theTolerance, theParams.myNodes);
4302             listNewNodes.push_back( newNode );
4303             //vecNewNodes[i]=newNode;
4304           }
4305           else {
4306             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4307             myLastCreatedNodes.Append(newNode);
4308             srcNodes.Append( node );
4309             listNewNodes.push_back( newNode );
4310             //vecNewNodes[i]=newNode;
4311           }
4312         }
4313       }
4314       else {
4315         // if current elem is quadratic and current node is not medium
4316         // we have to check - may be it is needed to insert additional nodes
4317         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4318           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4319           if(listNewNodes.size()==nbsteps) {
4320             listNewNodes.clear();
4321             double coord[] = { node->X(), node->Y(), node->Z() };
4322             for ( int i = 0; i < nbsteps; i++ ) {
4323               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4324               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4325               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4326               if( theFlags & EXTRUSION_FLAG_SEW ) {
4327                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4328                                                            theTolerance, theParams.myNodes);
4329                 listNewNodes.push_back( newNode );
4330               }
4331               else {
4332                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4333                 myLastCreatedNodes.Append(newNode);
4334                 srcNodes.Append( node );
4335                 listNewNodes.push_back( newNode );
4336               }
4337               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4338               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4339               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4340               if( theFlags & EXTRUSION_FLAG_SEW ) {
4341                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4342                                                            theTolerance, theParams.myNodes);
4343                 listNewNodes.push_back( newNode );
4344               }
4345               else {
4346                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4347                 myLastCreatedNodes.Append(newNode);
4348                 srcNodes.Append( node );
4349                 listNewNodes.push_back( newNode );
4350               }
4351             }
4352           }
4353         }
4354       }
4355       newNodesItVec.push_back( nIt );
4356     }
4357     // make new elements
4358     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4359   }
4360
4361   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4362     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4363   }
4364   PGroupIDs newGroupIDs;
4365   if ( theMakeGroups )
4366     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4367
4368   return newGroupIDs;
4369 }
4370
4371 /*
4372 //=======================================================================
4373 //class    : SMESH_MeshEditor_PathPoint
4374 //purpose  : auxiliary class
4375 //=======================================================================
4376 class SMESH_MeshEditor_PathPoint {
4377 public:
4378 SMESH_MeshEditor_PathPoint() {
4379 myPnt.SetCoord(99., 99., 99.);
4380 myTgt.SetCoord(1.,0.,0.);
4381 myAngle=0.;
4382 myPrm=0.;
4383 }
4384 void SetPnt(const gp_Pnt& aP3D){
4385 myPnt=aP3D;
4386 }
4387 void SetTangent(const gp_Dir& aTgt){
4388 myTgt=aTgt;
4389 }
4390 void SetAngle(const double& aBeta){
4391 myAngle=aBeta;
4392 }
4393 void SetParameter(const double& aPrm){
4394 myPrm=aPrm;
4395 }
4396 const gp_Pnt& Pnt()const{
4397 return myPnt;
4398 }
4399 const gp_Dir& Tangent()const{
4400 return myTgt;
4401 }
4402 double Angle()const{
4403 return myAngle;
4404 }
4405 double Parameter()const{
4406 return myPrm;
4407 }
4408
4409 protected:
4410 gp_Pnt myPnt;
4411 gp_Dir myTgt;
4412 double myAngle;
4413 double myPrm;
4414 };
4415 */
4416
4417 //=======================================================================
4418 //function : ExtrusionAlongTrack
4419 //purpose  :
4420 //=======================================================================
4421 SMESH_MeshEditor::Extrusion_Error
4422 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4423                                        SMESH_subMesh*       theTrack,
4424                                        const SMDS_MeshNode* theN1,
4425                                        const bool           theHasAngles,
4426                                        list<double>&        theAngles,
4427                                        const bool           theLinearVariation,
4428                                        const bool           theHasRefPoint,
4429                                        const gp_Pnt&        theRefPoint,
4430                                        const bool           theMakeGroups)
4431 {
4432   myLastCreatedElems.Clear();
4433   myLastCreatedNodes.Clear();
4434
4435   int aNbE;
4436   std::list<double> aPrms;
4437   TIDSortedElemSet::iterator itElem;
4438
4439   gp_XYZ aGC;
4440   TopoDS_Edge aTrackEdge;
4441   TopoDS_Vertex aV1, aV2;
4442
4443   SMDS_ElemIteratorPtr aItE;
4444   SMDS_NodeIteratorPtr aItN;
4445   SMDSAbs_ElementType aTypeE;
4446
4447   TNodeOfNodeListMap mapNewNodes;
4448
4449   // 1. Check data
4450   aNbE = theElements.size();
4451   // nothing to do
4452   if ( !aNbE )
4453     return EXTR_NO_ELEMENTS;
4454
4455   // 1.1 Track Pattern
4456   ASSERT( theTrack );
4457
4458   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4459
4460   aItE = pSubMeshDS->GetElements();
4461   while ( aItE->more() ) {
4462     const SMDS_MeshElement* pE = aItE->next();
4463     aTypeE = pE->GetType();
4464     // Pattern must contain links only
4465     if ( aTypeE != SMDSAbs_Edge )
4466       return EXTR_PATH_NOT_EDGE;
4467   }
4468
4469   list<SMESH_MeshEditor_PathPoint> fullList;
4470
4471   const TopoDS_Shape& aS = theTrack->GetSubShape();
4472   // Sub shape for the Pattern must be an Edge or Wire
4473   if( aS.ShapeType() == TopAbs_EDGE ) {
4474     aTrackEdge = TopoDS::Edge( aS );
4475     // the Edge must not be degenerated
4476     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4477       return EXTR_BAD_PATH_SHAPE;
4478     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4479     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4480     const SMDS_MeshNode* aN1 = aItN->next();
4481     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4482     const SMDS_MeshNode* aN2 = aItN->next();
4483     // starting node must be aN1 or aN2
4484     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4485       return EXTR_BAD_STARTING_NODE;
4486     aItN = pSubMeshDS->GetNodes();
4487     while ( aItN->more() ) {
4488       const SMDS_MeshNode* pNode = aItN->next();
4489       const SMDS_EdgePosition* pEPos =
4490         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4491       double aT = pEPos->GetUParameter();
4492       aPrms.push_back( aT );
4493     }
4494     //Extrusion_Error err =
4495     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4496   }
4497   else if( aS.ShapeType() == TopAbs_WIRE ) {
4498     list< SMESH_subMesh* > LSM;
4499     TopTools_SequenceOfShape Edges;
4500     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4501     while(itSM->more()) {
4502       SMESH_subMesh* SM = itSM->next();
4503       LSM.push_back(SM);
4504       const TopoDS_Shape& aS = SM->GetSubShape();
4505       Edges.Append(aS);
4506     }
4507     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4508     int startNid = theN1->GetID();
4509     TColStd_MapOfInteger UsedNums;
4510     int NbEdges = Edges.Length();
4511     int i = 1;
4512     for(; i<=NbEdges; i++) {
4513       int k = 0;
4514       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4515       for(; itLSM!=LSM.end(); itLSM++) {
4516         k++;
4517         if(UsedNums.Contains(k)) continue;
4518         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4519         SMESH_subMesh* locTrack = *itLSM;
4520         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4521         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4522         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4523         const SMDS_MeshNode* aN1 = aItN->next();
4524         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4525         const SMDS_MeshNode* aN2 = aItN->next();
4526         // starting node must be aN1 or aN2
4527         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4528         // 2. Collect parameters on the track edge
4529         aPrms.clear();
4530         aItN = locMeshDS->GetNodes();
4531         while ( aItN->more() ) {
4532           const SMDS_MeshNode* pNode = aItN->next();
4533           const SMDS_EdgePosition* pEPos =
4534             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4535           double aT = pEPos->GetUParameter();
4536           aPrms.push_back( aT );
4537         }
4538         list<SMESH_MeshEditor_PathPoint> LPP;
4539         //Extrusion_Error err =
4540         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4541         LLPPs.push_back(LPP);
4542         UsedNums.Add(k);
4543         // update startN for search following egde
4544         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4545         else startNid = aN1->GetID();
4546         break;
4547       }
4548     }
4549     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4550     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4551     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4552     for(; itPP!=firstList.end(); itPP++) {
4553       fullList.push_back( *itPP );
4554     }
4555     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4556     fullList.pop_back();
4557     itLLPP++;
4558     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4559       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4560       itPP = currList.begin();
4561       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4562       gp_Dir D1 = PP1.Tangent();
4563       gp_Dir D2 = PP2.Tangent();
4564       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4565                            (D1.Z()+D2.Z())/2 ) );
4566       PP1.SetTangent(Dnew);
4567       fullList.push_back(PP1);
4568       itPP++;
4569       for(; itPP!=firstList.end(); itPP++) {
4570         fullList.push_back( *itPP );
4571       }
4572       PP1 = fullList.back();
4573       fullList.pop_back();
4574     }
4575     // if wire not closed
4576     fullList.push_back(PP1);
4577     // else ???
4578   }
4579   else {
4580     return EXTR_BAD_PATH_SHAPE;
4581   }
4582
4583   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4584                           theHasRefPoint, theRefPoint, theMakeGroups);
4585 }
4586
4587
4588 //=======================================================================
4589 //function : ExtrusionAlongTrack
4590 //purpose  :
4591 //=======================================================================
4592 SMESH_MeshEditor::Extrusion_Error
4593 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4594                                        SMESH_Mesh*          theTrack,
4595                                        const SMDS_MeshNode* theN1,
4596                                        const bool           theHasAngles,
4597                                        list<double>&        theAngles,
4598                                        const bool           theLinearVariation,
4599                                        const bool           theHasRefPoint,
4600                                        const gp_Pnt&        theRefPoint,
4601                                        const bool           theMakeGroups)
4602 {
4603   myLastCreatedElems.Clear();
4604   myLastCreatedNodes.Clear();
4605
4606   int aNbE;
4607   std::list<double> aPrms;
4608   TIDSortedElemSet::iterator itElem;
4609
4610   gp_XYZ aGC;
4611   TopoDS_Edge aTrackEdge;
4612   TopoDS_Vertex aV1, aV2;
4613
4614   SMDS_ElemIteratorPtr aItE;
4615   SMDS_NodeIteratorPtr aItN;
4616   SMDSAbs_ElementType aTypeE;
4617
4618   TNodeOfNodeListMap mapNewNodes;
4619
4620   // 1. Check data
4621   aNbE = theElements.size();
4622   // nothing to do
4623   if ( !aNbE )
4624     return EXTR_NO_ELEMENTS;
4625
4626   // 1.1 Track Pattern
4627   ASSERT( theTrack );
4628
4629   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4630
4631   aItE = pMeshDS->elementsIterator();
4632   while ( aItE->more() ) {
4633     const SMDS_MeshElement* pE = aItE->next();
4634     aTypeE = pE->GetType();
4635     // Pattern must contain links only
4636     if ( aTypeE != SMDSAbs_Edge )
4637       return EXTR_PATH_NOT_EDGE;
4638   }
4639
4640   list<SMESH_MeshEditor_PathPoint> fullList;
4641
4642   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4643   // Sub shape for the Pattern must be an Edge or Wire
4644   if( aS.ShapeType() == TopAbs_EDGE ) {
4645     aTrackEdge = TopoDS::Edge( aS );
4646     // the Edge must not be degenerated
4647     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4648       return EXTR_BAD_PATH_SHAPE;
4649     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4650     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4651     const SMDS_MeshNode* aN1 = aItN->next();
4652     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4653     const SMDS_MeshNode* aN2 = aItN->next();
4654     // starting node must be aN1 or aN2
4655     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4656       return EXTR_BAD_STARTING_NODE;
4657     aItN = pMeshDS->nodesIterator();
4658     while ( aItN->more() ) {
4659       const SMDS_MeshNode* pNode = aItN->next();
4660       if( pNode==aN1 || pNode==aN2 ) continue;
4661       const SMDS_EdgePosition* pEPos =
4662         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4663       double aT = pEPos->GetUParameter();
4664       aPrms.push_back( aT );
4665     }
4666     //Extrusion_Error err =
4667     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4668   }
4669   else if( aS.ShapeType() == TopAbs_WIRE ) {
4670     list< SMESH_subMesh* > LSM;
4671     TopTools_SequenceOfShape Edges;
4672     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4673     for(; eExp.More(); eExp.Next()) {
4674       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4675       if( BRep_Tool::Degenerated(E) ) continue;
4676       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4677       if(SM) {
4678         LSM.push_back(SM);
4679         Edges.Append(E);
4680       }
4681     }
4682     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4683     int startNid = theN1->GetID();
4684     TColStd_MapOfInteger UsedNums;
4685     int NbEdges = Edges.Length();
4686     int i = 1;
4687     for(; i<=NbEdges; i++) {
4688       int k = 0;
4689       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4690       for(; itLSM!=LSM.end(); itLSM++) {
4691         k++;
4692         if(UsedNums.Contains(k)) continue;
4693         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4694         SMESH_subMesh* locTrack = *itLSM;
4695         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4696         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4697         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4698         const SMDS_MeshNode* aN1 = aItN->next();
4699         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4700         const SMDS_MeshNode* aN2 = aItN->next();
4701         // starting node must be aN1 or aN2
4702         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4703         // 2. Collect parameters on the track edge
4704         aPrms.clear();
4705         aItN = locMeshDS->GetNodes();
4706         while ( aItN->more() ) {
4707           const SMDS_MeshNode* pNode = aItN->next();
4708           const SMDS_EdgePosition* pEPos =
4709             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4710           double aT = pEPos->GetUParameter();
4711           aPrms.push_back( aT );
4712         }
4713         list<SMESH_MeshEditor_PathPoint> LPP;
4714         //Extrusion_Error err =
4715         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4716         LLPPs.push_back(LPP);
4717         UsedNums.Add(k);
4718         // update startN for search following egde
4719         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4720         else startNid = aN1->GetID();
4721         break;
4722       }
4723     }
4724     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4725     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4726     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4727     for(; itPP!=firstList.end(); itPP++) {
4728       fullList.push_back( *itPP );
4729     }
4730     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4731     fullList.pop_back();
4732     itLLPP++;
4733     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4734       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4735       itPP = currList.begin();
4736       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4737       gp_Pnt P1 = PP1.Pnt();
4738       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4739       gp_Pnt P2 = PP2.Pnt();
4740       gp_Dir D1 = PP1.Tangent();
4741       gp_Dir D2 = PP2.Tangent();
4742       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4743                            (D1.Z()+D2.Z())/2 ) );
4744       PP1.SetTangent(Dnew);
4745       fullList.push_back(PP1);
4746       itPP++;
4747       for(; itPP!=currList.end(); itPP++) {
4748         fullList.push_back( *itPP );
4749       }
4750       PP1 = fullList.back();
4751       fullList.pop_back();
4752     }
4753     // if wire not closed
4754     fullList.push_back(PP1);
4755     // else ???
4756   }
4757   else {
4758     return EXTR_BAD_PATH_SHAPE;
4759   }
4760
4761   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4762                           theHasRefPoint, theRefPoint, theMakeGroups);
4763 }
4764
4765
4766 //=======================================================================
4767 //function : MakeEdgePathPoints
4768 //purpose  : auxilary for ExtrusionAlongTrack
4769 //=======================================================================
4770 SMESH_MeshEditor::Extrusion_Error
4771 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4772                                      const TopoDS_Edge& aTrackEdge,
4773                                      bool FirstIsStart,
4774                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4775 {
4776   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4777   aTolVec=1.e-7;
4778   aTolVec2=aTolVec*aTolVec;
4779   double aT1, aT2;
4780   TopoDS_Vertex aV1, aV2;
4781   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4782   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4783   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4784   // 2. Collect parameters on the track edge
4785   aPrms.push_front( aT1 );
4786   aPrms.push_back( aT2 );
4787   // sort parameters
4788   aPrms.sort();
4789   if( FirstIsStart ) {
4790     if ( aT1 > aT2 ) {
4791       aPrms.reverse();
4792     }
4793   }
4794   else {
4795     if ( aT2 > aT1 ) {
4796       aPrms.reverse();
4797     }
4798   }
4799   // 3. Path Points
4800   SMESH_MeshEditor_PathPoint aPP;
4801   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4802   std::list<double>::iterator aItD = aPrms.begin();
4803   for(; aItD != aPrms.end(); ++aItD) {
4804     double aT = *aItD;
4805     gp_Pnt aP3D;
4806     gp_Vec aVec;
4807     aC3D->D1( aT, aP3D, aVec );
4808     aL2 = aVec.SquareMagnitude();
4809     if ( aL2 < aTolVec2 )
4810       return EXTR_CANT_GET_TANGENT;
4811     gp_Dir aTgt( aVec );
4812     aPP.SetPnt( aP3D );
4813     aPP.SetTangent( aTgt );
4814     aPP.SetParameter( aT );
4815     LPP.push_back(aPP);
4816   }
4817   return EXTR_OK;
4818 }
4819
4820
4821 //=======================================================================
4822 //function : MakeExtrElements
4823 //purpose  : auxilary for ExtrusionAlongTrack
4824 //=======================================================================
4825 SMESH_MeshEditor::Extrusion_Error
4826 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4827                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4828                                    const bool theHasAngles,
4829                                    list<double>& theAngles,
4830                                    const bool theLinearVariation,
4831                                    const bool theHasRefPoint,
4832                                    const gp_Pnt& theRefPoint,
4833                                    const bool theMakeGroups)
4834 {
4835   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4836   int aNbTP = fullList.size();
4837   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4838   // Angles
4839   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4840     LinearAngleVariation(aNbTP-1, theAngles);
4841   }
4842   vector<double> aAngles( aNbTP );
4843   int j = 0;
4844   for(; j<aNbTP; ++j) {
4845     aAngles[j] = 0.;
4846   }
4847   if ( theHasAngles ) {
4848     double anAngle;;
4849     std::list<double>::iterator aItD = theAngles.begin();
4850     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4851       anAngle = *aItD;
4852       aAngles[j] = anAngle;
4853     }
4854   }
4855   // fill vector of path points with angles
4856   //aPPs.resize(fullList.size());
4857   j = -1;
4858   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4859   for(; itPP!=fullList.end(); itPP++) {
4860     j++;
4861     SMESH_MeshEditor_PathPoint PP = *itPP;
4862     PP.SetAngle(aAngles[j]);
4863     aPPs[j] = PP;
4864   }
4865
4866   TNodeOfNodeListMap mapNewNodes;
4867   TElemOfVecOfNnlmiMap mapElemNewNodes;
4868   TElemOfElemListMap newElemsMap;
4869   TIDSortedElemSet::iterator itElem;
4870   double aX, aY, aZ;
4871   int aNb;
4872   SMDSAbs_ElementType aTypeE;
4873   // source elements for each generated one
4874   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4875
4876   // 3. Center of rotation aV0
4877   gp_Pnt aV0 = theRefPoint;
4878   gp_XYZ aGC;
4879   if ( !theHasRefPoint ) {
4880     aNb = 0;
4881     aGC.SetCoord( 0.,0.,0. );
4882
4883     itElem = theElements.begin();
4884     for ( ; itElem != theElements.end(); itElem++ ) {
4885       const SMDS_MeshElement* elem = *itElem;
4886
4887       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4888       while ( itN->more() ) {
4889         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4890         aX = node->X();
4891         aY = node->Y();
4892         aZ = node->Z();
4893
4894         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4895           list<const SMDS_MeshNode*> aLNx;
4896           mapNewNodes[node] = aLNx;
4897           //
4898           gp_XYZ aXYZ( aX, aY, aZ );
4899           aGC += aXYZ;
4900           ++aNb;
4901         }
4902       }
4903     }
4904     aGC /= aNb;
4905     aV0.SetXYZ( aGC );
4906   } // if (!theHasRefPoint) {
4907   mapNewNodes.clear();
4908
4909   // 4. Processing the elements
4910   SMESHDS_Mesh* aMesh = GetMeshDS();
4911
4912   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4913     // check element type
4914     const SMDS_MeshElement* elem = *itElem;
4915     aTypeE = elem->GetType();
4916     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4917       continue;
4918
4919     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4920     newNodesItVec.reserve( elem->NbNodes() );
4921
4922     // loop on elem nodes
4923     int nodeIndex = -1;
4924     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4925     while ( itN->more() )
4926     {
4927       ++nodeIndex;
4928       // check if a node has been already processed
4929       const SMDS_MeshNode* node =
4930         static_cast<const SMDS_MeshNode*>( itN->next() );
4931       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4932       if ( nIt == mapNewNodes.end() ) {
4933         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4934         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4935
4936         // make new nodes
4937         aX = node->X();  aY = node->Y(); aZ = node->Z();
4938
4939         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4940         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4941         gp_Ax1 anAx1, anAxT1T0;
4942         gp_Dir aDT1x, aDT0x, aDT1T0;
4943
4944         aTolAng=1.e-4;
4945
4946         aV0x = aV0;
4947         aPN0.SetCoord(aX, aY, aZ);
4948
4949         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4950         aP0x = aPP0.Pnt();
4951         aDT0x= aPP0.Tangent();
4952         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4953
4954         for ( j = 1; j < aNbTP; ++j ) {
4955           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4956           aP1x = aPP1.Pnt();
4957           aDT1x = aPP1.Tangent();
4958           aAngle1x = aPP1.Angle();
4959
4960           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4961           // Translation
4962           gp_Vec aV01x( aP0x, aP1x );
4963           aTrsf.SetTranslation( aV01x );
4964
4965           // traslated point
4966           aV1x = aV0x.Transformed( aTrsf );
4967           aPN1 = aPN0.Transformed( aTrsf );
4968
4969           // rotation 1 [ T1,T0 ]
4970           aAngleT1T0=-aDT1x.Angle( aDT0x );
4971           if (fabs(aAngleT1T0) > aTolAng) {
4972             aDT1T0=aDT1x^aDT0x;
4973             anAxT1T0.SetLocation( aV1x );
4974             anAxT1T0.SetDirection( aDT1T0 );
4975             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4976
4977             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4978           }
4979
4980           // rotation 2
4981           if ( theHasAngles ) {
4982             anAx1.SetLocation( aV1x );
4983             anAx1.SetDirection( aDT1x );
4984             aTrsfRot.SetRotation( anAx1, aAngle1x );
4985
4986             aPN1 = aPN1.Transformed( aTrsfRot );
4987           }
4988
4989           // make new node
4990           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4991             // create additional node
4992             double x = ( aPN1.X() + aPN0.X() )/2.;
4993             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4994             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4995             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4996             myLastCreatedNodes.Append(newNode);
4997             srcNodes.Append( node );
4998             listNewNodes.push_back( newNode );
4999           }
5000           aX = aPN1.X();
5001           aY = aPN1.Y();
5002           aZ = aPN1.Z();
5003           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5004           myLastCreatedNodes.Append(newNode);
5005           srcNodes.Append( node );
5006           listNewNodes.push_back( newNode );
5007
5008           aPN0 = aPN1;
5009           aP0x = aP1x;
5010           aV0x = aV1x;
5011           aDT0x = aDT1x;
5012         }
5013       }
5014
5015       else {
5016         // if current elem is quadratic and current node is not medium
5017         // we have to check - may be it is needed to insert additional nodes
5018         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5019           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5020           if(listNewNodes.size()==aNbTP-1) {
5021             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5022             gp_XYZ P(node->X(), node->Y(), node->Z());
5023             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5024             int i;
5025             for(i=0; i<aNbTP-1; i++) {
5026               const SMDS_MeshNode* N = *it;
5027               double x = ( N->X() + P.X() )/2.;
5028               double y = ( N->Y() + P.Y() )/2.;
5029               double z = ( N->Z() + P.Z() )/2.;
5030               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5031               srcNodes.Append( node );
5032               myLastCreatedNodes.Append(newN);
5033               aNodes[2*i] = newN;
5034               aNodes[2*i+1] = N;
5035               P = gp_XYZ(N->X(),N->Y(),N->Z());
5036             }
5037             listNewNodes.clear();
5038             for(i=0; i<2*(aNbTP-1); i++) {
5039               listNewNodes.push_back(aNodes[i]);
5040             }
5041           }
5042         }
5043       }
5044
5045       newNodesItVec.push_back( nIt );
5046     }
5047     // make new elements
5048     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5049     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5050     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5051   }
5052
5053   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5054
5055   if ( theMakeGroups )
5056     generateGroups( srcNodes, srcElems, "extruded");
5057
5058   return EXTR_OK;
5059 }
5060
5061
5062 //=======================================================================
5063 //function : LinearAngleVariation
5064 //purpose  : auxilary for ExtrusionAlongTrack
5065 //=======================================================================
5066 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5067                                             list<double>& Angles)
5068 {
5069   int nbAngles = Angles.size();
5070   if( nbSteps > nbAngles ) {
5071     vector<double> theAngles(nbAngles);
5072     list<double>::iterator it = Angles.begin();
5073     int i = -1;
5074     for(; it!=Angles.end(); it++) {
5075       i++;
5076       theAngles[i] = (*it);
5077     }
5078     list<double> res;
5079     double rAn2St = double( nbAngles ) / double( nbSteps );
5080     double angPrev = 0, angle;
5081     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5082       double angCur = rAn2St * ( iSt+1 );
5083       double angCurFloor  = floor( angCur );
5084       double angPrevFloor = floor( angPrev );
5085       if ( angPrevFloor == angCurFloor )
5086         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5087       else {
5088         int iP = int( angPrevFloor );
5089         double angPrevCeil = ceil(angPrev);
5090         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5091
5092         int iC = int( angCurFloor );
5093         if ( iC < nbAngles )
5094           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5095
5096         iP = int( angPrevCeil );
5097         while ( iC-- > iP )
5098           angle += theAngles[ iC ];
5099       }
5100       res.push_back(angle);
5101       angPrev = angCur;
5102     }
5103     Angles.clear();
5104     it = res.begin();
5105     for(; it!=res.end(); it++)
5106       Angles.push_back( *it );
5107   }
5108 }
5109
5110
5111 //=======================================================================
5112 //function : Transform
5113 //purpose  :
5114 //=======================================================================
5115
5116 SMESH_MeshEditor::PGroupIDs
5117 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5118                              const gp_Trsf&     theTrsf,
5119                              const bool         theCopy,
5120                              const bool         theMakeGroups,
5121                              SMESH_Mesh*        theTargetMesh)
5122 {
5123   myLastCreatedElems.Clear();
5124   myLastCreatedNodes.Clear();
5125
5126   bool needReverse = false;
5127   string groupPostfix;
5128   switch ( theTrsf.Form() ) {
5129   case gp_PntMirror:
5130   case gp_Ax1Mirror:
5131   case gp_Ax2Mirror:
5132     needReverse = true;
5133     groupPostfix = "mirrored";
5134     break;
5135   case gp_Rotation:
5136     groupPostfix = "rotated";
5137     break;
5138   case gp_Translation:
5139     groupPostfix = "translated";
5140     break;
5141   case gp_Scale:
5142     groupPostfix = "scaled";
5143     break;
5144   default:
5145     needReverse = false;
5146     groupPostfix = "transformed";
5147   }
5148
5149   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5150   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5151   SMESHDS_Mesh* aMesh    = GetMeshDS();
5152
5153
5154   // map old node to new one
5155   TNodeNodeMap nodeMap;
5156
5157   // elements sharing moved nodes; those of them which have all
5158   // nodes mirrored but are not in theElems are to be reversed
5159   TIDSortedElemSet inverseElemSet;
5160
5161   // source elements for each generated one
5162   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5163
5164   // loop on theElems
5165   TIDSortedElemSet::iterator itElem;
5166   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5167     const SMDS_MeshElement* elem = *itElem;
5168     if ( !elem )
5169       continue;
5170
5171     // loop on elem nodes
5172     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5173     while ( itN->more() ) {
5174
5175       // check if a node has been already transformed
5176       const SMDS_MeshNode* node = cast2Node( itN->next() );
5177       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5178         nodeMap.insert( make_pair ( node, node ));
5179       if ( !n2n_isnew.second )
5180         continue;
5181
5182       double coord[3];
5183       coord[0] = node->X();
5184       coord[1] = node->Y();
5185       coord[2] = node->Z();
5186       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5187       if ( theTargetMesh ) {
5188         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5189         n2n_isnew.first->second = newNode;
5190         myLastCreatedNodes.Append(newNode);
5191         srcNodes.Append( node );
5192       }
5193       else if ( theCopy ) {
5194         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5195         n2n_isnew.first->second = newNode;
5196         myLastCreatedNodes.Append(newNode);
5197         srcNodes.Append( node );
5198       }
5199       else {
5200         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5201         // node position on shape becomes invalid
5202         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5203           ( SMDS_SpacePosition::originSpacePosition() );
5204       }
5205
5206       // keep inverse elements
5207       if ( !theCopy && !theTargetMesh && needReverse ) {
5208         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5209         while ( invElemIt->more() ) {
5210           const SMDS_MeshElement* iel = invElemIt->next();
5211           inverseElemSet.insert( iel );
5212         }
5213       }
5214     }
5215   }
5216
5217   // either create new elements or reverse mirrored ones
5218   if ( !theCopy && !needReverse && !theTargetMesh )
5219     return PGroupIDs();
5220
5221   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5222   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5223     theElems.insert( *invElemIt );
5224
5225   // replicate or reverse elements
5226
5227   enum {
5228     REV_TETRA   = 0,  //  = nbNodes - 4
5229     REV_PYRAMID = 1,  //  = nbNodes - 4
5230     REV_PENTA   = 2,  //  = nbNodes - 4
5231     REV_FACE    = 3,
5232     REV_HEXA    = 4,  //  = nbNodes - 4
5233     FORWARD     = 5
5234   };
5235   int index[][8] = {
5236     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5237     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5238     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5239     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5240     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5241     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5242   };
5243
5244   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5245   {
5246     const SMDS_MeshElement* elem = *itElem;
5247     if ( !elem || elem->GetType() == SMDSAbs_Node )
5248       continue;
5249
5250     int nbNodes = elem->NbNodes();
5251     int elemType = elem->GetType();
5252
5253     if (elem->IsPoly()) {
5254       // Polygon or Polyhedral Volume
5255       switch ( elemType ) {
5256       case SMDSAbs_Face:
5257         {
5258           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5259           int iNode = 0;
5260           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5261           while (itN->more()) {
5262             const SMDS_MeshNode* node =
5263               static_cast<const SMDS_MeshNode*>(itN->next());
5264             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5265             if (nodeMapIt == nodeMap.end())
5266               break; // not all nodes transformed
5267             if (needReverse) {
5268               // reverse mirrored faces and volumes
5269               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5270             } else {
5271               poly_nodes[iNode] = (*nodeMapIt).second;
5272             }
5273             iNode++;
5274           }
5275           if ( iNode != nbNodes )
5276             continue; // not all nodes transformed
5277
5278           if ( theTargetMesh ) {
5279             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5280             srcElems.Append( elem );
5281           }
5282           else if ( theCopy ) {
5283             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5284             srcElems.Append( elem );
5285           }
5286           else {
5287             aMesh->ChangePolygonNodes(elem, poly_nodes);
5288           }
5289         }
5290         break;
5291       case SMDSAbs_Volume:
5292         {
5293           // ATTENTION: Reversing is not yet done!!!
5294           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5295             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5296           if (!aPolyedre) {
5297             MESSAGE("Warning: bad volumic element");
5298             continue;
5299           }
5300
5301           vector<const SMDS_MeshNode*> poly_nodes;
5302           vector<int> quantities;
5303
5304           bool allTransformed = true;
5305           int nbFaces = aPolyedre->NbFaces();
5306           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5307             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5308             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5309               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5310               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5311               if (nodeMapIt == nodeMap.end()) {
5312                 allTransformed = false; // not all nodes transformed
5313               } else {
5314                 poly_nodes.push_back((*nodeMapIt).second);
5315               }
5316             }
5317             quantities.push_back(nbFaceNodes);
5318           }
5319           if ( !allTransformed )
5320             continue; // not all nodes transformed
5321
5322           if ( theTargetMesh ) {
5323             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5324             srcElems.Append( elem );
5325           }
5326           else if ( theCopy ) {
5327             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5328             srcElems.Append( elem );
5329           }
5330           else {
5331             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5332           }
5333         }
5334         break;
5335       default:;
5336       }
5337       continue;
5338     }
5339
5340     // Regular elements
5341     int* i = index[ FORWARD ];
5342     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5343       if ( elemType == SMDSAbs_Face )
5344         i = index[ REV_FACE ];
5345       else
5346         i = index[ nbNodes - 4 ];
5347
5348     if(elem->IsQuadratic()) {
5349       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5350       i = anIds;
5351       if(needReverse) {
5352         if(nbNodes==3) { // quadratic edge
5353           static int anIds[] = {1,0,2};
5354           i = anIds;
5355         }
5356         else if(nbNodes==6) { // quadratic triangle
5357           static int anIds[] = {0,2,1,5,4,3};
5358           i = anIds;
5359         }
5360         else if(nbNodes==8) { // quadratic quadrangle
5361           static int anIds[] = {0,3,2,1,7,6,5,4};
5362           i = anIds;
5363         }
5364         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5365           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5366           i = anIds;
5367         }
5368         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5369           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5370           i = anIds;
5371         }
5372         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5373           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5374           i = anIds;
5375         }
5376         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5377           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5378           i = anIds;
5379         }
5380       }
5381     }
5382
5383     // find transformed nodes
5384     vector<const SMDS_MeshNode*> nodes(nbNodes);
5385     int iNode = 0;
5386     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5387     while ( itN->more() ) {
5388       const SMDS_MeshNode* node =
5389         static_cast<const SMDS_MeshNode*>( itN->next() );
5390       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5391       if ( nodeMapIt == nodeMap.end() )
5392         break; // not all nodes transformed
5393       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5394     }
5395     if ( iNode != nbNodes )
5396       continue; // not all nodes transformed
5397
5398     if ( theTargetMesh ) {
5399       if ( SMDS_MeshElement* copy =
5400            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5401         myLastCreatedElems.Append( copy );
5402         srcElems.Append( elem );
5403       }
5404     }
5405     else if ( theCopy ) {
5406       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5407         myLastCreatedElems.Append( copy );
5408         srcElems.Append( elem );
5409       }
5410     }
5411     else {
5412       // reverse element as it was reversed by transformation
5413       if ( nbNodes > 2 )
5414         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5415     }
5416   }
5417
5418   PGroupIDs newGroupIDs;
5419
5420   if ( theMakeGroups && theCopy ||
5421        theMakeGroups && theTargetMesh )
5422     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5423
5424   return newGroupIDs;
5425 }
5426
5427
5428 //=======================================================================
5429 //function : Scale
5430 //purpose  :
5431 //=======================================================================
5432
5433 SMESH_MeshEditor::PGroupIDs
5434 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5435                          const gp_Pnt&            thePoint,
5436                          const std::list<double>& theScaleFact,
5437                          const bool         theCopy,
5438                          const bool         theMakeGroups,
5439                          SMESH_Mesh*        theTargetMesh)
5440 {
5441   myLastCreatedElems.Clear();
5442   myLastCreatedNodes.Clear();
5443
5444   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5445   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5446   SMESHDS_Mesh* aMesh    = GetMeshDS();
5447
5448   double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5449   std::list<double>::const_iterator itS = theScaleFact.begin();
5450   scaleX = (*itS);
5451   if(theScaleFact.size()==1) {
5452     scaleY = (*itS);
5453     scaleZ= (*itS);
5454   }
5455   if(theScaleFact.size()==2) {
5456     itS++;
5457     scaleY = (*itS);
5458     scaleZ= (*itS);
5459   }
5460   if(theScaleFact.size()>2) {
5461     itS++;
5462     scaleY = (*itS);
5463     itS++;
5464     scaleZ= (*itS);
5465   }
5466   
5467   // map old node to new one
5468   TNodeNodeMap nodeMap;
5469
5470   // elements sharing moved nodes; those of them which have all
5471   // nodes mirrored but are not in theElems are to be reversed
5472   TIDSortedElemSet inverseElemSet;
5473
5474   // source elements for each generated one
5475   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5476
5477   // loop on theElems
5478   TIDSortedElemSet::iterator itElem;
5479   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5480     const SMDS_MeshElement* elem = *itElem;
5481     if ( !elem )
5482       continue;
5483
5484     // loop on elem nodes
5485     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5486     while ( itN->more() ) {
5487
5488       // check if a node has been already transformed
5489       const SMDS_MeshNode* node = cast2Node( itN->next() );
5490       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5491         nodeMap.insert( make_pair ( node, node ));
5492       if ( !n2n_isnew.second )
5493         continue;
5494
5495       //double coord[3];
5496       //coord[0] = node->X();
5497       //coord[1] = node->Y();
5498       //coord[2] = node->Z();
5499       //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5500       double dx = (node->X() - thePoint.X()) * scaleX;
5501       double dy = (node->Y() - thePoint.Y()) * scaleY;
5502       double dz = (node->Z() - thePoint.Z()) * scaleZ;
5503       if ( theTargetMesh ) {
5504         //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5505         const SMDS_MeshNode * newNode =
5506           aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5507         n2n_isnew.first->second = newNode;
5508         myLastCreatedNodes.Append(newNode);
5509         srcNodes.Append( node );
5510       }
5511       else if ( theCopy ) {
5512         //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5513         const SMDS_MeshNode * newNode =
5514           aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5515         n2n_isnew.first->second = newNode;
5516         myLastCreatedNodes.Append(newNode);
5517         srcNodes.Append( node );
5518       }
5519       else {
5520         //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5521         aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5522         // node position on shape becomes invalid
5523         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5524           ( SMDS_SpacePosition::originSpacePosition() );
5525       }
5526
5527       // keep inverse elements
5528       //if ( !theCopy && !theTargetMesh && needReverse ) {
5529       //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5530       //  while ( invElemIt->more() ) {
5531       //    const SMDS_MeshElement* iel = invElemIt->next();
5532       //    inverseElemSet.insert( iel );
5533       //  }
5534       //}
5535     }
5536   }
5537
5538   // either create new elements or reverse mirrored ones
5539   //if ( !theCopy && !needReverse && !theTargetMesh )
5540   if ( !theCopy && !theTargetMesh )
5541     return PGroupIDs();
5542
5543   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5544   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5545     theElems.insert( *invElemIt );
5546
5547   // replicate or reverse elements
5548
5549   enum {
5550     REV_TETRA   = 0,  //  = nbNodes - 4
5551     REV_PYRAMID = 1,  //  = nbNodes - 4
5552     REV_PENTA   = 2,  //  = nbNodes - 4
5553     REV_FACE    = 3,
5554     REV_HEXA    = 4,  //  = nbNodes - 4
5555     FORWARD     = 5
5556   };
5557   int index[][8] = {
5558     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5559     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5560     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5561     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5562     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5563     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5564   };
5565
5566   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5567   {
5568     const SMDS_MeshElement* elem = *itElem;
5569     if ( !elem || elem->GetType() == SMDSAbs_Node )
5570       continue;
5571
5572     int nbNodes = elem->NbNodes();
5573     int elemType = elem->GetType();
5574
5575     if (elem->IsPoly()) {
5576       // Polygon or Polyhedral Volume
5577       switch ( elemType ) {
5578       case SMDSAbs_Face:
5579         {
5580           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5581           int iNode = 0;
5582           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5583           while (itN->more()) {
5584             const SMDS_MeshNode* node =
5585               static_cast<const SMDS_MeshNode*>(itN->next());
5586             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5587             if (nodeMapIt == nodeMap.end())
5588               break; // not all nodes transformed
5589             //if (needReverse) {
5590             //  // reverse mirrored faces and volumes
5591             //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5592             //} else {
5593             poly_nodes[iNode] = (*nodeMapIt).second;
5594             //}
5595             iNode++;
5596           }
5597           if ( iNode != nbNodes )
5598             continue; // not all nodes transformed
5599
5600           if ( theTargetMesh ) {
5601             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5602             srcElems.Append( elem );
5603           }
5604           else if ( theCopy ) {
5605             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5606             srcElems.Append( elem );
5607           }
5608           else {
5609             aMesh->ChangePolygonNodes(elem, poly_nodes);
5610           }
5611         }
5612         break;
5613       case SMDSAbs_Volume:
5614         {
5615           // ATTENTION: Reversing is not yet done!!!
5616           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5617             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5618           if (!aPolyedre) {
5619             MESSAGE("Warning: bad volumic element");
5620             continue;
5621           }
5622
5623           vector<const SMDS_MeshNode*> poly_nodes;
5624           vector<int> quantities;
5625
5626           bool allTransformed = true;
5627           int nbFaces = aPolyedre->NbFaces();
5628           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5629             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5630             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5631               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5632               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5633               if (nodeMapIt == nodeMap.end()) {
5634                 allTransformed = false; // not all nodes transformed
5635               } else {
5636                 poly_nodes.push_back((*nodeMapIt).second);
5637               }
5638             }
5639             quantities.push_back(nbFaceNodes);
5640           }
5641           if ( !allTransformed )
5642             continue; // not all nodes transformed
5643
5644           if ( theTargetMesh ) {
5645             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5646             srcElems.Append( elem );
5647           }
5648           else if ( theCopy ) {
5649             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5650             srcElems.Append( elem );
5651           }
5652           else {
5653             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5654           }
5655         }
5656         break;
5657       default:;
5658       }
5659       continue;
5660     }
5661
5662     // Regular elements
5663     int* i = index[ FORWARD ];
5664     //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5665     //  if ( elemType == SMDSAbs_Face )
5666     //    i = index[ REV_FACE ];
5667     //  else
5668     //    i = index[ nbNodes - 4 ];
5669
5670     if(elem->IsQuadratic()) {
5671       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5672       i = anIds;
5673       //if(needReverse) {
5674       //  if(nbNodes==3) { // quadratic edge
5675       //    static int anIds[] = {1,0,2};
5676       //    i = anIds;
5677       //  }
5678       //  else if(nbNodes==6) { // quadratic triangle
5679       //    static int anIds[] = {0,2,1,5,4,3};
5680       //    i = anIds;
5681       //  }
5682       //  else if(nbNodes==8) { // quadratic quadrangle
5683       //    static int anIds[] = {0,3,2,1,7,6,5,4};
5684       //    i = anIds;
5685       //  }
5686       //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5687       //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5688       //    i = anIds;
5689       //  }
5690       //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5691       //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5692       //    i = anIds;
5693       //  }
5694       //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5695       //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5696       //    i = anIds;
5697       //  }
5698       //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5699       //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5700       //    i = anIds;
5701       //  }
5702       //}
5703     }
5704
5705     // find transformed nodes
5706     vector<const SMDS_MeshNode*> nodes(nbNodes);
5707     int iNode = 0;
5708     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5709     while ( itN->more() ) {
5710       const SMDS_MeshNode* node =
5711         static_cast<const SMDS_MeshNode*>( itN->next() );
5712       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5713       if ( nodeMapIt == nodeMap.end() )
5714         break; // not all nodes transformed
5715       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5716     }
5717     if ( iNode != nbNodes )
5718       continue; // not all nodes transformed
5719
5720     if ( theTargetMesh ) {
5721       if ( SMDS_MeshElement* copy =
5722            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5723         myLastCreatedElems.Append( copy );
5724         srcElems.Append( elem );
5725       }
5726     }
5727     else if ( theCopy ) {
5728       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5729         myLastCreatedElems.Append( copy );
5730         srcElems.Append( elem );
5731       }
5732     }
5733     else {
5734       // reverse element as it was reversed by transformation
5735       if ( nbNodes > 2 )
5736         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5737     }
5738   }
5739
5740   PGroupIDs newGroupIDs;
5741
5742   if ( theMakeGroups && theCopy ||
5743        theMakeGroups && theTargetMesh ) {
5744     string groupPostfix = "scaled";
5745     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5746   }
5747
5748   return newGroupIDs;
5749 }
5750
5751
5752 //=======================================================================
5753 /*!
5754  * \brief Create groups of elements made during transformation
5755  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5756  * \param elemGens - elements making corresponding myLastCreatedElems
5757  * \param postfix - to append to names of new groups
5758  */
5759 //=======================================================================
5760
5761 SMESH_MeshEditor::PGroupIDs
5762 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5763                                  const SMESH_SequenceOfElemPtr& elemGens,
5764                                  const std::string&             postfix,
5765                                  SMESH_Mesh*                    targetMesh)
5766 {
5767   PGroupIDs newGroupIDs( new list<int> );
5768   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5769
5770   // Sort existing groups by types and collect their names
5771
5772   // to store an old group and a generated new one
5773   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5774   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5775   // group names
5776   set< string > groupNames;
5777   //
5778   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5779   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5780   while ( groupIt->more() ) {
5781     SMESH_Group * group = groupIt->next();
5782     if ( !group ) continue;
5783     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5784     if ( !groupDS || groupDS->IsEmpty() ) continue;
5785     groupNames.insert( group->GetName() );
5786     groupDS->SetStoreName( group->GetName() );
5787     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5788   }
5789
5790   // Groups creation
5791
5792   // loop on nodes and elements
5793   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5794   {
5795     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5796     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5797     if ( gens.Length() != elems.Length() )
5798       throw SALOME_Exception(LOCALIZED("invalid args"));
5799
5800     // loop on created elements
5801     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5802     {
5803       const SMDS_MeshElement* sourceElem = gens( iElem );
5804       if ( !sourceElem ) {
5805         MESSAGE("generateGroups(): NULL source element");
5806         continue;
5807       }
5808       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5809       if ( groupsOldNew.empty() ) {
5810         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5811           ++iElem; // skip all elements made by sourceElem
5812         continue;
5813       }
5814       // collect all elements made by sourceElem
5815       list< const SMDS_MeshElement* > resultElems;
5816       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5817         if ( resElem != sourceElem )
5818           resultElems.push_back( resElem );
5819       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5820         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5821           if ( resElem != sourceElem )
5822             resultElems.push_back( resElem );
5823       // do not generate element groups from node ones
5824       if ( sourceElem->GetType() == SMDSAbs_Node &&
5825            elems( iElem )->GetType() != SMDSAbs_Node )
5826         continue;
5827
5828       // add resultElems to groups made by ones the sourceElem belongs to
5829       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5830       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5831       {
5832         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5833         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5834         {
5835           SMDS_MeshGroup* & newGroup = gOldNew->second;
5836           if ( !newGroup )// create a new group
5837           {
5838             // make a name
5839             string name = oldGroup->GetStoreName();
5840             if ( !targetMesh ) {
5841               name += "_";
5842               name += postfix;
5843               int nb = 0;
5844               while ( !groupNames.insert( name ).second ) // name exists
5845               {
5846                 if ( nb == 0 ) {
5847                   name += "_1";
5848                 }
5849                 else {
5850                   TCollection_AsciiString nbStr(nb+1);
5851                   name.resize( name.rfind('_')+1 );
5852                   name += nbStr.ToCString();
5853                 }
5854                 ++nb;
5855               }
5856             }
5857             // make a group
5858             int id;
5859             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5860                                                  name.c_str(), id );
5861             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5862             newGroup = & groupDS->SMDSGroup();
5863             newGroupIDs->push_back( id );
5864           }
5865
5866           // fill in a new group
5867           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5868           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5869             newGroup->Add( *resElemIt );
5870         }
5871       }
5872     } // loop on created elements
5873   }// loop on nodes and elements
5874
5875   return newGroupIDs;
5876 }
5877
5878 //================================================================================
5879 /*!
5880  * \brief Return list of group of nodes close to each other within theTolerance
5881  *        Search among theNodes or in the whole mesh if theNodes is empty using
5882  *        an Octree algorithm
5883  */
5884 //================================================================================
5885
5886 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5887                                             const double         theTolerance,
5888                                             TListOfListOfNodes & theGroupsOfNodes)
5889 {
5890   myLastCreatedElems.Clear();
5891   myLastCreatedNodes.Clear();
5892
5893   if ( theNodes.empty() )
5894   { // get all nodes in the mesh
5895     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5896     while ( nIt->more() )
5897       theNodes.insert( theNodes.end(),nIt->next());
5898   }
5899
5900   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &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     TIDSortedNodeSet nodes;
5921     if ( theMesh ) {
5922       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
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       bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5975       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5976       {
5977         SMESH_OctreeNode* tree = *trIt;
5978         if ( !tree->isLeaf() ) // put children to the queue
5979         {
5980           if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5981           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5982           while ( cIt->more() )
5983             treeList.push_back( cIt->next() );
5984         }
5985         else if ( tree->NbNodes() ) // put a tree to the treeMap
5986         {
5987           const Bnd_B3d& box = tree->getBox();
5988           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5989           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5990           if ( !it_in.second ) // not unique distance to box center
5991             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5992         }
5993       }
5994       // find distance after which there is no sense to check tree's
5995       double sqLimit = DBL_MAX;
5996       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5997       if ( treeMap.size() > 5 ) {
5998         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5999         const Bnd_B3d& box = closestTree->getBox();
6000         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6001         sqLimit = limit * limit;
6002       }
6003       // get all nodes from trees
6004       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6005         if ( sqDist_tree->first > sqLimit )
6006           break;
6007         SMESH_OctreeNode* tree = sqDist_tree->second;
6008         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6009       }
6010     }
6011     // find closest among nodes
6012     minSqDist = DBL_MAX;
6013     const SMDS_MeshNode* closestNode = 0;
6014     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6015     for ( ; nIt != nodes.end(); ++nIt ) {
6016       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6017       if ( minSqDist > sqDist ) {
6018         closestNode = *nIt;
6019         minSqDist = sqDist;
6020       }
6021     }
6022     return closestNode;
6023   }
6024
6025   //---------------------------------------------------------------------
6026   /*!
6027    * \brief Destructor
6028    */
6029   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6030
6031   //---------------------------------------------------------------------
6032   /*!
6033    * \brief Return the node tree
6034    */
6035   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6036
6037 private:
6038   SMESH_OctreeNode* myOctreeNode;
6039   SMESHDS_Mesh*     myMesh;
6040   double            myHalfLeafSize; // max size of a leaf box
6041 };
6042
6043 //=======================================================================
6044 /*!
6045  * \brief Return SMESH_NodeSearcher
6046  */
6047 //=======================================================================
6048
6049 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6050 {
6051   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6052 }
6053
6054 // ========================================================================
6055 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6056 {
6057   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6058   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6059   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6060
6061   //=======================================================================
6062   /*!
6063    * \brief Octal tree of bounding boxes of elements
6064    */
6065   //=======================================================================
6066
6067   class ElementBndBoxTree : public SMESH_Octree
6068   {
6069   public:
6070
6071     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
6072     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6073     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6074     ~ElementBndBoxTree();
6075
6076   protected:
6077     ElementBndBoxTree() {}
6078     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6079     void buildChildrenData();
6080     Bnd_B3d* buildRootBox();
6081   private:
6082     //!< Bounding box of element
6083     struct ElementBox : public Bnd_B3d
6084     {
6085       const SMDS_MeshElement* _element;
6086       int                     _refCount; // an ElementBox can be included in several tree branches
6087       ElementBox(const SMDS_MeshElement* elem);
6088     };
6089     vector< ElementBox* > _elements;
6090   };
6091
6092   //================================================================================
6093   /*!
6094    * \brief ElementBndBoxTree creation
6095    */
6096   //================================================================================
6097
6098   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
6099     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6100   {
6101     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6102     _elements.reserve( nbElems );
6103
6104     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6105     while ( elemIt->more() )
6106       _elements.push_back( new ElementBox( elemIt->next() ));
6107
6108     if ( _elements.size() > MaxNbElemsInLeaf )
6109       compute();
6110     else
6111       myIsLeaf = true;
6112   }
6113
6114   //================================================================================
6115   /*!
6116    * \brief Destructor
6117    */
6118   //================================================================================
6119
6120   ElementBndBoxTree::~ElementBndBoxTree()
6121   {
6122     for ( int i = 0; i < _elements.size(); ++i )
6123       if ( --_elements[i]->_refCount <= 0 )
6124         delete _elements[i];
6125   }
6126
6127   //================================================================================
6128   /*!
6129    * \brief Return the maximal box
6130    */
6131   //================================================================================
6132
6133   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6134   {
6135     Bnd_B3d* box = new Bnd_B3d;
6136     for ( int i = 0; i < _elements.size(); ++i )
6137       box->Add( *_elements[i] );
6138     return box;
6139   }
6140
6141   //================================================================================
6142   /*!
6143    * \brief Redistrubute element boxes among children
6144    */
6145   //================================================================================
6146
6147   void ElementBndBoxTree::buildChildrenData()
6148   {
6149     for ( int i = 0; i < _elements.size(); ++i )
6150     {
6151       for (int j = 0; j < 8; j++)
6152       {
6153         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6154         {
6155           _elements[i]->_refCount++;
6156           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6157         }
6158       }
6159       _elements[i]->_refCount--;
6160     }
6161     _elements.clear();
6162
6163     for (int j = 0; j < 8; j++)
6164     {
6165       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6166       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6167         child->myIsLeaf = true;
6168
6169       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6170         child->_elements.resize( child->_elements.size() ); // compact
6171     }
6172   }
6173
6174   //================================================================================
6175   /*!
6176    * \brief Return elements which can include the point
6177    */
6178   //================================================================================
6179
6180   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6181                                                 TIDSortedElemSet& foundElems)
6182   {
6183     if ( level() && getBox().IsOut( point.XYZ() ))
6184       return;
6185
6186     if ( isLeaf() )
6187     {
6188       for ( int i = 0; i < _elements.size(); ++i )
6189         if ( !_elements[i]->IsOut( point.XYZ() ))
6190           foundElems.insert( _elements[i]->_element );
6191     }
6192     else
6193     {
6194       for (int i = 0; i < 8; i++)
6195         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6196     }
6197   }
6198
6199   //================================================================================
6200   /*!
6201    * \brief Return elements which can be intersected by the line
6202    */
6203   //================================================================================
6204
6205   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6206                                                TIDSortedElemSet& foundElems)
6207   {
6208     if ( level() && getBox().IsOut( line ))
6209       return;
6210
6211     if ( isLeaf() )
6212     {
6213       for ( int i = 0; i < _elements.size(); ++i )
6214         if ( !_elements[i]->IsOut( line ))
6215           foundElems.insert( _elements[i]->_element );
6216     }
6217     else
6218     {
6219       for (int i = 0; i < 8; i++)
6220         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6221     }
6222   }
6223
6224   //================================================================================
6225   /*!
6226    * \brief Construct the element box
6227    */
6228   //================================================================================
6229
6230   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
6231   {
6232     _element  = elem;
6233     _refCount = 1;
6234     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6235     while ( nIt->more() )
6236       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6237     Enlarge( NodeRadius );
6238   }
6239
6240 } // namespace
6241
6242 //=======================================================================
6243 /*!
6244  * \brief Implementation of search for the elements by point and
6245  *        of classification of point in 2D mesh
6246  */
6247 //=======================================================================
6248
6249 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6250 {
6251   SMESHDS_Mesh*                _mesh;
6252   ElementBndBoxTree*           _ebbTree;
6253   SMESH_NodeSearcherImpl*      _nodeSearcher;
6254   SMDSAbs_ElementType          _elementType;
6255   double                       _tolerance;
6256   bool                         _outerFacesFound;
6257   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6258
6259   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6260     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6261   ~SMESH_ElementSearcherImpl()
6262   {
6263     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6264     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6265   }
6266   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6267                                   SMDSAbs_ElementType                type,
6268                                   vector< const SMDS_MeshElement* >& foundElements);
6269   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6270
6271   void GetElementsNearLine( const gp_Ax1&                      line,
6272                             SMDSAbs_ElementType                type,
6273                             vector< const SMDS_MeshElement* >& foundElems);
6274   double getTolerance();
6275   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6276                             const double tolerance, double & param);
6277   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6278   bool isOuterBoundary(const SMDS_MeshElement* face) const
6279   {
6280     return _outerFaces.empty() || _outerFaces.count(face);
6281   }
6282   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6283   {
6284     const SMDS_MeshElement* _face;
6285     gp_Vec                  _faceNorm;
6286     bool                    _coincides; //!< the line lays in face plane
6287     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6288       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6289   };
6290   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6291   {
6292     SMESH_TLink      _link;
6293     TIDSortedElemSet _faces;
6294     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6295       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6296   };
6297 };
6298
6299 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6300 {
6301   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6302              << ", _coincides="<<i._coincides << ")";
6303 }
6304
6305 //=======================================================================
6306 /*!
6307  * \brief define tolerance for search
6308  */
6309 //=======================================================================
6310
6311 double SMESH_ElementSearcherImpl::getTolerance()
6312 {
6313   if ( _tolerance < 0 )
6314   {
6315     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6316
6317     _tolerance = 0;
6318     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6319     {
6320       double boxSize = _nodeSearcher->getTree()->maxSize();
6321       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6322     }
6323     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6324     {
6325       double boxSize = _ebbTree->maxSize();
6326       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6327     }
6328     if ( _tolerance == 0 )
6329     {
6330       // define tolerance by size of a most complex element
6331       int complexType = SMDSAbs_Volume;
6332       while ( complexType > SMDSAbs_All &&
6333               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6334         --complexType;
6335       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6336
6337       double elemSize;
6338       if ( complexType == int( SMDSAbs_Node ))
6339       {
6340         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6341         elemSize = 1;
6342         if ( meshInfo.NbNodes() > 2 )
6343           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6344       }
6345       else
6346       {
6347         const SMDS_MeshElement* elem =
6348           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6349         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6350         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6351         while ( nodeIt->more() )
6352         {
6353           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6354           elemSize = max( dist, elemSize );
6355         }
6356       }
6357       _tolerance = 1e-6 * elemSize;
6358     }
6359   }
6360   return _tolerance;
6361 }
6362
6363 //================================================================================
6364 /*!
6365  * \brief Find intersection of the line and an edge of face and return parameter on line
6366  */
6367 //================================================================================
6368
6369 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6370                                                      const SMDS_MeshElement* face,
6371                                                      const double            tol,
6372                                                      double &                param)
6373 {
6374   int nbInts = 0;
6375   param = 0;
6376
6377   GeomAPI_ExtremaCurveCurve anExtCC;
6378   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6379   
6380   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6381   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6382   {
6383     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6384                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6385     anExtCC.Init( lineCurve, edge);
6386     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6387     {
6388       Quantity_Parameter pl, pe;
6389       anExtCC.LowerDistanceParameters( pl, pe );
6390       param += pl;
6391       if ( ++nbInts == 2 )
6392         break;
6393     }
6394   }
6395   if ( nbInts > 0 ) param /= nbInts;
6396   return nbInts > 0;
6397 }
6398 //================================================================================
6399 /*!
6400  * \brief Find all faces belonging to the outer boundary of mesh
6401  */
6402 //================================================================================
6403
6404 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6405 {
6406   if ( _outerFacesFound ) return;
6407
6408   // Collect all outer faces by passing from one outer face to another via their links
6409   // and BTW find out if there are internal faces at all.
6410
6411   // checked links and links where outer boundary meets internal one
6412   set< SMESH_TLink > visitedLinks, seamLinks;
6413
6414   // links to treat with already visited faces sharing them
6415   list < TFaceLink > startLinks;
6416
6417   // load startLinks with the first outerFace
6418   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6419   _outerFaces.insert( outerFace );
6420
6421   TIDSortedElemSet emptySet;
6422   while ( !startLinks.empty() )
6423   {
6424     const SMESH_TLink& link  = startLinks.front()._link;
6425     TIDSortedElemSet&  faces = startLinks.front()._faces;
6426
6427     outerFace = *faces.begin();
6428     // find other faces sharing the link
6429     const SMDS_MeshElement* f;
6430     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6431       faces.insert( f );
6432
6433     // select another outer face among the found 
6434     const SMDS_MeshElement* outerFace2 = 0;
6435     if ( faces.size() == 2 )
6436     {
6437       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6438     }
6439     else if ( faces.size() > 2 )
6440     {
6441       seamLinks.insert( link );
6442
6443       // link direction within the outerFace
6444       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6445                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6446       int i1 = outerFace->GetNodeIndex( link.node1() );
6447       int i2 = outerFace->GetNodeIndex( link.node2() );
6448       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6449       if ( rev ) n1n2.Reverse();
6450       // outerFace normal
6451       gp_XYZ ofNorm, fNorm;
6452       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6453       {
6454         // direction from the link inside outerFace
6455         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6456         // sort all other faces by angle with the dirInOF
6457         map< double, const SMDS_MeshElement* > angle2Face;
6458         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6459         for ( ; face != faces.end(); ++face )
6460         {
6461           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6462             continue;
6463           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6464           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6465           if ( angle < 0 ) angle += 2*PI;
6466           angle2Face.insert( make_pair( angle, *face ));
6467         }
6468         if ( !angle2Face.empty() )
6469           outerFace2 = angle2Face.begin()->second;
6470       }
6471     }
6472     // store the found outer face and add its links to continue seaching from
6473     if ( outerFace2 )
6474     {
6475       _outerFaces.insert( outerFace );
6476       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6477       for ( int i = 0; i < nbNodes; ++i )
6478       {
6479         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6480         if ( visitedLinks.insert( link2 ).second )
6481           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6482       }
6483     }
6484     startLinks.pop_front();
6485   }
6486   _outerFacesFound = true;
6487
6488   if ( !seamLinks.empty() )
6489   {
6490     // There are internal boundaries touching the outher one,
6491     // find all faces of internal boundaries in order to find
6492     // faces of boundaries of holes, if any.
6493     
6494   }
6495   else
6496   {
6497     _outerFaces.clear();
6498   }
6499 }
6500
6501 //=======================================================================
6502 /*!
6503  * \brief Find elements of given type where the given point is IN or ON.
6504  *        Returns nb of found elements and elements them-selves.
6505  *
6506  * 'ALL' type means elements of any type excluding nodes and 0D elements
6507  */
6508 //=======================================================================
6509
6510 int SMESH_ElementSearcherImpl::
6511 FindElementsByPoint(const gp_Pnt&                      point,
6512                     SMDSAbs_ElementType                type,
6513                     vector< const SMDS_MeshElement* >& foundElements)
6514 {
6515   foundElements.clear();
6516
6517   double tolerance = getTolerance();
6518
6519   // =================================================================================
6520   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6521   {
6522     if ( !_nodeSearcher )
6523       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6524
6525     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6526     if ( !closeNode ) return foundElements.size();
6527
6528     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6529       return foundElements.size(); // to far from any node
6530
6531     if ( type == SMDSAbs_Node )
6532     {
6533       foundElements.push_back( closeNode );
6534     }
6535     else
6536     {
6537       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6538       while ( elemIt->more() )
6539         foundElements.push_back( elemIt->next() );
6540     }
6541   }
6542   // =================================================================================
6543   else // elements more complex than 0D
6544   {
6545     if ( !_ebbTree || _elementType != type )
6546     {
6547       if ( _ebbTree ) delete _ebbTree;
6548       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6549     }
6550     TIDSortedElemSet suspectElems;
6551     _ebbTree->getElementsNearPoint( point, suspectElems );
6552     TIDSortedElemSet::iterator elem = suspectElems.begin();
6553     for ( ; elem != suspectElems.end(); ++elem )
6554       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6555         foundElements.push_back( *elem );
6556   }
6557   return foundElements.size();
6558 }
6559
6560 //================================================================================
6561 /*!
6562  * \brief Classify the given point in the closed 2D mesh
6563  */
6564 //================================================================================
6565
6566 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6567 {
6568   double tolerance = getTolerance();
6569   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6570   {
6571     if ( _ebbTree ) delete _ebbTree;
6572     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6573   }
6574   // Algo: analyse transition of a line starting at the point through mesh boundary;
6575   // try three lines parallel to axis of the coordinate system and perform rough
6576   // analysis. If solution is not clear perform thorough analysis.
6577
6578   const int nbAxes = 3;
6579   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6580   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6581   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6582   multimap< int, int > nbInt2Axis; // to find the simplest case
6583   for ( int axis = 0; axis < nbAxes; ++axis )
6584   {
6585     gp_Ax1 lineAxis( point, axisDir[axis]);
6586     gp_Lin line    ( lineAxis );
6587
6588     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6589     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6590
6591     // Intersect faces with the line
6592
6593     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6594     TIDSortedElemSet::iterator face = suspectFaces.begin();
6595     for ( ; face != suspectFaces.end(); ++face )
6596     {
6597       // get face plane
6598       gp_XYZ fNorm;
6599       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6600       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6601
6602       // perform intersection
6603       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6604       if ( !intersection.IsDone() )
6605         continue;
6606       if ( intersection.IsInQuadric() )
6607       {
6608         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6609       }
6610       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6611       {
6612         gp_Pnt intersectionPoint = intersection.Point(1);
6613         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6614           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6615       }
6616     }
6617     // Analyse intersections roughly
6618
6619     int nbInter = u2inters.size();
6620     if ( nbInter == 0 )
6621       return TopAbs_OUT; 
6622
6623     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6624     if ( nbInter == 1 ) // not closed mesh
6625       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6626
6627     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6628       return TopAbs_ON;
6629
6630     if ( (f<0) == (l<0) )
6631       return TopAbs_OUT;
6632
6633     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6634     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6635     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6636       return TopAbs_IN;
6637
6638     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6639
6640     if ( _outerFacesFound ) break; // pass to thorough analysis
6641
6642   } // three attempts - loop on CS axes
6643
6644   // Analyse intersections thoroughly.
6645   // We make two loops maximum, on the first one we only exclude touching intersections,
6646   // on the second, if situation is still unclear, we gather and use information on
6647   // position of faces (internal or outer). If faces position is already gathered,
6648   // we make the second loop right away.
6649
6650   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6651   {
6652     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6653     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6654     {
6655       int axis = nb_axis->second;
6656       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6657
6658       gp_Ax1 lineAxis( point, axisDir[axis]);
6659       gp_Lin line    ( lineAxis );
6660
6661       // add tangent intersections to u2inters
6662       double param;
6663       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6664       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6665         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6666           u2inters.insert(make_pair( param, *tgtInt ));
6667       tangentInters[ axis ].clear();
6668
6669       // Count intersections before and after the point excluding touching ones.
6670       // If hasPositionInfo we count intersections of outer boundary only
6671
6672       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6673       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6674       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6675       bool ok = ! u_int1->second._coincides;
6676       while ( ok && u_int1 != u2inters.end() )
6677       {
6678         double u = u_int1->first;
6679         bool touchingInt = false;
6680         if ( ++u_int2 != u2inters.end() )
6681         {
6682           // skip intersections at the same point (if the line passes through edge or node)
6683           int nbSamePnt = 0;
6684           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6685           {
6686             ++nbSamePnt;
6687             ++u_int2;
6688           }
6689
6690           // skip tangent intersections
6691           int nbTgt = 0;
6692           const SMDS_MeshElement* prevFace = u_int1->second._face;
6693           while ( ok && u_int2->second._coincides )
6694           {
6695             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6696               ok = false;
6697             else
6698             {
6699               nbTgt++;
6700               u_int2++;
6701               ok = ( u_int2 != u2inters.end() );
6702             }
6703           }
6704           if ( !ok ) break;
6705
6706           // skip intersections at the same point after tangent intersections
6707           if ( nbTgt > 0 )
6708           {
6709             double u2 = u_int2->first;
6710             ++u_int2;
6711             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6712             {
6713               ++nbSamePnt;
6714               ++u_int2;
6715             }
6716           }
6717           // decide if we skipped a touching intersection
6718           if ( nbSamePnt + nbTgt > 0 )
6719           {
6720             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6721             map< double, TInters >::iterator u_int = u_int1;
6722             for ( ; u_int != u_int2; ++u_int )
6723             {
6724               if ( u_int->second._coincides ) continue;
6725               double dot = u_int->second._faceNorm * line.Direction();
6726               if ( dot > maxDot ) maxDot = dot;
6727               if ( dot < minDot ) minDot = dot;
6728             }
6729             touchingInt = ( minDot*maxDot < 0 );
6730           }
6731         }
6732         if ( !touchingInt )
6733         {
6734           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6735           {
6736             if ( u < 0 )
6737               ++nbIntBeforePoint;
6738             else
6739               ++nbIntAfterPoint;
6740           }
6741           if ( u < f ) f = u;
6742           if ( u > l ) l = u;
6743         }
6744
6745         u_int1 = u_int2; // to next intersection
6746
6747       } // loop on intersections with one line
6748
6749       if ( ok )
6750       {
6751         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6752           return TopAbs_ON;
6753
6754         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6755           return TopAbs_OUT; 
6756
6757         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6758           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6759
6760         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6761           return TopAbs_IN;
6762
6763         if ( (f<0) == (l<0) )
6764           return TopAbs_OUT;
6765
6766         if ( hasPositionInfo )
6767           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6768       }
6769     } // loop on intersections of the tree lines - thorough analysis
6770
6771     if ( !hasPositionInfo )
6772     {
6773       // gather info on faces position - is face in the outer boundary or not
6774       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6775       findOuterBoundary( u2inters.begin()->second._face );
6776     }
6777
6778   } // two attempts - with and w/o faces position info in the mesh
6779
6780   return TopAbs_UNKNOWN;
6781 }
6782
6783 //=======================================================================
6784 /*!
6785  * \brief Return elements possibly intersecting the line
6786  */
6787 //=======================================================================
6788
6789 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6790                                                      SMDSAbs_ElementType                type,
6791                                                      vector< const SMDS_MeshElement* >& foundElems)
6792 {
6793   if ( !_ebbTree || _elementType != type )
6794   {
6795     if ( _ebbTree ) delete _ebbTree;
6796     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6797   }
6798   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6799   _ebbTree->getElementsNearLine( line, suspectFaces );
6800   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6801 }
6802
6803 //=======================================================================
6804 /*!
6805  * \brief Return SMESH_ElementSearcher
6806  */
6807 //=======================================================================
6808
6809 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6810 {
6811   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6812 }
6813
6814 //=======================================================================
6815 /*!
6816  * \brief Return true if the point is IN or ON of the element
6817  */
6818 //=======================================================================
6819
6820 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6821 {
6822   if ( element->GetType() == SMDSAbs_Volume)
6823   {
6824     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6825   }
6826
6827   // get ordered nodes
6828
6829   vector< gp_XYZ > xyz;
6830
6831   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6832   if ( element->IsQuadratic() )
6833     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6834       nodeIt = f->interlacedNodesElemIterator();
6835     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6836       nodeIt = e->interlacedNodesElemIterator();
6837
6838   while ( nodeIt->more() )
6839     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6840
6841   int i, nbNodes = element->NbNodes();
6842
6843   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6844   {
6845     // compute face normal
6846     gp_Vec faceNorm(0,0,0);
6847     xyz.push_back( xyz.front() );
6848     for ( i = 0; i < nbNodes; ++i )
6849     {
6850       gp_Vec edge1( xyz[i+1], xyz[i]);
6851       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6852       faceNorm += edge1 ^ edge2;
6853     }
6854     double normSize = faceNorm.Magnitude();
6855     if ( normSize <= tol )
6856     {
6857       // degenerated face: point is out if it is out of all face edges
6858       for ( i = 0; i < nbNodes; ++i )
6859       {
6860         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6861         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6862         SMDS_MeshEdge edge( &n1, &n2 );
6863         if ( !isOut( &edge, point, tol ))
6864           return false;
6865       }
6866       return true;
6867     }
6868     faceNorm /= normSize;
6869
6870     // check if the point lays on face plane
6871     gp_Vec n2p( xyz[0], point );
6872     if ( fabs( n2p * faceNorm ) > tol )
6873       return true; // not on face plane
6874
6875     // check if point is out of face boundary:
6876     // define it by closest transition of a ray point->infinity through face boundary
6877     // on the face plane.
6878     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6879     // to find intersections of the ray with the boundary.
6880     gp_Vec ray = n2p;
6881     gp_Vec plnNorm = ray ^ faceNorm;
6882     normSize = plnNorm.Magnitude();
6883     if ( normSize <= tol ) return false; // point coincides with the first node
6884     plnNorm /= normSize;
6885     // for each node of the face, compute its signed distance to the plane
6886     vector<double> dist( nbNodes + 1);
6887     for ( i = 0; i < nbNodes; ++i )
6888     {
6889       gp_Vec n2p( xyz[i], point );
6890       dist[i] = n2p * plnNorm;
6891     }
6892     dist.back() = dist.front();
6893     // find the closest intersection
6894     int    iClosest = -1;
6895     double rClosest, distClosest = 1e100;;
6896     gp_Pnt pClosest;
6897     for ( i = 0; i < nbNodes; ++i )
6898     {
6899       double r;
6900       if ( fabs( dist[i]) < tol )
6901         r = 0.;
6902       else if ( fabs( dist[i+1]) < tol )
6903         r = 1.;
6904       else if ( dist[i] * dist[i+1] < 0 )
6905         r = dist[i] / ( dist[i] - dist[i+1] );
6906       else
6907         continue; // no intersection
6908       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6909       gp_Vec p2int ( point, pInt);
6910       if ( p2int * ray > -tol ) // right half-space
6911       {
6912         double intDist = p2int.SquareMagnitude();
6913         if ( intDist < distClosest )
6914         {
6915           iClosest = i;
6916           rClosest = r;
6917           pClosest = pInt;
6918           distClosest = intDist;
6919         }
6920       }
6921     }
6922     if ( iClosest < 0 )
6923       return true; // no intesections - out
6924
6925     // analyse transition
6926     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6927     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6928     gp_Vec p2int ( point, pClosest );
6929     bool out = (edgeNorm * p2int) < -tol;
6930     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6931       return out;
6932
6933     // ray pass through a face node; analyze transition through an adjacent edge
6934     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6935     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6936     gp_Vec edgeAdjacent( p1, p2 );
6937     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6938     bool out2 = (edgeNorm2 * p2int) < -tol;
6939
6940     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6941     return covexCorner ? (out || out2) : (out && out2);
6942   }
6943   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6944   {
6945     // point is out of edge if it is NOT ON any straight part of edge
6946     // (we consider quadratic edge as being composed of two straight parts)
6947     for ( i = 1; i < nbNodes; ++i )
6948     {
6949       gp_Vec edge( xyz[i-1], xyz[i]);
6950       gp_Vec n1p ( xyz[i-1], point);
6951       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6952       if ( dist > tol )
6953         continue;
6954       gp_Vec n2p( xyz[i], point );
6955       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6956         continue;
6957       return false; // point is ON this part
6958     }
6959     return true;
6960   }
6961   // Node or 0D element -------------------------------------------------------------------------
6962   {
6963     gp_Vec n2p ( xyz[0], point );
6964     return n2p.Magnitude() <= tol;
6965   }
6966   return true;
6967 }
6968
6969 //=======================================================================
6970 //function : SimplifyFace
6971 //purpose  :
6972 //=======================================================================
6973 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6974                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6975                                     vector<int>&                        quantities) const
6976 {
6977   int nbNodes = faceNodes.size();
6978
6979   if (nbNodes < 3)
6980     return 0;
6981
6982   set<const SMDS_MeshNode*> nodeSet;
6983
6984   // get simple seq of nodes
6985   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6986   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6987   int iSimple = 0, nbUnique = 0;
6988
6989   simpleNodes[iSimple++] = faceNodes[0];
6990   nbUnique++;
6991   for (int iCur = 1; iCur < nbNodes; iCur++) {
6992     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6993       simpleNodes[iSimple++] = faceNodes[iCur];
6994       if (nodeSet.insert( faceNodes[iCur] ).second)
6995         nbUnique++;
6996     }
6997   }
6998   int nbSimple = iSimple;
6999   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7000     nbSimple--;
7001     iSimple--;
7002   }
7003
7004   if (nbUnique < 3)
7005     return 0;
7006
7007   // separate loops
7008   int nbNew = 0;
7009   bool foundLoop = (nbSimple > nbUnique);
7010   while (foundLoop) {
7011     foundLoop = false;
7012     set<const SMDS_MeshNode*> loopSet;
7013     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7014       const SMDS_MeshNode* n = simpleNodes[iSimple];
7015       if (!loopSet.insert( n ).second) {
7016         foundLoop = true;
7017
7018         // separate loop
7019         int iC = 0, curLast = iSimple;
7020         for (; iC < curLast; iC++) {
7021           if (simpleNodes[iC] == n) break;
7022         }
7023         int loopLen = curLast - iC;
7024         if (loopLen > 2) {
7025           // create sub-element
7026           nbNew++;
7027           quantities.push_back(loopLen);
7028           for (; iC < curLast; iC++) {
7029             poly_nodes.push_back(simpleNodes[iC]);
7030           }
7031         }
7032         // shift the rest nodes (place from the first loop position)
7033         for (iC = curLast + 1; iC < nbSimple; iC++) {
7034           simpleNodes[iC - loopLen] = simpleNodes[iC];
7035         }
7036         nbSimple -= loopLen;
7037         iSimple -= loopLen;
7038       }
7039     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7040   } // while (foundLoop)
7041
7042   if (iSimple > 2) {
7043     nbNew++;
7044     quantities.push_back(iSimple);
7045     for (int i = 0; i < iSimple; i++)
7046       poly_nodes.push_back(simpleNodes[i]);
7047   }
7048
7049   return nbNew;
7050 }
7051
7052 //=======================================================================
7053 //function : MergeNodes
7054 //purpose  : In each group, the cdr of nodes are substituted by the first one
7055 //           in all elements.
7056 //=======================================================================
7057
7058 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7059 {
7060   myLastCreatedElems.Clear();
7061   myLastCreatedNodes.Clear();
7062
7063   SMESHDS_Mesh* aMesh = GetMeshDS();
7064
7065   TNodeNodeMap nodeNodeMap; // node to replace - new node
7066   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7067   list< int > rmElemIds, rmNodeIds;
7068
7069   // Fill nodeNodeMap and elems
7070
7071   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7072   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7073     list<const SMDS_MeshNode*>& nodes = *grIt;
7074     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7075     const SMDS_MeshNode* nToKeep = *nIt;
7076     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7077       const SMDS_MeshNode* nToRemove = *nIt;
7078       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7079       if ( nToRemove != nToKeep ) {
7080         rmNodeIds.push_back( nToRemove->GetID() );
7081         AddToSameGroups( nToKeep, nToRemove, aMesh );
7082       }
7083
7084       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7085       while ( invElemIt->more() ) {
7086         const SMDS_MeshElement* elem = invElemIt->next();
7087         elems.insert(elem);
7088       }
7089     }
7090   }
7091   // Change element nodes or remove an element
7092
7093   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7094   for ( ; eIt != elems.end(); eIt++ ) {
7095     const SMDS_MeshElement* elem = *eIt;
7096     int nbNodes = elem->NbNodes();
7097     int aShapeId = FindShape( elem );
7098
7099     set<const SMDS_MeshNode*> nodeSet;
7100     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7101     int iUnique = 0, iCur = 0, nbRepl = 0;
7102     vector<int> iRepl( nbNodes );
7103
7104     // get new seq of nodes
7105     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7106     while ( itN->more() ) {
7107       const SMDS_MeshNode* n =
7108         static_cast<const SMDS_MeshNode*>( itN->next() );
7109
7110       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7111       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7112         n = (*nnIt).second;
7113         // BUG 0020185: begin
7114         {
7115           bool stopRecur = false;
7116           set<const SMDS_MeshNode*> nodesRecur;
7117           nodesRecur.insert(n);
7118           while (!stopRecur) {
7119             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7120             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7121               n = (*nnIt_i).second;
7122               if (!nodesRecur.insert(n).second) {
7123                 // error: recursive dependancy
7124                 stopRecur = true;
7125               }
7126             }
7127             else
7128               stopRecur = true;
7129           }
7130         }
7131         // BUG 0020185: end
7132         iRepl[ nbRepl++ ] = iCur;
7133       }
7134       curNodes[ iCur ] = n;
7135       bool isUnique = nodeSet.insert( n ).second;
7136       if ( isUnique )
7137         uniqueNodes[ iUnique++ ] = n;
7138       iCur++;
7139     }
7140
7141     // Analyse element topology after replacement
7142
7143     bool isOk = true;
7144     int nbUniqueNodes = nodeSet.size();
7145     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7146       // Polygons and Polyhedral volumes
7147       if (elem->IsPoly()) {
7148
7149         if (elem->GetType() == SMDSAbs_Face) {
7150           // Polygon
7151           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7152           int inode = 0;
7153           for (; inode < nbNodes; inode++) {
7154             face_nodes[inode] = curNodes[inode];
7155           }
7156
7157           vector<const SMDS_MeshNode *> polygons_nodes;
7158           vector<int> quantities;
7159           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7160
7161           if (nbNew > 0) {
7162             inode = 0;
7163             for (int iface = 0; iface < nbNew - 1; iface++) {
7164               int nbNodes = quantities[iface];
7165               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7166               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7167                 poly_nodes[ii] = polygons_nodes[inode];
7168               }
7169               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7170               myLastCreatedElems.Append(newElem);
7171               if (aShapeId)
7172                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7173             }
7174             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7175           }
7176           else {
7177             rmElemIds.push_back(elem->GetID());
7178           }
7179
7180         }
7181         else if (elem->GetType() == SMDSAbs_Volume) {
7182           // Polyhedral volume
7183           if (nbUniqueNodes < 4) {
7184             rmElemIds.push_back(elem->GetID());
7185           }
7186           else {
7187             // each face has to be analized in order to check volume validity
7188             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7189               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7190             if (aPolyedre) {
7191               int nbFaces = aPolyedre->NbFaces();
7192
7193               vector<const SMDS_MeshNode *> poly_nodes;
7194               vector<int> quantities;
7195
7196               for (int iface = 1; iface <= nbFaces; iface++) {
7197                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7198                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7199
7200                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7201                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7202                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7203                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7204                     faceNode = (*nnIt).second;
7205                   }
7206                   faceNodes[inode - 1] = faceNode;
7207                 }
7208
7209                 SimplifyFace(faceNodes, poly_nodes, quantities);
7210               }
7211
7212               if (quantities.size() > 3) {
7213                 // to be done: remove coincident faces
7214               }
7215
7216               if (quantities.size() > 3)
7217                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7218               else
7219                 rmElemIds.push_back(elem->GetID());
7220
7221             }
7222             else {
7223               rmElemIds.push_back(elem->GetID());
7224             }
7225           }
7226         }
7227         else {
7228         }
7229
7230         continue;
7231       }
7232
7233       // Regular elements
7234       switch ( nbNodes ) {
7235       case 2: ///////////////////////////////////// EDGE
7236         isOk = false; break;
7237       case 3: ///////////////////////////////////// TRIANGLE
7238         isOk = false; break;
7239       case 4:
7240         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7241           isOk = false;
7242         else { //////////////////////////////////// QUADRANGLE
7243           if ( nbUniqueNodes < 3 )
7244             isOk = false;
7245           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7246             isOk = false; // opposite nodes stick
7247         }
7248         break;
7249       case 6: ///////////////////////////////////// PENTAHEDRON
7250         if ( nbUniqueNodes == 4 ) {
7251           // ---------------------------------> tetrahedron
7252           if (nbRepl == 3 &&
7253               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7254             // all top nodes stick: reverse a bottom
7255             uniqueNodes[ 0 ] = curNodes [ 1 ];
7256             uniqueNodes[ 1 ] = curNodes [ 0 ];
7257           }
7258           else if (nbRepl == 3 &&
7259                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7260             // all bottom nodes stick: set a top before
7261             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7262             uniqueNodes[ 0 ] = curNodes [ 3 ];
7263             uniqueNodes[ 1 ] = curNodes [ 4 ];
7264             uniqueNodes[ 2 ] = curNodes [ 5 ];
7265           }
7266           else if (nbRepl == 4 &&
7267                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7268             // a lateral face turns into a line: reverse a bottom
7269             uniqueNodes[ 0 ] = curNodes [ 1 ];
7270             uniqueNodes[ 1 ] = curNodes [ 0 ];
7271           }
7272           else
7273             isOk = false;
7274         }
7275         else if ( nbUniqueNodes == 5 ) {
7276           // PENTAHEDRON --------------------> 2 tetrahedrons
7277           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7278             // a bottom node sticks with a linked top one
7279             // 1.
7280             SMDS_MeshElement* newElem =
7281               aMesh->AddVolume(curNodes[ 3 ],
7282                                curNodes[ 4 ],
7283                                curNodes[ 5 ],
7284                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7285             myLastCreatedElems.Append(newElem);
7286             if ( aShapeId )
7287               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7288             // 2. : reverse a bottom
7289             uniqueNodes[ 0 ] = curNodes [ 1 ];
7290             uniqueNodes[ 1 ] = curNodes [ 0 ];
7291             nbUniqueNodes = 4;
7292           }
7293           else
7294             isOk = false;
7295         }
7296         else
7297           isOk = false;
7298         break;
7299       case 8: {
7300         if(elem->IsQuadratic()) { // Quadratic quadrangle
7301           //   1    5    2
7302           //    +---+---+
7303           //    |       |
7304           //    |       |
7305           //   4+       +6
7306           //    |       |
7307           //    |       |
7308           //    +---+---+
7309           //   0    7    3
7310           isOk = false;
7311           if(nbRepl==3) {
7312             nbUniqueNodes = 6;
7313             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7314               uniqueNodes[0] = curNodes[0];
7315               uniqueNodes[1] = curNodes[2];
7316               uniqueNodes[2] = curNodes[3];
7317               uniqueNodes[3] = curNodes[5];
7318               uniqueNodes[4] = curNodes[6];
7319               uniqueNodes[5] = curNodes[7];
7320               isOk = true;
7321             }
7322             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7323               uniqueNodes[0] = curNodes[0];
7324               uniqueNodes[1] = curNodes[1];
7325               uniqueNodes[2] = curNodes[2];
7326               uniqueNodes[3] = curNodes[4];
7327               uniqueNodes[4] = curNodes[5];
7328               uniqueNodes[5] = curNodes[6];
7329               isOk = true;
7330             }
7331             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7332               uniqueNodes[0] = curNodes[1];
7333               uniqueNodes[1] = curNodes[2];
7334               uniqueNodes[2] = curNodes[3];
7335               uniqueNodes[3] = curNodes[5];
7336               uniqueNodes[4] = curNodes[6];
7337               uniqueNodes[5] = curNodes[0];
7338               isOk = true;
7339             }
7340             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7341               uniqueNodes[0] = curNodes[0];
7342               uniqueNodes[1] = curNodes[1];
7343               uniqueNodes[2] = curNodes[3];
7344               uniqueNodes[3] = curNodes[4];
7345               uniqueNodes[4] = curNodes[6];
7346               uniqueNodes[5] = curNodes[7];
7347               isOk = true;
7348             }
7349             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7350               uniqueNodes[0] = curNodes[0];
7351               uniqueNodes[1] = curNodes[2];
7352               uniqueNodes[2] = curNodes[3];
7353               uniqueNodes[3] = curNodes[1];
7354               uniqueNodes[4] = curNodes[6];
7355               uniqueNodes[5] = curNodes[7];
7356               isOk = true;
7357             }
7358             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7359               uniqueNodes[0] = curNodes[0];
7360               uniqueNodes[1] = curNodes[1];
7361               uniqueNodes[2] = curNodes[2];
7362               uniqueNodes[3] = curNodes[4];
7363               uniqueNodes[4] = curNodes[5];
7364               uniqueNodes[5] = curNodes[7];
7365               isOk = true;
7366             }
7367             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7368               uniqueNodes[0] = curNodes[0];
7369               uniqueNodes[1] = curNodes[1];
7370               uniqueNodes[2] = curNodes[3];
7371               uniqueNodes[3] = curNodes[4];
7372               uniqueNodes[4] = curNodes[2];
7373               uniqueNodes[5] = curNodes[7];
7374               isOk = true;
7375             }
7376             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7377               uniqueNodes[0] = curNodes[0];
7378               uniqueNodes[1] = curNodes[1];
7379               uniqueNodes[2] = curNodes[2];
7380               uniqueNodes[3] = curNodes[4];
7381               uniqueNodes[4] = curNodes[5];
7382               uniqueNodes[5] = curNodes[3];
7383               isOk = true;
7384             }
7385           }
7386           break;
7387         }
7388         //////////////////////////////////// HEXAHEDRON
7389         isOk = false;
7390         SMDS_VolumeTool hexa (elem);
7391         hexa.SetExternalNormal();
7392         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7393           //////////////////////// ---> tetrahedron
7394           for ( int iFace = 0; iFace < 6; iFace++ ) {
7395             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7396             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7397                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7398                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7399               // one face turns into a point ...
7400               int iOppFace = hexa.GetOppFaceIndex( iFace );
7401               ind = hexa.GetFaceNodesIndices( iOppFace );
7402               int nbStick = 0;
7403               iUnique = 2; // reverse a tetrahedron bottom
7404               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7405                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7406                   nbStick++;
7407                 else if ( iUnique >= 0 )
7408                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7409               }
7410               if ( nbStick == 1 ) {
7411                 // ... and the opposite one - into a triangle.
7412                 // set a top node
7413                 ind = hexa.GetFaceNodesIndices( iFace );
7414                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7415                 isOk = true;
7416               }
7417               break;
7418             }
7419           }
7420         }
7421         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7422           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7423           for ( int iFace = 0; iFace < 6; iFace++ ) {
7424             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7425             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7426                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7427                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7428               // one face turns into a point ...
7429               int iOppFace = hexa.GetOppFaceIndex( iFace );
7430               ind = hexa.GetFaceNodesIndices( iOppFace );
7431               int nbStick = 0;
7432               iUnique = 2;  // reverse a tetrahedron 1 bottom
7433               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7434                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7435                   nbStick++;
7436                 else if ( iUnique >= 0 )
7437                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7438               }
7439               if ( nbStick == 0 ) {
7440                 // ... and the opposite one is a quadrangle
7441                 // set a top node
7442                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7443                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7444                 nbUniqueNodes = 4;
7445                 // tetrahedron 2
7446                 SMDS_MeshElement* newElem =
7447                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7448                                    curNodes[ind[ 3 ]],
7449                                    curNodes[ind[ 2 ]],
7450                                    curNodes[indTop[ 0 ]]);
7451                 myLastCreatedElems.Append(newElem);
7452                 if ( aShapeId )
7453                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7454                 isOk = true;
7455               }
7456               break;
7457             }
7458           }
7459         }
7460         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7461           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7462           // find indices of quad and tri faces
7463           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7464           for ( iFace = 0; iFace < 6; iFace++ ) {
7465             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7466             nodeSet.clear();
7467             for ( iCur = 0; iCur < 4; iCur++ )
7468               nodeSet.insert( curNodes[ind[ iCur ]] );
7469             nbUniqueNodes = nodeSet.size();
7470             if ( nbUniqueNodes == 3 )
7471               iTriFace[ nbTri++ ] = iFace;
7472             else if ( nbUniqueNodes == 4 )
7473               iQuadFace[ nbQuad++ ] = iFace;
7474           }
7475           if (nbQuad == 2 && nbTri == 4 &&
7476               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7477             // 2 opposite quadrangles stuck with a diagonal;
7478             // sample groups of merged indices: (0-4)(2-6)
7479             // --------------------------------------------> 2 tetrahedrons
7480             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7481             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7482             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7483             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7484                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7485               // stuck with 0-2 diagonal
7486               i0  = ind1[ 3 ];
7487               i1d = ind1[ 0 ];
7488               i2  = ind1[ 1 ];
7489               i3d = ind1[ 2 ];
7490               i0t = ind2[ 1 ];
7491               i2t = ind2[ 3 ];
7492             }
7493             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7494                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7495               // stuck with 1-3 diagonal
7496               i0  = ind1[ 0 ];
7497               i1d = ind1[ 1 ];
7498               i2  = ind1[ 2 ];
7499               i3d = ind1[ 3 ];
7500               i0t = ind2[ 0 ];
7501               i2t = ind2[ 1 ];
7502             }
7503             else {
7504               ASSERT(0);
7505             }
7506             // tetrahedron 1
7507             uniqueNodes[ 0 ] = curNodes [ i0 ];
7508             uniqueNodes[ 1 ] = curNodes [ i1d ];
7509             uniqueNodes[ 2 ] = curNodes [ i3d ];
7510             uniqueNodes[ 3 ] = curNodes [ i0t ];
7511             nbUniqueNodes = 4;
7512             // tetrahedron 2
7513             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7514                                                          curNodes[ i2 ],
7515                                                          curNodes[ i3d ],
7516                                                          curNodes[ i2t ]);
7517             myLastCreatedElems.Append(newElem);
7518             if ( aShapeId )
7519               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7520             isOk = true;
7521           }
7522           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7523                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7524             // --------------------------------------------> prism
7525             // find 2 opposite triangles
7526             nbUniqueNodes = 6;
7527             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7528               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7529                 // find indices of kept and replaced nodes
7530                 // and fill unique nodes of 2 opposite triangles
7531                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7532                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7533                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7534                 // fill unique nodes
7535                 iUnique = 0;
7536                 isOk = true;
7537                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7538                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7539                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7540                   if ( n == nInit ) {
7541                     // iCur of a linked node of the opposite face (make normals co-directed):
7542                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7543                     // check that correspondent corners of triangles are linked
7544                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7545                       isOk = false;
7546                     else {
7547                       uniqueNodes[ iUnique ] = n;
7548                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7549                       iUnique++;
7550                     }
7551                   }
7552                 }
7553                 break;
7554               }
7555             }
7556           }
7557         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7558         break;
7559       } // HEXAHEDRON
7560
7561       default:
7562         isOk = false;
7563       } // switch ( nbNodes )
7564
7565     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7566
7567     if ( isOk ) {
7568       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7569         // Change nodes of polyedre
7570         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7571           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7572         if (aPolyedre) {
7573           int nbFaces = aPolyedre->NbFaces();
7574
7575           vector<const SMDS_MeshNode *> poly_nodes;
7576           vector<int> quantities (nbFaces);
7577
7578           for (int iface = 1; iface <= nbFaces; iface++) {
7579             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7580             quantities[iface - 1] = nbFaceNodes;
7581
7582             for (inode = 1; inode <= nbFaceNodes; inode++) {
7583               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7584
7585               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7586               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7587                 curNode = (*nnIt).second;
7588               }
7589               poly_nodes.push_back(curNode);
7590             }
7591           }
7592           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7593         }
7594       }
7595       else {
7596         // Change regular element or polygon
7597         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7598       }
7599     }
7600     else {
7601       // Remove invalid regular element or invalid polygon
7602       rmElemIds.push_back( elem->GetID() );
7603     }
7604
7605   } // loop on elements
7606
7607   // Remove equal nodes and bad elements
7608
7609   Remove( rmNodeIds, true );
7610   Remove( rmElemIds, false );
7611
7612 }
7613
7614
7615 // ========================================================
7616 // class   : SortableElement
7617 // purpose : allow sorting elements basing on their nodes
7618 // ========================================================
7619 class SortableElement : public set <const SMDS_MeshElement*>
7620 {
7621 public:
7622
7623   SortableElement( const SMDS_MeshElement* theElem )
7624   {
7625     myElem = theElem;
7626     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7627     while ( nodeIt->more() )
7628       this->insert( nodeIt->next() );
7629   }
7630
7631   const SMDS_MeshElement* Get() const
7632   { return myElem; }
7633
7634   void Set(const SMDS_MeshElement* e) const
7635   { myElem = e; }
7636
7637
7638 private:
7639   mutable const SMDS_MeshElement* myElem;
7640 };
7641
7642 //=======================================================================
7643 //function : FindEqualElements
7644 //purpose  : Return list of group of elements built on the same nodes.
7645 //           Search among theElements or in the whole mesh if theElements is empty
7646 //=======================================================================
7647 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7648                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7649 {
7650   myLastCreatedElems.Clear();
7651   myLastCreatedNodes.Clear();
7652
7653   typedef set<const SMDS_MeshElement*> TElemsSet;
7654   typedef map< SortableElement, int > TMapOfNodeSet;
7655   typedef list<int> TGroupOfElems;
7656
7657   TElemsSet elems;
7658   if ( theElements.empty() )
7659   { // get all elements in the mesh
7660     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7661     while ( eIt->more() )
7662       elems.insert( elems.end(), eIt->next());
7663   }
7664   else
7665     elems = theElements;
7666
7667   vector< TGroupOfElems > arrayOfGroups;
7668   TGroupOfElems groupOfElems;
7669   TMapOfNodeSet mapOfNodeSet;
7670
7671   TElemsSet::iterator elemIt = elems.begin();
7672   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7673     const SMDS_MeshElement* curElem = *elemIt;
7674     SortableElement SE(curElem);
7675     int ind = -1;
7676     // check uniqueness
7677     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7678     if( !(pp.second) ) {
7679       TMapOfNodeSet::iterator& itSE = pp.first;
7680       ind = (*itSE).second;
7681       arrayOfGroups[ind].push_back(curElem->GetID());
7682     }
7683     else {
7684       groupOfElems.clear();
7685       groupOfElems.push_back(curElem->GetID());
7686       arrayOfGroups.push_back(groupOfElems);
7687       i++;
7688     }
7689   }
7690
7691   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7692   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7693     groupOfElems = *groupIt;
7694     if ( groupOfElems.size() > 1 ) {
7695       groupOfElems.sort();
7696       theGroupsOfElementsID.push_back(groupOfElems);
7697     }
7698   }
7699 }
7700
7701 //=======================================================================
7702 //function : MergeElements
7703 //purpose  : In each given group, substitute all elements by the first one.
7704 //=======================================================================
7705
7706 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7707 {
7708   myLastCreatedElems.Clear();
7709   myLastCreatedNodes.Clear();
7710
7711   typedef list<int> TListOfIDs;
7712   TListOfIDs rmElemIds; // IDs of elems to remove
7713
7714   SMESHDS_Mesh* aMesh = GetMeshDS();
7715
7716   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7717   while ( groupsIt != theGroupsOfElementsID.end() ) {
7718     TListOfIDs& aGroupOfElemID = *groupsIt;
7719     aGroupOfElemID.sort();
7720     int elemIDToKeep = aGroupOfElemID.front();
7721     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7722     aGroupOfElemID.pop_front();
7723     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7724     while ( idIt != aGroupOfElemID.end() ) {
7725       int elemIDToRemove = *idIt;
7726       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7727       // add the kept element in groups of removed one (PAL15188)
7728       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7729       rmElemIds.push_back( elemIDToRemove );
7730       ++idIt;
7731     }
7732     ++groupsIt;
7733   }
7734
7735   Remove( rmElemIds, false );
7736 }
7737
7738 //=======================================================================
7739 //function : MergeEqualElements
7740 //purpose  : Remove all but one of elements built on the same nodes.
7741 //=======================================================================
7742
7743 void SMESH_MeshEditor::MergeEqualElements()
7744 {
7745   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7746                                                  to merge equal elements in the whole mesh */
7747   TListOfListOfElementsID aGroupsOfElementsID;
7748   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7749   MergeElements(aGroupsOfElementsID);
7750 }
7751
7752 //=======================================================================
7753 //function : FindFaceInSet
7754 //purpose  : Return a face having linked nodes n1 and n2 and which is
7755 //           - not in avoidSet,
7756 //           - in elemSet provided that !elemSet.empty()
7757 //           i1 and i2 optionally returns indices of n1 and n2
7758 //=======================================================================
7759
7760 const SMDS_MeshElement*
7761 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7762                                 const SMDS_MeshNode*    n2,
7763                                 const TIDSortedElemSet& elemSet,
7764                                 const TIDSortedElemSet& avoidSet,
7765                                 int*                    n1ind,
7766                                 int*                    n2ind)
7767
7768 {
7769   int i1, i2;
7770   const SMDS_MeshElement* face = 0;
7771
7772   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7773   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7774   {
7775     const SMDS_MeshElement* elem = invElemIt->next();
7776     if (avoidSet.count( elem ))
7777       continue;
7778     if ( !elemSet.empty() && !elemSet.count( elem ))
7779       continue;
7780     // index of n1
7781     i1 = elem->GetNodeIndex( n1 );
7782     // find a n2 linked to n1
7783     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7784     for ( int di = -1; di < 2 && !face; di += 2 )
7785     {
7786       i2 = (i1+di+nbN) % nbN;
7787       if ( elem->GetNode( i2 ) == n2 )
7788         face = elem;
7789     }
7790     if ( !face && elem->IsQuadratic())
7791     {
7792       // analysis for quadratic elements using all nodes
7793       const SMDS_QuadraticFaceOfNodes* F =
7794         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7795       // use special nodes iterator
7796       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7797       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7798       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7799       {
7800         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7801         if ( n1 == prevN && n2 == n )
7802         {
7803           face = elem;
7804         }
7805         else if ( n2 == prevN && n1 == n )
7806         {
7807           face = elem; swap( i1, i2 );
7808         }
7809         prevN = n;
7810       }
7811     }
7812   }
7813   if ( n1ind ) *n1ind = i1;
7814   if ( n2ind ) *n2ind = i2;
7815   return face;
7816 }
7817
7818 //=======================================================================
7819 //function : findAdjacentFace
7820 //purpose  :
7821 //=======================================================================
7822
7823 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7824                                                 const SMDS_MeshNode* n2,
7825                                                 const SMDS_MeshElement* elem)
7826 {
7827   TIDSortedElemSet elemSet, avoidSet;
7828   if ( elem )
7829     avoidSet.insert ( elem );
7830   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7831 }
7832
7833 //=======================================================================
7834 //function : FindFreeBorder
7835 //purpose  :
7836 //=======================================================================
7837
7838 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7839
7840 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7841                                        const SMDS_MeshNode*             theSecondNode,
7842                                        const SMDS_MeshNode*             theLastNode,
7843                                        list< const SMDS_MeshNode* > &   theNodes,
7844                                        list< const SMDS_MeshElement* >& theFaces)
7845 {
7846   if ( !theFirstNode || !theSecondNode )
7847     return false;
7848   // find border face between theFirstNode and theSecondNode
7849   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7850   if ( !curElem )
7851     return false;
7852
7853   theFaces.push_back( curElem );
7854   theNodes.push_back( theFirstNode );
7855   theNodes.push_back( theSecondNode );
7856
7857   //vector<const SMDS_MeshNode*> nodes;
7858   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7859   TIDSortedElemSet foundElems;
7860   bool needTheLast = ( theLastNode != 0 );
7861
7862   while ( nStart != theLastNode ) {
7863     if ( nStart == theFirstNode )
7864       return !needTheLast;
7865
7866     // find all free border faces sharing form nStart
7867
7868     list< const SMDS_MeshElement* > curElemList;
7869     list< const SMDS_MeshNode* > nStartList;
7870     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7871     while ( invElemIt->more() ) {
7872       const SMDS_MeshElement* e = invElemIt->next();
7873       if ( e == curElem || foundElems.insert( e ).second ) {
7874         // get nodes
7875         int iNode = 0, nbNodes = e->NbNodes();
7876         //const SMDS_MeshNode* nodes[nbNodes+1];
7877         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7878
7879         if(e->IsQuadratic()) {
7880           const SMDS_QuadraticFaceOfNodes* F =
7881             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7882           // use special nodes iterator
7883           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7884           while( anIter->more() ) {
7885             nodes[ iNode++ ] = anIter->next();
7886           }
7887         }
7888         else {
7889           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7890           while ( nIt->more() )
7891             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7892         }
7893         nodes[ iNode ] = nodes[ 0 ];
7894         // check 2 links
7895         for ( iNode = 0; iNode < nbNodes; iNode++ )
7896           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7897                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7898               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7899           {
7900             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7901             curElemList.push_back( e );
7902           }
7903       }
7904     }
7905     // analyse the found
7906
7907     int nbNewBorders = curElemList.size();
7908     if ( nbNewBorders == 0 ) {
7909       // no free border furthermore
7910       return !needTheLast;
7911     }
7912     else if ( nbNewBorders == 1 ) {
7913       // one more element found
7914       nIgnore = nStart;
7915       nStart = nStartList.front();
7916       curElem = curElemList.front();
7917       theFaces.push_back( curElem );
7918       theNodes.push_back( nStart );
7919     }
7920     else {
7921       // several continuations found
7922       list< const SMDS_MeshElement* >::iterator curElemIt;
7923       list< const SMDS_MeshNode* >::iterator nStartIt;
7924       // check if one of them reached the last node
7925       if ( needTheLast ) {
7926         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7927              curElemIt!= curElemList.end();
7928              curElemIt++, nStartIt++ )
7929           if ( *nStartIt == theLastNode ) {
7930             theFaces.push_back( *curElemIt );
7931             theNodes.push_back( *nStartIt );
7932             return true;
7933           }
7934       }
7935       // find the best free border by the continuations
7936       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7937       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7938       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7939            curElemIt!= curElemList.end();
7940            curElemIt++, nStartIt++ )
7941       {
7942         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7943         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7944         // find one more free border
7945         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7946           cNL->clear();
7947           cFL->clear();
7948         }
7949         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7950           // choice: clear a worse one
7951           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7952           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7953           contNodes[ iWorse ].clear();
7954           contFaces[ iWorse ].clear();
7955         }
7956       }
7957       if ( contNodes[0].empty() && contNodes[1].empty() )
7958         return false;
7959
7960       // append the best free border
7961       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7962       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7963       theNodes.pop_back(); // remove nIgnore
7964       theNodes.pop_back(); // remove nStart
7965       theFaces.pop_back(); // remove curElem
7966       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7967       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7968       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7969       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7970       return true;
7971
7972     } // several continuations found
7973   } // while ( nStart != theLastNode )
7974
7975   return true;
7976 }
7977
7978 //=======================================================================
7979 //function : CheckFreeBorderNodes
7980 //purpose  : Return true if the tree nodes are on a free border
7981 //=======================================================================
7982
7983 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7984                                             const SMDS_MeshNode* theNode2,
7985                                             const SMDS_MeshNode* theNode3)
7986 {
7987   list< const SMDS_MeshNode* > nodes;
7988   list< const SMDS_MeshElement* > faces;
7989   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7990 }
7991
7992 //=======================================================================
7993 //function : SewFreeBorder
7994 //purpose  :
7995 //=======================================================================
7996
7997 SMESH_MeshEditor::Sew_Error
7998 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7999                                  const SMDS_MeshNode* theBordSecondNode,
8000                                  const SMDS_MeshNode* theBordLastNode,
8001                                  const SMDS_MeshNode* theSideFirstNode,
8002                                  const SMDS_MeshNode* theSideSecondNode,
8003                                  const SMDS_MeshNode* theSideThirdNode,
8004                                  const bool           theSideIsFreeBorder,
8005                                  const bool           toCreatePolygons,
8006                                  const bool           toCreatePolyedrs)
8007 {
8008   myLastCreatedElems.Clear();
8009   myLastCreatedNodes.Clear();
8010
8011   MESSAGE("::SewFreeBorder()");
8012   Sew_Error aResult = SEW_OK;
8013
8014   // ====================================
8015   //    find side nodes and elements
8016   // ====================================
8017
8018   list< const SMDS_MeshNode* > nSide[ 2 ];
8019   list< const SMDS_MeshElement* > eSide[ 2 ];
8020   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8021   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8022
8023   // Free border 1
8024   // --------------
8025   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8026                       nSide[0], eSide[0])) {
8027     MESSAGE(" Free Border 1 not found " );
8028     aResult = SEW_BORDER1_NOT_FOUND;
8029   }
8030   if (theSideIsFreeBorder) {
8031     // Free border 2
8032     // --------------
8033     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8034                         nSide[1], eSide[1])) {
8035       MESSAGE(" Free Border 2 not found " );
8036       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8037     }
8038   }
8039   if ( aResult != SEW_OK )
8040     return aResult;
8041
8042   if (!theSideIsFreeBorder) {
8043     // Side 2
8044     // --------------
8045
8046     // -------------------------------------------------------------------------
8047     // Algo:
8048     // 1. If nodes to merge are not coincident, move nodes of the free border
8049     //    from the coord sys defined by the direction from the first to last
8050     //    nodes of the border to the correspondent sys of the side 2
8051     // 2. On the side 2, find the links most co-directed with the correspondent
8052     //    links of the free border
8053     // -------------------------------------------------------------------------
8054
8055     // 1. Since sewing may brake if there are volumes to split on the side 2,
8056     //    we wont move nodes but just compute new coordinates for them
8057     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8058     TNodeXYZMap nBordXYZ;
8059     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8060     list< const SMDS_MeshNode* >::iterator nBordIt;
8061
8062     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8063     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8064     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8065     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8066     double tol2 = 1.e-8;
8067     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8068     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8069       // Need node movement.
8070
8071       // find X and Z axes to create trsf
8072       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8073       gp_Vec X = Zs ^ Zb;
8074       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8075         // Zb || Zs
8076         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8077
8078       // coord systems
8079       gp_Ax3 toBordAx( Pb1, Zb, X );
8080       gp_Ax3 fromSideAx( Ps1, Zs, X );
8081       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8082       // set trsf
8083       gp_Trsf toBordSys, fromSide2Sys;
8084       toBordSys.SetTransformation( toBordAx );
8085       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8086       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8087
8088       // move
8089       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8090         const SMDS_MeshNode* n = *nBordIt;
8091         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8092         toBordSys.Transforms( xyz );
8093         fromSide2Sys.Transforms( xyz );
8094         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8095       }
8096     }
8097     else {
8098       // just insert nodes XYZ in the nBordXYZ map
8099       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8100         const SMDS_MeshNode* n = *nBordIt;
8101         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8102       }
8103     }
8104
8105     // 2. On the side 2, find the links most co-directed with the correspondent
8106     //    links of the free border
8107
8108     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8109     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8110     sideNodes.push_back( theSideFirstNode );
8111
8112     bool hasVolumes = false;
8113     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8114     set<long> foundSideLinkIDs, checkedLinkIDs;
8115     SMDS_VolumeTool volume;
8116     //const SMDS_MeshNode* faceNodes[ 4 ];
8117
8118     const SMDS_MeshNode*    sideNode;
8119     const SMDS_MeshElement* sideElem;
8120     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8121     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8122     nBordIt = bordNodes.begin();
8123     nBordIt++;
8124     // border node position and border link direction to compare with
8125     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8126     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8127     // choose next side node by link direction or by closeness to
8128     // the current border node:
8129     bool searchByDir = ( *nBordIt != theBordLastNode );
8130     do {
8131       // find the next node on the Side 2
8132       sideNode = 0;
8133       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8134       long linkID;
8135       checkedLinkIDs.clear();
8136       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8137
8138       // loop on inverse elements of current node (prevSideNode) on the Side 2
8139       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8140       while ( invElemIt->more() )
8141       {
8142         const SMDS_MeshElement* elem = invElemIt->next();
8143         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8144         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8145         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8146         bool isVolume = volume.Set( elem );
8147         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8148         if ( isVolume ) // --volume
8149           hasVolumes = true;
8150         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8151           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8152           if(elem->IsQuadratic()) {
8153             const SMDS_QuadraticFaceOfNodes* F =
8154               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8155             // use special nodes iterator
8156             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8157             while( anIter->more() ) {
8158               nodes[ iNode ] = anIter->next();
8159               if ( nodes[ iNode++ ] == prevSideNode )
8160                 iPrevNode = iNode - 1;
8161             }
8162           }
8163           else {
8164             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8165             while ( nIt->more() ) {
8166               nodes[ iNode ] = cast2Node( nIt->next() );
8167               if ( nodes[ iNode++ ] == prevSideNode )
8168                 iPrevNode = iNode - 1;
8169             }
8170           }
8171           // there are 2 links to check
8172           nbNodes = 2;
8173         }
8174         else // --edge
8175           continue;
8176         // loop on links, to be precise, on the second node of links
8177         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8178           const SMDS_MeshNode* n = nodes[ iNode ];
8179           if ( isVolume ) {
8180             if ( !volume.IsLinked( n, prevSideNode ))
8181               continue;
8182           }
8183           else {
8184             if ( iNode ) // a node before prevSideNode
8185               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8186             else         // a node after prevSideNode
8187               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8188           }
8189           // check if this link was already used
8190           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8191           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8192           if (!isJustChecked &&
8193               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8194           {
8195             // test a link geometrically
8196             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8197             bool linkIsBetter = false;
8198             double dot = 0.0, dist = 0.0;
8199             if ( searchByDir ) { // choose most co-directed link
8200               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8201               linkIsBetter = ( dot > maxDot );
8202             }
8203             else { // choose link with the node closest to bordPos
8204               dist = ( nextXYZ - bordPos ).SquareModulus();
8205               linkIsBetter = ( dist < minDist );
8206             }
8207             if ( linkIsBetter ) {
8208               maxDot = dot;
8209               minDist = dist;
8210               linkID = iLink;
8211               sideNode = n;
8212               sideElem = elem;
8213             }
8214           }
8215         }
8216       } // loop on inverse elements of prevSideNode
8217
8218       if ( !sideNode ) {
8219         MESSAGE(" Cant find path by links of the Side 2 ");
8220         return SEW_BAD_SIDE_NODES;
8221       }
8222       sideNodes.push_back( sideNode );
8223       sideElems.push_back( sideElem );
8224       foundSideLinkIDs.insert ( linkID );
8225       prevSideNode = sideNode;
8226
8227       if ( *nBordIt == theBordLastNode )
8228         searchByDir = false;
8229       else {
8230         // find the next border link to compare with
8231         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8232         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8233         // move to next border node if sideNode is before forward border node (bordPos)
8234         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8235           prevBordNode = *nBordIt;
8236           nBordIt++;
8237           bordPos = nBordXYZ[ *nBordIt ];
8238           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8239           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8240         }
8241       }
8242     }
8243     while ( sideNode != theSideSecondNode );
8244
8245     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8246       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8247       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8248     }
8249   } // end nodes search on the side 2
8250
8251   // ============================
8252   // sew the border to the side 2
8253   // ============================
8254
8255   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8256   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8257
8258   TListOfListOfNodes nodeGroupsToMerge;
8259   if ( nbNodes[0] == nbNodes[1] ||
8260        ( theSideIsFreeBorder && !theSideThirdNode)) {
8261
8262     // all nodes are to be merged
8263
8264     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8265          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8266          nIt[0]++, nIt[1]++ )
8267     {
8268       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8269       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8270       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8271     }
8272   }
8273   else {
8274
8275     // insert new nodes into the border and the side to get equal nb of segments
8276
8277     // get normalized parameters of nodes on the borders
8278     //double param[ 2 ][ maxNbNodes ];
8279     double* param[ 2 ];
8280     param[0] = new double [ maxNbNodes ];
8281     param[1] = new double [ maxNbNodes ];
8282     int iNode, iBord;
8283     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8284       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8285       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8286       const SMDS_MeshNode* nPrev = *nIt;
8287       double bordLength = 0;
8288       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8289         const SMDS_MeshNode* nCur = *nIt;
8290         gp_XYZ segment (nCur->X() - nPrev->X(),
8291                         nCur->Y() - nPrev->Y(),
8292                         nCur->Z() - nPrev->Z());
8293         double segmentLen = segment.Modulus();
8294         bordLength += segmentLen;
8295         param[ iBord ][ iNode ] = bordLength;
8296         nPrev = nCur;
8297       }
8298       // normalize within [0,1]
8299       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8300         param[ iBord ][ iNode ] /= bordLength;
8301       }
8302     }
8303
8304     // loop on border segments
8305     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8306     int i[ 2 ] = { 0, 0 };
8307     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8308     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8309
8310     TElemOfNodeListMap insertMap;
8311     TElemOfNodeListMap::iterator insertMapIt;
8312     // insertMap is
8313     // key:   elem to insert nodes into
8314     // value: 2 nodes to insert between + nodes to be inserted
8315     do {
8316       bool next[ 2 ] = { false, false };
8317
8318       // find min adjacent segment length after sewing
8319       double nextParam = 10., prevParam = 0;
8320       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8321         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8322           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8323         if ( i[ iBord ] > 0 )
8324           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8325       }
8326       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8327       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8328       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8329
8330       // choose to insert or to merge nodes
8331       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8332       if ( Abs( du ) <= minSegLen * 0.2 ) {
8333         // merge
8334         // ------
8335         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8336         const SMDS_MeshNode* n0 = *nIt[0];
8337         const SMDS_MeshNode* n1 = *nIt[1];
8338         nodeGroupsToMerge.back().push_back( n1 );
8339         nodeGroupsToMerge.back().push_back( n0 );
8340         // position of node of the border changes due to merge
8341         param[ 0 ][ i[0] ] += du;
8342         // move n1 for the sake of elem shape evaluation during insertion.
8343         // n1 will be removed by MergeNodes() anyway
8344         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8345         next[0] = next[1] = true;
8346       }
8347       else {
8348         // insert
8349         // ------
8350         int intoBord = ( du < 0 ) ? 0 : 1;
8351         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8352         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8353         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8354         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8355         if ( intoBord == 1 ) {
8356           // move node of the border to be on a link of elem of the side
8357           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8358           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8359           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8360           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8361           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8362         }
8363         insertMapIt = insertMap.find( elem );
8364         bool notFound = ( insertMapIt == insertMap.end() );
8365         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8366         if ( otherLink ) {
8367           // insert into another link of the same element:
8368           // 1. perform insertion into the other link of the elem
8369           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8370           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8371           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8372           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8373           // 2. perform insertion into the link of adjacent faces
8374           while (true) {
8375             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8376             if ( adjElem )
8377               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8378             else
8379               break;
8380           }
8381           if (toCreatePolyedrs) {
8382             // perform insertion into the links of adjacent volumes
8383             UpdateVolumes(n12, n22, nodeList);
8384           }
8385           // 3. find an element appeared on n1 and n2 after the insertion
8386           insertMap.erase( elem );
8387           elem = findAdjacentFace( n1, n2, 0 );
8388         }
8389         if ( notFound || otherLink ) {
8390           // add element and nodes of the side into the insertMap
8391           insertMapIt = insertMap.insert
8392             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8393           (*insertMapIt).second.push_back( n1 );
8394           (*insertMapIt).second.push_back( n2 );
8395         }
8396         // add node to be inserted into elem
8397         (*insertMapIt).second.push_back( nIns );
8398         next[ 1 - intoBord ] = true;
8399       }
8400
8401       // go to the next segment
8402       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8403         if ( next[ iBord ] ) {
8404           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8405             eIt[ iBord ]++;
8406           nPrev[ iBord ] = *nIt[ iBord ];
8407           nIt[ iBord ]++; i[ iBord ]++;
8408         }
8409       }
8410     }
8411     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8412
8413     // perform insertion of nodes into elements
8414
8415     for (insertMapIt = insertMap.begin();
8416          insertMapIt != insertMap.end();
8417          insertMapIt++ )
8418     {
8419       const SMDS_MeshElement* elem = (*insertMapIt).first;
8420       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8421       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8422       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8423
8424       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8425
8426       if ( !theSideIsFreeBorder ) {
8427         // look for and insert nodes into the faces adjacent to elem
8428         while (true) {
8429           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8430           if ( adjElem )
8431             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8432           else
8433             break;
8434         }
8435       }
8436       if (toCreatePolyedrs) {
8437         // perform insertion into the links of adjacent volumes
8438         UpdateVolumes(n1, n2, nodeList);
8439       }
8440     }
8441
8442     delete param[0];
8443     delete param[1];
8444   } // end: insert new nodes
8445
8446   MergeNodes ( nodeGroupsToMerge );
8447
8448   return aResult;
8449 }
8450
8451 //=======================================================================
8452 //function : InsertNodesIntoLink
8453 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8454 //           and theBetweenNode2 and split theElement
8455 //=======================================================================
8456
8457 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8458                                            const SMDS_MeshNode*        theBetweenNode1,
8459                                            const SMDS_MeshNode*        theBetweenNode2,
8460                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8461                                            const bool                  toCreatePoly)
8462 {
8463   if ( theFace->GetType() != SMDSAbs_Face ) return;
8464
8465   // find indices of 2 link nodes and of the rest nodes
8466   int iNode = 0, il1, il2, i3, i4;
8467   il1 = il2 = i3 = i4 = -1;
8468   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8469   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8470
8471   if(theFace->IsQuadratic()) {
8472     const SMDS_QuadraticFaceOfNodes* F =
8473       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8474     // use special nodes iterator
8475     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8476     while( anIter->more() ) {
8477       const SMDS_MeshNode* n = anIter->next();
8478       if ( n == theBetweenNode1 )
8479         il1 = iNode;
8480       else if ( n == theBetweenNode2 )
8481         il2 = iNode;
8482       else if ( i3 < 0 )
8483         i3 = iNode;
8484       else
8485         i4 = iNode;
8486       nodes[ iNode++ ] = n;
8487     }
8488   }
8489   else {
8490     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8491     while ( nodeIt->more() ) {
8492       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8493       if ( n == theBetweenNode1 )
8494         il1 = iNode;
8495       else if ( n == theBetweenNode2 )
8496         il2 = iNode;
8497       else if ( i3 < 0 )
8498         i3 = iNode;
8499       else
8500         i4 = iNode;
8501       nodes[ iNode++ ] = n;
8502     }
8503   }
8504   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8505     return ;
8506
8507   // arrange link nodes to go one after another regarding the face orientation
8508   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8509   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8510   if ( reverse ) {
8511     iNode = il1;
8512     il1 = il2;
8513     il2 = iNode;
8514     aNodesToInsert.reverse();
8515   }
8516   // check that not link nodes of a quadrangles are in good order
8517   int nbFaceNodes = theFace->NbNodes();
8518   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8519     iNode = i3;
8520     i3 = i4;
8521     i4 = iNode;
8522   }
8523
8524   if (toCreatePoly || theFace->IsPoly()) {
8525
8526     iNode = 0;
8527     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8528
8529     // add nodes of face up to first node of link
8530     bool isFLN = false;
8531
8532     if(theFace->IsQuadratic()) {
8533       const SMDS_QuadraticFaceOfNodes* F =
8534         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8535       // use special nodes iterator
8536       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8537       while( anIter->more()  && !isFLN ) {
8538         const SMDS_MeshNode* n = anIter->next();
8539         poly_nodes[iNode++] = n;
8540         if (n == nodes[il1]) {
8541           isFLN = true;
8542         }
8543       }
8544       // add nodes to insert
8545       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8546       for (; nIt != aNodesToInsert.end(); nIt++) {
8547         poly_nodes[iNode++] = *nIt;
8548       }
8549       // add nodes of face starting from last node of link
8550       while ( anIter->more() ) {
8551         poly_nodes[iNode++] = anIter->next();
8552       }
8553     }
8554     else {
8555       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8556       while ( nodeIt->more() && !isFLN ) {
8557         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8558         poly_nodes[iNode++] = n;
8559         if (n == nodes[il1]) {
8560           isFLN = true;
8561         }
8562       }
8563       // add nodes to insert
8564       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8565       for (; nIt != aNodesToInsert.end(); nIt++) {
8566         poly_nodes[iNode++] = *nIt;
8567       }
8568       // add nodes of face starting from last node of link
8569       while ( nodeIt->more() ) {
8570         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8571         poly_nodes[iNode++] = n;
8572       }
8573     }
8574
8575     // edit or replace the face
8576     SMESHDS_Mesh *aMesh = GetMeshDS();
8577
8578     if (theFace->IsPoly()) {
8579       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8580     }
8581     else {
8582       int aShapeId = FindShape( theFace );
8583
8584       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8585       myLastCreatedElems.Append(newElem);
8586       if ( aShapeId && newElem )
8587         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8588
8589       aMesh->RemoveElement(theFace);
8590     }
8591     return;
8592   }
8593
8594   if( !theFace->IsQuadratic() ) {
8595
8596     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8597     int nbLinkNodes = 2 + aNodesToInsert.size();
8598     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8599     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8600     linkNodes[ 0 ] = nodes[ il1 ];
8601     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8602     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8603     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8604       linkNodes[ iNode++ ] = *nIt;
8605     }
8606     // decide how to split a quadrangle: compare possible variants
8607     // and choose which of splits to be a quadrangle
8608     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8609     if ( nbFaceNodes == 3 ) {
8610       iBestQuad = nbSplits;
8611       i4 = i3;
8612     }
8613     else if ( nbFaceNodes == 4 ) {
8614       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8615       double aBestRate = DBL_MAX;
8616       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8617         i1 = 0; i2 = 1;
8618         double aBadRate = 0;
8619         // evaluate elements quality
8620         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8621           if ( iSplit == iQuad ) {
8622             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8623                                    linkNodes[ i2++ ],
8624                                    nodes[ i3 ],
8625                                    nodes[ i4 ]);
8626             aBadRate += getBadRate( &quad, aCrit );
8627           }
8628           else {
8629             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8630                                    linkNodes[ i2++ ],
8631                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8632             aBadRate += getBadRate( &tria, aCrit );
8633           }
8634         }
8635         // choice
8636         if ( aBadRate < aBestRate ) {
8637           iBestQuad = iQuad;
8638           aBestRate = aBadRate;
8639         }
8640       }
8641     }
8642
8643     // create new elements
8644     SMESHDS_Mesh *aMesh = GetMeshDS();
8645     int aShapeId = FindShape( theFace );
8646
8647     i1 = 0; i2 = 1;
8648     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8649       SMDS_MeshElement* newElem = 0;
8650       if ( iSplit == iBestQuad )
8651         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8652                                   linkNodes[ i2++ ],
8653                                   nodes[ i3 ],
8654                                   nodes[ i4 ]);
8655       else
8656         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8657                                   linkNodes[ i2++ ],
8658                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8659       myLastCreatedElems.Append(newElem);
8660       if ( aShapeId && newElem )
8661         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8662     }
8663
8664     // change nodes of theFace
8665     const SMDS_MeshNode* newNodes[ 4 ];
8666     newNodes[ 0 ] = linkNodes[ i1 ];
8667     newNodes[ 1 ] = linkNodes[ i2 ];
8668     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8669     newNodes[ 3 ] = nodes[ i4 ];
8670     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8671   } // end if(!theFace->IsQuadratic())
8672   else { // theFace is quadratic
8673     // we have to split theFace on simple triangles and one simple quadrangle
8674     int tmp = il1/2;
8675     int nbshift = tmp*2;
8676     // shift nodes in nodes[] by nbshift
8677     int i,j;
8678     for(i=0; i<nbshift; i++) {
8679       const SMDS_MeshNode* n = nodes[0];
8680       for(j=0; j<nbFaceNodes-1; j++) {
8681         nodes[j] = nodes[j+1];
8682       }
8683       nodes[nbFaceNodes-1] = n;
8684     }
8685     il1 = il1 - nbshift;
8686     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8687     //   n0      n1     n2    n0      n1     n2
8688     //     +-----+-----+        +-----+-----+
8689     //      \         /         |           |
8690     //       \       /          |           |
8691     //      n5+     +n3       n7+           +n3
8692     //         \   /            |           |
8693     //          \ /             |           |
8694     //           +              +-----+-----+
8695     //           n4           n6      n5     n4
8696
8697     // create new elements
8698     SMESHDS_Mesh *aMesh = GetMeshDS();
8699     int aShapeId = FindShape( theFace );
8700
8701     int n1,n2,n3;
8702     if(nbFaceNodes==6) { // quadratic triangle
8703       SMDS_MeshElement* newElem =
8704         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8705       myLastCreatedElems.Append(newElem);
8706       if ( aShapeId && newElem )
8707         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8708       if(theFace->IsMediumNode(nodes[il1])) {
8709         // create quadrangle
8710         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8711         myLastCreatedElems.Append(newElem);
8712         if ( aShapeId && newElem )
8713           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8714         n1 = 1;
8715         n2 = 2;
8716         n3 = 3;
8717       }
8718       else {
8719         // create quadrangle
8720         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8721         myLastCreatedElems.Append(newElem);
8722         if ( aShapeId && newElem )
8723           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8724         n1 = 0;
8725         n2 = 1;
8726         n3 = 5;
8727       }
8728     }
8729     else { // nbFaceNodes==8 - quadratic quadrangle
8730       SMDS_MeshElement* newElem =
8731         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8732       myLastCreatedElems.Append(newElem);
8733       if ( aShapeId && newElem )
8734         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8735       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8736       myLastCreatedElems.Append(newElem);
8737       if ( aShapeId && newElem )
8738         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8739       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8740       myLastCreatedElems.Append(newElem);
8741       if ( aShapeId && newElem )
8742         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8743       if(theFace->IsMediumNode(nodes[il1])) {
8744         // create quadrangle
8745         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8746         myLastCreatedElems.Append(newElem);
8747         if ( aShapeId && newElem )
8748           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8749         n1 = 1;
8750         n2 = 2;
8751         n3 = 3;
8752       }
8753       else {
8754         // create quadrangle
8755         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8756         myLastCreatedElems.Append(newElem);
8757         if ( aShapeId && newElem )
8758           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8759         n1 = 0;
8760         n2 = 1;
8761         n3 = 7;
8762       }
8763     }
8764     // create needed triangles using n1,n2,n3 and inserted nodes
8765     int nbn = 2 + aNodesToInsert.size();
8766     //const SMDS_MeshNode* aNodes[nbn];
8767     vector<const SMDS_MeshNode*> aNodes(nbn);
8768     aNodes[0] = nodes[n1];
8769     aNodes[nbn-1] = nodes[n2];
8770     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8771     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8772       aNodes[iNode++] = *nIt;
8773     }
8774     for(i=1; i<nbn; i++) {
8775       SMDS_MeshElement* newElem =
8776         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8777       myLastCreatedElems.Append(newElem);
8778       if ( aShapeId && newElem )
8779         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8780     }
8781     // remove old quadratic face
8782     aMesh->RemoveElement(theFace);
8783   }
8784 }
8785
8786 //=======================================================================
8787 //function : UpdateVolumes
8788 //purpose  :
8789 //=======================================================================
8790 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8791                                       const SMDS_MeshNode*        theBetweenNode2,
8792                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8793 {
8794   myLastCreatedElems.Clear();
8795   myLastCreatedNodes.Clear();
8796
8797   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8798   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8799     const SMDS_MeshElement* elem = invElemIt->next();
8800
8801     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8802     SMDS_VolumeTool aVolume (elem);
8803     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8804       continue;
8805
8806     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8807     int iface, nbFaces = aVolume.NbFaces();
8808     vector<const SMDS_MeshNode *> poly_nodes;
8809     vector<int> quantities (nbFaces);
8810
8811     for (iface = 0; iface < nbFaces; iface++) {
8812       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8813       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8814       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8815
8816       for (int inode = 0; inode < nbFaceNodes; inode++) {
8817         poly_nodes.push_back(faceNodes[inode]);
8818
8819         if (nbInserted == 0) {
8820           if (faceNodes[inode] == theBetweenNode1) {
8821             if (faceNodes[inode + 1] == theBetweenNode2) {
8822               nbInserted = theNodesToInsert.size();
8823
8824               // add nodes to insert
8825               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8826               for (; nIt != theNodesToInsert.end(); nIt++) {
8827                 poly_nodes.push_back(*nIt);
8828               }
8829             }
8830           }
8831           else if (faceNodes[inode] == theBetweenNode2) {
8832             if (faceNodes[inode + 1] == theBetweenNode1) {
8833               nbInserted = theNodesToInsert.size();
8834
8835               // add nodes to insert in reversed order
8836               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8837               nIt--;
8838               for (; nIt != theNodesToInsert.begin(); nIt--) {
8839                 poly_nodes.push_back(*nIt);
8840               }
8841               poly_nodes.push_back(*nIt);
8842             }
8843           }
8844           else {
8845           }
8846         }
8847       }
8848       quantities[iface] = nbFaceNodes + nbInserted;
8849     }
8850
8851     // Replace or update the volume
8852     SMESHDS_Mesh *aMesh = GetMeshDS();
8853
8854     if (elem->IsPoly()) {
8855       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8856
8857     }
8858     else {
8859       int aShapeId = FindShape( elem );
8860
8861       SMDS_MeshElement* newElem =
8862         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8863       myLastCreatedElems.Append(newElem);
8864       if (aShapeId && newElem)
8865         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8866
8867       aMesh->RemoveElement(elem);
8868     }
8869   }
8870 }
8871
8872 //=======================================================================
8873 /*!
8874  * \brief Convert elements contained in a submesh to quadratic
8875  * \retval int - nb of checked elements
8876  */
8877 //=======================================================================
8878
8879 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8880                                              SMESH_MesherHelper& theHelper,
8881                                              const bool          theForce3d)
8882 {
8883   int nbElem = 0;
8884   if( !theSm ) return nbElem;
8885
8886   const bool notFromGroups = false;
8887   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8888   while(ElemItr->more())
8889   {
8890     nbElem++;
8891     const SMDS_MeshElement* elem = ElemItr->next();
8892     if( !elem || elem->IsQuadratic() ) continue;
8893
8894     int id = elem->GetID();
8895     int nbNodes = elem->NbNodes();
8896     vector<const SMDS_MeshNode *> aNds (nbNodes);
8897
8898     for(int i = 0; i < nbNodes; i++)
8899     {
8900       aNds[i] = elem->GetNode(i);
8901     }
8902     SMDSAbs_ElementType aType = elem->GetType();
8903
8904     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8905
8906     const SMDS_MeshElement* NewElem = 0;
8907
8908     switch( aType )
8909     {
8910     case SMDSAbs_Edge :
8911       {
8912         NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8913         break;
8914       }
8915     case SMDSAbs_Face :
8916       {
8917         switch(nbNodes)
8918         {
8919         case 3:
8920           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8921           break;
8922         case 4:
8923           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8924           break;
8925         default:
8926           continue;
8927         }
8928         break;
8929       }
8930     case SMDSAbs_Volume :
8931       {
8932         switch(nbNodes)
8933         {
8934         case 4:
8935           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8936           break;
8937         case 5:
8938           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8939           break;
8940         case 6:
8941           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8942           break;
8943         case 8:
8944           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8945                                         aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8946           break;
8947         default:
8948           continue;
8949         }
8950         break;
8951       }
8952     default :
8953       continue;
8954     }
8955     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8956     if( NewElem )
8957       theSm->AddElement( NewElem );
8958   }
8959   return nbElem;
8960 }
8961
8962 //=======================================================================
8963 //function : ConvertToQuadratic
8964 //purpose  :
8965 //=======================================================================
8966 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8967 {
8968   SMESHDS_Mesh* meshDS = GetMeshDS();
8969
8970   SMESH_MesherHelper aHelper(*myMesh);
8971   aHelper.SetIsQuadratic( true );
8972   const bool notFromGroups = false;
8973
8974   int nbCheckedElems = 0;
8975   if ( myMesh->HasShapeToMesh() )
8976   {
8977     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8978     {
8979       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8980       while ( smIt->more() ) {
8981         SMESH_subMesh* sm = smIt->next();
8982         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8983           aHelper.SetSubShape( sm->GetSubShape() );
8984           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8985         }
8986       }
8987     }
8988   }
8989   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8990   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8991   {
8992     SMESHDS_SubMesh *smDS = 0;
8993     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8994     while(aEdgeItr->more())
8995     {
8996       const SMDS_MeshEdge* edge = aEdgeItr->next();
8997       if(edge && !edge->IsQuadratic())
8998       {
8999         int id = edge->GetID();
9000         const SMDS_MeshNode* n1 = edge->GetNode(0);
9001         const SMDS_MeshNode* n2 = edge->GetNode(1);
9002
9003         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
9004
9005         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9006         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9007       }
9008     }
9009     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9010     while(aFaceItr->more())
9011     {
9012       const SMDS_MeshFace* face = aFaceItr->next();
9013       if(!face || face->IsQuadratic() ) continue;
9014
9015       int id = face->GetID();
9016       int nbNodes = face->NbNodes();
9017       vector<const SMDS_MeshNode *> aNds (nbNodes);
9018
9019       for(int i = 0; i < nbNodes; i++)
9020       {
9021         aNds[i] = face->GetNode(i);
9022       }
9023
9024       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9025
9026       SMDS_MeshFace * NewFace = 0;
9027       switch(nbNodes)
9028       {
9029       case 3:
9030         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9031         break;
9032       case 4:
9033         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9034         break;
9035       default:
9036         continue;
9037       }
9038       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9039     }
9040     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9041     while(aVolumeItr->more())
9042     {
9043       const SMDS_MeshVolume* volume = aVolumeItr->next();
9044       if(!volume || volume->IsQuadratic() ) continue;
9045
9046       int id = volume->GetID();
9047       int nbNodes = volume->NbNodes();
9048       vector<const SMDS_MeshNode *> aNds (nbNodes);
9049
9050       for(int i = 0; i < nbNodes; i++)
9051       {
9052         aNds[i] = volume->GetNode(i);
9053       }
9054
9055       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9056
9057       SMDS_MeshVolume * NewVolume = 0;
9058       switch(nbNodes)
9059       {
9060       case 4:
9061         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9062                                       aNds[3], id, theForce3d );
9063         break;
9064       case 5:
9065         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9066                                       aNds[3], aNds[4], id, theForce3d);
9067         break;
9068       case 6:
9069         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9070                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
9071         break;
9072       case 8:
9073         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9074                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9075         break;
9076       default:
9077         continue;
9078       }
9079       ReplaceElemInGroups(volume, NewVolume, meshDS);
9080     }
9081   }
9082   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9083   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9084     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9085     aHelper.FixQuadraticElements();
9086   }
9087 }
9088
9089 //=======================================================================
9090 /*!
9091  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9092  * \retval int - nb of checked elements
9093  */
9094 //=======================================================================
9095
9096 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9097                                      SMDS_ElemIteratorPtr theItr,
9098                                      const int            theShapeID)
9099 {
9100   int nbElem = 0;
9101   SMESHDS_Mesh* meshDS = GetMeshDS();
9102   const bool notFromGroups = false;
9103
9104   while( theItr->more() )
9105   {
9106     const SMDS_MeshElement* elem = theItr->next();
9107     nbElem++;
9108     if( elem && elem->IsQuadratic())
9109     {
9110       int id = elem->GetID();
9111       int nbNodes = elem->NbNodes();
9112       vector<const SMDS_MeshNode *> aNds, mediumNodes;
9113       aNds.reserve( nbNodes );
9114       mediumNodes.reserve( nbNodes );
9115
9116       for(int i = 0; i < nbNodes; i++)
9117       {
9118         const SMDS_MeshNode* n = elem->GetNode(i);
9119
9120         if( elem->IsMediumNode( n ) )
9121           mediumNodes.push_back( n );
9122         else
9123           aNds.push_back( n );
9124       }
9125       if( aNds.empty() ) continue;
9126       SMDSAbs_ElementType aType = elem->GetType();
9127
9128       //remove old quadratic element
9129       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9130
9131       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9132       ReplaceElemInGroups(elem, NewElem, meshDS);
9133       if( theSm && NewElem )
9134         theSm->AddElement( NewElem );
9135
9136       // remove medium nodes
9137       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9138       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9139         const SMDS_MeshNode* n = *nIt;
9140         if ( n->NbInverseElements() == 0 ) {
9141           if ( n->GetPosition()->GetShapeId() != theShapeID )
9142             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9143                                     ( n->GetPosition()->GetShapeId() ));
9144           else
9145             meshDS->RemoveFreeNode( n, theSm );
9146         }
9147       }
9148     }
9149   }
9150   return nbElem;
9151 }
9152
9153 //=======================================================================
9154 //function : ConvertFromQuadratic
9155 //purpose  :
9156 //=======================================================================
9157 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9158 {
9159   int nbCheckedElems = 0;
9160   if ( myMesh->HasShapeToMesh() )
9161   {
9162     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9163     {
9164       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9165       while ( smIt->more() ) {
9166         SMESH_subMesh* sm = smIt->next();
9167         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9168           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9169       }
9170     }
9171   }
9172
9173   int totalNbElems =
9174     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9175   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9176   {
9177     SMESHDS_SubMesh *aSM = 0;
9178     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9179   }
9180
9181   return true;
9182 }
9183
9184 //=======================================================================
9185 //function : SewSideElements
9186 //purpose  :
9187 //=======================================================================
9188
9189 SMESH_MeshEditor::Sew_Error
9190 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9191                                    TIDSortedElemSet&    theSide2,
9192                                    const SMDS_MeshNode* theFirstNode1,
9193                                    const SMDS_MeshNode* theFirstNode2,
9194                                    const SMDS_MeshNode* theSecondNode1,
9195                                    const SMDS_MeshNode* theSecondNode2)
9196 {
9197   myLastCreatedElems.Clear();
9198   myLastCreatedNodes.Clear();
9199
9200   MESSAGE ("::::SewSideElements()");
9201   if ( theSide1.size() != theSide2.size() )
9202     return SEW_DIFF_NB_OF_ELEMENTS;
9203
9204   Sew_Error aResult = SEW_OK;
9205   // Algo:
9206   // 1. Build set of faces representing each side
9207   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9208   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9209
9210   // =======================================================================
9211   // 1. Build set of faces representing each side:
9212   // =======================================================================
9213   // a. build set of nodes belonging to faces
9214   // b. complete set of faces: find missing fices whose nodes are in set of nodes
9215   // c. create temporary faces representing side of volumes if correspondent
9216   //    face does not exist
9217
9218   SMESHDS_Mesh* aMesh = GetMeshDS();
9219   SMDS_Mesh aTmpFacesMesh;
9220   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9221   set<const SMDS_MeshElement*> volSet1,  volSet2;
9222   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9223   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9224   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9225   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9226   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9227   int iSide, iFace, iNode;
9228
9229   for ( iSide = 0; iSide < 2; iSide++ ) {
9230     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9231     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9232     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9233     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9234     set<const SMDS_MeshElement*>::iterator vIt;
9235     TIDSortedElemSet::iterator eIt;
9236     set<const SMDS_MeshNode*>::iterator    nIt;
9237
9238     // check that given nodes belong to given elements
9239     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9240     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9241     int firstIndex = -1, secondIndex = -1;
9242     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9243       const SMDS_MeshElement* elem = *eIt;
9244       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9245       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9246       if ( firstIndex > -1 && secondIndex > -1 ) break;
9247     }
9248     if ( firstIndex < 0 || secondIndex < 0 ) {
9249       // we can simply return until temporary faces created
9250       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9251     }
9252
9253     // -----------------------------------------------------------
9254     // 1a. Collect nodes of existing faces
9255     //     and build set of face nodes in order to detect missing
9256     //     faces corresponing to sides of volumes
9257     // -----------------------------------------------------------
9258
9259     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9260
9261     // loop on the given element of a side
9262     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9263       //const SMDS_MeshElement* elem = *eIt;
9264       const SMDS_MeshElement* elem = *eIt;
9265       if ( elem->GetType() == SMDSAbs_Face ) {
9266         faceSet->insert( elem );
9267         set <const SMDS_MeshNode*> faceNodeSet;
9268         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9269         while ( nodeIt->more() ) {
9270           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9271           nodeSet->insert( n );
9272           faceNodeSet.insert( n );
9273         }
9274         setOfFaceNodeSet.insert( faceNodeSet );
9275       }
9276       else if ( elem->GetType() == SMDSAbs_Volume )
9277         volSet->insert( elem );
9278     }
9279     // ------------------------------------------------------------------------------
9280     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9281     // ------------------------------------------------------------------------------
9282
9283     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9284       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9285       while ( fIt->more() ) { // loop on faces sharing a node
9286         const SMDS_MeshElement* f = fIt->next();
9287         if ( faceSet->find( f ) == faceSet->end() ) {
9288           // check if all nodes are in nodeSet and
9289           // complete setOfFaceNodeSet if they are
9290           set <const SMDS_MeshNode*> faceNodeSet;
9291           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9292           bool allInSet = true;
9293           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9294             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9295             if ( nodeSet->find( n ) == nodeSet->end() )
9296               allInSet = false;
9297             else
9298               faceNodeSet.insert( n );
9299           }
9300           if ( allInSet ) {
9301             faceSet->insert( f );
9302             setOfFaceNodeSet.insert( faceNodeSet );
9303           }
9304         }
9305       }
9306     }
9307
9308     // -------------------------------------------------------------------------
9309     // 1c. Create temporary faces representing sides of volumes if correspondent
9310     //     face does not exist
9311     // -------------------------------------------------------------------------
9312
9313     if ( !volSet->empty() ) {
9314       //int nodeSetSize = nodeSet->size();
9315
9316       // loop on given volumes
9317       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9318         SMDS_VolumeTool vol (*vIt);
9319         // loop on volume faces: find free faces
9320         // --------------------------------------
9321         list<const SMDS_MeshElement* > freeFaceList;
9322         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9323           if ( !vol.IsFreeFace( iFace ))
9324             continue;
9325           // check if there is already a face with same nodes in a face set
9326           const SMDS_MeshElement* aFreeFace = 0;
9327           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9328           int nbNodes = vol.NbFaceNodes( iFace );
9329           set <const SMDS_MeshNode*> faceNodeSet;
9330           vol.GetFaceNodes( iFace, faceNodeSet );
9331           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9332           if ( isNewFace ) {
9333             // no such a face is given but it still can exist, check it
9334             if ( nbNodes == 3 ) {
9335               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9336             }
9337             else if ( nbNodes == 4 ) {
9338               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9339             }
9340             else {
9341               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9342               aFreeFace = aMesh->FindFace(poly_nodes);
9343             }
9344           }
9345           if ( !aFreeFace ) {
9346             // create a temporary face
9347             if ( nbNodes == 3 ) {
9348               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9349             }
9350             else if ( nbNodes == 4 ) {
9351               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9352             }
9353             else {
9354               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9355               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9356             }
9357           }
9358           if ( aFreeFace )
9359             freeFaceList.push_back( aFreeFace );
9360
9361         } // loop on faces of a volume
9362
9363         // choose one of several free faces
9364         // --------------------------------------
9365         if ( freeFaceList.size() > 1 ) {
9366           // choose a face having max nb of nodes shared by other elems of a side
9367           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9368           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9369           while ( fIt != freeFaceList.end() ) { // loop on free faces
9370             int nbSharedNodes = 0;
9371             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9372             while ( nodeIt->more() ) { // loop on free face nodes
9373               const SMDS_MeshNode* n =
9374                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9375               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9376               while ( invElemIt->more() ) {
9377                 const SMDS_MeshElement* e = invElemIt->next();
9378                 if ( faceSet->find( e ) != faceSet->end() )
9379                   nbSharedNodes++;
9380                 if ( elemSet->find( e ) != elemSet->end() )
9381                   nbSharedNodes++;
9382               }
9383             }
9384             if ( nbSharedNodes >= maxNbNodes ) {
9385               maxNbNodes = nbSharedNodes;
9386               fIt++;
9387             }
9388             else
9389               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9390           }
9391           if ( freeFaceList.size() > 1 )
9392           {
9393             // could not choose one face, use another way
9394             // choose a face most close to the bary center of the opposite side
9395             gp_XYZ aBC( 0., 0., 0. );
9396             set <const SMDS_MeshNode*> addedNodes;
9397             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9398             eIt = elemSet2->begin();
9399             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9400               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9401               while ( nodeIt->more() ) { // loop on free face nodes
9402                 const SMDS_MeshNode* n =
9403                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9404                 if ( addedNodes.insert( n ).second )
9405                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9406               }
9407             }
9408             aBC /= addedNodes.size();
9409             double minDist = DBL_MAX;
9410             fIt = freeFaceList.begin();
9411             while ( fIt != freeFaceList.end() ) { // loop on free faces
9412               double dist = 0;
9413               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9414               while ( nodeIt->more() ) { // loop on free face nodes
9415                 const SMDS_MeshNode* n =
9416                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9417                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9418                 dist += ( aBC - p ).SquareModulus();
9419               }
9420               if ( dist < minDist ) {
9421                 minDist = dist;
9422                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9423               }
9424               else
9425                 fIt = freeFaceList.erase( fIt++ );
9426             }
9427           }
9428         } // choose one of several free faces of a volume
9429
9430         if ( freeFaceList.size() == 1 ) {
9431           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9432           faceSet->insert( aFreeFace );
9433           // complete a node set with nodes of a found free face
9434           //           for ( iNode = 0; iNode < ; iNode++ )
9435           //             nodeSet->insert( fNodes[ iNode ] );
9436         }
9437
9438       } // loop on volumes of a side
9439
9440       //       // complete a set of faces if new nodes in a nodeSet appeared
9441       //       // ----------------------------------------------------------
9442       //       if ( nodeSetSize != nodeSet->size() ) {
9443       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9444       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9445       //           while ( fIt->more() ) { // loop on faces sharing a node
9446       //             const SMDS_MeshElement* f = fIt->next();
9447       //             if ( faceSet->find( f ) == faceSet->end() ) {
9448       //               // check if all nodes are in nodeSet and
9449       //               // complete setOfFaceNodeSet if they are
9450       //               set <const SMDS_MeshNode*> faceNodeSet;
9451       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9452       //               bool allInSet = true;
9453       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9454       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9455       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9456       //                   allInSet = false;
9457       //                 else
9458       //                   faceNodeSet.insert( n );
9459       //               }
9460       //               if ( allInSet ) {
9461       //                 faceSet->insert( f );
9462       //                 setOfFaceNodeSet.insert( faceNodeSet );
9463       //               }
9464       //             }
9465       //           }
9466       //         }
9467       //       }
9468     } // Create temporary faces, if there are volumes given
9469   } // loop on sides
9470
9471   if ( faceSet1.size() != faceSet2.size() ) {
9472     // delete temporary faces: they are in reverseElements of actual nodes
9473     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9474     while ( tmpFaceIt->more() )
9475       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9476     MESSAGE("Diff nb of faces");
9477     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9478   }
9479
9480   // ============================================================
9481   // 2. Find nodes to merge:
9482   //              bind a node to remove to a node to put instead
9483   // ============================================================
9484
9485   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9486   if ( theFirstNode1 != theFirstNode2 )
9487     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9488   if ( theSecondNode1 != theSecondNode2 )
9489     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9490
9491   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9492   set< long > linkIdSet; // links to process
9493   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9494
9495   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9496   list< NLink > linkList[2];
9497   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9498   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9499   // loop on links in linkList; find faces by links and append links
9500   // of the found faces to linkList
9501   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9502   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9503     NLink link[] = { *linkIt[0], *linkIt[1] };
9504     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9505     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9506       continue;
9507
9508     // by links, find faces in the face sets,
9509     // and find indices of link nodes in the found faces;
9510     // in a face set, there is only one or no face sharing a link
9511     // ---------------------------------------------------------------
9512
9513     const SMDS_MeshElement* face[] = { 0, 0 };
9514     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9515     vector<const SMDS_MeshNode*> fnodes1(9);
9516     vector<const SMDS_MeshNode*> fnodes2(9);
9517     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9518     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9519     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9520     int iLinkNode[2][2];
9521     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9522       const SMDS_MeshNode* n1 = link[iSide].first;
9523       const SMDS_MeshNode* n2 = link[iSide].second;
9524       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9525       set< const SMDS_MeshElement* > fMap;
9526       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9527         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9528         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9529         while ( fIt->more() ) { // loop on faces sharing a node
9530           const SMDS_MeshElement* f = fIt->next();
9531           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9532               ! fMap.insert( f ).second ) // f encounters twice
9533           {
9534             if ( face[ iSide ] ) {
9535               MESSAGE( "2 faces per link " );
9536               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9537               break;
9538             }
9539             face[ iSide ] = f;
9540             faceSet->erase( f );
9541             // get face nodes and find ones of a link
9542             iNode = 0;
9543             int nbl = -1;
9544             if(f->IsPoly()) {
9545               if(iSide==0) {
9546                 fnodes1.resize(f->NbNodes()+1);
9547                 notLinkNodes1.resize(f->NbNodes()-2);
9548               }
9549               else {
9550                 fnodes2.resize(f->NbNodes()+1);
9551                 notLinkNodes2.resize(f->NbNodes()-2);
9552               }
9553             }
9554             if(!f->IsQuadratic()) {
9555               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9556               while ( nIt->more() ) {
9557                 const SMDS_MeshNode* n =
9558                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9559                 if ( n == n1 ) {
9560                   iLinkNode[ iSide ][ 0 ] = iNode;
9561                 }
9562                 else if ( n == n2 ) {
9563                   iLinkNode[ iSide ][ 1 ] = iNode;
9564                 }
9565                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9566                 //  notLinkNodes[ iSide ][ 1 ] = n;
9567                 //else
9568                 //  notLinkNodes[ iSide ][ 0 ] = n;
9569                 else {
9570                   nbl++;
9571                   if(iSide==0)
9572                     notLinkNodes1[nbl] = n;
9573                   //notLinkNodes1.push_back(n);
9574                   else
9575                     notLinkNodes2[nbl] = n;
9576                   //notLinkNodes2.push_back(n);
9577                 }
9578                 //faceNodes[ iSide ][ iNode++ ] = n;
9579                 if(iSide==0) {
9580                   fnodes1[iNode++] = n;
9581                 }
9582                 else {
9583                   fnodes2[iNode++] = n;
9584                 }
9585               }
9586             }
9587             else { // f->IsQuadratic()
9588               const SMDS_QuadraticFaceOfNodes* F =
9589                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9590               // use special nodes iterator
9591               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9592               while ( anIter->more() ) {
9593                 const SMDS_MeshNode* n =
9594                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9595                 if ( n == n1 ) {
9596                   iLinkNode[ iSide ][ 0 ] = iNode;
9597                 }
9598                 else if ( n == n2 ) {
9599                   iLinkNode[ iSide ][ 1 ] = iNode;
9600                 }
9601                 else {
9602                   nbl++;
9603                   if(iSide==0) {
9604                     notLinkNodes1[nbl] = n;
9605                   }
9606                   else {
9607                     notLinkNodes2[nbl] = n;
9608                   }
9609                 }
9610                 if(iSide==0) {
9611                   fnodes1[iNode++] = n;
9612                 }
9613                 else {
9614                   fnodes2[iNode++] = n;
9615                 }
9616               }
9617             }
9618             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9619             if(iSide==0) {
9620               fnodes1[iNode] = fnodes1[0];
9621             }
9622             else {
9623               fnodes2[iNode] = fnodes1[0];
9624             }
9625           }
9626         }
9627       }
9628     }
9629
9630     // check similarity of elements of the sides
9631     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9632       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9633       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9634         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9635       }
9636       else {
9637         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9638       }
9639       break; // do not return because it s necessary to remove tmp faces
9640     }
9641
9642     // set nodes to merge
9643     // -------------------
9644
9645     if ( face[0] && face[1] )  {
9646       int nbNodes = face[0]->NbNodes();
9647       if ( nbNodes != face[1]->NbNodes() ) {
9648         MESSAGE("Diff nb of face nodes");
9649         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9650         break; // do not return because it s necessary to remove tmp faces
9651       }
9652       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9653       if ( nbNodes == 3 ) {
9654         //nReplaceMap.insert( TNodeNodeMap::value_type
9655         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9656         nReplaceMap.insert( TNodeNodeMap::value_type
9657                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9658       }
9659       else {
9660         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9661           // analyse link orientation in faces
9662           int i1 = iLinkNode[ iSide ][ 0 ];
9663           int i2 = iLinkNode[ iSide ][ 1 ];
9664           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9665           // if notLinkNodes are the first and the last ones, then
9666           // their order does not correspond to the link orientation
9667           if (( i1 == 1 && i2 == 2 ) ||
9668               ( i1 == 2 && i2 == 1 ))
9669             reverse[ iSide ] = !reverse[ iSide ];
9670         }
9671         if ( reverse[0] == reverse[1] ) {
9672           //nReplaceMap.insert( TNodeNodeMap::value_type
9673           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9674           //nReplaceMap.insert( TNodeNodeMap::value_type
9675           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9676           for(int nn=0; nn<nbNodes-2; nn++) {
9677             nReplaceMap.insert( TNodeNodeMap::value_type
9678                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9679           }
9680         }
9681         else {
9682           //nReplaceMap.insert( TNodeNodeMap::value_type
9683           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9684           //nReplaceMap.insert( TNodeNodeMap::value_type
9685           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9686           for(int nn=0; nn<nbNodes-2; nn++) {
9687             nReplaceMap.insert( TNodeNodeMap::value_type
9688                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9689           }
9690         }
9691       }
9692
9693       // add other links of the faces to linkList
9694       // -----------------------------------------
9695
9696       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9697       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9698         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9699         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9700         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9701         if ( !iter_isnew.second ) { // already in a set: no need to process
9702           linkIdSet.erase( iter_isnew.first );
9703         }
9704         else // new in set == encountered for the first time: add
9705         {
9706           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9707           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9708           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9709           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9710           linkList[0].push_back ( NLink( n1, n2 ));
9711           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9712         }
9713       }
9714     } // 2 faces found
9715   } // loop on link lists
9716
9717   if ( aResult == SEW_OK &&
9718        ( linkIt[0] != linkList[0].end() ||
9719          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9720     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9721              " " << (faceSetPtr[1]->empty()));
9722     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9723   }
9724
9725   // ====================================================================
9726   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9727   // ====================================================================
9728
9729   // delete temporary faces: they are in reverseElements of actual nodes
9730   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9731   while ( tmpFaceIt->more() )
9732     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9733
9734   if ( aResult != SEW_OK)
9735     return aResult;
9736
9737   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9738   // loop on nodes replacement map
9739   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9740   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9741     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9742       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9743       nodeIDsToRemove.push_back( nToRemove->GetID() );
9744       // loop on elements sharing nToRemove
9745       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9746       while ( invElemIt->more() ) {
9747         const SMDS_MeshElement* e = invElemIt->next();
9748         // get a new suite of nodes: make replacement
9749         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9750         vector< const SMDS_MeshNode*> nodes( nbNodes );
9751         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9752         while ( nIt->more() ) {
9753           const SMDS_MeshNode* n =
9754             static_cast<const SMDS_MeshNode*>( nIt->next() );
9755           nnIt = nReplaceMap.find( n );
9756           if ( nnIt != nReplaceMap.end() ) {
9757             nbReplaced++;
9758             n = (*nnIt).second;
9759           }
9760           nodes[ i++ ] = n;
9761         }
9762         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9763         //         elemIDsToRemove.push_back( e->GetID() );
9764         //       else
9765         if ( nbReplaced )
9766           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9767       }
9768     }
9769
9770   Remove( nodeIDsToRemove, true );
9771
9772   return aResult;
9773 }
9774
9775 //================================================================================
9776 /*!
9777  * \brief Find corresponding nodes in two sets of faces
9778  * \param theSide1 - first face set
9779  * \param theSide2 - second first face
9780  * \param theFirstNode1 - a boundary node of set 1
9781  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9782  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9783  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9784  * \param nReplaceMap - output map of corresponding nodes
9785  * \retval bool  - is a success or not
9786  */
9787 //================================================================================
9788
9789 #ifdef _DEBUG_
9790 //#define DEBUG_MATCHING_NODES
9791 #endif
9792
9793 SMESH_MeshEditor::Sew_Error
9794 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9795                                     set<const SMDS_MeshElement*>& theSide2,
9796                                     const SMDS_MeshNode*          theFirstNode1,
9797                                     const SMDS_MeshNode*          theFirstNode2,
9798                                     const SMDS_MeshNode*          theSecondNode1,
9799                                     const SMDS_MeshNode*          theSecondNode2,
9800                                     TNodeNodeMap &                nReplaceMap)
9801 {
9802   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9803
9804   nReplaceMap.clear();
9805   if ( theFirstNode1 != theFirstNode2 )
9806     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9807   if ( theSecondNode1 != theSecondNode2 )
9808     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9809
9810   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9811   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9812
9813   list< NLink > linkList[2];
9814   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9815   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9816
9817   // loop on links in linkList; find faces by links and append links
9818   // of the found faces to linkList
9819   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9820   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9821     NLink link[] = { *linkIt[0], *linkIt[1] };
9822     if ( linkSet.find( link[0] ) == linkSet.end() )
9823       continue;
9824
9825     // by links, find faces in the face sets,
9826     // and find indices of link nodes in the found faces;
9827     // in a face set, there is only one or no face sharing a link
9828     // ---------------------------------------------------------------
9829
9830     const SMDS_MeshElement* face[] = { 0, 0 };
9831     list<const SMDS_MeshNode*> notLinkNodes[2];
9832     //bool reverse[] = { false, false }; // order of notLinkNodes
9833     int nbNodes[2];
9834     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9835     {
9836       const SMDS_MeshNode* n1 = link[iSide].first;
9837       const SMDS_MeshNode* n2 = link[iSide].second;
9838       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9839       set< const SMDS_MeshElement* > facesOfNode1;
9840       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9841       {
9842         // during a loop of the first node, we find all faces around n1,
9843         // during a loop of the second node, we find one face sharing both n1 and n2
9844         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9845         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9846         while ( fIt->more() ) { // loop on faces sharing a node
9847           const SMDS_MeshElement* f = fIt->next();
9848           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9849               ! facesOfNode1.insert( f ).second ) // f encounters twice
9850           {
9851             if ( face[ iSide ] ) {
9852               MESSAGE( "2 faces per link " );
9853               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9854             }
9855             face[ iSide ] = f;
9856             faceSet->erase( f );
9857
9858             // get not link nodes
9859             int nbN = f->NbNodes();
9860             if ( f->IsQuadratic() )
9861               nbN /= 2;
9862             nbNodes[ iSide ] = nbN;
9863             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9864             int i1 = f->GetNodeIndex( n1 );
9865             int i2 = f->GetNodeIndex( n2 );
9866             int iEnd = nbN, iBeg = -1, iDelta = 1;
9867             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9868             if ( reverse ) {
9869               std::swap( iEnd, iBeg ); iDelta = -1;
9870             }
9871             int i = i2;
9872             while ( true ) {
9873               i += iDelta;
9874               if ( i == iEnd ) i = iBeg + iDelta;
9875               if ( i == i1 ) break;
9876               nodes.push_back ( f->GetNode( i ) );
9877             }
9878           }
9879         }
9880       }
9881     }
9882     // check similarity of elements of the sides
9883     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9884       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9885       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9886         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9887       }
9888       else {
9889         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9890       }
9891     }
9892
9893     // set nodes to merge
9894     // -------------------
9895
9896     if ( face[0] && face[1] )  {
9897       if ( nbNodes[0] != nbNodes[1] ) {
9898         MESSAGE("Diff nb of face nodes");
9899         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9900       }
9901 #ifdef DEBUG_MATCHING_NODES
9902       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9903                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9904                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9905 #endif
9906       int nbN = nbNodes[0];
9907       {
9908         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9909         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9910         for ( int i = 0 ; i < nbN - 2; ++i ) {
9911 #ifdef DEBUG_MATCHING_NODES
9912           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9913 #endif
9914           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9915         }
9916       }
9917
9918       // add other links of the face 1 to linkList
9919       // -----------------------------------------
9920
9921       const SMDS_MeshElement* f0 = face[0];
9922       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9923       for ( int i = 0; i < nbN; i++ )
9924       {
9925         const SMDS_MeshNode* n2 = f0->GetNode( i );
9926         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9927           linkSet.insert( SMESH_TLink( n1, n2 ));
9928         if ( !iter_isnew.second ) { // already in a set: no need to process
9929           linkSet.erase( iter_isnew.first );
9930         }
9931         else // new in set == encountered for the first time: add
9932         {
9933 #ifdef DEBUG_MATCHING_NODES
9934           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9935                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9936 #endif
9937           linkList[0].push_back ( NLink( n1, n2 ));
9938           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9939         }
9940         n1 = n2;
9941       }
9942     } // 2 faces found
9943   } // loop on link lists
9944
9945   return SEW_OK;
9946 }
9947
9948 //================================================================================
9949 /*!
9950   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9951   \param theElems - the list of elements (edges or faces) to be replicated
9952   The nodes for duplication could be found from these elements
9953   \param theNodesNot - list of nodes to NOT replicate
9954   \param theAffectedElems - the list of elements (cells and edges) to which the 
9955   replicated nodes should be associated to.
9956   \return TRUE if operation has been completed successfully, FALSE otherwise
9957 */
9958 //================================================================================
9959
9960 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9961                                     const TIDSortedElemSet& theNodesNot,
9962                                     const TIDSortedElemSet& theAffectedElems )
9963 {
9964   myLastCreatedElems.Clear();
9965   myLastCreatedNodes.Clear();
9966
9967   if ( theElems.size() == 0 )
9968     return false;
9969
9970   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9971   if ( !aMeshDS )
9972     return false;
9973
9974   bool res = false;
9975   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9976   // duplicate elements and nodes
9977   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9978   // replce nodes by duplications
9979   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9980   return res;
9981 }
9982
9983 //================================================================================
9984 /*!
9985   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9986   \param theMeshDS - mesh instance
9987   \param theElems - the elements replicated or modified (nodes should be changed)
9988   \param theNodesNot - nodes to NOT replicate
9989   \param theNodeNodeMap - relation of old node to new created node
9990   \param theIsDoubleElem - flag os to replicate element or modify
9991   \return TRUE if operation has been completed successfully, FALSE otherwise
9992 */
9993 //================================================================================
9994
9995 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9996                                     const TIDSortedElemSet& theElems,
9997                                     const TIDSortedElemSet& theNodesNot,
9998                                     std::map< const SMDS_MeshNode*,
9999                                     const SMDS_MeshNode* >& theNodeNodeMap,
10000                                     const bool theIsDoubleElem )
10001 {
10002   // iterate on through element and duplicate them (by nodes duplication)
10003   bool res = false;
10004   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10005   for ( ;  elemItr != theElems.end(); ++elemItr )
10006   {
10007     const SMDS_MeshElement* anElem = *elemItr;
10008     if (!anElem)
10009       continue;
10010
10011     bool isDuplicate = false;
10012     // duplicate nodes to duplicate element
10013     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10014     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10015     int ind = 0;
10016     while ( anIter->more() ) 
10017     { 
10018
10019       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10020       SMDS_MeshNode* aNewNode = aCurrNode;
10021       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10022         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10023       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10024       {
10025         // duplicate node
10026         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10027         theNodeNodeMap[ aCurrNode ] = aNewNode;
10028         myLastCreatedNodes.Append( aNewNode );
10029       }
10030       isDuplicate |= (aCurrNode != aNewNode);
10031       newNodes[ ind++ ] = aNewNode;
10032     }
10033     if ( !isDuplicate )
10034       continue;
10035
10036     if ( theIsDoubleElem )
10037       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10038     else
10039       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10040
10041     res = true;
10042   }
10043   return res;
10044 }
10045
10046 //================================================================================
10047 /*!
10048   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10049   \param theNodes - identifiers of nodes to be doubled
10050   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10051          nodes. If list of element identifiers is empty then nodes are doubled but 
10052          they not assigned to elements
10053   \return TRUE if operation has been completed successfully, FALSE otherwise
10054 */
10055 //================================================================================
10056
10057 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10058                                     const std::list< int >& theListOfModifiedElems )
10059 {
10060   myLastCreatedElems.Clear();
10061   myLastCreatedNodes.Clear();
10062
10063   if ( theListOfNodes.size() == 0 )
10064     return false;
10065
10066   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10067   if ( !aMeshDS )
10068     return false;
10069
10070   // iterate through nodes and duplicate them
10071
10072   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10073
10074   std::list< int >::const_iterator aNodeIter;
10075   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10076   {
10077     int aCurr = *aNodeIter;
10078     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10079     if ( !aNode )
10080       continue;
10081
10082     // duplicate node
10083
10084     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10085     if ( aNewNode )
10086     {
10087       anOldNodeToNewNode[ aNode ] = aNewNode;
10088       myLastCreatedNodes.Append( aNewNode );
10089     }
10090   }
10091
10092   // Create map of new nodes for modified elements
10093
10094   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10095
10096   std::list< int >::const_iterator anElemIter;
10097   for ( anElemIter = theListOfModifiedElems.begin(); 
10098         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10099   {
10100     int aCurr = *anElemIter;
10101     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10102     if ( !anElem )
10103       continue;
10104
10105     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10106
10107     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10108     int ind = 0;
10109     while ( anIter->more() ) 
10110     { 
10111       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10112       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10113       {
10114         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10115         aNodeArr[ ind++ ] = aNewNode;
10116       }
10117       else
10118         aNodeArr[ ind++ ] = aCurrNode;
10119     }
10120     anElemToNodes[ anElem ] = aNodeArr;
10121   }
10122
10123   // Change nodes of elements  
10124
10125   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10126     anElemToNodesIter = anElemToNodes.begin();
10127   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10128   {
10129     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10130     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10131     if ( anElem )
10132       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10133   }
10134
10135   return true;
10136 }
10137
10138 namespace {
10139
10140   //================================================================================
10141   /*!
10142   \brief Check if element located inside shape
10143   \return TRUE if IN or ON shape, FALSE otherwise
10144   */
10145   //================================================================================
10146
10147   template<class Classifier>
10148   bool isInside(const SMDS_MeshElement* theElem,
10149                 Classifier&             theClassifier,
10150                 const double            theTol)
10151   {
10152     gp_XYZ centerXYZ (0, 0, 0);
10153     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10154     while (aNodeItr->more())
10155       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10156
10157     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10158     theClassifier.Perform(aPnt, theTol);
10159     TopAbs_State aState = theClassifier.State();
10160     return (aState == TopAbs_IN || aState == TopAbs_ON );
10161   }
10162
10163   //================================================================================
10164   /*!
10165    * \brief Classifier of the 3D point on the TopoDS_Face
10166    *        with interaface suitable for isInside()
10167    */
10168   //================================================================================
10169
10170   struct _FaceClassifier
10171   {
10172     Extrema_ExtPS       _extremum;
10173     BRepAdaptor_Surface _surface;
10174     TopAbs_State        _state;
10175
10176     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10177     {
10178       _extremum.Initialize( _surface,
10179                             _surface.FirstUParameter(), _surface.LastUParameter(),
10180                             _surface.FirstVParameter(), _surface.LastVParameter(),
10181                             _surface.Tolerance(), _surface.Tolerance() );
10182     }
10183     void Perform(const gp_Pnt& aPnt, double theTol)
10184     {
10185       _state = TopAbs_OUT;
10186       _extremum.Perform(aPnt);
10187       if ( _extremum.IsDone() )
10188         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10189           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10190     }
10191     TopAbs_State State() const
10192     {
10193       return _state;
10194     }
10195   };
10196 }
10197
10198 //================================================================================
10199 /*!
10200   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10201   \param theElems - group of of elements (edges or faces) to be replicated
10202   \param theNodesNot - group of nodes not to replicate
10203   \param theShape - shape to detect affected elements (element which geometric center
10204   located on or inside shape).
10205   The replicated nodes should be associated to affected elements.
10206   \return TRUE if operation has been completed successfully, FALSE otherwise
10207 */
10208 //================================================================================
10209
10210 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10211                                             const TIDSortedElemSet& theNodesNot,
10212                                             const TopoDS_Shape&     theShape )
10213 {
10214   if ( theShape.IsNull() )
10215     return false;
10216
10217   const double aTol = Precision::Confusion();
10218   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10219   auto_ptr<_FaceClassifier>              aFaceClassifier;
10220   if ( theShape.ShapeType() == TopAbs_SOLID )
10221   {
10222     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10223     bsc3d->PerformInfinitePoint(aTol);
10224   }
10225   else if (theShape.ShapeType() == TopAbs_FACE )
10226   {
10227     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10228   }
10229
10230   // iterates on indicated elements and get elements by back references from their nodes
10231   TIDSortedElemSet anAffected;
10232   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10233   for ( ;  elemItr != theElems.end(); ++elemItr )
10234   {
10235     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10236     if (!anElem)
10237       continue;
10238
10239     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10240     while ( nodeItr->more() )
10241     {
10242       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10243       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10244         continue;
10245       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10246       while ( backElemItr->more() )
10247       {
10248         const SMDS_MeshElement* curElem = backElemItr->next();
10249         if ( curElem && theElems.find(curElem) == theElems.end() &&
10250              ( bsc3d.get() ?
10251                isInside( curElem, *bsc3d, aTol ) :
10252                isInside( curElem, *aFaceClassifier, aTol )))
10253           anAffected.insert( curElem );
10254       }
10255     }
10256   }
10257   return DoubleNodes( theElems, theNodesNot, anAffected );
10258 }
10259
10260 //================================================================================
10261 /*!
10262  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10263  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10264  * \return TRUE if operation has been completed successfully, FALSE otherwise
10265  */
10266 //================================================================================
10267
10268 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10269 {
10270   // iterates on volume elements and detect all free faces on them
10271   SMESHDS_Mesh* aMesh = GetMeshDS();
10272   if (!aMesh)
10273     return false;
10274   //bool res = false;
10275   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10276   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10277   while(vIt->more())
10278   {
10279     const SMDS_MeshVolume* volume = vIt->next();
10280     SMDS_VolumeTool vTool( volume );
10281     vTool.SetExternalNormal();
10282     const bool isPoly = volume->IsPoly();
10283     const bool isQuad = volume->IsQuadratic();
10284     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10285     {
10286       if (!vTool.IsFreeFace(iface))
10287         continue;
10288       nbFree++;
10289       vector<const SMDS_MeshNode *> nodes;
10290       int nbFaceNodes = vTool.NbFaceNodes(iface);
10291       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10292       int inode = 0;
10293       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10294         nodes.push_back(faceNodes[inode]);
10295       if (isQuad)
10296         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10297           nodes.push_back(faceNodes[inode]);
10298
10299       // add new face based on volume nodes
10300       if (aMesh->FindFace( nodes ) ) {
10301         nbExisted++;
10302         continue; // face already exsist
10303       }
10304       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10305       nbCreated++;
10306     }
10307   }
10308   return ( nbFree==(nbExisted+nbCreated) );
10309 }