Salome HOME
Merge from PHASE_25_BR 09/12/2010
[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 #include "SMDS_SetIterator.hxx"
39
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
42
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
49
50 #include "utilities.h"
51
52 #include <BRepAdaptor_Surface.hxx>
53 #include <BRepClass3d_SolidClassifier.hxx>
54 #include <BRep_Tool.hxx>
55 #include <ElCLib.hxx>
56 #include <Extrema_GenExtPS.hxx>
57 #include <Extrema_POnCurv.hxx>
58 #include <Extrema_POnSurf.hxx>
59 #include <GC_MakeSegment.hxx>
60 #include <Geom2d_Curve.hxx>
61 #include <GeomAPI_ExtremaCurveCurve.hxx>
62 #include <GeomAdaptor_Surface.hxx>
63 #include <Geom_Curve.hxx>
64 #include <Geom_Line.hxx>
65 #include <Geom_Surface.hxx>
66 #include <IntAna_IntConicQuad.hxx>
67 #include <IntAna_Quadric.hxx>
68 #include <Precision.hxx>
69 #include <TColStd_ListOfInteger.hxx>
70 #include <TopAbs_State.hxx>
71 #include <TopExp.hxx>
72 #include <TopExp_Explorer.hxx>
73 #include <TopTools_ListIteratorOfListOfShape.hxx>
74 #include <TopTools_ListOfShape.hxx>
75 #include <TopTools_SequenceOfShape.hxx>
76 #include <TopoDS.hxx>
77 #include <TopoDS_Face.hxx>
78 #include <gp.hxx>
79 #include <gp_Ax1.hxx>
80 #include <gp_Dir.hxx>
81 #include <gp_Lin.hxx>
82 #include <gp_Pln.hxx>
83 #include <gp_Trsf.hxx>
84 #include <gp_Vec.hxx>
85 #include <gp_XY.hxx>
86 #include <gp_XYZ.hxx>
87
88 #include <math.h>
89
90 #include <map>
91 #include <set>
92 #include <numeric>
93 #include <limits>
94
95 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
96
97 using namespace std;
98 using namespace SMESH::Controls;
99
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
101 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
102
103 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
104
105 //=======================================================================
106 //function : SMESH_MeshEditor
107 //purpose  :
108 //=======================================================================
109
110 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
111   :myMesh( theMesh ) // theMesh may be NULL
112 {
113 }
114
115 //=======================================================================
116 /*!
117  * \brief Add element
118  */
119 //=======================================================================
120
121 SMDS_MeshElement*
122 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
123                              const SMDSAbs_ElementType            type,
124                              const bool                           isPoly,
125                              const int                            ID)
126 {
127   SMDS_MeshElement* e = 0;
128   int nbnode = node.size();
129   SMESHDS_Mesh* mesh = GetMeshDS();
130   switch ( type ) {
131
132   case SMDSAbs_Face:
133     if ( !isPoly ) {
134       if      (nbnode == 3)
135         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
136         else      e = mesh->AddFace      (node[0], node[1], node[2] );
137       else if (nbnode == 4) 
138         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
139         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
140       else if (nbnode == 6)
141         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
142                                           node[4], node[5], ID);
143         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
144                                           node[4], node[5] );
145       else if (nbnode == 8)
146         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
147                                           node[4], node[5], node[6], node[7], ID);
148         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
149                                           node[4], node[5], node[6], node[7] );
150     } else {
151       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
152       else      e = mesh->AddPolygonalFace      (node    );
153     }
154     break;
155
156   case SMDSAbs_Volume:
157     if ( !isPoly ) {
158       if      (nbnode == 4)
159         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
160         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
161       else if (nbnode == 5)
162         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
163                                             node[4], ID);
164         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
165                                             node[4] );
166       else if (nbnode == 6)
167         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
168                                             node[4], node[5], ID);
169         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
170                                             node[4], node[5] );
171       else if (nbnode == 8)
172         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173                                             node[4], node[5], node[6], node[7], ID);
174         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
175                                             node[4], node[5], node[6], node[7] );
176       else if (nbnode == 10)
177         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
178                                             node[4], node[5], node[6], node[7],
179                                             node[8], node[9], ID);
180         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
181                                             node[4], node[5], node[6], node[7],
182                                             node[8], node[9] );
183       else if (nbnode == 13)
184         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                             node[4], node[5], node[6], node[7],
186                                             node[8], node[9], node[10],node[11],
187                                             node[12],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], node[10],node[11],
191                                             node[12] );
192       else if (nbnode == 15)
193         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
194                                             node[4], node[5], node[6], node[7],
195                                             node[8], node[9], node[10],node[11],
196                                             node[12],node[13],node[14],ID);
197         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
198                                             node[4], node[5], node[6], node[7],
199                                             node[8], node[9], node[10],node[11],
200                                             node[12],node[13],node[14] );
201       else if (nbnode == 20)
202         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
203                                             node[4], node[5], node[6], node[7],
204                                             node[8], node[9], node[10],node[11],
205                                             node[12],node[13],node[14],node[15],
206                                             node[16],node[17],node[18],node[19],ID);
207         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
208                                             node[4], node[5], node[6], node[7],
209                                             node[8], node[9], node[10],node[11],
210                                             node[12],node[13],node[14],node[15],
211                                             node[16],node[17],node[18],node[19] );
212     }
213     break;
214
215   case SMDSAbs_Edge:
216     if ( nbnode == 2 )
217       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
218       else      e = mesh->AddEdge      (node[0], node[1] );
219     else if ( nbnode == 3 )
220       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
221       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
222     break;
223
224   case SMDSAbs_0DElement:
225     if ( nbnode == 1 )
226       if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
227       else      e = mesh->Add0DElement      (node[0] );
228     break;
229
230   case SMDSAbs_Node:
231     if ( ID ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
232     else      e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
233     break;
234
235   default:;
236   }
237   if ( e ) myLastCreatedElems.Append( e );
238   return e;
239 }
240
241 //=======================================================================
242 /*!
243  * \brief Add element
244  */
245 //=======================================================================
246
247 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
248                                                const SMDSAbs_ElementType type,
249                                                const bool                isPoly,
250                                                const int                 ID)
251 {
252   vector<const SMDS_MeshNode*> nodes;
253   nodes.reserve( nodeIDs.size() );
254   vector<int>::const_iterator id = nodeIDs.begin();
255   while ( id != nodeIDs.end() ) {
256     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
257       nodes.push_back( node );
258     else
259       return 0;
260   }
261   return AddElement( nodes, type, isPoly, ID );
262 }
263
264 //=======================================================================
265 //function : Remove
266 //purpose  : Remove a node or an element.
267 //           Modify a compute state of sub-meshes which become empty
268 //=======================================================================
269
270 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
271                               const bool         isNodes )
272 {
273   myLastCreatedElems.Clear();
274   myLastCreatedNodes.Clear();
275
276   SMESHDS_Mesh* aMesh = GetMeshDS();
277   set< SMESH_subMesh *> smmap;
278
279   int removed = 0;
280   list<int>::const_iterator it = theIDs.begin();
281   for ( ; it != theIDs.end(); it++ ) {
282     const SMDS_MeshElement * elem;
283     if ( isNodes )
284       elem = aMesh->FindNode( *it );
285     else
286       elem = aMesh->FindElement( *it );
287     if ( !elem )
288       continue;
289
290     // Notify VERTEX sub-meshes about modification
291     if ( isNodes ) {
292       const SMDS_MeshNode* node = cast2Node( elem );
293       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
294         if ( int aShapeID = node->GetPosition()->GetShapeId() )
295           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
296             smmap.insert( sm );
297     }
298     // Find sub-meshes to notify about modification
299     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
300     //     while ( nodeIt->more() ) {
301     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
302     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
303     //       if ( aPosition.get() ) {
304     //         if ( int aShapeID = aPosition->GetShapeId() ) {
305     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
306     //             smmap.insert( sm );
307     //         }
308     //       }
309     //     }
310
311     // Do remove
312     if ( isNodes )
313       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
314     else
315       aMesh->RemoveElement( elem );
316     removed++;
317   }
318
319   // Notify sub-meshes about modification
320   if ( !smmap.empty() ) {
321     set< SMESH_subMesh *>::iterator smIt;
322     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
323       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
324   }
325
326   //   // Check if the whole mesh becomes empty
327   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
328   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
329
330   return removed;
331 }
332
333 //=======================================================================
334 //function : FindShape
335 //purpose  : Return an index of the shape theElem is on
336 //           or zero if a shape not found
337 //=======================================================================
338
339 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
340 {
341   myLastCreatedElems.Clear();
342   myLastCreatedNodes.Clear();
343
344   SMESHDS_Mesh * aMesh = GetMeshDS();
345   if ( aMesh->ShapeToMesh().IsNull() )
346     return 0;
347
348   if ( theElem->GetType() == SMDSAbs_Node ) {
349     const SMDS_PositionPtr& aPosition =
350       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
351     if ( aPosition.get() )
352       return aPosition->GetShapeId();
353     else
354       return 0;
355   }
356
357   TopoDS_Shape aShape; // the shape a node is on
358   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
359   while ( nodeIt->more() ) {
360     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
361     const SMDS_PositionPtr& aPosition = node->GetPosition();
362     if ( aPosition.get() ) {
363       int aShapeID = aPosition->GetShapeId();
364       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
365       if ( sm ) {
366         if ( sm->Contains( theElem ))
367           return aShapeID;
368         if ( aShape.IsNull() )
369           aShape = aMesh->IndexToShape( aShapeID );
370       }
371       else {
372         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
373       }
374     }
375   }
376
377   // None of nodes is on a proper shape,
378   // find the shape among ancestors of aShape on which a node is
379   if ( aShape.IsNull() ) {
380     //MESSAGE ("::FindShape() - NONE node is on shape")
381     return 0;
382   }
383   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
384   for ( ; ancIt.More(); ancIt.Next() ) {
385     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
386     if ( sm && sm->Contains( theElem ))
387       return aMesh->ShapeToIndex( ancIt.Value() );
388   }
389
390   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
391   return 0;
392 }
393
394 //=======================================================================
395 //function : IsMedium
396 //purpose  :
397 //=======================================================================
398
399 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
400                                 const SMDSAbs_ElementType typeToCheck)
401 {
402   bool isMedium = false;
403   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
404   while (it->more() && !isMedium ) {
405     const SMDS_MeshElement* elem = it->next();
406     isMedium = elem->IsMediumNode(node);
407   }
408   return isMedium;
409 }
410
411 //=======================================================================
412 //function : ShiftNodesQuadTria
413 //purpose  : auxilary
414 //           Shift nodes in the array corresponded to quadratic triangle
415 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
416 //=======================================================================
417 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
418 {
419   const SMDS_MeshNode* nd1 = aNodes[0];
420   aNodes[0] = aNodes[1];
421   aNodes[1] = aNodes[2];
422   aNodes[2] = nd1;
423   const SMDS_MeshNode* nd2 = aNodes[3];
424   aNodes[3] = aNodes[4];
425   aNodes[4] = aNodes[5];
426   aNodes[5] = nd2;
427 }
428
429 //=======================================================================
430 //function : GetNodesFromTwoTria
431 //purpose  : auxilary
432 //           Shift nodes in the array corresponded to quadratic triangle
433 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
434 //=======================================================================
435 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
436                                 const SMDS_MeshElement * theTria2,
437                                 const SMDS_MeshNode* N1[],
438                                 const SMDS_MeshNode* N2[])
439 {
440   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
441   int i=0;
442   while(i<6) {
443     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
444     i++;
445   }
446   if(it->more()) return false;
447   it = theTria2->nodesIterator();
448   i=0;
449   while(i<6) {
450     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
451     i++;
452   }
453   if(it->more()) return false;
454
455   int sames[3] = {-1,-1,-1};
456   int nbsames = 0;
457   int j;
458   for(i=0; i<3; i++) {
459     for(j=0; j<3; j++) {
460       if(N1[i]==N2[j]) {
461         sames[i] = j;
462         nbsames++;
463         break;
464       }
465     }
466   }
467   if(nbsames!=2) return false;
468   if(sames[0]>-1) {
469     ShiftNodesQuadTria(N1);
470     if(sames[1]>-1) {
471       ShiftNodesQuadTria(N1);
472     }
473   }
474   i = sames[0] + sames[1] + sames[2];
475   for(; i<2; i++) {
476     ShiftNodesQuadTria(N2);
477   }
478   // now we receive following N1 and N2 (using numeration as above image)
479   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
480   // i.e. first nodes from both arrays determ new diagonal
481   return true;
482 }
483
484 //=======================================================================
485 //function : InverseDiag
486 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
487 //           but having other common link.
488 //           Return False if args are improper
489 //=======================================================================
490
491 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
492                                     const SMDS_MeshElement * theTria2 )
493 {
494   myLastCreatedElems.Clear();
495   myLastCreatedNodes.Clear();
496
497   if (!theTria1 || !theTria2)
498     return false;
499
500   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
501   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
502   if (F1 && F2) {
503
504     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
505     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
506     //    |/ |                                         | \|
507     //  B +--+ 2                                     B +--+ 2
508
509     // put nodes in array and find out indices of the same ones
510     const SMDS_MeshNode* aNodes [6];
511     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
512     int i = 0;
513     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
514     while ( it->more() ) {
515       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
516
517       if ( i > 2 ) // theTria2
518         // find same node of theTria1
519         for ( int j = 0; j < 3; j++ )
520           if ( aNodes[ i ] == aNodes[ j ]) {
521             sameInd[ j ] = i;
522             sameInd[ i ] = j;
523             break;
524           }
525       // next
526       i++;
527       if ( i == 3 ) {
528         if ( it->more() )
529           return false; // theTria1 is not a triangle
530         it = theTria2->nodesIterator();
531       }
532       if ( i == 6 && it->more() )
533         return false; // theTria2 is not a triangle
534     }
535
536     // find indices of 1,2 and of A,B in theTria1
537     int iA = 0, iB = 0, i1 = 0, i2 = 0;
538     for ( i = 0; i < 6; i++ ) {
539       if ( sameInd [ i ] == 0 )
540         if ( i < 3 ) i1 = i;
541         else         i2 = i;
542       else if (i < 3)
543         if ( iA ) iB = i;
544         else      iA = i;
545     }
546     // nodes 1 and 2 should not be the same
547     if ( aNodes[ i1 ] == aNodes[ i2 ] )
548       return false;
549
550     // theTria1: A->2
551     aNodes[ iA ] = aNodes[ i2 ];
552     // theTria2: B->1
553     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
554
555     //MESSAGE( theTria1 << theTria2 );
556
557     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
558     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
559
560     //MESSAGE( theTria1 << theTria2 );
561
562     return true;
563
564   } // end if(F1 && F2)
565
566   // check case of quadratic faces
567   const SMDS_QuadraticFaceOfNodes* QF1 =
568     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
569   if(!QF1) return false;
570   const SMDS_QuadraticFaceOfNodes* QF2 =
571     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
572   if(!QF2) return false;
573
574   //       5
575   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
576   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
577   //    |   / |
578   //  7 +  +  + 6
579   //    | /9  |
580   //    |/    |
581   //  4 +--+--+ 3
582   //       8
583
584   const SMDS_MeshNode* N1 [6];
585   const SMDS_MeshNode* N2 [6];
586   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
587     return false;
588   // now we receive following N1 and N2 (using numeration as above image)
589   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
590   // i.e. first nodes from both arrays determ new diagonal
591
592   const SMDS_MeshNode* N1new [6];
593   const SMDS_MeshNode* N2new [6];
594   N1new[0] = N1[0];
595   N1new[1] = N2[0];
596   N1new[2] = N2[1];
597   N1new[3] = N1[4];
598   N1new[4] = N2[3];
599   N1new[5] = N1[5];
600   N2new[0] = N1[0];
601   N2new[1] = N1[1];
602   N2new[2] = N2[0];
603   N2new[3] = N1[3];
604   N2new[4] = N2[5];
605   N2new[5] = N1[4];
606   // replaces nodes in faces
607   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
608   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
609
610   return true;
611 }
612
613 //=======================================================================
614 //function : findTriangles
615 //purpose  : find triangles sharing theNode1-theNode2 link
616 //=======================================================================
617
618 static bool findTriangles(const SMDS_MeshNode *    theNode1,
619                           const SMDS_MeshNode *    theNode2,
620                           const SMDS_MeshElement*& theTria1,
621                           const SMDS_MeshElement*& theTria2)
622 {
623   if ( !theNode1 || !theNode2 ) return false;
624
625   theTria1 = theTria2 = 0;
626
627   set< const SMDS_MeshElement* > emap;
628   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
629   while (it->more()) {
630     const SMDS_MeshElement* elem = it->next();
631     if ( elem->NbNodes() == 3 )
632       emap.insert( elem );
633   }
634   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
635   while (it->more()) {
636     const SMDS_MeshElement* elem = it->next();
637     if ( emap.find( elem ) != emap.end() )
638       if ( theTria1 ) {
639         // theTria1 must be element with minimum ID
640         if( theTria1->GetID() < elem->GetID() ) {
641           theTria2 = elem;
642         }
643         else {
644           theTria2 = theTria1;
645           theTria1 = elem;
646         }
647         break;
648       }
649       else {
650         theTria1 = elem;
651       }
652   }
653   return ( theTria1 && theTria2 );
654 }
655
656 //=======================================================================
657 //function : InverseDiag
658 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
659 //           with ones built on the same 4 nodes but having other common link.
660 //           Return false if proper faces not found
661 //=======================================================================
662
663 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
664                                     const SMDS_MeshNode * theNode2)
665 {
666   myLastCreatedElems.Clear();
667   myLastCreatedNodes.Clear();
668
669   MESSAGE( "::InverseDiag()" );
670
671   const SMDS_MeshElement *tr1, *tr2;
672   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
673     return false;
674
675   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
676   //if (!F1) return false;
677   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
678   //if (!F2) return false;
679   if (F1 && F2) {
680
681     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
682     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
683     //    |/ |                                    | \|
684     //  B +--+ 2                                B +--+ 2
685
686     // put nodes in array
687     // and find indices of 1,2 and of A in tr1 and of B in tr2
688     int i, iA1 = 0, i1 = 0;
689     const SMDS_MeshNode* aNodes1 [3];
690     SMDS_ElemIteratorPtr it;
691     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
692       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
693       if ( aNodes1[ i ] == theNode1 )
694         iA1 = i; // node A in tr1
695       else if ( aNodes1[ i ] != theNode2 )
696         i1 = i;  // node 1
697     }
698     int iB2 = 0, i2 = 0;
699     const SMDS_MeshNode* aNodes2 [3];
700     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
701       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
702       if ( aNodes2[ i ] == theNode2 )
703         iB2 = i; // node B in tr2
704       else if ( aNodes2[ i ] != theNode1 )
705         i2 = i;  // node 2
706     }
707
708     // nodes 1 and 2 should not be the same
709     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
710       return false;
711
712     // tr1: A->2
713     aNodes1[ iA1 ] = aNodes2[ i2 ];
714     // tr2: B->1
715     aNodes2[ iB2 ] = aNodes1[ i1 ];
716
717     //MESSAGE( tr1 << tr2 );
718
719     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
720     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
721
722     //MESSAGE( tr1 << tr2 );
723
724     return true;
725   }
726
727   // check case of quadratic faces
728   const SMDS_QuadraticFaceOfNodes* QF1 =
729     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
730   if(!QF1) return false;
731   const SMDS_QuadraticFaceOfNodes* QF2 =
732     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
733   if(!QF2) return false;
734   return InverseDiag(tr1,tr2);
735 }
736
737 //=======================================================================
738 //function : getQuadrangleNodes
739 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
740 //           fusion of triangles tr1 and tr2 having shared link on
741 //           theNode1 and theNode2
742 //=======================================================================
743
744 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
745                         const SMDS_MeshNode *    theNode1,
746                         const SMDS_MeshNode *    theNode2,
747                         const SMDS_MeshElement * tr1,
748                         const SMDS_MeshElement * tr2 )
749 {
750   if( tr1->NbNodes() != tr2->NbNodes() )
751     return false;
752   // find the 4-th node to insert into tr1
753   const SMDS_MeshNode* n4 = 0;
754   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
755   int i=0;
756   while ( !n4 && i<3 ) {
757     const SMDS_MeshNode * n = cast2Node( it->next() );
758     i++;
759     bool isDiag = ( n == theNode1 || n == theNode2 );
760     if ( !isDiag )
761       n4 = n;
762   }
763   // Make an array of nodes to be in a quadrangle
764   int iNode = 0, iFirstDiag = -1;
765   it = tr1->nodesIterator();
766   i=0;
767   while ( i<3 ) {
768     const SMDS_MeshNode * n = cast2Node( it->next() );
769     i++;
770     bool isDiag = ( n == theNode1 || n == theNode2 );
771     if ( isDiag ) {
772       if ( iFirstDiag < 0 )
773         iFirstDiag = iNode;
774       else if ( iNode - iFirstDiag == 1 )
775         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
776     }
777     else if ( n == n4 ) {
778       return false; // tr1 and tr2 should not have all the same nodes
779     }
780     theQuadNodes[ iNode++ ] = n;
781   }
782   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
783     theQuadNodes[ iNode ] = n4;
784
785   return true;
786 }
787
788 //=======================================================================
789 //function : DeleteDiag
790 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
791 //           with a quadrangle built on the same 4 nodes.
792 //           Return false if proper faces not found
793 //=======================================================================
794
795 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
796                                    const SMDS_MeshNode * theNode2)
797 {
798   myLastCreatedElems.Clear();
799   myLastCreatedNodes.Clear();
800
801   MESSAGE( "::DeleteDiag()" );
802
803   const SMDS_MeshElement *tr1, *tr2;
804   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
805     return false;
806
807   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
808   //if (!F1) return false;
809   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
810   //if (!F2) return false;
811   if (F1 && F2) {
812
813     const SMDS_MeshNode* aNodes [ 4 ];
814     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
815       return false;
816
817     //MESSAGE( endl << tr1 << tr2 );
818
819     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
820     myLastCreatedElems.Append(tr1);
821     GetMeshDS()->RemoveElement( tr2 );
822
823     //MESSAGE( endl << tr1 );
824
825     return true;
826   }
827
828   // check case of quadratic faces
829   const SMDS_QuadraticFaceOfNodes* QF1 =
830     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
831   if(!QF1) return false;
832   const SMDS_QuadraticFaceOfNodes* QF2 =
833     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
834   if(!QF2) return false;
835
836   //       5
837   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
838   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
839   //    |   / |
840   //  7 +  +  + 6
841   //    | /9  |
842   //    |/    |
843   //  4 +--+--+ 3
844   //       8
845
846   const SMDS_MeshNode* N1 [6];
847   const SMDS_MeshNode* N2 [6];
848   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
849     return false;
850   // now we receive following N1 and N2 (using numeration as above image)
851   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
852   // i.e. first nodes from both arrays determ new diagonal
853
854   const SMDS_MeshNode* aNodes[8];
855   aNodes[0] = N1[0];
856   aNodes[1] = N1[1];
857   aNodes[2] = N2[0];
858   aNodes[3] = N2[1];
859   aNodes[4] = N1[3];
860   aNodes[5] = N2[5];
861   aNodes[6] = N2[3];
862   aNodes[7] = N1[5];
863
864   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
865   myLastCreatedElems.Append(tr1);
866   GetMeshDS()->RemoveElement( tr2 );
867
868   // remove middle node (9)
869   GetMeshDS()->RemoveNode( N1[4] );
870
871   return true;
872 }
873
874 //=======================================================================
875 //function : Reorient
876 //purpose  : Reverse theElement orientation
877 //=======================================================================
878
879 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
880 {
881   myLastCreatedElems.Clear();
882   myLastCreatedNodes.Clear();
883
884   if (!theElem)
885     return false;
886   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
887   if ( !it || !it->more() )
888     return false;
889
890   switch ( theElem->GetType() ) {
891
892   case SMDSAbs_Edge:
893   case SMDSAbs_Face: {
894     if(!theElem->IsQuadratic()) {
895       int i = theElem->NbNodes();
896       vector<const SMDS_MeshNode*> aNodes( i );
897       while ( it->more() )
898         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
899       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
900     }
901     else {
902       // quadratic elements
903       if(theElem->GetType()==SMDSAbs_Edge) {
904         vector<const SMDS_MeshNode*> aNodes(3);
905         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
906         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
907         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
908         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
909       }
910       else {
911         int nbn = theElem->NbNodes();
912         vector<const SMDS_MeshNode*> aNodes(nbn);
913         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
914         int i=1;
915         for(; i<nbn/2; i++) {
916           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
917         }
918         for(i=0; i<nbn/2; i++) {
919           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
920         }
921         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
922       }
923     }
924   }
925   case SMDSAbs_Volume: {
926     if (theElem->IsPoly()) {
927       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
928         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
929       if (!aPolyedre) {
930         MESSAGE("Warning: bad volumic element");
931         return false;
932       }
933
934       int nbFaces = aPolyedre->NbFaces();
935       vector<const SMDS_MeshNode *> poly_nodes;
936       vector<int> quantities (nbFaces);
937
938       // reverse each face of the polyedre
939       for (int iface = 1; iface <= nbFaces; iface++) {
940         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
941         quantities[iface - 1] = nbFaceNodes;
942
943         for (inode = nbFaceNodes; inode >= 1; inode--) {
944           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
945           poly_nodes.push_back(curNode);
946         }
947       }
948
949       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
950
951     }
952     else {
953       SMDS_VolumeTool vTool;
954       if ( !vTool.Set( theElem ))
955         return false;
956       vTool.Inverse();
957       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
958     }
959   }
960   default:;
961   }
962
963   return false;
964 }
965
966 //=======================================================================
967 //function : getBadRate
968 //purpose  :
969 //=======================================================================
970
971 static double getBadRate (const SMDS_MeshElement*               theElem,
972                           SMESH::Controls::NumericalFunctorPtr& theCrit)
973 {
974   SMESH::Controls::TSequenceOfXYZ P;
975   if ( !theElem || !theCrit->GetPoints( theElem, P ))
976     return 1e100;
977   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
978   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
979 }
980
981 //=======================================================================
982 //function : QuadToTri
983 //purpose  : Cut quadrangles into triangles.
984 //           theCrit is used to select a diagonal to cut
985 //=======================================================================
986
987 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
988                                   SMESH::Controls::NumericalFunctorPtr theCrit)
989 {
990   myLastCreatedElems.Clear();
991   myLastCreatedNodes.Clear();
992
993   MESSAGE( "::QuadToTri()" );
994
995   if ( !theCrit.get() )
996     return false;
997
998   SMESHDS_Mesh * aMesh = GetMeshDS();
999
1000   Handle(Geom_Surface) surface;
1001   SMESH_MesherHelper   helper( *GetMesh() );
1002
1003   TIDSortedElemSet::iterator itElem;
1004   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1005     const SMDS_MeshElement* elem = *itElem;
1006     if ( !elem || elem->GetType() != SMDSAbs_Face )
1007       continue;
1008     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1009       continue;
1010
1011     // retrieve element nodes
1012     const SMDS_MeshNode* aNodes [8];
1013     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1014     int i = 0;
1015     while ( itN->more() )
1016       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1017
1018     // compare two sets of possible triangles
1019     double aBadRate1, aBadRate2; // to what extent a set is bad
1020     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1021     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1022     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1023
1024     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1025     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1026     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1027
1028     int aShapeId = FindShape( elem );
1029     const SMDS_MeshElement* newElem = 0;
1030
1031     if( !elem->IsQuadratic() ) {
1032
1033       // split liner quadrangle
1034
1035       if ( aBadRate1 <= aBadRate2 ) {
1036         // tr1 + tr2 is better
1037         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1038         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1039       }
1040       else {
1041         // tr3 + tr4 is better
1042         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1043         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1044       }
1045     }
1046     else {
1047
1048       // split quadratic quadrangle
1049
1050       // get surface elem is on
1051       if ( aShapeId != helper.GetSubShapeID() ) {
1052         surface.Nullify();
1053         TopoDS_Shape shape;
1054         if ( aShapeId > 0 )
1055           shape = aMesh->IndexToShape( aShapeId );
1056         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1057           TopoDS_Face face = TopoDS::Face( shape );
1058           surface = BRep_Tool::Surface( face );
1059           if ( !surface.IsNull() )
1060             helper.SetSubShape( shape );
1061         }
1062       }
1063       // get elem nodes
1064       const SMDS_MeshNode* aNodes [8];
1065       const SMDS_MeshNode* inFaceNode = 0;
1066       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1067       int i = 0;
1068       while ( itN->more() ) {
1069         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1070         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1071              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1072         {
1073           inFaceNode = aNodes[ i-1 ];
1074         }
1075       }
1076       // find middle point for (0,1,2,3)
1077       // and create a node in this point;
1078       gp_XYZ p( 0,0,0 );
1079       if ( surface.IsNull() ) {
1080         for(i=0; i<4; i++)
1081           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1082         p /= 4;
1083       }
1084       else {
1085         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1086         gp_XY uv( 0,0 );
1087         for(i=0; i<4; i++)
1088           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1089         uv /= 4.;
1090         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1091       }
1092       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1093       myLastCreatedNodes.Append(newN);
1094
1095       // create a new element
1096       const SMDS_MeshNode* N[6];
1097       if ( aBadRate1 <= aBadRate2 ) {
1098         N[0] = aNodes[0];
1099         N[1] = aNodes[1];
1100         N[2] = aNodes[2];
1101         N[3] = aNodes[4];
1102         N[4] = aNodes[5];
1103         N[5] = newN;
1104         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1105                                  aNodes[6], aNodes[7], newN );
1106       }
1107       else {
1108         N[0] = aNodes[1];
1109         N[1] = aNodes[2];
1110         N[2] = aNodes[3];
1111         N[3] = aNodes[5];
1112         N[4] = aNodes[6];
1113         N[5] = newN;
1114         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1115                                  aNodes[7], aNodes[4], newN );
1116       }
1117       aMesh->ChangeElementNodes( elem, N, 6 );
1118
1119     } // quadratic case
1120
1121     // care of a new element
1122
1123     myLastCreatedElems.Append(newElem);
1124     AddToSameGroups( newElem, elem, aMesh );
1125
1126     // put a new triangle on the same shape
1127     if ( aShapeId )
1128       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1129   }
1130   return true;
1131 }
1132
1133 //=======================================================================
1134 //function : BestSplit
1135 //purpose  : Find better diagonal for cutting.
1136 //=======================================================================
1137
1138 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1139                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1140 {
1141   myLastCreatedElems.Clear();
1142   myLastCreatedNodes.Clear();
1143
1144   if (!theCrit.get())
1145     return -1;
1146
1147   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1148     return -1;
1149
1150   if( theQuad->NbNodes()==4 ||
1151       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1152
1153     // retrieve element nodes
1154     const SMDS_MeshNode* aNodes [4];
1155     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1156     int i = 0;
1157     //while (itN->more())
1158     while (i<4) {
1159       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1160     }
1161     // compare two sets of possible triangles
1162     double aBadRate1, aBadRate2; // to what extent a set is bad
1163     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1164     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1165     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1166
1167     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1168     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1169     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1170
1171     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1172       return 1; // diagonal 1-3
1173
1174     return 2; // diagonal 2-4
1175   }
1176   return -1;
1177 }
1178
1179 namespace
1180 {
1181   // Methods of splitting volumes into tetra
1182
1183   const int theHexTo5_1[5*4+1] =
1184     {
1185       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1186     };
1187   const int theHexTo5_2[5*4+1] =
1188     {
1189       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1190     };
1191   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1192
1193   const int theHexTo6_1[6*4+1] =
1194     {
1195       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
1196     };
1197   const int theHexTo6_2[6*4+1] =
1198     {
1199       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
1200     };
1201   const int theHexTo6_3[6*4+1] =
1202     {
1203       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
1204     };
1205   const int theHexTo6_4[6*4+1] =
1206     {
1207       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
1208     };
1209   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1210
1211   const int thePyraTo2_1[2*4+1] =
1212     {
1213       0, 1, 2, 4,    0, 2, 3, 4,   -1
1214     };
1215   const int thePyraTo2_2[2*4+1] =
1216     {
1217       1, 2, 3, 4,    1, 3, 0, 4,   -1
1218     };
1219   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1220
1221   const int thePentaTo3_1[3*4+1] =
1222     {
1223       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1224     };
1225   const int thePentaTo3_2[3*4+1] =
1226     {
1227       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1228     };
1229   const int thePentaTo3_3[3*4+1] =
1230     {
1231       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1232     };
1233   const int thePentaTo3_4[3*4+1] =
1234     {
1235       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1236     };
1237   const int thePentaTo3_5[3*4+1] =
1238     {
1239       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1240     };
1241   const int thePentaTo3_6[3*4+1] =
1242     {
1243       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1244     };
1245   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1246                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1247
1248   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1249   {
1250     int _n1, _n2, _n3;
1251     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1252     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1253     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1254   };
1255   struct TSplitMethod
1256   {
1257     int        _nbTetra;
1258     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1259     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1260     bool       _ownConn;      //!< to delete _connectivity in destructor
1261     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1262
1263     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1264       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1265     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1266     bool hasFacet( const TTriangleFacet& facet ) const
1267     {
1268       const int* tetConn = _connectivity;
1269       for ( ; tetConn[0] >= 0; tetConn += 4 )
1270         if (( facet.contains( tetConn[0] ) +
1271               facet.contains( tetConn[1] ) +
1272               facet.contains( tetConn[2] ) +
1273               facet.contains( tetConn[3] )) == 3 )
1274           return true;
1275       return false;
1276     }
1277   };
1278
1279   //=======================================================================
1280   /*!
1281    * \brief return TSplitMethod for the given element
1282    */
1283   //=======================================================================
1284
1285   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1286   {
1287     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1288
1289     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1290     // an edge and a face barycenter; tertaherdons are based on triangles and
1291     // a volume barycenter
1292     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1293
1294     // Find out how adjacent volumes are split
1295
1296     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1297     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1298     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1299     {
1300       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1301       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1302       if ( nbNodes < 4 ) continue;
1303
1304       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1305       const int* nInd = vol.GetFaceNodesIndices( iF );
1306       if ( nbNodes == 4 )
1307       {
1308         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1309         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1310         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1311         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1312       }
1313       else
1314       {
1315         int iCom = 0; // common node of triangle faces to split into
1316         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1317         {
1318           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1319                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1320                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1321           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1322                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1323                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1324           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1325           {
1326             triaSplits.push_back( t012 );
1327             triaSplits.push_back( t023 );
1328             break;
1329           }
1330         }
1331       }
1332       if ( !triaSplits.empty() )
1333         hasAdjacentSplits = true;
1334     }
1335
1336     // Among variants of split method select one compliant with adjacent volumes
1337
1338     TSplitMethod method;
1339     if ( !vol.Element()->IsPoly() && !is24TetMode )
1340     {
1341       int nbVariants = 2, nbTet = 0;
1342       const int** connVariants = 0;
1343       switch ( vol.Element()->GetEntityType() )
1344       {
1345       case SMDSEntity_Hexa:
1346       case SMDSEntity_Quad_Hexa:
1347         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1348           connVariants = theHexTo5, nbTet = 5;
1349         else
1350           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1351         break;
1352       case SMDSEntity_Pyramid:
1353       case SMDSEntity_Quad_Pyramid:
1354         connVariants = thePyraTo2;  nbTet = 2;
1355         break;
1356       case SMDSEntity_Penta:
1357       case SMDSEntity_Quad_Penta:
1358         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1359         break;
1360       default:
1361         nbVariants = 0;
1362       }
1363       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1364       {
1365         // check method compliancy with adjacent tetras,
1366         // all found splits must be among facets of tetras described by this method
1367         method = TSplitMethod( nbTet, connVariants[variant] );
1368         if ( hasAdjacentSplits && method._nbTetra > 0 )
1369         {
1370           bool facetCreated = true;
1371           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1372           {
1373             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1374             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1375               facetCreated = method.hasFacet( *facet );
1376           }
1377           if ( !facetCreated )
1378             method = TSplitMethod(0); // incompatible method
1379         }
1380       }
1381     }
1382     if ( method._nbTetra < 1 )
1383     {
1384       // No standard method is applicable, use a generic solution:
1385       // each facet of a volume is split into triangles and
1386       // each of triangles and a volume barycenter form a tetrahedron.
1387
1388       int* connectivity = new int[ maxTetConnSize + 1 ];
1389       method._connectivity = connectivity;
1390       method._ownConn = true;
1391       method._baryNode = true;
1392
1393       int connSize = 0;
1394       int baryCenInd = vol.NbNodes();
1395       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1396       {
1397         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1398         const int*   nInd = vol.GetFaceNodesIndices( iF );
1399         // find common node of triangle facets of tetra to create
1400         int iCommon = 0; // index in linear numeration
1401         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1402         if ( !triaSplits.empty() )
1403         {
1404           // by found facets
1405           const TTriangleFacet* facet = &triaSplits.front();
1406           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1407             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1408                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1409               break;
1410         }
1411         else if ( nbNodes > 3 && !is24TetMode )
1412         {
1413           // find the best method of splitting into triangles by aspect ratio
1414           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1415           map< double, int > badness2iCommon;
1416           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1417           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1418           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1419             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1420             {
1421               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1422                                       nodes[ iQ*((iLast-1)%nbNodes)],
1423                                       nodes[ iQ*((iLast  )%nbNodes)]);
1424               double badness = getBadRate( &tria, aspectRatio );
1425               badness2iCommon.insert( make_pair( badness, iCommon ));
1426             }
1427           // use iCommon with lowest badness
1428           iCommon = badness2iCommon.begin()->second;
1429         }
1430         if ( iCommon >= nbNodes )
1431           iCommon = 0; // something wrong
1432
1433         // fill connectivity of tetrahedra based on a current face
1434         int nbTet = nbNodes - 2;
1435         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1436         {
1437           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1438           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1439           nbTet = nbNodes;
1440           for ( int i = 0; i < nbTet; ++i )
1441           {
1442             int i1 = i, i2 = (i+1) % nbNodes;
1443             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1444             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1445             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1446             connectivity[ connSize++ ] = faceBaryCenInd;
1447             connectivity[ connSize++ ] = baryCenInd;
1448           }
1449         }
1450         else
1451         {
1452           for ( int i = 0; i < nbTet; ++i )
1453           {
1454             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1455             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1456             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1457             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1458             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1459             connectivity[ connSize++ ] = baryCenInd;
1460           }
1461         }
1462         method._nbTetra += nbTet;
1463       }
1464       connectivity[ connSize++ ] = -1;
1465     }
1466     return method;
1467   }
1468   //================================================================================
1469   /*!
1470    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1471    */
1472   //================================================================================
1473
1474   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1475   {
1476     // find the tetrahedron including the three nodes of facet
1477     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1478     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1479     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1480     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1481     while ( volIt1->more() )
1482     {
1483       const SMDS_MeshElement* v = volIt1->next();
1484       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1485         continue;
1486       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1487       while ( volIt2->more() )
1488         if ( v != volIt2->next() )
1489           continue;
1490       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1491       while ( volIt3->more() )
1492         if ( v == volIt3->next() )
1493           return true;
1494     }
1495     return false;
1496   }
1497
1498   //=======================================================================
1499   /*!
1500    * \brief A key of a face of volume
1501    */
1502   //=======================================================================
1503
1504   struct TVolumeFaceKey: pair< int, pair< int, int> >
1505   {
1506     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1507     {
1508       TIDSortedNodeSet sortedNodes;
1509       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1510       int nbNodes = vol.NbFaceNodes( iF );
1511       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1512       for ( int i = 0; i < nbNodes; i += iQ )
1513         sortedNodes.insert( fNodes[i] );
1514       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1515       first = (*(n++))->GetID();
1516       second.first = (*(n++))->GetID();
1517       second.second = (*(n++))->GetID();
1518     }
1519   };
1520 } // namespace
1521
1522 //=======================================================================
1523 //function : SplitVolumesIntoTetra
1524 //purpose  : Split volumic elements into tetrahedra.
1525 //=======================================================================
1526
1527 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1528                                               const int                theMethodFlags)
1529 {
1530   // std-like iterator on coordinates of nodes of mesh element
1531   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1532   NXyzIterator xyzEnd;
1533
1534   SMDS_VolumeTool    volTool;
1535   SMESH_MesherHelper helper( *GetMesh());
1536
1537   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1538   SMESHDS_SubMesh* fSubMesh = subMesh;
1539   
1540   SMESH_SequenceOfElemPtr newNodes, newElems;
1541
1542   // map face of volume to it's baricenrtic node
1543   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1544   double bc[3];
1545
1546   TIDSortedElemSet::const_iterator elem = theElems.begin();
1547   for ( ; elem != theElems.end(); ++elem )
1548   {
1549     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1550     if ( geomType <= SMDSEntity_Quad_Tetra )
1551       continue; // tetra or face or ...
1552
1553     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1554
1555     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1556     if ( splitMethod._nbTetra < 1 ) continue;
1557
1558     // find submesh to add new tetras to
1559     if ( !subMesh || !subMesh->Contains( *elem ))
1560     {
1561       int shapeID = FindShape( *elem );
1562       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1563       subMesh = GetMeshDS()->MeshElements( shapeID );
1564     }
1565     int iQ;
1566     if ( (*elem)->IsQuadratic() )
1567     {
1568       iQ = 2;
1569       // add quadratic links to the helper
1570       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1571       {
1572         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1573         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1574           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1575       }
1576       helper.SetIsQuadratic( true );
1577     }
1578     else
1579     {
1580       iQ = 1;
1581       helper.SetIsQuadratic( false );
1582     }
1583     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1584     if ( splitMethod._baryNode )
1585     {
1586       // make a node at barycenter
1587       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1588       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1589       nodes.push_back( gcNode );
1590       newNodes.Append( gcNode );
1591     }
1592     if ( !splitMethod._faceBaryNode.empty() )
1593     {
1594       // make or find baricentric nodes of faces
1595       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1596       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1597       {
1598         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1599           volFace2BaryNode.insert
1600           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1601         if ( !f_n->second )
1602         {
1603           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1604           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1605         }
1606         nodes.push_back( iF_n->second = f_n->second );
1607       }
1608     }
1609
1610     // make tetras
1611     helper.SetElementsOnShape( true );
1612     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1613     const int* tetConn = splitMethod._connectivity;
1614     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1615       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1616                                                        nodes[ tetConn[1] ],
1617                                                        nodes[ tetConn[2] ],
1618                                                        nodes[ tetConn[3] ]));
1619
1620     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1621
1622     // Split faces on sides of the split volume
1623
1624     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1625     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1626     {
1627       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1628       if ( nbNodes < 4 ) continue;
1629
1630       // find an existing face
1631       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1632                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1633       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1634       {
1635         // make triangles
1636         helper.SetElementsOnShape( false );
1637         vector< const SMDS_MeshElement* > triangles;
1638
1639         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1640         if ( iF_n != splitMethod._faceBaryNode.end() )
1641         {
1642           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1643           {
1644             const SMDS_MeshNode* n1 = fNodes[iN];
1645             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1646             const SMDS_MeshNode *n3 = iF_n->second;
1647             if ( !volTool.IsFaceExternal( iF ))
1648               swap( n2, n3 );
1649             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1650           }
1651         }
1652         else
1653         {
1654           // among possible triangles create ones discribed by split method
1655           const int* nInd = volTool.GetFaceNodesIndices( iF );
1656           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1657           int iCom = 0; // common node of triangle faces to split into
1658           list< TTriangleFacet > facets;
1659           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1660           {
1661             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1662                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1663                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1664             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1665                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1666                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1667             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1668             {
1669               facets.push_back( t012 );
1670               facets.push_back( t023 );
1671               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1672                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1673                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1674                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1675               break;
1676             }
1677           }
1678           list< TTriangleFacet >::iterator facet = facets.begin();
1679           for ( ; facet != facets.end(); ++facet )
1680           {
1681             if ( !volTool.IsFaceExternal( iF ))
1682               swap( facet->_n2, facet->_n3 );
1683             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1684                                                  volNodes[ facet->_n2 ],
1685                                                  volNodes[ facet->_n3 ]));
1686           }
1687         }
1688         // find submesh to add new triangles in
1689         if ( !fSubMesh || !fSubMesh->Contains( face ))
1690         {
1691           int shapeID = FindShape( face );
1692           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1693         }
1694         for ( int i = 0; i < triangles.size(); ++i )
1695         {
1696           if ( !triangles.back() ) continue;
1697           if ( fSubMesh )
1698             fSubMesh->AddElement( triangles.back());
1699           newElems.Append( triangles.back() );
1700         }
1701         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1702         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1703       }
1704
1705     } // loop on volume faces to split them into triangles
1706
1707     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1708
1709   } // loop on volumes to split
1710
1711   myLastCreatedNodes = newNodes;
1712   myLastCreatedElems = newElems;
1713 }
1714
1715 //=======================================================================
1716 //function : AddToSameGroups
1717 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1718 //=======================================================================
1719
1720 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1721                                         const SMDS_MeshElement* elemInGroups,
1722                                         SMESHDS_Mesh *          aMesh)
1723 {
1724   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1725   if (!groups.empty()) {
1726     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1727     for ( ; grIt != groups.end(); grIt++ ) {
1728       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1729       if ( group && group->Contains( elemInGroups ))
1730         group->SMDSGroup().Add( elemToAdd );
1731     }
1732   }
1733 }
1734
1735
1736 //=======================================================================
1737 //function : RemoveElemFromGroups
1738 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1739 //=======================================================================
1740 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1741                                              SMESHDS_Mesh *          aMesh)
1742 {
1743   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1744   if (!groups.empty())
1745   {
1746     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1747     for (; GrIt != groups.end(); GrIt++)
1748     {
1749       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1750       if (!grp || grp->IsEmpty()) continue;
1751       grp->SMDSGroup().Remove(removeelem);
1752     }
1753   }
1754 }
1755
1756 //================================================================================
1757 /*!
1758  * \brief Replace elemToRm by elemToAdd in the all groups
1759  */
1760 //================================================================================
1761
1762 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1763                                             const SMDS_MeshElement* elemToAdd,
1764                                             SMESHDS_Mesh *          aMesh)
1765 {
1766   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1767   if (!groups.empty()) {
1768     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1769     for ( ; grIt != groups.end(); grIt++ ) {
1770       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1771       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1772         group->SMDSGroup().Add( elemToAdd );
1773     }
1774   }
1775 }
1776
1777 //================================================================================
1778 /*!
1779  * \brief Replace elemToRm by elemToAdd in the all groups
1780  */
1781 //================================================================================
1782
1783 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1784                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1785                                             SMESHDS_Mesh *                         aMesh)
1786 {
1787   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1788   if (!groups.empty())
1789   {
1790     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1791     for ( ; grIt != groups.end(); grIt++ ) {
1792       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1793       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1794         for ( int i = 0; i < elemToAdd.size(); ++i )
1795           group->SMDSGroup().Add( elemToAdd[ i ] );
1796     }
1797   }
1798 }
1799
1800 //=======================================================================
1801 //function : QuadToTri
1802 //purpose  : Cut quadrangles into triangles.
1803 //           theCrit is used to select a diagonal to cut
1804 //=======================================================================
1805
1806 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1807                                   const bool         the13Diag)
1808 {
1809   myLastCreatedElems.Clear();
1810   myLastCreatedNodes.Clear();
1811
1812   MESSAGE( "::QuadToTri()" );
1813
1814   SMESHDS_Mesh * aMesh = GetMeshDS();
1815
1816   Handle(Geom_Surface) surface;
1817   SMESH_MesherHelper   helper( *GetMesh() );
1818
1819   TIDSortedElemSet::iterator itElem;
1820   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1821     const SMDS_MeshElement* elem = *itElem;
1822     if ( !elem || elem->GetType() != SMDSAbs_Face )
1823       continue;
1824     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1825     if(!isquad) continue;
1826
1827     if(elem->NbNodes()==4) {
1828       // retrieve element nodes
1829       const SMDS_MeshNode* aNodes [4];
1830       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1831       int i = 0;
1832       while ( itN->more() )
1833         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1834
1835       int aShapeId = FindShape( elem );
1836       const SMDS_MeshElement* newElem = 0;
1837       if ( the13Diag ) {
1838         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1839         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1840       }
1841       else {
1842         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1843         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1844       }
1845       myLastCreatedElems.Append(newElem);
1846       // put a new triangle on the same shape and add to the same groups
1847       if ( aShapeId )
1848         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1849       AddToSameGroups( newElem, elem, aMesh );
1850     }
1851
1852     // Quadratic quadrangle
1853
1854     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1855
1856       // get surface elem is on
1857       int aShapeId = FindShape( elem );
1858       if ( aShapeId != helper.GetSubShapeID() ) {
1859         surface.Nullify();
1860         TopoDS_Shape shape;
1861         if ( aShapeId > 0 )
1862           shape = aMesh->IndexToShape( aShapeId );
1863         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1864           TopoDS_Face face = TopoDS::Face( shape );
1865           surface = BRep_Tool::Surface( face );
1866           if ( !surface.IsNull() )
1867             helper.SetSubShape( shape );
1868         }
1869       }
1870
1871       const SMDS_MeshNode* aNodes [8];
1872       const SMDS_MeshNode* inFaceNode = 0;
1873       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1874       int i = 0;
1875       while ( itN->more() ) {
1876         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1877         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1878              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1879         {
1880           inFaceNode = aNodes[ i-1 ];
1881         }
1882       }
1883
1884       // find middle point for (0,1,2,3)
1885       // and create a node in this point;
1886       gp_XYZ p( 0,0,0 );
1887       if ( surface.IsNull() ) {
1888         for(i=0; i<4; i++)
1889           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1890         p /= 4;
1891       }
1892       else {
1893         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1894         gp_XY uv( 0,0 );
1895         for(i=0; i<4; i++)
1896           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1897         uv /= 4.;
1898         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1899       }
1900       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1901       myLastCreatedNodes.Append(newN);
1902
1903       // create a new element
1904       const SMDS_MeshElement* newElem = 0;
1905       const SMDS_MeshNode* N[6];
1906       if ( the13Diag ) {
1907         N[0] = aNodes[0];
1908         N[1] = aNodes[1];
1909         N[2] = aNodes[2];
1910         N[3] = aNodes[4];
1911         N[4] = aNodes[5];
1912         N[5] = newN;
1913         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1914                                  aNodes[6], aNodes[7], newN );
1915       }
1916       else {
1917         N[0] = aNodes[1];
1918         N[1] = aNodes[2];
1919         N[2] = aNodes[3];
1920         N[3] = aNodes[5];
1921         N[4] = aNodes[6];
1922         N[5] = newN;
1923         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1924                                  aNodes[7], aNodes[4], newN );
1925       }
1926       myLastCreatedElems.Append(newElem);
1927       aMesh->ChangeElementNodes( elem, N, 6 );
1928       // put a new triangle on the same shape and add to the same groups
1929       if ( aShapeId )
1930         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1931       AddToSameGroups( newElem, elem, aMesh );
1932     }
1933   }
1934
1935   return true;
1936 }
1937
1938 //=======================================================================
1939 //function : getAngle
1940 //purpose  :
1941 //=======================================================================
1942
1943 double getAngle(const SMDS_MeshElement * tr1,
1944                 const SMDS_MeshElement * tr2,
1945                 const SMDS_MeshNode *    n1,
1946                 const SMDS_MeshNode *    n2)
1947 {
1948   double angle = 2*PI; // bad angle
1949
1950   // get normals
1951   SMESH::Controls::TSequenceOfXYZ P1, P2;
1952   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1953        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1954     return angle;
1955   gp_Vec N1,N2;
1956   if(!tr1->IsQuadratic())
1957     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1958   else
1959     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1960   if ( N1.SquareMagnitude() <= gp::Resolution() )
1961     return angle;
1962   if(!tr2->IsQuadratic())
1963     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1964   else
1965     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1966   if ( N2.SquareMagnitude() <= gp::Resolution() )
1967     return angle;
1968
1969   // find the first diagonal node n1 in the triangles:
1970   // take in account a diagonal link orientation
1971   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1972   for ( int t = 0; t < 2; t++ ) {
1973     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1974     int i = 0, iDiag = -1;
1975     while ( it->more()) {
1976       const SMDS_MeshElement *n = it->next();
1977       if ( n == n1 || n == n2 )
1978         if ( iDiag < 0)
1979           iDiag = i;
1980         else {
1981           if ( i - iDiag == 1 )
1982             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1983           else
1984             nFirst[ t ] = n;
1985           break;
1986         }
1987       i++;
1988     }
1989   }
1990   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1991     N2.Reverse();
1992
1993   angle = N1.Angle( N2 );
1994   //SCRUTE( angle );
1995   return angle;
1996 }
1997
1998 // =================================================
1999 // class generating a unique ID for a pair of nodes
2000 // and able to return nodes by that ID
2001 // =================================================
2002 class LinkID_Gen {
2003 public:
2004
2005   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2006     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2007   {}
2008
2009   long GetLinkID (const SMDS_MeshNode * n1,
2010                   const SMDS_MeshNode * n2) const
2011   {
2012     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2013   }
2014
2015   bool GetNodes (const long             theLinkID,
2016                  const SMDS_MeshNode* & theNode1,
2017                  const SMDS_MeshNode* & theNode2) const
2018   {
2019     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2020     if ( !theNode1 ) return false;
2021     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2022     if ( !theNode2 ) return false;
2023     return true;
2024   }
2025
2026 private:
2027   LinkID_Gen();
2028   const SMESHDS_Mesh* myMesh;
2029   long                myMaxID;
2030 };
2031
2032
2033 //=======================================================================
2034 //function : TriToQuad
2035 //purpose  : Fuse neighbour triangles into quadrangles.
2036 //           theCrit is used to select a neighbour to fuse with.
2037 //           theMaxAngle is a max angle between element normals at which
2038 //           fusion is still performed.
2039 //=======================================================================
2040
2041 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2042                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2043                                   const double                         theMaxAngle)
2044 {
2045   myLastCreatedElems.Clear();
2046   myLastCreatedNodes.Clear();
2047
2048   MESSAGE( "::TriToQuad()" );
2049
2050   if ( !theCrit.get() )
2051     return false;
2052
2053   SMESHDS_Mesh * aMesh = GetMeshDS();
2054
2055   // Prepare data for algo: build
2056   // 1. map of elements with their linkIDs
2057   // 2. map of linkIDs with their elements
2058
2059   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2060   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2061   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2062   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2063
2064   TIDSortedElemSet::iterator itElem;
2065   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2066     const SMDS_MeshElement* elem = *itElem;
2067     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2068     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2069     if(!IsTria) continue;
2070
2071     // retrieve element nodes
2072     const SMDS_MeshNode* aNodes [4];
2073     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2074     int i = 0;
2075     while ( i<3 )
2076       aNodes[ i++ ] = cast2Node( itN->next() );
2077     aNodes[ 3 ] = aNodes[ 0 ];
2078
2079     // fill maps
2080     for ( i = 0; i < 3; i++ ) {
2081       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2082       // check if elements sharing a link can be fused
2083       itLE = mapLi_listEl.find( link );
2084       if ( itLE != mapLi_listEl.end() ) {
2085         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2086           continue;
2087         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2088         //if ( FindShape( elem ) != FindShape( elem2 ))
2089         //  continue; // do not fuse triangles laying on different shapes
2090         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2091           continue; // avoid making badly shaped quads
2092         (*itLE).second.push_back( elem );
2093       }
2094       else {
2095         mapLi_listEl[ link ].push_back( elem );
2096       }
2097       mapEl_setLi [ elem ].insert( link );
2098     }
2099   }
2100   // Clean the maps from the links shared by a sole element, ie
2101   // links to which only one element is bound in mapLi_listEl
2102
2103   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2104     int nbElems = (*itLE).second.size();
2105     if ( nbElems < 2  ) {
2106       const SMDS_MeshElement* elem = (*itLE).second.front();
2107       SMESH_TLink link = (*itLE).first;
2108       mapEl_setLi[ elem ].erase( link );
2109       if ( mapEl_setLi[ elem ].empty() )
2110         mapEl_setLi.erase( elem );
2111     }
2112   }
2113
2114   // Algo: fuse triangles into quadrangles
2115
2116   while ( ! mapEl_setLi.empty() ) {
2117     // Look for the start element:
2118     // the element having the least nb of shared links
2119     const SMDS_MeshElement* startElem = 0;
2120     int minNbLinks = 4;
2121     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2122       int nbLinks = (*itEL).second.size();
2123       if ( nbLinks < minNbLinks ) {
2124         startElem = (*itEL).first;
2125         minNbLinks = nbLinks;
2126         if ( minNbLinks == 1 )
2127           break;
2128       }
2129     }
2130
2131     // search elements to fuse starting from startElem or links of elements
2132     // fused earlyer - startLinks
2133     list< SMESH_TLink > startLinks;
2134     while ( startElem || !startLinks.empty() ) {
2135       while ( !startElem && !startLinks.empty() ) {
2136         // Get an element to start, by a link
2137         SMESH_TLink linkId = startLinks.front();
2138         startLinks.pop_front();
2139         itLE = mapLi_listEl.find( linkId );
2140         if ( itLE != mapLi_listEl.end() ) {
2141           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2142           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2143           for ( ; itE != listElem.end() ; itE++ )
2144             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2145               startElem = (*itE);
2146           mapLi_listEl.erase( itLE );
2147         }
2148       }
2149
2150       if ( startElem ) {
2151         // Get candidates to be fused
2152         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2153         const SMESH_TLink *link12, *link13;
2154         startElem = 0;
2155         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2156         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2157         ASSERT( !setLi.empty() );
2158         set< SMESH_TLink >::iterator itLi;
2159         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2160         {
2161           const SMESH_TLink & link = (*itLi);
2162           itLE = mapLi_listEl.find( link );
2163           if ( itLE == mapLi_listEl.end() )
2164             continue;
2165
2166           const SMDS_MeshElement* elem = (*itLE).second.front();
2167           if ( elem == tr1 )
2168             elem = (*itLE).second.back();
2169           mapLi_listEl.erase( itLE );
2170           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2171             continue;
2172           if ( tr2 ) {
2173             tr3 = elem;
2174             link13 = &link;
2175           }
2176           else {
2177             tr2 = elem;
2178             link12 = &link;
2179           }
2180
2181           // add other links of elem to list of links to re-start from
2182           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2183           set< SMESH_TLink >::iterator it;
2184           for ( it = links.begin(); it != links.end(); it++ ) {
2185             const SMESH_TLink& link2 = (*it);
2186             if ( link2 != link )
2187               startLinks.push_back( link2 );
2188           }
2189         }
2190
2191         // Get nodes of possible quadrangles
2192         const SMDS_MeshNode *n12 [4], *n13 [4];
2193         bool Ok12 = false, Ok13 = false;
2194         const SMDS_MeshNode *linkNode1, *linkNode2;
2195         if(tr2) {
2196           linkNode1 = link12->first;
2197           linkNode2 = link12->second;
2198           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2199             Ok12 = true;
2200         }
2201         if(tr3) {
2202           linkNode1 = link13->first;
2203           linkNode2 = link13->second;
2204           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2205             Ok13 = true;
2206         }
2207
2208         // Choose a pair to fuse
2209         if ( Ok12 && Ok13 ) {
2210           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2211           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2212           double aBadRate12 = getBadRate( &quad12, theCrit );
2213           double aBadRate13 = getBadRate( &quad13, theCrit );
2214           if (  aBadRate13 < aBadRate12 )
2215             Ok12 = false;
2216           else
2217             Ok13 = false;
2218         }
2219
2220         // Make quadrangles
2221         // and remove fused elems and removed links from the maps
2222         mapEl_setLi.erase( tr1 );
2223         if ( Ok12 ) {
2224           mapEl_setLi.erase( tr2 );
2225           mapLi_listEl.erase( *link12 );
2226           if(tr1->NbNodes()==3) {
2227             if( tr1->GetID() < tr2->GetID() ) {
2228               aMesh->ChangeElementNodes( tr1, n12, 4 );
2229               myLastCreatedElems.Append(tr1);
2230               aMesh->RemoveElement( tr2 );
2231             }
2232             else {
2233               aMesh->ChangeElementNodes( tr2, n12, 4 );
2234               myLastCreatedElems.Append(tr2);
2235               aMesh->RemoveElement( tr1);
2236             }
2237           }
2238           else {
2239             const SMDS_MeshNode* N1 [6];
2240             const SMDS_MeshNode* N2 [6];
2241             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2242             // now we receive following N1 and N2 (using numeration as above image)
2243             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2244             // i.e. first nodes from both arrays determ new diagonal
2245             const SMDS_MeshNode* aNodes[8];
2246             aNodes[0] = N1[0];
2247             aNodes[1] = N1[1];
2248             aNodes[2] = N2[0];
2249             aNodes[3] = N2[1];
2250             aNodes[4] = N1[3];
2251             aNodes[5] = N2[5];
2252             aNodes[6] = N2[3];
2253             aNodes[7] = N1[5];
2254             if( tr1->GetID() < tr2->GetID() ) {
2255               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2256               myLastCreatedElems.Append(tr1);
2257               GetMeshDS()->RemoveElement( tr2 );
2258             }
2259             else {
2260               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2261               myLastCreatedElems.Append(tr2);
2262               GetMeshDS()->RemoveElement( tr1 );
2263             }
2264             // remove middle node (9)
2265             GetMeshDS()->RemoveNode( N1[4] );
2266           }
2267         }
2268         else if ( Ok13 ) {
2269           mapEl_setLi.erase( tr3 );
2270           mapLi_listEl.erase( *link13 );
2271           if(tr1->NbNodes()==3) {
2272             if( tr1->GetID() < tr2->GetID() ) {
2273               aMesh->ChangeElementNodes( tr1, n13, 4 );
2274               myLastCreatedElems.Append(tr1);
2275               aMesh->RemoveElement( tr3 );
2276             }
2277             else {
2278               aMesh->ChangeElementNodes( tr3, n13, 4 );
2279               myLastCreatedElems.Append(tr3);
2280               aMesh->RemoveElement( tr1 );
2281             }
2282           }
2283           else {
2284             const SMDS_MeshNode* N1 [6];
2285             const SMDS_MeshNode* N2 [6];
2286             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2287             // now we receive following N1 and N2 (using numeration as above image)
2288             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2289             // i.e. first nodes from both arrays determ new diagonal
2290             const SMDS_MeshNode* aNodes[8];
2291             aNodes[0] = N1[0];
2292             aNodes[1] = N1[1];
2293             aNodes[2] = N2[0];
2294             aNodes[3] = N2[1];
2295             aNodes[4] = N1[3];
2296             aNodes[5] = N2[5];
2297             aNodes[6] = N2[3];
2298             aNodes[7] = N1[5];
2299             if( tr1->GetID() < tr2->GetID() ) {
2300               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2301               myLastCreatedElems.Append(tr1);
2302               GetMeshDS()->RemoveElement( tr3 );
2303             }
2304             else {
2305               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2306               myLastCreatedElems.Append(tr3);
2307               GetMeshDS()->RemoveElement( tr1 );
2308             }
2309             // remove middle node (9)
2310             GetMeshDS()->RemoveNode( N1[4] );
2311           }
2312         }
2313
2314         // Next element to fuse: the rejected one
2315         if ( tr3 )
2316           startElem = Ok12 ? tr3 : tr2;
2317
2318       } // if ( startElem )
2319     } // while ( startElem || !startLinks.empty() )
2320   } // while ( ! mapEl_setLi.empty() )
2321
2322   return true;
2323 }
2324
2325
2326 /*#define DUMPSO(txt) \
2327 //  cout << txt << endl;
2328 //=============================================================================
2329 //
2330 //
2331 //
2332 //=============================================================================
2333 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2334 {
2335 if ( i1 == i2 )
2336 return;
2337 int tmp = idNodes[ i1 ];
2338 idNodes[ i1 ] = idNodes[ i2 ];
2339 idNodes[ i2 ] = tmp;
2340 gp_Pnt Ptmp = P[ i1 ];
2341 P[ i1 ] = P[ i2 ];
2342 P[ i2 ] = Ptmp;
2343 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2344 }
2345
2346 //=======================================================================
2347 //function : SortQuadNodes
2348 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2349 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2350 //           1 or 2 else 0.
2351 //=======================================================================
2352
2353 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2354 int               idNodes[] )
2355 {
2356   gp_Pnt P[4];
2357   int i;
2358   for ( i = 0; i < 4; i++ ) {
2359     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2360     if ( !n ) return 0;
2361     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2362   }
2363
2364   gp_Vec V1(P[0], P[1]);
2365   gp_Vec V2(P[0], P[2]);
2366   gp_Vec V3(P[0], P[3]);
2367
2368   gp_Vec Cross1 = V1 ^ V2;
2369   gp_Vec Cross2 = V2 ^ V3;
2370
2371   i = 0;
2372   if (Cross1.Dot(Cross2) < 0)
2373   {
2374     Cross1 = V2 ^ V1;
2375     Cross2 = V1 ^ V3;
2376
2377     if (Cross1.Dot(Cross2) < 0)
2378       i = 2;
2379     else
2380       i = 1;
2381     swap ( i, i + 1, idNodes, P );
2382
2383     //     for ( int ii = 0; ii < 4; ii++ ) {
2384     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2385     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2386     //     }
2387   }
2388   return i;
2389 }
2390
2391 //=======================================================================
2392 //function : SortHexaNodes
2393 //purpose  : Set 8 nodes of a hexahedron in a good order.
2394 //           Return success status
2395 //=======================================================================
2396
2397 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2398                                       int               idNodes[] )
2399 {
2400   gp_Pnt P[8];
2401   int i;
2402   DUMPSO( "INPUT: ========================================");
2403   for ( i = 0; i < 8; i++ ) {
2404     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2405     if ( !n ) return false;
2406     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2407     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2408   }
2409   DUMPSO( "========================================");
2410
2411
2412   set<int> faceNodes;  // ids of bottom face nodes, to be found
2413   set<int> checkedId1; // ids of tried 2-nd nodes
2414   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2415   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2416   int iMin, iLoop1 = 0;
2417
2418   // Loop to try the 2-nd nodes
2419
2420   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2421   {
2422     // Find not checked 2-nd node
2423     for ( i = 1; i < 8; i++ )
2424       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2425         int id1 = idNodes[i];
2426         swap ( 1, i, idNodes, P );
2427         checkedId1.insert ( id1 );
2428         break;
2429       }
2430
2431     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2432     // ie that all but meybe one (id3 which is on the same face) nodes
2433     // lay on the same side from the triangle plane.
2434
2435     bool manyInPlane = false; // more than 4 nodes lay in plane
2436     int iLoop2 = 0;
2437     while ( ++iLoop2 < 6 ) {
2438
2439       // get 1-2-3 plane coeffs
2440       Standard_Real A, B, C, D;
2441       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2442       if ( N.SquareMagnitude() > gp::Resolution() )
2443       {
2444         gp_Pln pln ( P[0], N );
2445         pln.Coefficients( A, B, C, D );
2446
2447         // find the node (iMin) closest to pln
2448         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2449         set<int> idInPln;
2450         for ( i = 3; i < 8; i++ ) {
2451           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2452           if ( fabs( dist[i] ) < minDist ) {
2453             minDist = fabs( dist[i] );
2454             iMin = i;
2455           }
2456           if ( fabs( dist[i] ) <= tol )
2457             idInPln.insert( idNodes[i] );
2458         }
2459
2460         // there should not be more than 4 nodes in bottom plane
2461         if ( idInPln.size() > 1 )
2462         {
2463           DUMPSO( "### idInPln.size() = " << idInPln.size());
2464           // idInPlane does not contain the first 3 nodes
2465           if ( manyInPlane || idInPln.size() == 5)
2466             return false; // all nodes in one plane
2467           manyInPlane = true;
2468
2469           // set the 1-st node to be not in plane
2470           for ( i = 3; i < 8; i++ ) {
2471             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2472               DUMPSO( "### Reset 0-th node");
2473               swap( 0, i, idNodes, P );
2474               break;
2475             }
2476           }
2477
2478           // reset to re-check second nodes
2479           leastDist = DBL_MAX;
2480           faceNodes.clear();
2481           checkedId1.clear();
2482           iLoop1 = 0;
2483           break; // from iLoop2;
2484         }
2485
2486         // check that the other 4 nodes are on the same side
2487         bool sameSide = true;
2488         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2489         for ( i = 3; sameSide && i < 8; i++ ) {
2490           if ( i != iMin )
2491             sameSide = ( isNeg == dist[i] <= 0.);
2492         }
2493
2494         // keep best solution
2495         if ( sameSide && minDist < leastDist ) {
2496           leastDist = minDist;
2497           faceNodes.clear();
2498           faceNodes.insert( idNodes[ 1 ] );
2499           faceNodes.insert( idNodes[ 2 ] );
2500           faceNodes.insert( idNodes[ iMin ] );
2501           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2502                   << " leastDist = " << leastDist);
2503           if ( leastDist <= DBL_MIN )
2504             break;
2505         }
2506       }
2507
2508       // set next 3-d node to check
2509       int iNext = 2 + iLoop2;
2510       if ( iNext < 8 ) {
2511         DUMPSO( "Try 2-nd");
2512         swap ( 2, iNext, idNodes, P );
2513       }
2514     } // while ( iLoop2 < 6 )
2515   } // iLoop1
2516
2517   if ( faceNodes.empty() ) return false;
2518
2519   // Put the faceNodes in proper places
2520   for ( i = 4; i < 8; i++ ) {
2521     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2522       // find a place to put
2523       int iTo = 1;
2524       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2525         iTo++;
2526       DUMPSO( "Set faceNodes");
2527       swap ( iTo, i, idNodes, P );
2528     }
2529   }
2530
2531
2532   // Set nodes of the found bottom face in good order
2533   DUMPSO( " Found bottom face: ");
2534   i = SortQuadNodes( theMesh, idNodes );
2535   if ( i ) {
2536     gp_Pnt Ptmp = P[ i ];
2537     P[ i ] = P[ i+1 ];
2538     P[ i+1 ] = Ptmp;
2539   }
2540   //   else
2541   //     for ( int ii = 0; ii < 4; ii++ ) {
2542   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2543   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2544   //    }
2545
2546   // Gravity center of the top and bottom faces
2547   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2548   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2549
2550   // Get direction from the bottom to the top face
2551   gp_Vec upDir ( aGCb, aGCt );
2552   Standard_Real upDirSize = upDir.Magnitude();
2553   if ( upDirSize <= gp::Resolution() ) return false;
2554   upDir / upDirSize;
2555
2556   // Assure that the bottom face normal points up
2557   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2558   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2559   if ( Nb.Dot( upDir ) < 0 ) {
2560     DUMPSO( "Reverse bottom face");
2561     swap( 1, 3, idNodes, P );
2562   }
2563
2564   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2565   Standard_Real minDist = DBL_MAX;
2566   for ( i = 4; i < 8; i++ ) {
2567     // projection of P[i] to the plane defined by P[0] and upDir
2568     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2569     Standard_Real sqDist = P[0].SquareDistance( Pp );
2570     if ( sqDist < minDist ) {
2571       minDist = sqDist;
2572       iMin = i;
2573     }
2574   }
2575   DUMPSO( "Set 4-th");
2576   swap ( 4, iMin, idNodes, P );
2577
2578   // Set nodes of the top face in good order
2579   DUMPSO( "Sort top face");
2580   i = SortQuadNodes( theMesh, &idNodes[4] );
2581   if ( i ) {
2582     i += 4;
2583     gp_Pnt Ptmp = P[ i ];
2584     P[ i ] = P[ i+1 ];
2585     P[ i+1 ] = Ptmp;
2586   }
2587
2588   // Assure that direction of the top face normal is from the bottom face
2589   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2590   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2591   if ( Nt.Dot( upDir ) < 0 ) {
2592     DUMPSO( "Reverse top face");
2593     swap( 5, 7, idNodes, P );
2594   }
2595
2596   //   DUMPSO( "OUTPUT: ========================================");
2597   //   for ( i = 0; i < 8; i++ ) {
2598   //     float *p = ugrid->GetPoint(idNodes[i]);
2599   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2600   //   }
2601
2602   return true;
2603 }*/
2604
2605 //================================================================================
2606 /*!
2607  * \brief Return nodes linked to the given one
2608  * \param theNode - the node
2609  * \param linkedNodes - the found nodes
2610  * \param type - the type of elements to check
2611  *
2612  * Medium nodes are ignored
2613  */
2614 //================================================================================
2615
2616 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2617                                        TIDSortedElemSet &   linkedNodes,
2618                                        SMDSAbs_ElementType  type )
2619 {
2620   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2621   while ( elemIt->more() )
2622   {
2623     const SMDS_MeshElement* elem = elemIt->next();
2624     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2625     if ( elem->GetType() == SMDSAbs_Volume )
2626     {
2627       SMDS_VolumeTool vol( elem );
2628       while ( nodeIt->more() ) {
2629         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2630         if ( theNode != n && vol.IsLinked( theNode, n ))
2631           linkedNodes.insert( n );
2632       }
2633     }
2634     else
2635     {
2636       for ( int i = 0; nodeIt->more(); ++i ) {
2637         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2638         if ( n == theNode ) {
2639           int iBefore = i - 1;
2640           int iAfter  = i + 1;
2641           if ( elem->IsQuadratic() ) {
2642             int nb = elem->NbNodes() / 2;
2643             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2644             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2645           }
2646           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2647           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2648         }
2649       }
2650     }
2651   }
2652 }
2653
2654 //=======================================================================
2655 //function : laplacianSmooth
2656 //purpose  : pulls theNode toward the center of surrounding nodes directly
2657 //           connected to that node along an element edge
2658 //=======================================================================
2659
2660 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2661                      const Handle(Geom_Surface)&          theSurface,
2662                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2663 {
2664   // find surrounding nodes
2665
2666   TIDSortedElemSet nodeSet;
2667   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2668
2669   // compute new coodrs
2670
2671   double coord[] = { 0., 0., 0. };
2672   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2673   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2674     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2675     if ( theSurface.IsNull() ) { // smooth in 3D
2676       coord[0] += node->X();
2677       coord[1] += node->Y();
2678       coord[2] += node->Z();
2679     }
2680     else { // smooth in 2D
2681       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2682       gp_XY* uv = theUVMap[ node ];
2683       coord[0] += uv->X();
2684       coord[1] += uv->Y();
2685     }
2686   }
2687   int nbNodes = nodeSet.size();
2688   if ( !nbNodes )
2689     return;
2690   coord[0] /= nbNodes;
2691   coord[1] /= nbNodes;
2692
2693   if ( !theSurface.IsNull() ) {
2694     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2695     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2696     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2697     coord[0] = p3d.X();
2698     coord[1] = p3d.Y();
2699     coord[2] = p3d.Z();
2700   }
2701   else
2702     coord[2] /= nbNodes;
2703
2704   // move node
2705
2706   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2707 }
2708
2709 //=======================================================================
2710 //function : centroidalSmooth
2711 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2712 //           surrounding elements
2713 //=======================================================================
2714
2715 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2716                       const Handle(Geom_Surface)&          theSurface,
2717                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2718 {
2719   gp_XYZ aNewXYZ(0.,0.,0.);
2720   SMESH::Controls::Area anAreaFunc;
2721   double totalArea = 0.;
2722   int nbElems = 0;
2723
2724   // compute new XYZ
2725
2726   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2727   while ( elemIt->more() )
2728   {
2729     const SMDS_MeshElement* elem = elemIt->next();
2730     nbElems++;
2731
2732     gp_XYZ elemCenter(0.,0.,0.);
2733     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2734     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2735     int nn = elem->NbNodes();
2736     if(elem->IsQuadratic()) nn = nn/2;
2737     int i=0;
2738     //while ( itN->more() ) {
2739     while ( i<nn ) {
2740       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2741       i++;
2742       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2743       aNodePoints.push_back( aP );
2744       if ( !theSurface.IsNull() ) { // smooth in 2D
2745         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2746         gp_XY* uv = theUVMap[ aNode ];
2747         aP.SetCoord( uv->X(), uv->Y(), 0. );
2748       }
2749       elemCenter += aP;
2750     }
2751     double elemArea = anAreaFunc.GetValue( aNodePoints );
2752     totalArea += elemArea;
2753     elemCenter /= nn;
2754     aNewXYZ += elemCenter * elemArea;
2755   }
2756   aNewXYZ /= totalArea;
2757   if ( !theSurface.IsNull() ) {
2758     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2759     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2760   }
2761
2762   // move node
2763
2764   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2765 }
2766
2767 //=======================================================================
2768 //function : getClosestUV
2769 //purpose  : return UV of closest projection
2770 //=======================================================================
2771
2772 static bool getClosestUV (Extrema_GenExtPS& projector,
2773                           const gp_Pnt&     point,
2774                           gp_XY &           result)
2775 {
2776   projector.Perform( point );
2777   if ( projector.IsDone() ) {
2778     double u, v, minVal = DBL_MAX;
2779     for ( int i = projector.NbExt(); i > 0; i-- )
2780       if ( projector.Value( i ) < minVal ) {
2781         minVal = projector.Value( i );
2782         projector.Point( i ).Parameter( u, v );
2783       }
2784     result.SetCoord( u, v );
2785     return true;
2786   }
2787   return false;
2788 }
2789
2790 //=======================================================================
2791 //function : Smooth
2792 //purpose  : Smooth theElements during theNbIterations or until a worst
2793 //           element has aspect ratio <= theTgtAspectRatio.
2794 //           Aspect Ratio varies in range [1.0, inf].
2795 //           If theElements is empty, the whole mesh is smoothed.
2796 //           theFixedNodes contains additionally fixed nodes. Nodes built
2797 //           on edges and boundary nodes are always fixed.
2798 //=======================================================================
2799
2800 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2801                                set<const SMDS_MeshNode*> & theFixedNodes,
2802                                const SmoothMethod          theSmoothMethod,
2803                                const int                   theNbIterations,
2804                                double                      theTgtAspectRatio,
2805                                const bool                  the2D)
2806 {
2807   myLastCreatedElems.Clear();
2808   myLastCreatedNodes.Clear();
2809
2810   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2811
2812   if ( theTgtAspectRatio < 1.0 )
2813     theTgtAspectRatio = 1.0;
2814
2815   const double disttol = 1.e-16;
2816
2817   SMESH::Controls::AspectRatio aQualityFunc;
2818
2819   SMESHDS_Mesh* aMesh = GetMeshDS();
2820
2821   if ( theElems.empty() ) {
2822     // add all faces to theElems
2823     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2824     while ( fIt->more() ) {
2825       const SMDS_MeshElement* face = fIt->next();
2826       theElems.insert( face );
2827     }
2828   }
2829   // get all face ids theElems are on
2830   set< int > faceIdSet;
2831   TIDSortedElemSet::iterator itElem;
2832   if ( the2D )
2833     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2834       int fId = FindShape( *itElem );
2835       // check that corresponding submesh exists and a shape is face
2836       if (fId &&
2837           faceIdSet.find( fId ) == faceIdSet.end() &&
2838           aMesh->MeshElements( fId )) {
2839         TopoDS_Shape F = aMesh->IndexToShape( fId );
2840         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2841           faceIdSet.insert( fId );
2842       }
2843     }
2844   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2845
2846   // ===============================================
2847   // smooth elements on each TopoDS_Face separately
2848   // ===============================================
2849
2850   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2851   for ( ; fId != faceIdSet.rend(); ++fId ) {
2852     // get face surface and submesh
2853     Handle(Geom_Surface) surface;
2854     SMESHDS_SubMesh* faceSubMesh = 0;
2855     TopoDS_Face face;
2856     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2857     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2858     bool isUPeriodic = false, isVPeriodic = false;
2859     if ( *fId ) {
2860       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2861       surface = BRep_Tool::Surface( face );
2862       faceSubMesh = aMesh->MeshElements( *fId );
2863       fToler2 = BRep_Tool::Tolerance( face );
2864       fToler2 *= fToler2 * 10.;
2865       isUPeriodic = surface->IsUPeriodic();
2866       if ( isUPeriodic )
2867         vPeriod = surface->UPeriod();
2868       isVPeriodic = surface->IsVPeriodic();
2869       if ( isVPeriodic )
2870         uPeriod = surface->VPeriod();
2871       surface->Bounds( u1, u2, v1, v2 );
2872     }
2873     // ---------------------------------------------------------
2874     // for elements on a face, find movable and fixed nodes and
2875     // compute UV for them
2876     // ---------------------------------------------------------
2877     bool checkBoundaryNodes = false;
2878     bool isQuadratic = false;
2879     set<const SMDS_MeshNode*> setMovableNodes;
2880     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2881     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2882     list< const SMDS_MeshElement* > elemsOnFace;
2883
2884     Extrema_GenExtPS projector;
2885     GeomAdaptor_Surface surfAdaptor;
2886     if ( !surface.IsNull() ) {
2887       surfAdaptor.Load( surface );
2888       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2889     }
2890     int nbElemOnFace = 0;
2891     itElem = theElems.begin();
2892     // loop on not yet smoothed elements: look for elems on a face
2893     while ( itElem != theElems.end() ) {
2894       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2895         break; // all elements found
2896
2897       const SMDS_MeshElement* elem = *itElem;
2898       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2899            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2900         ++itElem;
2901         continue;
2902       }
2903       elemsOnFace.push_back( elem );
2904       theElems.erase( itElem++ );
2905       nbElemOnFace++;
2906
2907       if ( !isQuadratic )
2908         isQuadratic = elem->IsQuadratic();
2909
2910       // get movable nodes of elem
2911       const SMDS_MeshNode* node;
2912       SMDS_TypeOfPosition posType;
2913       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2914       int nn = 0, nbn =  elem->NbNodes();
2915       if(elem->IsQuadratic())
2916         nbn = nbn/2;
2917       while ( nn++ < nbn ) {
2918         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2919         const SMDS_PositionPtr& pos = node->GetPosition();
2920         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2921         if (posType != SMDS_TOP_EDGE &&
2922             posType != SMDS_TOP_VERTEX &&
2923             theFixedNodes.find( node ) == theFixedNodes.end())
2924         {
2925           // check if all faces around the node are on faceSubMesh
2926           // because a node on edge may be bound to face
2927           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2928           bool all = true;
2929           if ( faceSubMesh ) {
2930             while ( eIt->more() && all ) {
2931               const SMDS_MeshElement* e = eIt->next();
2932               all = faceSubMesh->Contains( e );
2933             }
2934           }
2935           if ( all )
2936             setMovableNodes.insert( node );
2937           else
2938             checkBoundaryNodes = true;
2939         }
2940         if ( posType == SMDS_TOP_3DSPACE )
2941           checkBoundaryNodes = true;
2942       }
2943
2944       if ( surface.IsNull() )
2945         continue;
2946
2947       // get nodes to check UV
2948       list< const SMDS_MeshNode* > uvCheckNodes;
2949       itN = elem->nodesIterator();
2950       nn = 0; nbn =  elem->NbNodes();
2951       if(elem->IsQuadratic())
2952         nbn = nbn/2;
2953       while ( nn++ < nbn ) {
2954         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2955         if ( uvMap.find( node ) == uvMap.end() )
2956           uvCheckNodes.push_back( node );
2957         // add nodes of elems sharing node
2958         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2959         //         while ( eIt->more() ) {
2960         //           const SMDS_MeshElement* e = eIt->next();
2961         //           if ( e != elem ) {
2962         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2963         //             while ( nIt->more() ) {
2964         //               const SMDS_MeshNode* n =
2965         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2966         //               if ( uvMap.find( n ) == uvMap.end() )
2967         //                 uvCheckNodes.push_back( n );
2968         //             }
2969         //           }
2970         //         }
2971       }
2972       // check UV on face
2973       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2974       for ( ; n != uvCheckNodes.end(); ++n ) {
2975         node = *n;
2976         gp_XY uv( 0, 0 );
2977         const SMDS_PositionPtr& pos = node->GetPosition();
2978         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2979         // get existing UV
2980         switch ( posType ) {
2981         case SMDS_TOP_FACE: {
2982           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2983           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2984           break;
2985         }
2986         case SMDS_TOP_EDGE: {
2987           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2988           Handle(Geom2d_Curve) pcurve;
2989           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2990             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2991           if ( !pcurve.IsNull() ) {
2992             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2993             uv = pcurve->Value( u ).XY();
2994           }
2995           break;
2996         }
2997         case SMDS_TOP_VERTEX: {
2998           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2999           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3000             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3001           break;
3002         }
3003         default:;
3004         }
3005         // check existing UV
3006         bool project = true;
3007         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3008         double dist1 = DBL_MAX, dist2 = 0;
3009         if ( posType != SMDS_TOP_3DSPACE ) {
3010           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3011           project = dist1 > fToler2;
3012         }
3013         if ( project ) { // compute new UV
3014           gp_XY newUV;
3015           if ( !getClosestUV( projector, pNode, newUV )) {
3016             MESSAGE("Node Projection Failed " << node);
3017           }
3018           else {
3019             if ( isUPeriodic )
3020               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3021             if ( isVPeriodic )
3022               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3023             // check new UV
3024             if ( posType != SMDS_TOP_3DSPACE )
3025               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3026             if ( dist2 < dist1 )
3027               uv = newUV;
3028           }
3029         }
3030         // store UV in the map
3031         listUV.push_back( uv );
3032         uvMap.insert( make_pair( node, &listUV.back() ));
3033       }
3034     } // loop on not yet smoothed elements
3035
3036     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3037       checkBoundaryNodes = true;
3038
3039     // fix nodes on mesh boundary
3040
3041     if ( checkBoundaryNodes ) {
3042       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3043       map< NLink, int >::iterator link_nb;
3044       // put all elements links to linkNbMap
3045       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3046       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3047         const SMDS_MeshElement* elem = (*elemIt);
3048         int nbn =  elem->NbNodes();
3049         if(elem->IsQuadratic())
3050           nbn = nbn/2;
3051         // loop on elem links: insert them in linkNbMap
3052         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3053         for ( int iN = 0; iN < nbn; ++iN ) {
3054           curNode = elem->GetNode( iN );
3055           NLink link;
3056           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3057           else                      link = make_pair( prevNode , curNode );
3058           prevNode = curNode;
3059           link_nb = linkNbMap.find( link );
3060           if ( link_nb == linkNbMap.end() )
3061             linkNbMap.insert( make_pair ( link, 1 ));
3062           else
3063             link_nb->second++;
3064         }
3065       }
3066       // remove nodes that are in links encountered only once from setMovableNodes
3067       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3068         if ( link_nb->second == 1 ) {
3069           setMovableNodes.erase( link_nb->first.first );
3070           setMovableNodes.erase( link_nb->first.second );
3071         }
3072       }
3073     }
3074
3075     // -----------------------------------------------------
3076     // for nodes on seam edge, compute one more UV ( uvMap2 );
3077     // find movable nodes linked to nodes on seam and which
3078     // are to be smoothed using the second UV ( uvMap2 )
3079     // -----------------------------------------------------
3080
3081     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3082     if ( !surface.IsNull() ) {
3083       TopExp_Explorer eExp( face, TopAbs_EDGE );
3084       for ( ; eExp.More(); eExp.Next() ) {
3085         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3086         if ( !BRep_Tool::IsClosed( edge, face ))
3087           continue;
3088         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3089         if ( !sm ) continue;
3090         // find out which parameter varies for a node on seam
3091         double f,l;
3092         gp_Pnt2d uv1, uv2;
3093         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3094         if ( pcurve.IsNull() ) continue;
3095         uv1 = pcurve->Value( f );
3096         edge.Reverse();
3097         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3098         if ( pcurve.IsNull() ) continue;
3099         uv2 = pcurve->Value( f );
3100         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3101         // assure uv1 < uv2
3102         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3103           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3104         }
3105         // get nodes on seam and its vertices
3106         list< const SMDS_MeshNode* > seamNodes;
3107         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3108         while ( nSeamIt->more() ) {
3109           const SMDS_MeshNode* node = nSeamIt->next();
3110           if ( !isQuadratic || !IsMedium( node ))
3111             seamNodes.push_back( node );
3112         }
3113         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3114         for ( ; vExp.More(); vExp.Next() ) {
3115           sm = aMesh->MeshElements( vExp.Current() );
3116           if ( sm ) {
3117             nSeamIt = sm->GetNodes();
3118             while ( nSeamIt->more() )
3119               seamNodes.push_back( nSeamIt->next() );
3120           }
3121         }
3122         // loop on nodes on seam
3123         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3124         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3125           const SMDS_MeshNode* nSeam = *noSeIt;
3126           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3127           if ( n_uv == uvMap.end() )
3128             continue;
3129           // set the first UV
3130           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3131           // set the second UV
3132           listUV.push_back( *n_uv->second );
3133           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3134           if ( uvMap2.empty() )
3135             uvMap2 = uvMap; // copy the uvMap contents
3136           uvMap2[ nSeam ] = &listUV.back();
3137
3138           // collect movable nodes linked to ones on seam in nodesNearSeam
3139           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3140           while ( eIt->more() ) {
3141             const SMDS_MeshElement* e = eIt->next();
3142             int nbUseMap1 = 0, nbUseMap2 = 0;
3143             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3144             int nn = 0, nbn =  e->NbNodes();
3145             if(e->IsQuadratic()) nbn = nbn/2;
3146             while ( nn++ < nbn )
3147             {
3148               const SMDS_MeshNode* n =
3149                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3150               if (n == nSeam ||
3151                   setMovableNodes.find( n ) == setMovableNodes.end() )
3152                 continue;
3153               // add only nodes being closer to uv2 than to uv1
3154               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3155                            0.5 * ( n->Y() + nSeam->Y() ),
3156                            0.5 * ( n->Z() + nSeam->Z() ));
3157               gp_XY uv;
3158               getClosestUV( projector, pMid, uv );
3159               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3160                 nodesNearSeam.insert( n );
3161                 nbUseMap2++;
3162               }
3163               else
3164                 nbUseMap1++;
3165             }
3166             // for centroidalSmooth all element nodes must
3167             // be on one side of a seam
3168             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3169               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3170               nn = 0;
3171               while ( nn++ < nbn ) {
3172                 const SMDS_MeshNode* n =
3173                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3174                 setMovableNodes.erase( n );
3175               }
3176             }
3177           }
3178         } // loop on nodes on seam
3179       } // loop on edge of a face
3180     } // if ( !face.IsNull() )
3181
3182     if ( setMovableNodes.empty() ) {
3183       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3184       continue; // goto next face
3185     }
3186
3187     // -------------
3188     // SMOOTHING //
3189     // -------------
3190
3191     int it = -1;
3192     double maxRatio = -1., maxDisplacement = -1.;
3193     set<const SMDS_MeshNode*>::iterator nodeToMove;
3194     for ( it = 0; it < theNbIterations; it++ ) {
3195       maxDisplacement = 0.;
3196       nodeToMove = setMovableNodes.begin();
3197       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3198         const SMDS_MeshNode* node = (*nodeToMove);
3199         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3200
3201         // smooth
3202         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3203         if ( theSmoothMethod == LAPLACIAN )
3204           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3205         else
3206           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3207
3208         // node displacement
3209         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3210         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3211         if ( aDispl > maxDisplacement )
3212           maxDisplacement = aDispl;
3213       }
3214       // no node movement => exit
3215       //if ( maxDisplacement < 1.e-16 ) {
3216       if ( maxDisplacement < disttol ) {
3217         MESSAGE("-- no node movement --");
3218         break;
3219       }
3220
3221       // check elements quality
3222       maxRatio  = 0;
3223       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3224       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3225         const SMDS_MeshElement* elem = (*elemIt);
3226         if ( !elem || elem->GetType() != SMDSAbs_Face )
3227           continue;
3228         SMESH::Controls::TSequenceOfXYZ aPoints;
3229         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3230           double aValue = aQualityFunc.GetValue( aPoints );
3231           if ( aValue > maxRatio )
3232             maxRatio = aValue;
3233         }
3234       }
3235       if ( maxRatio <= theTgtAspectRatio ) {
3236         MESSAGE("-- quality achived --");
3237         break;
3238       }
3239       if (it+1 == theNbIterations) {
3240         MESSAGE("-- Iteration limit exceeded --");
3241       }
3242     } // smoothing iterations
3243
3244     MESSAGE(" Face id: " << *fId <<
3245             " Nb iterstions: " << it <<
3246             " Displacement: " << maxDisplacement <<
3247             " Aspect Ratio " << maxRatio);
3248
3249     // ---------------------------------------
3250     // new nodes positions are computed,
3251     // record movement in DS and set new UV
3252     // ---------------------------------------
3253     nodeToMove = setMovableNodes.begin();
3254     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3255       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3256       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3257       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3258       if ( node_uv != uvMap.end() ) {
3259         gp_XY* uv = node_uv->second;
3260         node->SetPosition
3261           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3262       }
3263     }
3264
3265     // move medium nodes of quadratic elements
3266     if ( isQuadratic )
3267     {
3268       SMESH_MesherHelper helper( *GetMesh() );
3269       if ( !face.IsNull() )
3270         helper.SetSubShape( face );
3271       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3272       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3273         const SMDS_QuadraticFaceOfNodes* QF =
3274           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3275         if(QF) {
3276           vector<const SMDS_MeshNode*> Ns;
3277           Ns.reserve(QF->NbNodes()+1);
3278           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3279           while ( anIter->more() )
3280             Ns.push_back( anIter->next() );
3281           Ns.push_back( Ns[0] );
3282           double x, y, z;
3283           for(int i=0; i<QF->NbNodes(); i=i+2) {
3284             if ( !surface.IsNull() ) {
3285               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3286               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3287               gp_XY uv = ( uv1 + uv2 ) / 2.;
3288               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3289               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3290             }
3291             else {
3292               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3293               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3294               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3295             }
3296             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3297                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3298                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3299               // we have to move i+1 node
3300               aMesh->MoveNode( Ns[i+1], x, y, z );
3301             }
3302           }
3303         }
3304       }
3305     }
3306
3307   } // loop on face ids
3308
3309 }
3310
3311 //=======================================================================
3312 //function : isReverse
3313 //purpose  : Return true if normal of prevNodes is not co-directied with
3314 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3315 //           iNotSame is where prevNodes and nextNodes are different
3316 //=======================================================================
3317
3318 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3319                       vector<const SMDS_MeshNode*> nextNodes,
3320                       const int            nbNodes,
3321                       const int            iNotSame)
3322 {
3323   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3324   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3325
3326   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3327   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3328   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3329   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3330
3331   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3332   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3333   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3334   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3335
3336   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3337
3338   return (vA ^ vB) * vN < 0.0;
3339 }
3340
3341 //=======================================================================
3342 /*!
3343  * \brief Create elements by sweeping an element
3344  * \param elem - element to sweep
3345  * \param newNodesItVec - nodes generated from each node of the element
3346  * \param newElems - generated elements
3347  * \param nbSteps - number of sweeping steps
3348  * \param srcElements - to append elem for each generated element
3349  */
3350 //=======================================================================
3351
3352 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3353                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3354                                     list<const SMDS_MeshElement*>&        newElems,
3355                                     const int                             nbSteps,
3356                                     SMESH_SequenceOfElemPtr&              srcElements)
3357 {
3358   SMESHDS_Mesh* aMesh = GetMeshDS();
3359
3360   // Loop on elem nodes:
3361   // find new nodes and detect same nodes indices
3362   int nbNodes = elem->NbNodes();
3363   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3364   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3365   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3366   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3367
3368   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3369   vector<int> sames(nbNodes);
3370   vector<bool> issimple(nbNodes);
3371
3372   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3373     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3374     const SMDS_MeshNode*                 node         = nnIt->first;
3375     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3376     if ( listNewNodes.empty() ) {
3377       return;
3378     }
3379
3380     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3381
3382     itNN[ iNode ] = listNewNodes.begin();
3383     prevNod[ iNode ] = node;
3384     nextNod[ iNode ] = listNewNodes.front();
3385     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3386       if ( prevNod[ iNode ] != nextNod [ iNode ])
3387         iNotSameNode = iNode;
3388       else {
3389         iSameNode = iNode;
3390         //nbSame++;
3391         sames[nbSame++] = iNode;
3392       }
3393     }
3394   }
3395
3396   //cout<<"  nbSame = "<<nbSame<<endl;
3397   if ( nbSame == nbNodes || nbSame > 2) {
3398     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3399     //INFOS( " Too many same nodes of element " << elem->GetID() );
3400     return;
3401   }
3402
3403   //  if( elem->IsQuadratic() && nbSame>0 ) {
3404   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3405   //    return;
3406   //  }
3407
3408   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3409   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3410   if ( nbSame > 0 ) {
3411     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3412     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3413     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3414   }
3415
3416   //if(nbNodes==8)
3417   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3418   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3419   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3420   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3421
3422   // check element orientation
3423   int i0 = 0, i2 = 2;
3424   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3425     //MESSAGE("Reversed elem " << elem );
3426     i0 = 2;
3427     i2 = 0;
3428     if ( nbSame > 0 )
3429       std::swap( iBeforeSame, iAfterSame );
3430   }
3431
3432   // make new elements
3433   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3434     // get next nodes
3435     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3436       if(issimple[iNode]) {
3437         nextNod[ iNode ] = *itNN[ iNode ];
3438         itNN[ iNode ]++;
3439       }
3440       else {
3441         if( elem->GetType()==SMDSAbs_Node ) {
3442           // we have to use two nodes
3443           midlNod[ iNode ] = *itNN[ iNode ];
3444           itNN[ iNode ]++;
3445           nextNod[ iNode ] = *itNN[ iNode ];
3446           itNN[ iNode ]++;
3447         }
3448         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3449           // we have to use each second node
3450           //itNN[ iNode ]++;
3451           nextNod[ iNode ] = *itNN[ iNode ];
3452           itNN[ iNode ]++;
3453         }
3454         else {
3455           // we have to use two nodes
3456           midlNod[ iNode ] = *itNN[ iNode ];
3457           itNN[ iNode ]++;
3458           nextNod[ iNode ] = *itNN[ iNode ];
3459           itNN[ iNode ]++;
3460         }
3461       }
3462     }
3463     SMDS_MeshElement* aNewElem = 0;
3464     if(!elem->IsPoly()) {
3465       switch ( nbNodes ) {
3466       case 0:
3467         return;
3468       case 1: { // NODE
3469         if ( nbSame == 0 ) {
3470           if(issimple[0])
3471             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3472           else
3473             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3474         }
3475         break;
3476       }
3477       case 2: { // EDGE
3478         if ( nbSame == 0 )
3479           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3480                                     nextNod[ 1 ], nextNod[ 0 ] );
3481         else
3482           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3483                                     nextNod[ iNotSameNode ] );
3484         break;
3485       }
3486
3487       case 3: { // TRIANGLE or quadratic edge
3488         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3489
3490           if ( nbSame == 0 )       // --- pentahedron
3491             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3492                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3493
3494           else if ( nbSame == 1 )  // --- pyramid
3495             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3496                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3497                                          nextNod[ iSameNode ]);
3498
3499           else // 2 same nodes:      --- tetrahedron
3500             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3501                                          nextNod[ iNotSameNode ]);
3502         }
3503         else { // quadratic edge
3504           if(nbSame==0) {     // quadratic quadrangle
3505             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3506                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3507           }
3508           else if(nbSame==1) { // quadratic triangle
3509             if(sames[0]==2) {
3510               return; // medium node on axis
3511             }
3512             else if(sames[0]==0) {
3513               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3514                                         nextNod[2], midlNod[1], prevNod[2]);
3515             }
3516             else { // sames[0]==1
3517               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3518                                         midlNod[0], nextNod[2], prevNod[2]);
3519             }
3520           }
3521           else {
3522             return;
3523           }
3524         }
3525         break;
3526       }
3527       case 4: { // QUADRANGLE
3528
3529         if ( nbSame == 0 )       // --- hexahedron
3530           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3531                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3532
3533         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3534           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3535                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3536                                        nextNod[ iSameNode ]);
3537           newElems.push_back( aNewElem );
3538           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3539                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3540                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3541         }
3542         else if ( nbSame == 2 ) { // pentahedron
3543           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3544             // iBeforeSame is same too
3545             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3546                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3547                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3548           else
3549             // iAfterSame is same too
3550             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3551                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3552                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3553         }
3554         break;
3555       }
3556       case 6: { // quadratic triangle
3557         // create pentahedron with 15 nodes
3558         if(nbSame==0) {
3559           if(i0>0) { // reversed case
3560             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3561                                          nextNod[0], nextNod[2], nextNod[1],
3562                                          prevNod[5], prevNod[4], prevNod[3],
3563                                          nextNod[5], nextNod[4], nextNod[3],
3564                                          midlNod[0], midlNod[2], midlNod[1]);
3565           }
3566           else { // not reversed case
3567             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3568                                          nextNod[0], nextNod[1], nextNod[2],
3569                                          prevNod[3], prevNod[4], prevNod[5],
3570                                          nextNod[3], nextNod[4], nextNod[5],
3571                                          midlNod[0], midlNod[1], midlNod[2]);
3572           }
3573         }
3574         else if(nbSame==1) {
3575           // 2d order pyramid of 13 nodes
3576           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3577           //                                 int n12,int n23,int n34,int n41,
3578           //                                 int n15,int n25,int n35,int n45, int ID);
3579           int n5 = iSameNode;
3580           int n1,n4,n41,n15,n45;
3581           if(i0>0) { // reversed case
3582             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3583             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3584             n41 = n1 + 3;
3585             n15 = n5 + 3;
3586             n45 = n4 + 3;
3587           }
3588           else {
3589             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3590             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3591             n41 = n4 + 3;
3592             n15 = n1 + 3;
3593             n45 = n5 + 3;
3594           }
3595           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3596                                       nextNod[n4], prevNod[n4], prevNod[n5],
3597                                       midlNod[n1], nextNod[n41],
3598                                       midlNod[n4], prevNod[n41],
3599                                       prevNod[n15], nextNod[n15],
3600                                       nextNod[n45], prevNod[n45]);
3601         }
3602         else if(nbSame==2) {
3603           // 2d order tetrahedron of 10 nodes
3604           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3605           //                                 int n12,int n23,int n31,
3606           //                                 int n14,int n24,int n34, int ID);
3607           int n1 = iNotSameNode;
3608           int n2,n3,n12,n23,n31;
3609           if(i0>0) { // reversed case
3610             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3611             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3612             n12 = n2 + 3;
3613             n23 = n3 + 3;
3614             n31 = n1 + 3;
3615           }
3616           else {
3617             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3618             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3619             n12 = n1 + 3;
3620             n23 = n2 + 3;
3621             n31 = n3 + 3;
3622           }
3623           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3624                                        prevNod[n12], prevNod[n23], prevNod[n31],
3625                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3626         }
3627         break;
3628       }
3629       case 8: { // quadratic quadrangle
3630         if(nbSame==0) {
3631           // create hexahedron with 20 nodes
3632           if(i0>0) { // reversed case
3633             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3634                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3635                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3636                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3637                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3638           }
3639           else { // not reversed case
3640             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3641                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3642                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3643                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3644                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3645           }
3646         }
3647         else if(nbSame==1) { 
3648           // --- pyramid + pentahedron - can not be created since it is needed 
3649           // additional middle node ot the center of face
3650           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3651           return;
3652         }
3653         else if(nbSame==2) {
3654           // 2d order Pentahedron with 15 nodes
3655           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3656           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3657           //                                 int n14,int n25,int n36, int ID);
3658           int n1,n2,n4,n5;
3659           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3660             // iBeforeSame is same too
3661             n1 = iBeforeSame;
3662             n2 = iOpposSame;
3663             n4 = iSameNode;
3664             n5 = iAfterSame;
3665           }
3666           else {
3667             // iAfterSame is same too
3668             n1 = iSameNode;
3669             n2 = iBeforeSame;
3670             n4 = iAfterSame;
3671             n5 = iOpposSame;
3672           }
3673           int n12,n45,n14,n25;
3674           if(i0>0) { //reversed case
3675             n12 = n1 + 4;
3676             n45 = n5 + 4;
3677             n14 = n4 + 4;
3678             n25 = n2 + 4;
3679           }
3680           else {
3681             n12 = n2 + 4;
3682             n45 = n4 + 4;
3683             n14 = n1 + 4;
3684             n25 = n5 + 4;
3685           }
3686           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3687                                        prevNod[n4], prevNod[n5], nextNod[n5],
3688                                        prevNod[n12], midlNod[n2], nextNod[n12],
3689                                        prevNod[n45], midlNod[n5], nextNod[n45],
3690                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3691         }
3692         break;
3693       }
3694       default: {
3695         // realized for extrusion only
3696         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3697         //vector<int> quantities (nbNodes + 2);
3698
3699         //quantities[0] = nbNodes; // bottom of prism
3700         //for (int inode = 0; inode < nbNodes; inode++) {
3701         //  polyedre_nodes[inode] = prevNod[inode];
3702         //}
3703
3704         //quantities[1] = nbNodes; // top of prism
3705         //for (int inode = 0; inode < nbNodes; inode++) {
3706         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3707         //}
3708
3709         //for (int iface = 0; iface < nbNodes; iface++) {
3710         //  quantities[iface + 2] = 4;
3711         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3712         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3713         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3714         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3715         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3716         //}
3717         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3718         break;
3719       }
3720       }
3721     }
3722
3723     if(!aNewElem) {
3724       // realized for extrusion only
3725       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3726       vector<int> quantities (nbNodes + 2);
3727
3728       quantities[0] = nbNodes; // bottom of prism
3729       for (int inode = 0; inode < nbNodes; inode++) {
3730         polyedre_nodes[inode] = prevNod[inode];
3731       }
3732
3733       quantities[1] = nbNodes; // top of prism
3734       for (int inode = 0; inode < nbNodes; inode++) {
3735         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3736       }
3737
3738       for (int iface = 0; iface < nbNodes; iface++) {
3739         quantities[iface + 2] = 4;
3740         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3741         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3742         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3743         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3744         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3745       }
3746       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3747     }
3748
3749     if ( aNewElem ) {
3750       newElems.push_back( aNewElem );
3751       myLastCreatedElems.Append(aNewElem);
3752       srcElements.Append( elem );
3753     }
3754
3755     // set new prev nodes
3756     for ( iNode = 0; iNode < nbNodes; iNode++ )
3757       prevNod[ iNode ] = nextNod[ iNode ];
3758
3759   } // for steps
3760 }
3761
3762 //=======================================================================
3763 /*!
3764  * \brief Create 1D and 2D elements around swept elements
3765  * \param mapNewNodes - source nodes and ones generated from them
3766  * \param newElemsMap - source elements and ones generated from them
3767  * \param elemNewNodesMap - nodes generated from each node of each element
3768  * \param elemSet - all swept elements
3769  * \param nbSteps - number of sweeping steps
3770  * \param srcElements - to append elem for each generated element
3771  */
3772 //=======================================================================
3773
3774 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3775                                   TElemOfElemListMap &     newElemsMap,
3776                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3777                                   TIDSortedElemSet&        elemSet,
3778                                   const int                nbSteps,
3779                                   SMESH_SequenceOfElemPtr& srcElements)
3780 {
3781   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3782   SMESHDS_Mesh* aMesh = GetMeshDS();
3783
3784   // Find nodes belonging to only one initial element - sweep them to get edges.
3785
3786   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3787   for ( ; nList != mapNewNodes.end(); nList++ ) {
3788     const SMDS_MeshNode* node =
3789       static_cast<const SMDS_MeshNode*>( nList->first );
3790     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3791     int nbInitElems = 0;
3792     const SMDS_MeshElement* el = 0;
3793     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3794     while ( eIt->more() && nbInitElems < 2 ) {
3795       el = eIt->next();
3796       SMDSAbs_ElementType type = el->GetType();
3797       if ( type == SMDSAbs_Volume || type < highType ) continue;
3798       if ( type > highType ) {
3799         nbInitElems = 0;
3800         highType = type;
3801       }
3802       if ( elemSet.find(el) != elemSet.end() )
3803         nbInitElems++;
3804     }
3805     if ( nbInitElems < 2 ) {
3806       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3807       if(!NotCreateEdge) {
3808         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3809         list<const SMDS_MeshElement*> newEdges;
3810         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3811       }
3812     }
3813   }
3814
3815   // Make a ceiling for each element ie an equal element of last new nodes.
3816   // Find free links of faces - make edges and sweep them into faces.
3817
3818   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3819   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3820   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3821     const SMDS_MeshElement* elem = itElem->first;
3822     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3823
3824     if ( elem->GetType() == SMDSAbs_Edge ) {
3825       // create a ceiling edge
3826       if (!elem->IsQuadratic()) {
3827         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3828                                vecNewNodes[ 1 ]->second.back())) {
3829           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3830                                                    vecNewNodes[ 1 ]->second.back()));
3831           srcElements.Append( myLastCreatedElems.Last() );
3832         }
3833       }
3834       else {
3835         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3836                                vecNewNodes[ 1 ]->second.back(),
3837                                vecNewNodes[ 2 ]->second.back())) {
3838           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3839                                                    vecNewNodes[ 1 ]->second.back(),
3840                                                    vecNewNodes[ 2 ]->second.back()));
3841           srcElements.Append( myLastCreatedElems.Last() );
3842         }
3843       }
3844     }
3845     if ( elem->GetType() != SMDSAbs_Face )
3846       continue;
3847
3848     if(itElem->second.size()==0) continue;
3849
3850     bool hasFreeLinks = false;
3851
3852     TIDSortedElemSet avoidSet;
3853     avoidSet.insert( elem );
3854
3855     set<const SMDS_MeshNode*> aFaceLastNodes;
3856     int iNode, nbNodes = vecNewNodes.size();
3857     if(!elem->IsQuadratic()) {
3858       // loop on the face nodes
3859       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3860         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3861         // look for free links of the face
3862         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3863         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3864         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3865         // check if a link is free
3866         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3867           hasFreeLinks = true;
3868           // make an edge and a ceiling for a new edge
3869           if ( !aMesh->FindEdge( n1, n2 )) {
3870             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3871             srcElements.Append( myLastCreatedElems.Last() );
3872           }
3873           n1 = vecNewNodes[ iNode ]->second.back();
3874           n2 = vecNewNodes[ iNext ]->second.back();
3875           if ( !aMesh->FindEdge( n1, n2 )) {
3876             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3877             srcElements.Append( myLastCreatedElems.Last() );
3878           }
3879         }
3880       }
3881     }
3882     else { // elem is quadratic face
3883       int nbn = nbNodes/2;
3884       for ( iNode = 0; iNode < nbn; iNode++ ) {
3885         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3886         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3887         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3888         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3889         // check if a link is free
3890         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3891           hasFreeLinks = true;
3892           // make an edge and a ceiling for a new edge
3893           // find medium node
3894           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3895           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3896             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3897             srcElements.Append( myLastCreatedElems.Last() );
3898           }
3899           n1 = vecNewNodes[ iNode ]->second.back();
3900           n2 = vecNewNodes[ iNext ]->second.back();
3901           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3902           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3903             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3904             srcElements.Append( myLastCreatedElems.Last() );
3905           }
3906         }
3907       }
3908       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3909         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3910       }
3911     }
3912
3913     // sweep free links into faces
3914
3915     if ( hasFreeLinks )  {
3916       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3917       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3918
3919       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3920       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3921         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3922         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3923       }
3924       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3925         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3926         iVol = 0;
3927         while ( iVol++ < volNb ) v++;
3928         // find indices of free faces of a volume and their source edges
3929         list< int > freeInd;
3930         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3931         SMDS_VolumeTool vTool( *v );
3932         int iF, nbF = vTool.NbFaces();
3933         for ( iF = 0; iF < nbF; iF ++ ) {
3934           if (vTool.IsFreeFace( iF ) &&
3935               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3936               initNodeSet != faceNodeSet) // except an initial face
3937           {
3938             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3939               continue;
3940             freeInd.push_back( iF );
3941             // find source edge of a free face iF
3942             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3943             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3944             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3945                                    initNodeSet.begin(), initNodeSet.end(),
3946                                    commonNodes.begin());
3947             if ( (*v)->IsQuadratic() )
3948               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3949             else
3950               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3951 #ifdef _DEBUG_
3952             if ( !srcEdges.back() )
3953             {
3954               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3955                    << iF << " of volume #" << vTool.ID() << endl;
3956             }
3957 #endif
3958           }
3959         }
3960         if ( freeInd.empty() )
3961           continue;
3962
3963         // create faces for all steps;
3964         // if such a face has been already created by sweep of edge,
3965         // assure that its orientation is OK
3966         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3967           vTool.Set( *v );
3968           vTool.SetExternalNormal();
3969           list< int >::iterator ind = freeInd.begin();
3970           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3971           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3972           {
3973             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3974             int nbn = vTool.NbFaceNodes( *ind );
3975             switch ( nbn ) {
3976             case 3: { ///// triangle
3977               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3978               if ( !f )
3979                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3980               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3981                 aMesh->ChangeElementNodes( f, nodes, nbn );
3982               break;
3983             }
3984             case 4: { ///// quadrangle
3985               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3986               if ( !f )
3987                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3988               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3989                 aMesh->ChangeElementNodes( f, nodes, nbn );
3990               break;
3991             }
3992             default:
3993               if( (*v)->IsQuadratic() ) {
3994                 if(nbn==6) { /////// quadratic triangle
3995                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3996                                                              nodes[1], nodes[3], nodes[5] );
3997                   if ( !f ) {
3998                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3999                                                              nodes[1], nodes[3], nodes[5]));
4000                   }
4001                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4002                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4003                     tmpnodes[0] = nodes[0];
4004                     tmpnodes[1] = nodes[2];
4005                     tmpnodes[2] = nodes[4];
4006                     tmpnodes[3] = nodes[1];
4007                     tmpnodes[4] = nodes[3];
4008                     tmpnodes[5] = nodes[5];
4009                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
4010                   }
4011                 }
4012                 else {       /////// quadratic quadrangle
4013                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4014                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4015                   if ( !f ) {
4016                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4017                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4018                   }
4019                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4020                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4021                     tmpnodes[0] = nodes[0];
4022                     tmpnodes[1] = nodes[2];
4023                     tmpnodes[2] = nodes[4];
4024                     tmpnodes[3] = nodes[6];
4025                     tmpnodes[4] = nodes[1];
4026                     tmpnodes[5] = nodes[3];
4027                     tmpnodes[6] = nodes[5];
4028                     tmpnodes[7] = nodes[7];
4029                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
4030                   }
4031                 }
4032               }
4033               else { //////// polygon
4034                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4035                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4036                 if ( !f )
4037                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4038                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4039                   aMesh->ChangeElementNodes( f, nodes, nbn );
4040               }
4041             }
4042             while ( srcElements.Length() < myLastCreatedElems.Length() )
4043               srcElements.Append( *srcEdge );
4044
4045           }  // loop on free faces
4046
4047           // go to the next volume
4048           iVol = 0;
4049           while ( iVol++ < nbVolumesByStep ) v++;
4050         }
4051       }
4052     } // sweep free links into faces
4053
4054     // Make a ceiling face with a normal external to a volume
4055
4056     SMDS_VolumeTool lastVol( itElem->second.back() );
4057
4058     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4059     if ( iF >= 0 ) {
4060       lastVol.SetExternalNormal();
4061       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4062       int nbn = lastVol.NbFaceNodes( iF );
4063       switch ( nbn ) {
4064       case 3:
4065         if (!hasFreeLinks ||
4066             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4067           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4068         break;
4069       case 4:
4070         if (!hasFreeLinks ||
4071             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4072           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4073         break;
4074       default:
4075         if(itElem->second.back()->IsQuadratic()) {
4076           if(nbn==6) {
4077             if (!hasFreeLinks ||
4078                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4079                                  nodes[1], nodes[3], nodes[5]) ) {
4080               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4081                                                        nodes[1], nodes[3], nodes[5]));
4082             }
4083           }
4084           else { // nbn==8
4085             if (!hasFreeLinks ||
4086                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4087                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4088               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4089                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4090           }
4091         }
4092         else {
4093           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4094           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4095             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4096         }
4097       } // switch
4098
4099       while ( srcElements.Length() < myLastCreatedElems.Length() )
4100         srcElements.Append( myLastCreatedElems.Last() );
4101     }
4102   } // loop on swept elements
4103 }
4104
4105 //=======================================================================
4106 //function : RotationSweep
4107 //purpose  :
4108 //=======================================================================
4109
4110 SMESH_MeshEditor::PGroupIDs
4111 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4112                                 const gp_Ax1&      theAxis,
4113                                 const double       theAngle,
4114                                 const int          theNbSteps,
4115                                 const double       theTol,
4116                                 const bool         theMakeGroups,
4117                                 const bool         theMakeWalls)
4118 {
4119   myLastCreatedElems.Clear();
4120   myLastCreatedNodes.Clear();
4121
4122   // source elements for each generated one
4123   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4124
4125   MESSAGE( "RotationSweep()");
4126   gp_Trsf aTrsf;
4127   aTrsf.SetRotation( theAxis, theAngle );
4128   gp_Trsf aTrsf2;
4129   aTrsf2.SetRotation( theAxis, theAngle/2. );
4130
4131   gp_Lin aLine( theAxis );
4132   double aSqTol = theTol * theTol;
4133
4134   SMESHDS_Mesh* aMesh = GetMeshDS();
4135
4136   TNodeOfNodeListMap mapNewNodes;
4137   TElemOfVecOfNnlmiMap mapElemNewNodes;
4138   TElemOfElemListMap newElemsMap;
4139
4140   // loop on theElems
4141   TIDSortedElemSet::iterator itElem;
4142   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4143     const SMDS_MeshElement* elem = *itElem;
4144     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4145       continue;
4146     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4147     newNodesItVec.reserve( elem->NbNodes() );
4148
4149     // loop on elem nodes
4150     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4151     while ( itN->more() ) {
4152       // check if a node has been already sweeped
4153       const SMDS_MeshNode* node = cast2Node( itN->next() );
4154
4155       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4156       double coord[3];
4157       aXYZ.Coord( coord[0], coord[1], coord[2] );
4158       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4159
4160       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4161       if ( nIt == mapNewNodes.end() ) {
4162         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4163         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4164
4165         // make new nodes
4166         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4167         //double coord[3];
4168         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4169         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4170         const SMDS_MeshNode * newNode = node;
4171         for ( int i = 0; i < theNbSteps; i++ ) {
4172           if ( !isOnAxis ) {
4173             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4174               // create two nodes
4175               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4176               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4177               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4178               myLastCreatedNodes.Append(newNode);
4179               srcNodes.Append( node );
4180               listNewNodes.push_back( newNode );
4181               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4182               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4183             }
4184             else {
4185               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4186             }
4187             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4188             myLastCreatedNodes.Append(newNode);
4189             srcNodes.Append( node );
4190             listNewNodes.push_back( newNode );
4191           }
4192           else {
4193             listNewNodes.push_back( newNode );
4194             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4195               listNewNodes.push_back( newNode );
4196             }
4197           }
4198         }
4199       }
4200       /*
4201         else {
4202         // if current elem is quadratic and current node is not medium
4203         // we have to check - may be it is needed to insert additional nodes
4204         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4205         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4206         if(listNewNodes.size()==theNbSteps) {
4207         listNewNodes.clear();
4208         // make new nodes
4209         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4210         //double coord[3];
4211         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4212         const SMDS_MeshNode * newNode = node;
4213         if ( !isOnAxis ) {
4214         for(int i = 0; i<theNbSteps; i++) {
4215         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4216         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4217         cout<<"    3 AddNode:  "<<newNode;
4218         myLastCreatedNodes.Append(newNode);
4219         listNewNodes.push_back( newNode );
4220         srcNodes.Append( node );
4221         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4222         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4223         cout<<"    4 AddNode:  "<<newNode;
4224         myLastCreatedNodes.Append(newNode);
4225         srcNodes.Append( node );
4226         listNewNodes.push_back( newNode );
4227         }
4228         }
4229         else {
4230         listNewNodes.push_back( newNode );
4231         }
4232         }
4233         }
4234         }
4235       */
4236       newNodesItVec.push_back( nIt );
4237     }
4238     // make new elements
4239     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4240   }
4241
4242   if ( theMakeWalls )
4243     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4244
4245   PGroupIDs newGroupIDs;
4246   if ( theMakeGroups )
4247     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4248
4249   return newGroupIDs;
4250 }
4251
4252
4253 //=======================================================================
4254 //function : CreateNode
4255 //purpose  :
4256 //=======================================================================
4257 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4258                                                   const double y,
4259                                                   const double z,
4260                                                   const double tolnode,
4261                                                   SMESH_SequenceOfNode& aNodes)
4262 {
4263   myLastCreatedElems.Clear();
4264   myLastCreatedNodes.Clear();
4265
4266   gp_Pnt P1(x,y,z);
4267   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4268
4269   // try to search in sequence of existing nodes
4270   // if aNodes.Length()>0 we 'nave to use given sequence
4271   // else - use all nodes of mesh
4272   if(aNodes.Length()>0) {
4273     int i;
4274     for(i=1; i<=aNodes.Length(); i++) {
4275       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4276       if(P1.Distance(P2)<tolnode)
4277         return aNodes.Value(i);
4278     }
4279   }
4280   else {
4281     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4282     while(itn->more()) {
4283       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4284       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4285       if(P1.Distance(P2)<tolnode)
4286         return aN;
4287     }
4288   }
4289
4290   // create new node and return it
4291   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4292   myLastCreatedNodes.Append(NewNode);
4293   return NewNode;
4294 }
4295
4296
4297 //=======================================================================
4298 //function : ExtrusionSweep
4299 //purpose  :
4300 //=======================================================================
4301
4302 SMESH_MeshEditor::PGroupIDs
4303 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4304                                   const gp_Vec&       theStep,
4305                                   const int           theNbSteps,
4306                                   TElemOfElemListMap& newElemsMap,
4307                                   const bool          theMakeGroups,
4308                                   const int           theFlags,
4309                                   const double        theTolerance)
4310 {
4311   ExtrusParam aParams;
4312   aParams.myDir = gp_Dir(theStep);
4313   aParams.myNodes.Clear();
4314   aParams.mySteps = new TColStd_HSequenceOfReal;
4315   int i;
4316   for(i=1; i<=theNbSteps; i++)
4317     aParams.mySteps->Append(theStep.Magnitude());
4318
4319   return
4320     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4321 }
4322
4323
4324 //=======================================================================
4325 //function : ExtrusionSweep
4326 //purpose  :
4327 //=======================================================================
4328
4329 SMESH_MeshEditor::PGroupIDs
4330 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4331                                   ExtrusParam&        theParams,
4332                                   TElemOfElemListMap& newElemsMap,
4333                                   const bool          theMakeGroups,
4334                                   const int           theFlags,
4335                                   const double        theTolerance)
4336 {
4337   myLastCreatedElems.Clear();
4338   myLastCreatedNodes.Clear();
4339
4340   // source elements for each generated one
4341   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4342
4343   SMESHDS_Mesh* aMesh = GetMeshDS();
4344
4345   int nbsteps = theParams.mySteps->Length();
4346
4347   TNodeOfNodeListMap mapNewNodes;
4348   //TNodeOfNodeVecMap mapNewNodes;
4349   TElemOfVecOfNnlmiMap mapElemNewNodes;
4350   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4351
4352   // loop on theElems
4353   TIDSortedElemSet::iterator itElem;
4354   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4355     // check element type
4356     const SMDS_MeshElement* elem = *itElem;
4357     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4358       continue;
4359
4360     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4361     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4362     newNodesItVec.reserve( elem->NbNodes() );
4363
4364     // loop on elem nodes
4365     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4366     while ( itN->more() )
4367     {
4368       // check if a node has been already sweeped
4369       const SMDS_MeshNode* node = cast2Node( itN->next() );
4370       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4371       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4372       if ( nIt == mapNewNodes.end() ) {
4373         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4374         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4375         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4376         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4377         //vecNewNodes.reserve(nbsteps);
4378
4379         // make new nodes
4380         double coord[] = { node->X(), node->Y(), node->Z() };
4381         //int nbsteps = theParams.mySteps->Length();
4382         for ( int i = 0; i < nbsteps; i++ ) {
4383           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4384             // create additional node
4385             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4386             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4387             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4388             if( theFlags & EXTRUSION_FLAG_SEW ) {
4389               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4390                                                          theTolerance, theParams.myNodes);
4391               listNewNodes.push_back( newNode );
4392             }
4393             else {
4394               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4395               myLastCreatedNodes.Append(newNode);
4396               srcNodes.Append( node );
4397               listNewNodes.push_back( newNode );
4398             }
4399           }
4400           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4401           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4402           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4403           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4404           if( theFlags & EXTRUSION_FLAG_SEW ) {
4405             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4406                                                        theTolerance, theParams.myNodes);
4407             listNewNodes.push_back( newNode );
4408             //vecNewNodes[i]=newNode;
4409           }
4410           else {
4411             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4412             myLastCreatedNodes.Append(newNode);
4413             srcNodes.Append( node );
4414             listNewNodes.push_back( newNode );
4415             //vecNewNodes[i]=newNode;
4416           }
4417         }
4418       }
4419       else {
4420         // if current elem is quadratic and current node is not medium
4421         // we have to check - may be it is needed to insert additional nodes
4422         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4423           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4424           if(listNewNodes.size()==nbsteps) {
4425             listNewNodes.clear();
4426             double coord[] = { node->X(), node->Y(), node->Z() };
4427             for ( int i = 0; i < nbsteps; i++ ) {
4428               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4429               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4430               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4431               if( theFlags & EXTRUSION_FLAG_SEW ) {
4432                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4433                                                            theTolerance, theParams.myNodes);
4434                 listNewNodes.push_back( newNode );
4435               }
4436               else {
4437                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4438                 myLastCreatedNodes.Append(newNode);
4439                 srcNodes.Append( node );
4440                 listNewNodes.push_back( newNode );
4441               }
4442               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4443               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4444               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4445               if( theFlags & EXTRUSION_FLAG_SEW ) {
4446                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4447                                                            theTolerance, theParams.myNodes);
4448                 listNewNodes.push_back( newNode );
4449               }
4450               else {
4451                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4452                 myLastCreatedNodes.Append(newNode);
4453                 srcNodes.Append( node );
4454                 listNewNodes.push_back( newNode );
4455               }
4456             }
4457           }
4458         }
4459       }
4460       newNodesItVec.push_back( nIt );
4461     }
4462     // make new elements
4463     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4464   }
4465
4466   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4467     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4468   }
4469   PGroupIDs newGroupIDs;
4470   if ( theMakeGroups )
4471     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4472
4473   return newGroupIDs;
4474 }
4475
4476 /*
4477 //=======================================================================
4478 //class    : SMESH_MeshEditor_PathPoint
4479 //purpose  : auxiliary class
4480 //=======================================================================
4481 class SMESH_MeshEditor_PathPoint {
4482 public:
4483 SMESH_MeshEditor_PathPoint() {
4484 myPnt.SetCoord(99., 99., 99.);
4485 myTgt.SetCoord(1.,0.,0.);
4486 myAngle=0.;
4487 myPrm=0.;
4488 }
4489 void SetPnt(const gp_Pnt& aP3D){
4490 myPnt=aP3D;
4491 }
4492 void SetTangent(const gp_Dir& aTgt){
4493 myTgt=aTgt;
4494 }
4495 void SetAngle(const double& aBeta){
4496 myAngle=aBeta;
4497 }
4498 void SetParameter(const double& aPrm){
4499 myPrm=aPrm;
4500 }
4501 const gp_Pnt& Pnt()const{
4502 return myPnt;
4503 }
4504 const gp_Dir& Tangent()const{
4505 return myTgt;
4506 }
4507 double Angle()const{
4508 return myAngle;
4509 }
4510 double Parameter()const{
4511 return myPrm;
4512 }
4513
4514 protected:
4515 gp_Pnt myPnt;
4516 gp_Dir myTgt;
4517 double myAngle;
4518 double myPrm;
4519 };
4520 */
4521
4522 //=======================================================================
4523 //function : ExtrusionAlongTrack
4524 //purpose  :
4525 //=======================================================================
4526 SMESH_MeshEditor::Extrusion_Error
4527 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4528                                        SMESH_subMesh*       theTrack,
4529                                        const SMDS_MeshNode* theN1,
4530                                        const bool           theHasAngles,
4531                                        list<double>&        theAngles,
4532                                        const bool           theLinearVariation,
4533                                        const bool           theHasRefPoint,
4534                                        const gp_Pnt&        theRefPoint,
4535                                        const bool           theMakeGroups)
4536 {
4537   myLastCreatedElems.Clear();
4538   myLastCreatedNodes.Clear();
4539
4540   int aNbE;
4541   std::list<double> aPrms;
4542   TIDSortedElemSet::iterator itElem;
4543
4544   gp_XYZ aGC;
4545   TopoDS_Edge aTrackEdge;
4546   TopoDS_Vertex aV1, aV2;
4547
4548   SMDS_ElemIteratorPtr aItE;
4549   SMDS_NodeIteratorPtr aItN;
4550   SMDSAbs_ElementType aTypeE;
4551
4552   TNodeOfNodeListMap mapNewNodes;
4553
4554   // 1. Check data
4555   aNbE = theElements.size();
4556   // nothing to do
4557   if ( !aNbE )
4558     return EXTR_NO_ELEMENTS;
4559
4560   // 1.1 Track Pattern
4561   ASSERT( theTrack );
4562
4563   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4564
4565   aItE = pSubMeshDS->GetElements();
4566   while ( aItE->more() ) {
4567     const SMDS_MeshElement* pE = aItE->next();
4568     aTypeE = pE->GetType();
4569     // Pattern must contain links only
4570     if ( aTypeE != SMDSAbs_Edge )
4571       return EXTR_PATH_NOT_EDGE;
4572   }
4573
4574   list<SMESH_MeshEditor_PathPoint> fullList;
4575
4576   const TopoDS_Shape& aS = theTrack->GetSubShape();
4577   // Sub shape for the Pattern must be an Edge or Wire
4578   if( aS.ShapeType() == TopAbs_EDGE ) {
4579     aTrackEdge = TopoDS::Edge( aS );
4580     // the Edge must not be degenerated
4581     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4582       return EXTR_BAD_PATH_SHAPE;
4583     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4584     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4585     const SMDS_MeshNode* aN1 = aItN->next();
4586     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4587     const SMDS_MeshNode* aN2 = aItN->next();
4588     // starting node must be aN1 or aN2
4589     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4590       return EXTR_BAD_STARTING_NODE;
4591     aItN = pSubMeshDS->GetNodes();
4592     while ( aItN->more() ) {
4593       const SMDS_MeshNode* pNode = aItN->next();
4594       const SMDS_EdgePosition* pEPos =
4595         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4596       double aT = pEPos->GetUParameter();
4597       aPrms.push_back( aT );
4598     }
4599     //Extrusion_Error err =
4600     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4601   }
4602   else if( aS.ShapeType() == TopAbs_WIRE ) {
4603     list< SMESH_subMesh* > LSM;
4604     TopTools_SequenceOfShape Edges;
4605     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4606     while(itSM->more()) {
4607       SMESH_subMesh* SM = itSM->next();
4608       LSM.push_back(SM);
4609       const TopoDS_Shape& aS = SM->GetSubShape();
4610       Edges.Append(aS);
4611     }
4612     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4613     int startNid = theN1->GetID();
4614     TColStd_MapOfInteger UsedNums;
4615     int NbEdges = Edges.Length();
4616     int i = 1;
4617     for(; i<=NbEdges; i++) {
4618       int k = 0;
4619       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4620       for(; itLSM!=LSM.end(); itLSM++) {
4621         k++;
4622         if(UsedNums.Contains(k)) continue;
4623         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4624         SMESH_subMesh* locTrack = *itLSM;
4625         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4626         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4627         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4628         const SMDS_MeshNode* aN1 = aItN->next();
4629         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4630         const SMDS_MeshNode* aN2 = aItN->next();
4631         // starting node must be aN1 or aN2
4632         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4633         // 2. Collect parameters on the track edge
4634         aPrms.clear();
4635         aItN = locMeshDS->GetNodes();
4636         while ( aItN->more() ) {
4637           const SMDS_MeshNode* pNode = aItN->next();
4638           const SMDS_EdgePosition* pEPos =
4639             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4640           double aT = pEPos->GetUParameter();
4641           aPrms.push_back( aT );
4642         }
4643         list<SMESH_MeshEditor_PathPoint> LPP;
4644         //Extrusion_Error err =
4645         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4646         LLPPs.push_back(LPP);
4647         UsedNums.Add(k);
4648         // update startN for search following egde
4649         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4650         else startNid = aN1->GetID();
4651         break;
4652       }
4653     }
4654     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4655     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4656     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4657     for(; itPP!=firstList.end(); itPP++) {
4658       fullList.push_back( *itPP );
4659     }
4660     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4661     fullList.pop_back();
4662     itLLPP++;
4663     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4664       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4665       itPP = currList.begin();
4666       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4667       gp_Dir D1 = PP1.Tangent();
4668       gp_Dir D2 = PP2.Tangent();
4669       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4670                            (D1.Z()+D2.Z())/2 ) );
4671       PP1.SetTangent(Dnew);
4672       fullList.push_back(PP1);
4673       itPP++;
4674       for(; itPP!=firstList.end(); itPP++) {
4675         fullList.push_back( *itPP );
4676       }
4677       PP1 = fullList.back();
4678       fullList.pop_back();
4679     }
4680     // if wire not closed
4681     fullList.push_back(PP1);
4682     // else ???
4683   }
4684   else {
4685     return EXTR_BAD_PATH_SHAPE;
4686   }
4687
4688   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4689                           theHasRefPoint, theRefPoint, theMakeGroups);
4690 }
4691
4692
4693 //=======================================================================
4694 //function : ExtrusionAlongTrack
4695 //purpose  :
4696 //=======================================================================
4697 SMESH_MeshEditor::Extrusion_Error
4698 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4699                                        SMESH_Mesh*          theTrack,
4700                                        const SMDS_MeshNode* theN1,
4701                                        const bool           theHasAngles,
4702                                        list<double>&        theAngles,
4703                                        const bool           theLinearVariation,
4704                                        const bool           theHasRefPoint,
4705                                        const gp_Pnt&        theRefPoint,
4706                                        const bool           theMakeGroups)
4707 {
4708   myLastCreatedElems.Clear();
4709   myLastCreatedNodes.Clear();
4710
4711   int aNbE;
4712   std::list<double> aPrms;
4713   TIDSortedElemSet::iterator itElem;
4714
4715   gp_XYZ aGC;
4716   TopoDS_Edge aTrackEdge;
4717   TopoDS_Vertex aV1, aV2;
4718
4719   SMDS_ElemIteratorPtr aItE;
4720   SMDS_NodeIteratorPtr aItN;
4721   SMDSAbs_ElementType aTypeE;
4722
4723   TNodeOfNodeListMap mapNewNodes;
4724
4725   // 1. Check data
4726   aNbE = theElements.size();
4727   // nothing to do
4728   if ( !aNbE )
4729     return EXTR_NO_ELEMENTS;
4730
4731   // 1.1 Track Pattern
4732   ASSERT( theTrack );
4733
4734   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4735
4736   aItE = pMeshDS->elementsIterator();
4737   while ( aItE->more() ) {
4738     const SMDS_MeshElement* pE = aItE->next();
4739     aTypeE = pE->GetType();
4740     // Pattern must contain links only
4741     if ( aTypeE != SMDSAbs_Edge )
4742       return EXTR_PATH_NOT_EDGE;
4743   }
4744
4745   list<SMESH_MeshEditor_PathPoint> fullList;
4746
4747   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4748   // Sub shape for the Pattern must be an Edge or Wire
4749   if( aS.ShapeType() == TopAbs_EDGE ) {
4750     aTrackEdge = TopoDS::Edge( aS );
4751     // the Edge must not be degenerated
4752     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4753       return EXTR_BAD_PATH_SHAPE;
4754     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4755     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4756     const SMDS_MeshNode* aN1 = aItN->next();
4757     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4758     const SMDS_MeshNode* aN2 = aItN->next();
4759     // starting node must be aN1 or aN2
4760     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4761       return EXTR_BAD_STARTING_NODE;
4762     aItN = pMeshDS->nodesIterator();
4763     while ( aItN->more() ) {
4764       const SMDS_MeshNode* pNode = aItN->next();
4765       if( pNode==aN1 || pNode==aN2 ) continue;
4766       const SMDS_EdgePosition* pEPos =
4767         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4768       double aT = pEPos->GetUParameter();
4769       aPrms.push_back( aT );
4770     }
4771     //Extrusion_Error err =
4772     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4773   }
4774   else if( aS.ShapeType() == TopAbs_WIRE ) {
4775     list< SMESH_subMesh* > LSM;
4776     TopTools_SequenceOfShape Edges;
4777     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4778     for(; eExp.More(); eExp.Next()) {
4779       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4780       if( BRep_Tool::Degenerated(E) ) continue;
4781       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4782       if(SM) {
4783         LSM.push_back(SM);
4784         Edges.Append(E);
4785       }
4786     }
4787     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4788     int startNid = theN1->GetID();
4789     TColStd_MapOfInteger UsedNums;
4790     int NbEdges = Edges.Length();
4791     int i = 1;
4792     for(; i<=NbEdges; i++) {
4793       int k = 0;
4794       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4795       for(; itLSM!=LSM.end(); itLSM++) {
4796         k++;
4797         if(UsedNums.Contains(k)) continue;
4798         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4799         SMESH_subMesh* locTrack = *itLSM;
4800         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4801         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4802         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4803         const SMDS_MeshNode* aN1 = aItN->next();
4804         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4805         const SMDS_MeshNode* aN2 = aItN->next();
4806         // starting node must be aN1 or aN2
4807         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4808         // 2. Collect parameters on the track edge
4809         aPrms.clear();
4810         aItN = locMeshDS->GetNodes();
4811         while ( aItN->more() ) {
4812           const SMDS_MeshNode* pNode = aItN->next();
4813           const SMDS_EdgePosition* pEPos =
4814             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4815           double aT = pEPos->GetUParameter();
4816           aPrms.push_back( aT );
4817         }
4818         list<SMESH_MeshEditor_PathPoint> LPP;
4819         //Extrusion_Error err =
4820         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4821         LLPPs.push_back(LPP);
4822         UsedNums.Add(k);
4823         // update startN for search following egde
4824         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4825         else startNid = aN1->GetID();
4826         break;
4827       }
4828     }
4829     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4830     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4831     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4832     for(; itPP!=firstList.end(); itPP++) {
4833       fullList.push_back( *itPP );
4834     }
4835     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4836     fullList.pop_back();
4837     itLLPP++;
4838     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4839       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4840       itPP = currList.begin();
4841       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4842       gp_Pnt P1 = PP1.Pnt();
4843       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4844       gp_Pnt P2 = PP2.Pnt();
4845       gp_Dir D1 = PP1.Tangent();
4846       gp_Dir D2 = PP2.Tangent();
4847       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4848                            (D1.Z()+D2.Z())/2 ) );
4849       PP1.SetTangent(Dnew);
4850       fullList.push_back(PP1);
4851       itPP++;
4852       for(; itPP!=currList.end(); itPP++) {
4853         fullList.push_back( *itPP );
4854       }
4855       PP1 = fullList.back();
4856       fullList.pop_back();
4857     }
4858     // if wire not closed
4859     fullList.push_back(PP1);
4860     // else ???
4861   }
4862   else {
4863     return EXTR_BAD_PATH_SHAPE;
4864   }
4865
4866   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4867                           theHasRefPoint, theRefPoint, theMakeGroups);
4868 }
4869
4870
4871 //=======================================================================
4872 //function : MakeEdgePathPoints
4873 //purpose  : auxilary for ExtrusionAlongTrack
4874 //=======================================================================
4875 SMESH_MeshEditor::Extrusion_Error
4876 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4877                                      const TopoDS_Edge& aTrackEdge,
4878                                      bool FirstIsStart,
4879                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4880 {
4881   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4882   aTolVec=1.e-7;
4883   aTolVec2=aTolVec*aTolVec;
4884   double aT1, aT2;
4885   TopoDS_Vertex aV1, aV2;
4886   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4887   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4888   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4889   // 2. Collect parameters on the track edge
4890   aPrms.push_front( aT1 );
4891   aPrms.push_back( aT2 );
4892   // sort parameters
4893   aPrms.sort();
4894   if( FirstIsStart ) {
4895     if ( aT1 > aT2 ) {
4896       aPrms.reverse();
4897     }
4898   }
4899   else {
4900     if ( aT2 > aT1 ) {
4901       aPrms.reverse();
4902     }
4903   }
4904   // 3. Path Points
4905   SMESH_MeshEditor_PathPoint aPP;
4906   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4907   std::list<double>::iterator aItD = aPrms.begin();
4908   for(; aItD != aPrms.end(); ++aItD) {
4909     double aT = *aItD;
4910     gp_Pnt aP3D;
4911     gp_Vec aVec;
4912     aC3D->D1( aT, aP3D, aVec );
4913     aL2 = aVec.SquareMagnitude();
4914     if ( aL2 < aTolVec2 )
4915       return EXTR_CANT_GET_TANGENT;
4916     gp_Dir aTgt( aVec );
4917     aPP.SetPnt( aP3D );
4918     aPP.SetTangent( aTgt );
4919     aPP.SetParameter( aT );
4920     LPP.push_back(aPP);
4921   }
4922   return EXTR_OK;
4923 }
4924
4925
4926 //=======================================================================
4927 //function : MakeExtrElements
4928 //purpose  : auxilary for ExtrusionAlongTrack
4929 //=======================================================================
4930 SMESH_MeshEditor::Extrusion_Error
4931 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4932                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4933                                    const bool theHasAngles,
4934                                    list<double>& theAngles,
4935                                    const bool theLinearVariation,
4936                                    const bool theHasRefPoint,
4937                                    const gp_Pnt& theRefPoint,
4938                                    const bool theMakeGroups)
4939 {
4940   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4941   int aNbTP = fullList.size();
4942   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4943   // Angles
4944   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4945     LinearAngleVariation(aNbTP-1, theAngles);
4946   }
4947   vector<double> aAngles( aNbTP );
4948   int j = 0;
4949   for(; j<aNbTP; ++j) {
4950     aAngles[j] = 0.;
4951   }
4952   if ( theHasAngles ) {
4953     double anAngle;;
4954     std::list<double>::iterator aItD = theAngles.begin();
4955     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4956       anAngle = *aItD;
4957       aAngles[j] = anAngle;
4958     }
4959   }
4960   // fill vector of path points with angles
4961   //aPPs.resize(fullList.size());
4962   j = -1;
4963   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4964   for(; itPP!=fullList.end(); itPP++) {
4965     j++;
4966     SMESH_MeshEditor_PathPoint PP = *itPP;
4967     PP.SetAngle(aAngles[j]);
4968     aPPs[j] = PP;
4969   }
4970
4971   TNodeOfNodeListMap mapNewNodes;
4972   TElemOfVecOfNnlmiMap mapElemNewNodes;
4973   TElemOfElemListMap newElemsMap;
4974   TIDSortedElemSet::iterator itElem;
4975   double aX, aY, aZ;
4976   int aNb;
4977   SMDSAbs_ElementType aTypeE;
4978   // source elements for each generated one
4979   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4980
4981   // 3. Center of rotation aV0
4982   gp_Pnt aV0 = theRefPoint;
4983   gp_XYZ aGC;
4984   if ( !theHasRefPoint ) {
4985     aNb = 0;
4986     aGC.SetCoord( 0.,0.,0. );
4987
4988     itElem = theElements.begin();
4989     for ( ; itElem != theElements.end(); itElem++ ) {
4990       const SMDS_MeshElement* elem = *itElem;
4991
4992       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4993       while ( itN->more() ) {
4994         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4995         aX = node->X();
4996         aY = node->Y();
4997         aZ = node->Z();
4998
4999         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5000           list<const SMDS_MeshNode*> aLNx;
5001           mapNewNodes[node] = aLNx;
5002           //
5003           gp_XYZ aXYZ( aX, aY, aZ );
5004           aGC += aXYZ;
5005           ++aNb;
5006         }
5007       }
5008     }
5009     aGC /= aNb;
5010     aV0.SetXYZ( aGC );
5011   } // if (!theHasRefPoint) {
5012   mapNewNodes.clear();
5013
5014   // 4. Processing the elements
5015   SMESHDS_Mesh* aMesh = GetMeshDS();
5016
5017   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5018     // check element type
5019     const SMDS_MeshElement* elem = *itElem;
5020     aTypeE = elem->GetType();
5021     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5022       continue;
5023
5024     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5025     newNodesItVec.reserve( elem->NbNodes() );
5026
5027     // loop on elem nodes
5028     int nodeIndex = -1;
5029     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5030     while ( itN->more() )
5031     {
5032       ++nodeIndex;
5033       // check if a node has been already processed
5034       const SMDS_MeshNode* node =
5035         static_cast<const SMDS_MeshNode*>( itN->next() );
5036       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5037       if ( nIt == mapNewNodes.end() ) {
5038         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5039         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5040
5041         // make new nodes
5042         aX = node->X();  aY = node->Y(); aZ = node->Z();
5043
5044         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5045         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5046         gp_Ax1 anAx1, anAxT1T0;
5047         gp_Dir aDT1x, aDT0x, aDT1T0;
5048
5049         aTolAng=1.e-4;
5050
5051         aV0x = aV0;
5052         aPN0.SetCoord(aX, aY, aZ);
5053
5054         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5055         aP0x = aPP0.Pnt();
5056         aDT0x= aPP0.Tangent();
5057         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5058
5059         for ( j = 1; j < aNbTP; ++j ) {
5060           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5061           aP1x = aPP1.Pnt();
5062           aDT1x = aPP1.Tangent();
5063           aAngle1x = aPP1.Angle();
5064
5065           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5066           // Translation
5067           gp_Vec aV01x( aP0x, aP1x );
5068           aTrsf.SetTranslation( aV01x );
5069
5070           // traslated point
5071           aV1x = aV0x.Transformed( aTrsf );
5072           aPN1 = aPN0.Transformed( aTrsf );
5073
5074           // rotation 1 [ T1,T0 ]
5075           aAngleT1T0=-aDT1x.Angle( aDT0x );
5076           if (fabs(aAngleT1T0) > aTolAng) {
5077             aDT1T0=aDT1x^aDT0x;
5078             anAxT1T0.SetLocation( aV1x );
5079             anAxT1T0.SetDirection( aDT1T0 );
5080             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5081
5082             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5083           }
5084
5085           // rotation 2
5086           if ( theHasAngles ) {
5087             anAx1.SetLocation( aV1x );
5088             anAx1.SetDirection( aDT1x );
5089             aTrsfRot.SetRotation( anAx1, aAngle1x );
5090
5091             aPN1 = aPN1.Transformed( aTrsfRot );
5092           }
5093
5094           // make new node
5095           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5096             // create additional node
5097             double x = ( aPN1.X() + aPN0.X() )/2.;
5098             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5099             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5100             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5101             myLastCreatedNodes.Append(newNode);
5102             srcNodes.Append( node );
5103             listNewNodes.push_back( newNode );
5104           }
5105           aX = aPN1.X();
5106           aY = aPN1.Y();
5107           aZ = aPN1.Z();
5108           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5109           myLastCreatedNodes.Append(newNode);
5110           srcNodes.Append( node );
5111           listNewNodes.push_back( newNode );
5112
5113           aPN0 = aPN1;
5114           aP0x = aP1x;
5115           aV0x = aV1x;
5116           aDT0x = aDT1x;
5117         }
5118       }
5119
5120       else {
5121         // if current elem is quadratic and current node is not medium
5122         // we have to check - may be it is needed to insert additional nodes
5123         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5124           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5125           if(listNewNodes.size()==aNbTP-1) {
5126             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5127             gp_XYZ P(node->X(), node->Y(), node->Z());
5128             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5129             int i;
5130             for(i=0; i<aNbTP-1; i++) {
5131               const SMDS_MeshNode* N = *it;
5132               double x = ( N->X() + P.X() )/2.;
5133               double y = ( N->Y() + P.Y() )/2.;
5134               double z = ( N->Z() + P.Z() )/2.;
5135               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5136               srcNodes.Append( node );
5137               myLastCreatedNodes.Append(newN);
5138               aNodes[2*i] = newN;
5139               aNodes[2*i+1] = N;
5140               P = gp_XYZ(N->X(),N->Y(),N->Z());
5141             }
5142             listNewNodes.clear();
5143             for(i=0; i<2*(aNbTP-1); i++) {
5144               listNewNodes.push_back(aNodes[i]);
5145             }
5146           }
5147         }
5148       }
5149
5150       newNodesItVec.push_back( nIt );
5151     }
5152     // make new elements
5153     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5154     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5155     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5156   }
5157
5158   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5159
5160   if ( theMakeGroups )
5161     generateGroups( srcNodes, srcElems, "extruded");
5162
5163   return EXTR_OK;
5164 }
5165
5166
5167 //=======================================================================
5168 //function : LinearAngleVariation
5169 //purpose  : auxilary for ExtrusionAlongTrack
5170 //=======================================================================
5171 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5172                                             list<double>& Angles)
5173 {
5174   int nbAngles = Angles.size();
5175   if( nbSteps > nbAngles ) {
5176     vector<double> theAngles(nbAngles);
5177     list<double>::iterator it = Angles.begin();
5178     int i = -1;
5179     for(; it!=Angles.end(); it++) {
5180       i++;
5181       theAngles[i] = (*it);
5182     }
5183     list<double> res;
5184     double rAn2St = double( nbAngles ) / double( nbSteps );
5185     double angPrev = 0, angle;
5186     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5187       double angCur = rAn2St * ( iSt+1 );
5188       double angCurFloor  = floor( angCur );
5189       double angPrevFloor = floor( angPrev );
5190       if ( angPrevFloor == angCurFloor )
5191         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5192       else {
5193         int iP = int( angPrevFloor );
5194         double angPrevCeil = ceil(angPrev);
5195         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5196
5197         int iC = int( angCurFloor );
5198         if ( iC < nbAngles )
5199           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5200
5201         iP = int( angPrevCeil );
5202         while ( iC-- > iP )
5203           angle += theAngles[ iC ];
5204       }
5205       res.push_back(angle);
5206       angPrev = angCur;
5207     }
5208     Angles.clear();
5209     it = res.begin();
5210     for(; it!=res.end(); it++)
5211       Angles.push_back( *it );
5212   }
5213 }
5214
5215
5216 //================================================================================
5217 /*!
5218  * \brief Move or copy theElements applying theTrsf to their nodes
5219  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5220  *  \param theTrsf - transformation to apply
5221  *  \param theCopy - if true, create translated copies of theElems
5222  *  \param theMakeGroups - if true and theCopy, create translated groups
5223  *  \param theTargetMesh - mesh to copy translated elements into
5224  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5225  */
5226 //================================================================================
5227
5228 SMESH_MeshEditor::PGroupIDs
5229 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5230                              const gp_Trsf&     theTrsf,
5231                              const bool         theCopy,
5232                              const bool         theMakeGroups,
5233                              SMESH_Mesh*        theTargetMesh)
5234 {
5235   myLastCreatedElems.Clear();
5236   myLastCreatedNodes.Clear();
5237
5238   bool needReverse = false;
5239   string groupPostfix;
5240   switch ( theTrsf.Form() ) {
5241   case gp_PntMirror:
5242   case gp_Ax1Mirror:
5243   case gp_Ax2Mirror:
5244     needReverse = true;
5245     groupPostfix = "mirrored";
5246     break;
5247   case gp_Rotation:
5248     groupPostfix = "rotated";
5249     break;
5250   case gp_Translation:
5251     groupPostfix = "translated";
5252     break;
5253   case gp_Scale:
5254   case gp_CompoundTrsf: // different scale by axis
5255     groupPostfix = "scaled";
5256     break;
5257   default:
5258     needReverse = false;
5259     groupPostfix = "transformed";
5260   }
5261
5262   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5263   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5264   SMESHDS_Mesh* aMesh    = GetMeshDS();
5265
5266
5267   // map old node to new one
5268   TNodeNodeMap nodeMap;
5269
5270   // elements sharing moved nodes; those of them which have all
5271   // nodes mirrored but are not in theElems are to be reversed
5272   TIDSortedElemSet inverseElemSet;
5273
5274   // source elements for each generated one
5275   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5276
5277   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5278   list<SMDS_MeshNode>          orphanCopy; // copies of orphan nodes
5279   vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5280
5281   if ( theElems.empty() ) // transform the whole mesh
5282   {
5283     // add all elements
5284     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5285     while ( eIt->more() ) theElems.insert( eIt->next() );
5286     // add orphan nodes
5287     SMDS_MeshElementIDFactory idFactory;
5288     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5289     while ( nIt->more() )
5290     {
5291       const SMDS_MeshNode* node = nIt->next();
5292       if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5293       {
5294         // node was not inserted into theElems because an element with the same ID
5295         // is already there. As a work around we insert a copy of node with
5296         // an ID = -<index in orphanNode>
5297         orphanCopy.push_back( *node ); // copy node
5298         SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5299         int uniqueID = -orphanNode.size();
5300         orphanNode.push_back( node );
5301         idFactory.BindID( uniqueID, nodeCopy );
5302         theElems.insert( nodeCopy );
5303       }
5304     }
5305   }
5306   // loop on theElems to transorm nodes
5307   TIDSortedElemSet::iterator itElem;
5308   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5309     const SMDS_MeshElement* elem = *itElem;
5310     if ( !elem )
5311       continue;
5312
5313     // loop on elem nodes
5314     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5315     while ( itN->more() ) {
5316
5317       const SMDS_MeshNode* node = cast2Node( itN->next() );
5318       if ( node->GetID() < 0 )
5319         node = orphanNode[ -node->GetID() ];
5320       // check if a node has been already transformed
5321       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5322         nodeMap.insert( make_pair ( node, node ));
5323       if ( !n2n_isnew.second )
5324         continue;
5325
5326       double coord[3];
5327       coord[0] = node->X();
5328       coord[1] = node->Y();
5329       coord[2] = node->Z();
5330       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5331       if ( theTargetMesh ) {
5332         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5333         n2n_isnew.first->second = newNode;
5334         myLastCreatedNodes.Append(newNode);
5335         srcNodes.Append( node );
5336       }
5337       else if ( theCopy ) {
5338         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5339         n2n_isnew.first->second = newNode;
5340         myLastCreatedNodes.Append(newNode);
5341         srcNodes.Append( node );
5342       }
5343       else {
5344         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5345         // node position on shape becomes invalid
5346         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5347           ( SMDS_SpacePosition::originSpacePosition() );
5348       }
5349
5350       // keep inverse elements
5351       if ( !theCopy && !theTargetMesh && needReverse ) {
5352         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5353         while ( invElemIt->more() ) {
5354           const SMDS_MeshElement* iel = invElemIt->next();
5355           inverseElemSet.insert( iel );
5356         }
5357       }
5358     }
5359   }
5360
5361   // either create new elements or reverse mirrored ones
5362   if ( !theCopy && !needReverse && !theTargetMesh )
5363     return PGroupIDs();
5364
5365   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5366   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5367     theElems.insert( *invElemIt );
5368
5369   // replicate or reverse elements
5370
5371   enum {
5372     REV_TETRA   = 0,  //  = nbNodes - 4
5373     REV_PYRAMID = 1,  //  = nbNodes - 4
5374     REV_PENTA   = 2,  //  = nbNodes - 4
5375     REV_FACE    = 3,
5376     REV_HEXA    = 4,  //  = nbNodes - 4
5377     FORWARD     = 5
5378   };
5379   int index[][8] = {
5380     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5381     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5382     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5383     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5384     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5385     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5386   };
5387
5388   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5389   {
5390     const SMDS_MeshElement* elem = *itElem;
5391     if ( !elem || elem->GetType() == SMDSAbs_Node )
5392       continue;
5393
5394     int nbNodes = elem->NbNodes();
5395     int elemType = elem->GetType();
5396
5397     if (elem->IsPoly()) {
5398       // Polygon or Polyhedral Volume
5399       switch ( elemType ) {
5400       case SMDSAbs_Face:
5401         {
5402           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5403           int iNode = 0;
5404           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5405           while (itN->more()) {
5406             const SMDS_MeshNode* node =
5407               static_cast<const SMDS_MeshNode*>(itN->next());
5408             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5409             if (nodeMapIt == nodeMap.end())
5410               break; // not all nodes transformed
5411             if (needReverse) {
5412               // reverse mirrored faces and volumes
5413               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5414             } else {
5415               poly_nodes[iNode] = (*nodeMapIt).second;
5416             }
5417             iNode++;
5418           }
5419           if ( iNode != nbNodes )
5420             continue; // not all nodes transformed
5421
5422           if ( theTargetMesh ) {
5423             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5424             srcElems.Append( elem );
5425           }
5426           else if ( theCopy ) {
5427             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5428             srcElems.Append( elem );
5429           }
5430           else {
5431             aMesh->ChangePolygonNodes(elem, poly_nodes);
5432           }
5433         }
5434         break;
5435       case SMDSAbs_Volume:
5436         {
5437           // ATTENTION: Reversing is not yet done!!!
5438           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5439             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5440           if (!aPolyedre) {
5441             MESSAGE("Warning: bad volumic element");
5442             continue;
5443           }
5444
5445           vector<const SMDS_MeshNode*> poly_nodes;
5446           vector<int> quantities;
5447
5448           bool allTransformed = true;
5449           int nbFaces = aPolyedre->NbFaces();
5450           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5451             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5452             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5453               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5454               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5455               if (nodeMapIt == nodeMap.end()) {
5456                 allTransformed = false; // not all nodes transformed
5457               } else {
5458                 poly_nodes.push_back((*nodeMapIt).second);
5459               }
5460             }
5461             quantities.push_back(nbFaceNodes);
5462           }
5463           if ( !allTransformed )
5464             continue; // not all nodes transformed
5465
5466           if ( theTargetMesh ) {
5467             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5468             srcElems.Append( elem );
5469           }
5470           else if ( theCopy ) {
5471             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5472             srcElems.Append( elem );
5473           }
5474           else {
5475             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5476           }
5477         }
5478         break;
5479       default:;
5480       }
5481       continue;
5482     }
5483
5484     // Regular elements
5485     int* i = index[ FORWARD ];
5486     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5487       if ( elemType == SMDSAbs_Face )
5488         i = index[ REV_FACE ];
5489       else
5490         i = index[ nbNodes - 4 ];
5491
5492     if(elem->IsQuadratic()) {
5493       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5494       i = anIds;
5495       if(needReverse) {
5496         if(nbNodes==3) { // quadratic edge
5497           static int anIds[] = {1,0,2};
5498           i = anIds;
5499         }
5500         else if(nbNodes==6) { // quadratic triangle
5501           static int anIds[] = {0,2,1,5,4,3};
5502           i = anIds;
5503         }
5504         else if(nbNodes==8) { // quadratic quadrangle
5505           static int anIds[] = {0,3,2,1,7,6,5,4};
5506           i = anIds;
5507         }
5508         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5509           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5510           i = anIds;
5511         }
5512         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5513           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5514           i = anIds;
5515         }
5516         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5517           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5518           i = anIds;
5519         }
5520         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5521           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5522           i = anIds;
5523         }
5524       }
5525     }
5526
5527     // find transformed nodes
5528     vector<const SMDS_MeshNode*> nodes(nbNodes);
5529     int iNode = 0;
5530     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5531     while ( itN->more() ) {
5532       const SMDS_MeshNode* node =
5533         static_cast<const SMDS_MeshNode*>( itN->next() );
5534       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5535       if ( nodeMapIt == nodeMap.end() )
5536         break; // not all nodes transformed
5537       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5538     }
5539     if ( iNode != nbNodes )
5540       continue; // not all nodes transformed
5541
5542     if ( theTargetMesh ) {
5543       if ( SMDS_MeshElement* copy =
5544            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5545         myLastCreatedElems.Append( copy );
5546         srcElems.Append( elem );
5547       }
5548     }
5549     else if ( theCopy ) {
5550       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5551         srcElems.Append( elem );
5552     }
5553     else {
5554       // reverse element as it was reversed by transformation
5555       if ( nbNodes > 2 )
5556         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5557     }
5558   }
5559
5560   PGroupIDs newGroupIDs;
5561
5562   if ( theMakeGroups && theCopy ||
5563        theMakeGroups && theTargetMesh )
5564     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5565
5566   return newGroupIDs;
5567 }
5568
5569 //=======================================================================
5570 /*!
5571  * \brief Create groups of elements made during transformation
5572  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5573  * \param elemGens - elements making corresponding myLastCreatedElems
5574  * \param postfix - to append to names of new groups
5575  */
5576 //=======================================================================
5577
5578 SMESH_MeshEditor::PGroupIDs
5579 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5580                                  const SMESH_SequenceOfElemPtr& elemGens,
5581                                  const std::string&             postfix,
5582                                  SMESH_Mesh*                    targetMesh)
5583 {
5584   PGroupIDs newGroupIDs( new list<int> );
5585   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5586
5587   // Sort existing groups by types and collect their names
5588
5589   // to store an old group and a generated new one
5590   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5591   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5592   // group names
5593   set< string > groupNames;
5594   //
5595   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5596   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5597   while ( groupIt->more() ) {
5598     SMESH_Group * group = groupIt->next();
5599     if ( !group ) continue;
5600     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5601     if ( !groupDS || groupDS->IsEmpty() ) continue;
5602     groupNames.insert( group->GetName() );
5603     groupDS->SetStoreName( group->GetName() );
5604     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5605   }
5606
5607   // Groups creation
5608
5609   // loop on nodes and elements
5610   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5611   {
5612     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5613     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5614     if ( gens.Length() != elems.Length() )
5615       throw SALOME_Exception(LOCALIZED("invalid args"));
5616
5617     // loop on created elements
5618     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5619     {
5620       const SMDS_MeshElement* sourceElem = gens( iElem );
5621       if ( !sourceElem ) {
5622         MESSAGE("generateGroups(): NULL source element");
5623         continue;
5624       }
5625       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5626       if ( groupsOldNew.empty() ) {
5627         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5628           ++iElem; // skip all elements made by sourceElem
5629         continue;
5630       }
5631       // collect all elements made by sourceElem
5632       list< const SMDS_MeshElement* > resultElems;
5633       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5634         if ( resElem != sourceElem )
5635           resultElems.push_back( resElem );
5636       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5637         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5638           if ( resElem != sourceElem )
5639             resultElems.push_back( resElem );
5640       // do not generate element groups from node ones
5641       if ( sourceElem->GetType() == SMDSAbs_Node &&
5642            elems( iElem )->GetType() != SMDSAbs_Node )
5643         continue;
5644
5645       // add resultElems to groups made by ones the sourceElem belongs to
5646       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5647       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5648       {
5649         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5650         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5651         {
5652           SMDS_MeshGroup* & newGroup = gOldNew->second;
5653           if ( !newGroup )// create a new group
5654           {
5655             // make a name
5656             string name = oldGroup->GetStoreName();
5657             if ( !targetMesh ) {
5658               name += "_";
5659               name += postfix;
5660               int nb = 0;
5661               while ( !groupNames.insert( name ).second ) // name exists
5662               {
5663                 if ( nb == 0 ) {
5664                   name += "_1";
5665                 }
5666                 else {
5667                   TCollection_AsciiString nbStr(nb+1);
5668                   name.resize( name.rfind('_')+1 );
5669                   name += nbStr.ToCString();
5670                 }
5671                 ++nb;
5672               }
5673             }
5674             // make a group
5675             int id;
5676             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5677                                                  name.c_str(), id );
5678             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5679             newGroup = & groupDS->SMDSGroup();
5680             newGroupIDs->push_back( id );
5681           }
5682
5683           // fill in a new group
5684           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5685           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5686             newGroup->Add( *resElemIt );
5687         }
5688       }
5689     } // loop on created elements
5690   }// loop on nodes and elements
5691
5692   return newGroupIDs;
5693 }
5694
5695 //================================================================================
5696 /*!
5697  * \brief Return list of group of nodes close to each other within theTolerance
5698  *        Search among theNodes or in the whole mesh if theNodes is empty using
5699  *        an Octree algorithm
5700  */
5701 //================================================================================
5702
5703 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5704                                             const double         theTolerance,
5705                                             TListOfListOfNodes & theGroupsOfNodes)
5706 {
5707   myLastCreatedElems.Clear();
5708   myLastCreatedNodes.Clear();
5709
5710   if ( theNodes.empty() )
5711   { // get all nodes in the mesh
5712     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5713     while ( nIt->more() )
5714       theNodes.insert( theNodes.end(),nIt->next());
5715   }
5716
5717   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5718 }
5719
5720
5721 //=======================================================================
5722 /*!
5723  * \brief Implementation of search for the node closest to point
5724  */
5725 //=======================================================================
5726
5727 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5728 {
5729   //---------------------------------------------------------------------
5730   /*!
5731    * \brief Constructor
5732    */
5733   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5734   {
5735     myMesh = ( SMESHDS_Mesh* ) theMesh;
5736
5737     TIDSortedNodeSet nodes;
5738     if ( theMesh ) {
5739       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5740       while ( nIt->more() )
5741         nodes.insert( nodes.end(), nIt->next() );
5742     }
5743     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5744
5745     // get max size of a leaf box
5746     SMESH_OctreeNode* tree = myOctreeNode;
5747     while ( !tree->isLeaf() )
5748     {
5749       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5750       if ( cIt->more() )
5751         tree = cIt->next();
5752     }
5753     myHalfLeafSize = tree->maxSize() / 2.;
5754   }
5755
5756   //---------------------------------------------------------------------
5757   /*!
5758    * \brief Move node and update myOctreeNode accordingly
5759    */
5760   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5761   {
5762     myOctreeNode->UpdateByMoveNode( node, toPnt );
5763     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5764   }
5765
5766   //---------------------------------------------------------------------
5767   /*!
5768    * \brief Do it's job
5769    */
5770   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5771   {
5772     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5773     map<double, const SMDS_MeshNode*> dist2Nodes;
5774     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5775     if ( !dist2Nodes.empty() )
5776       return dist2Nodes.begin()->second;
5777     list<const SMDS_MeshNode*> nodes;
5778     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5779
5780     double minSqDist = DBL_MAX;
5781     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5782     {
5783       // sort leafs by their distance from thePnt
5784       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5785       TDistTreeMap treeMap;
5786       list< SMESH_OctreeNode* > treeList;
5787       list< SMESH_OctreeNode* >::iterator trIt;
5788       treeList.push_back( myOctreeNode );
5789
5790       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5791       bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5792       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5793       {
5794         SMESH_OctreeNode* tree = *trIt;
5795         if ( !tree->isLeaf() ) // put children to the queue
5796         {
5797           if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5798           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5799           while ( cIt->more() )
5800             treeList.push_back( cIt->next() );
5801         }
5802         else if ( tree->NbNodes() ) // put a tree to the treeMap
5803         {
5804           const Bnd_B3d& box = tree->getBox();
5805           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5806           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5807           if ( !it_in.second ) // not unique distance to box center
5808             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5809         }
5810       }
5811       // find distance after which there is no sense to check tree's
5812       double sqLimit = DBL_MAX;
5813       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5814       if ( treeMap.size() > 5 ) {
5815         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5816         const Bnd_B3d& box = closestTree->getBox();
5817         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5818         sqLimit = limit * limit;
5819       }
5820       // get all nodes from trees
5821       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5822         if ( sqDist_tree->first > sqLimit )
5823           break;
5824         SMESH_OctreeNode* tree = sqDist_tree->second;
5825         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5826       }
5827     }
5828     // find closest among nodes
5829     minSqDist = DBL_MAX;
5830     const SMDS_MeshNode* closestNode = 0;
5831     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5832     for ( ; nIt != nodes.end(); ++nIt ) {
5833       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5834       if ( minSqDist > sqDist ) {
5835         closestNode = *nIt;
5836         minSqDist = sqDist;
5837       }
5838     }
5839     return closestNode;
5840   }
5841
5842   //---------------------------------------------------------------------
5843   /*!
5844    * \brief Destructor
5845    */
5846   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5847
5848   //---------------------------------------------------------------------
5849   /*!
5850    * \brief Return the node tree
5851    */
5852   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5853
5854 private:
5855   SMESH_OctreeNode* myOctreeNode;
5856   SMESHDS_Mesh*     myMesh;
5857   double            myHalfLeafSize; // max size of a leaf box
5858 };
5859
5860 //=======================================================================
5861 /*!
5862  * \brief Return SMESH_NodeSearcher
5863  */
5864 //=======================================================================
5865
5866 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
5867 {
5868   return new SMESH_NodeSearcherImpl( GetMeshDS() );
5869 }
5870
5871 // ========================================================================
5872 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5873 {
5874   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5875   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5876   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
5877
5878   //=======================================================================
5879   /*!
5880    * \brief Octal tree of bounding boxes of elements
5881    */
5882   //=======================================================================
5883
5884   class ElementBndBoxTree : public SMESH_Octree
5885   {
5886   public:
5887
5888     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
5889     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5890     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5891     ~ElementBndBoxTree();
5892
5893   protected:
5894     ElementBndBoxTree() {}
5895     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5896     void buildChildrenData();
5897     Bnd_B3d* buildRootBox();
5898   private:
5899     //!< Bounding box of element
5900     struct ElementBox : public Bnd_B3d
5901     {
5902       const SMDS_MeshElement* _element;
5903       int                     _refCount; // an ElementBox can be included in several tree branches
5904       ElementBox(const SMDS_MeshElement* elem, double tolerance);
5905     };
5906     vector< ElementBox* > _elements;
5907   };
5908
5909   //================================================================================
5910   /*!
5911    * \brief ElementBndBoxTree creation
5912    */
5913   //================================================================================
5914
5915   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
5916     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5917   {
5918     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5919     _elements.reserve( nbElems );
5920
5921     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5922     while ( elemIt->more() )
5923       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
5924
5925     if ( _elements.size() > MaxNbElemsInLeaf )
5926       compute();
5927     else
5928       myIsLeaf = true;
5929   }
5930
5931   //================================================================================
5932   /*!
5933    * \brief Destructor
5934    */
5935   //================================================================================
5936
5937   ElementBndBoxTree::~ElementBndBoxTree()
5938   {
5939     for ( int i = 0; i < _elements.size(); ++i )
5940       if ( --_elements[i]->_refCount <= 0 )
5941         delete _elements[i];
5942   }
5943
5944   //================================================================================
5945   /*!
5946    * \brief Return the maximal box
5947    */
5948   //================================================================================
5949
5950   Bnd_B3d* ElementBndBoxTree::buildRootBox()
5951   {
5952     Bnd_B3d* box = new Bnd_B3d;
5953     for ( int i = 0; i < _elements.size(); ++i )
5954       box->Add( *_elements[i] );
5955     return box;
5956   }
5957
5958   //================================================================================
5959   /*!
5960    * \brief Redistrubute element boxes among children
5961    */
5962   //================================================================================
5963
5964   void ElementBndBoxTree::buildChildrenData()
5965   {
5966     for ( int i = 0; i < _elements.size(); ++i )
5967     {
5968       for (int j = 0; j < 8; j++)
5969       {
5970         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5971         {
5972           _elements[i]->_refCount++;
5973           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5974         }
5975       }
5976       _elements[i]->_refCount--;
5977     }
5978     _elements.clear();
5979
5980     for (int j = 0; j < 8; j++)
5981     {
5982       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5983       if ( child->_elements.size() <= MaxNbElemsInLeaf )
5984         child->myIsLeaf = true;
5985
5986       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5987         child->_elements.resize( child->_elements.size() ); // compact
5988     }
5989   }
5990
5991   //================================================================================
5992   /*!
5993    * \brief Return elements which can include the point
5994    */
5995   //================================================================================
5996
5997   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
5998                                                 TIDSortedElemSet& foundElems)
5999   {
6000     if ( level() && getBox().IsOut( point.XYZ() ))
6001       return;
6002
6003     if ( isLeaf() )
6004     {
6005       for ( int i = 0; i < _elements.size(); ++i )
6006         if ( !_elements[i]->IsOut( point.XYZ() ))
6007           foundElems.insert( _elements[i]->_element );
6008     }
6009     else
6010     {
6011       for (int i = 0; i < 8; i++)
6012         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6013     }
6014   }
6015
6016   //================================================================================
6017   /*!
6018    * \brief Return elements which can be intersected by the line
6019    */
6020   //================================================================================
6021
6022   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6023                                                TIDSortedElemSet& foundElems)
6024   {
6025     if ( level() && getBox().IsOut( line ))
6026       return;
6027
6028     if ( isLeaf() )
6029     {
6030       for ( int i = 0; i < _elements.size(); ++i )
6031         if ( !_elements[i]->IsOut( line ))
6032           foundElems.insert( _elements[i]->_element );
6033     }
6034     else
6035     {
6036       for (int i = 0; i < 8; i++)
6037         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6038     }
6039   }
6040
6041   //================================================================================
6042   /*!
6043    * \brief Construct the element box
6044    */
6045   //================================================================================
6046
6047   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6048   {
6049     _element  = elem;
6050     _refCount = 1;
6051     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6052     while ( nIt->more() )
6053       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6054     Enlarge( tolerance );
6055   }
6056
6057 } // namespace
6058
6059 //=======================================================================
6060 /*!
6061  * \brief Implementation of search for the elements by point and
6062  *        of classification of point in 2D mesh
6063  */
6064 //=======================================================================
6065
6066 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6067 {
6068   SMESHDS_Mesh*                _mesh;
6069   ElementBndBoxTree*           _ebbTree;
6070   SMESH_NodeSearcherImpl*      _nodeSearcher;
6071   SMDSAbs_ElementType          _elementType;
6072   double                       _tolerance;
6073   bool                         _outerFacesFound;
6074   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6075
6076   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6077     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6078   ~SMESH_ElementSearcherImpl()
6079   {
6080     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6081     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6082   }
6083   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6084                                   SMDSAbs_ElementType                type,
6085                                   vector< const SMDS_MeshElement* >& foundElements);
6086   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6087
6088   void GetElementsNearLine( const gp_Ax1&                      line,
6089                             SMDSAbs_ElementType                type,
6090                             vector< const SMDS_MeshElement* >& foundElems);
6091   double getTolerance();
6092   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6093                             const double tolerance, double & param);
6094   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6095   bool isOuterBoundary(const SMDS_MeshElement* face) const
6096   {
6097     return _outerFaces.empty() || _outerFaces.count(face);
6098   }
6099   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6100   {
6101     const SMDS_MeshElement* _face;
6102     gp_Vec                  _faceNorm;
6103     bool                    _coincides; //!< the line lays in face plane
6104     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6105       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6106   };
6107   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6108   {
6109     SMESH_TLink      _link;
6110     TIDSortedElemSet _faces;
6111     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6112       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6113   };
6114 };
6115
6116 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6117 {
6118   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6119              << ", _coincides="<<i._coincides << ")";
6120 }
6121
6122 //=======================================================================
6123 /*!
6124  * \brief define tolerance for search
6125  */
6126 //=======================================================================
6127
6128 double SMESH_ElementSearcherImpl::getTolerance()
6129 {
6130   if ( _tolerance < 0 )
6131   {
6132     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6133
6134     _tolerance = 0;
6135     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6136     {
6137       double boxSize = _nodeSearcher->getTree()->maxSize();
6138       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6139     }
6140     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6141     {
6142       double boxSize = _ebbTree->maxSize();
6143       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6144     }
6145     if ( _tolerance == 0 )
6146     {
6147       // define tolerance by size of a most complex element
6148       int complexType = SMDSAbs_Volume;
6149       while ( complexType > SMDSAbs_All &&
6150               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6151         --complexType;
6152       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6153
6154       double elemSize;
6155       if ( complexType == int( SMDSAbs_Node ))
6156       {
6157         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6158         elemSize = 1;
6159         if ( meshInfo.NbNodes() > 2 )
6160           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6161       }
6162       else
6163       {
6164         const SMDS_MeshElement* elem =
6165           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6166         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6167         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6168         while ( nodeIt->more() )
6169         {
6170           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6171           elemSize = max( dist, elemSize );
6172         }
6173       }
6174       _tolerance = 1e-4 * elemSize;
6175     }
6176   }
6177   return _tolerance;
6178 }
6179
6180 //================================================================================
6181 /*!
6182  * \brief Find intersection of the line and an edge of face and return parameter on line
6183  */
6184 //================================================================================
6185
6186 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6187                                                      const SMDS_MeshElement* face,
6188                                                      const double            tol,
6189                                                      double &                param)
6190 {
6191   int nbInts = 0;
6192   param = 0;
6193
6194   GeomAPI_ExtremaCurveCurve anExtCC;
6195   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6196   
6197   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6198   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6199   {
6200     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6201                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6202     anExtCC.Init( lineCurve, edge);
6203     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6204     {
6205       Quantity_Parameter pl, pe;
6206       anExtCC.LowerDistanceParameters( pl, pe );
6207       param += pl;
6208       if ( ++nbInts == 2 )
6209         break;
6210     }
6211   }
6212   if ( nbInts > 0 ) param /= nbInts;
6213   return nbInts > 0;
6214 }
6215 //================================================================================
6216 /*!
6217  * \brief Find all faces belonging to the outer boundary of mesh
6218  */
6219 //================================================================================
6220
6221 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6222 {
6223   if ( _outerFacesFound ) return;
6224
6225   // Collect all outer faces by passing from one outer face to another via their links
6226   // and BTW find out if there are internal faces at all.
6227
6228   // checked links and links where outer boundary meets internal one
6229   set< SMESH_TLink > visitedLinks, seamLinks;
6230
6231   // links to treat with already visited faces sharing them
6232   list < TFaceLink > startLinks;
6233
6234   // load startLinks with the first outerFace
6235   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6236   _outerFaces.insert( outerFace );
6237
6238   TIDSortedElemSet emptySet;
6239   while ( !startLinks.empty() )
6240   {
6241     const SMESH_TLink& link  = startLinks.front()._link;
6242     TIDSortedElemSet&  faces = startLinks.front()._faces;
6243
6244     outerFace = *faces.begin();
6245     // find other faces sharing the link
6246     const SMDS_MeshElement* f;
6247     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6248       faces.insert( f );
6249
6250     // select another outer face among the found 
6251     const SMDS_MeshElement* outerFace2 = 0;
6252     if ( faces.size() == 2 )
6253     {
6254       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6255     }
6256     else if ( faces.size() > 2 )
6257     {
6258       seamLinks.insert( link );
6259
6260       // link direction within the outerFace
6261       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6262                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6263       int i1 = outerFace->GetNodeIndex( link.node1() );
6264       int i2 = outerFace->GetNodeIndex( link.node2() );
6265       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6266       if ( rev ) n1n2.Reverse();
6267       // outerFace normal
6268       gp_XYZ ofNorm, fNorm;
6269       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6270       {
6271         // direction from the link inside outerFace
6272         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6273         // sort all other faces by angle with the dirInOF
6274         map< double, const SMDS_MeshElement* > angle2Face;
6275         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6276         for ( ; face != faces.end(); ++face )
6277         {
6278           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6279             continue;
6280           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6281           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6282           if ( angle < 0 ) angle += 2*PI;
6283           angle2Face.insert( make_pair( angle, *face ));
6284         }
6285         if ( !angle2Face.empty() )
6286           outerFace2 = angle2Face.begin()->second;
6287       }
6288     }
6289     // store the found outer face and add its links to continue seaching from
6290     if ( outerFace2 )
6291     {
6292       _outerFaces.insert( outerFace );
6293       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6294       for ( int i = 0; i < nbNodes; ++i )
6295       {
6296         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6297         if ( visitedLinks.insert( link2 ).second )
6298           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6299       }
6300     }
6301     startLinks.pop_front();
6302   }
6303   _outerFacesFound = true;
6304
6305   if ( !seamLinks.empty() )
6306   {
6307     // There are internal boundaries touching the outher one,
6308     // find all faces of internal boundaries in order to find
6309     // faces of boundaries of holes, if any.
6310     
6311   }
6312   else
6313   {
6314     _outerFaces.clear();
6315   }
6316 }
6317
6318 //=======================================================================
6319 /*!
6320  * \brief Find elements of given type where the given point is IN or ON.
6321  *        Returns nb of found elements and elements them-selves.
6322  *
6323  * 'ALL' type means elements of any type excluding nodes and 0D elements
6324  */
6325 //=======================================================================
6326
6327 int SMESH_ElementSearcherImpl::
6328 FindElementsByPoint(const gp_Pnt&                      point,
6329                     SMDSAbs_ElementType                type,
6330                     vector< const SMDS_MeshElement* >& foundElements)
6331 {
6332   foundElements.clear();
6333
6334   double tolerance = getTolerance();
6335
6336   // =================================================================================
6337   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6338   {
6339     if ( !_nodeSearcher )
6340       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6341
6342     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6343     if ( !closeNode ) return foundElements.size();
6344
6345     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6346       return foundElements.size(); // to far from any node
6347
6348     if ( type == SMDSAbs_Node )
6349     {
6350       foundElements.push_back( closeNode );
6351     }
6352     else
6353     {
6354       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6355       while ( elemIt->more() )
6356         foundElements.push_back( elemIt->next() );
6357     }
6358   }
6359   // =================================================================================
6360   else // elements more complex than 0D
6361   {
6362     if ( !_ebbTree || _elementType != type )
6363     {
6364       if ( _ebbTree ) delete _ebbTree;
6365       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6366     }
6367     TIDSortedElemSet suspectElems;
6368     _ebbTree->getElementsNearPoint( point, suspectElems );
6369     TIDSortedElemSet::iterator elem = suspectElems.begin();
6370     for ( ; elem != suspectElems.end(); ++elem )
6371       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6372         foundElements.push_back( *elem );
6373   }
6374   return foundElements.size();
6375 }
6376
6377 //================================================================================
6378 /*!
6379  * \brief Classify the given point in the closed 2D mesh
6380  */
6381 //================================================================================
6382
6383 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6384 {
6385   double tolerance = getTolerance();
6386   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6387   {
6388     if ( _ebbTree ) delete _ebbTree;
6389     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6390   }
6391   // Algo: analyse transition of a line starting at the point through mesh boundary;
6392   // try three lines parallel to axis of the coordinate system and perform rough
6393   // analysis. If solution is not clear perform thorough analysis.
6394
6395   const int nbAxes = 3;
6396   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6397   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6398   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6399   multimap< int, int > nbInt2Axis; // to find the simplest case
6400   for ( int axis = 0; axis < nbAxes; ++axis )
6401   {
6402     gp_Ax1 lineAxis( point, axisDir[axis]);
6403     gp_Lin line    ( lineAxis );
6404
6405     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6406     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6407
6408     // Intersect faces with the line
6409
6410     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6411     TIDSortedElemSet::iterator face = suspectFaces.begin();
6412     for ( ; face != suspectFaces.end(); ++face )
6413     {
6414       // get face plane
6415       gp_XYZ fNorm;
6416       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6417       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6418
6419       // perform intersection
6420       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6421       if ( !intersection.IsDone() )
6422         continue;
6423       if ( intersection.IsInQuadric() )
6424       {
6425         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6426       }
6427       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6428       {
6429         gp_Pnt intersectionPoint = intersection.Point(1);
6430         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6431           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6432       }
6433     }
6434     // Analyse intersections roughly
6435
6436     int nbInter = u2inters.size();
6437     if ( nbInter == 0 )
6438       return TopAbs_OUT; 
6439
6440     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6441     if ( nbInter == 1 ) // not closed mesh
6442       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6443
6444     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6445       return TopAbs_ON;
6446
6447     if ( (f<0) == (l<0) )
6448       return TopAbs_OUT;
6449
6450     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6451     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6452     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6453       return TopAbs_IN;
6454
6455     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6456
6457     if ( _outerFacesFound ) break; // pass to thorough analysis
6458
6459   } // three attempts - loop on CS axes
6460
6461   // Analyse intersections thoroughly.
6462   // We make two loops maximum, on the first one we only exclude touching intersections,
6463   // on the second, if situation is still unclear, we gather and use information on
6464   // position of faces (internal or outer). If faces position is already gathered,
6465   // we make the second loop right away.
6466
6467   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6468   {
6469     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6470     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6471     {
6472       int axis = nb_axis->second;
6473       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6474
6475       gp_Ax1 lineAxis( point, axisDir[axis]);
6476       gp_Lin line    ( lineAxis );
6477
6478       // add tangent intersections to u2inters
6479       double param;
6480       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6481       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6482         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6483           u2inters.insert(make_pair( param, *tgtInt ));
6484       tangentInters[ axis ].clear();
6485
6486       // Count intersections before and after the point excluding touching ones.
6487       // If hasPositionInfo we count intersections of outer boundary only
6488
6489       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6490       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6491       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6492       bool ok = ! u_int1->second._coincides;
6493       while ( ok && u_int1 != u2inters.end() )
6494       {
6495         double u = u_int1->first;
6496         bool touchingInt = false;
6497         if ( ++u_int2 != u2inters.end() )
6498         {
6499           // skip intersections at the same point (if the line passes through edge or node)
6500           int nbSamePnt = 0;
6501           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6502           {
6503             ++nbSamePnt;
6504             ++u_int2;
6505           }
6506
6507           // skip tangent intersections
6508           int nbTgt = 0;
6509           const SMDS_MeshElement* prevFace = u_int1->second._face;
6510           while ( ok && u_int2->second._coincides )
6511           {
6512             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6513               ok = false;
6514             else
6515             {
6516               nbTgt++;
6517               u_int2++;
6518               ok = ( u_int2 != u2inters.end() );
6519             }
6520           }
6521           if ( !ok ) break;
6522
6523           // skip intersections at the same point after tangent intersections
6524           if ( nbTgt > 0 )
6525           {
6526             double u2 = u_int2->first;
6527             ++u_int2;
6528             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6529             {
6530               ++nbSamePnt;
6531               ++u_int2;
6532             }
6533           }
6534           // decide if we skipped a touching intersection
6535           if ( nbSamePnt + nbTgt > 0 )
6536           {
6537             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6538             map< double, TInters >::iterator u_int = u_int1;
6539             for ( ; u_int != u_int2; ++u_int )
6540             {
6541               if ( u_int->second._coincides ) continue;
6542               double dot = u_int->second._faceNorm * line.Direction();
6543               if ( dot > maxDot ) maxDot = dot;
6544               if ( dot < minDot ) minDot = dot;
6545             }
6546             touchingInt = ( minDot*maxDot < 0 );
6547           }
6548         }
6549         if ( !touchingInt )
6550         {
6551           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6552           {
6553             if ( u < 0 )
6554               ++nbIntBeforePoint;
6555             else
6556               ++nbIntAfterPoint;
6557           }
6558           if ( u < f ) f = u;
6559           if ( u > l ) l = u;
6560         }
6561
6562         u_int1 = u_int2; // to next intersection
6563
6564       } // loop on intersections with one line
6565
6566       if ( ok )
6567       {
6568         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6569           return TopAbs_ON;
6570
6571         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6572           return TopAbs_OUT; 
6573
6574         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6575           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6576
6577         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6578           return TopAbs_IN;
6579
6580         if ( (f<0) == (l<0) )
6581           return TopAbs_OUT;
6582
6583         if ( hasPositionInfo )
6584           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6585       }
6586     } // loop on intersections of the tree lines - thorough analysis
6587
6588     if ( !hasPositionInfo )
6589     {
6590       // gather info on faces position - is face in the outer boundary or not
6591       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6592       findOuterBoundary( u2inters.begin()->second._face );
6593     }
6594
6595   } // two attempts - with and w/o faces position info in the mesh
6596
6597   return TopAbs_UNKNOWN;
6598 }
6599
6600 //=======================================================================
6601 /*!
6602  * \brief Return elements possibly intersecting the line
6603  */
6604 //=======================================================================
6605
6606 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6607                                                      SMDSAbs_ElementType                type,
6608                                                      vector< const SMDS_MeshElement* >& foundElems)
6609 {
6610   if ( !_ebbTree || _elementType != type )
6611   {
6612     if ( _ebbTree ) delete _ebbTree;
6613     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6614   }
6615   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6616   _ebbTree->getElementsNearLine( line, suspectFaces );
6617   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6618 }
6619
6620 //=======================================================================
6621 /*!
6622  * \brief Return SMESH_ElementSearcher
6623  */
6624 //=======================================================================
6625
6626 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6627 {
6628   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6629 }
6630
6631 //=======================================================================
6632 /*!
6633  * \brief Return true if the point is IN or ON of the element
6634  */
6635 //=======================================================================
6636
6637 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6638 {
6639   if ( element->GetType() == SMDSAbs_Volume)
6640   {
6641     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6642   }
6643
6644   // get ordered nodes
6645
6646   vector< gp_XYZ > xyz;
6647
6648   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6649   if ( element->IsQuadratic() )
6650     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6651       nodeIt = f->interlacedNodesElemIterator();
6652     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6653       nodeIt = e->interlacedNodesElemIterator();
6654
6655   while ( nodeIt->more() )
6656     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6657
6658   int i, nbNodes = element->NbNodes();
6659
6660   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6661   {
6662     // compute face normal
6663     gp_Vec faceNorm(0,0,0);
6664     xyz.push_back( xyz.front() );
6665     for ( i = 0; i < nbNodes; ++i )
6666     {
6667       gp_Vec edge1( xyz[i+1], xyz[i]);
6668       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6669       faceNorm += edge1 ^ edge2;
6670     }
6671     double normSize = faceNorm.Magnitude();
6672     if ( normSize <= tol )
6673     {
6674       // degenerated face: point is out if it is out of all face edges
6675       for ( i = 0; i < nbNodes; ++i )
6676       {
6677         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6678         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6679         SMDS_MeshEdge edge( &n1, &n2 );
6680         if ( !isOut( &edge, point, tol ))
6681           return false;
6682       }
6683       return true;
6684     }
6685     faceNorm /= normSize;
6686
6687     // check if the point lays on face plane
6688     gp_Vec n2p( xyz[0], point );
6689     if ( fabs( n2p * faceNorm ) > tol )
6690       return true; // not on face plane
6691
6692     // check if point is out of face boundary:
6693     // define it by closest transition of a ray point->infinity through face boundary
6694     // on the face plane.
6695     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6696     // to find intersections of the ray with the boundary.
6697     gp_Vec ray = n2p;
6698     gp_Vec plnNorm = ray ^ faceNorm;
6699     normSize = plnNorm.Magnitude();
6700     if ( normSize <= tol ) return false; // point coincides with the first node
6701     plnNorm /= normSize;
6702     // for each node of the face, compute its signed distance to the plane
6703     vector<double> dist( nbNodes + 1);
6704     for ( i = 0; i < nbNodes; ++i )
6705     {
6706       gp_Vec n2p( xyz[i], point );
6707       dist[i] = n2p * plnNorm;
6708     }
6709     dist.back() = dist.front();
6710     // find the closest intersection
6711     int    iClosest = -1;
6712     double rClosest, distClosest = 1e100;;
6713     gp_Pnt pClosest;
6714     for ( i = 0; i < nbNodes; ++i )
6715     {
6716       double r;
6717       if ( fabs( dist[i]) < tol )
6718         r = 0.;
6719       else if ( fabs( dist[i+1]) < tol )
6720         r = 1.;
6721       else if ( dist[i] * dist[i+1] < 0 )
6722         r = dist[i] / ( dist[i] - dist[i+1] );
6723       else
6724         continue; // no intersection
6725       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6726       gp_Vec p2int ( point, pInt);
6727       if ( p2int * ray > -tol ) // right half-space
6728       {
6729         double intDist = p2int.SquareMagnitude();
6730         if ( intDist < distClosest )
6731         {
6732           iClosest = i;
6733           rClosest = r;
6734           pClosest = pInt;
6735           distClosest = intDist;
6736         }
6737       }
6738     }
6739     if ( iClosest < 0 )
6740       return true; // no intesections - out
6741
6742     // analyse transition
6743     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6744     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6745     gp_Vec p2int ( point, pClosest );
6746     bool out = (edgeNorm * p2int) < -tol;
6747     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6748       return out;
6749
6750     // ray pass through a face node; analyze transition through an adjacent edge
6751     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6752     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6753     gp_Vec edgeAdjacent( p1, p2 );
6754     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6755     bool out2 = (edgeNorm2 * p2int) < -tol;
6756
6757     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6758     return covexCorner ? (out || out2) : (out && out2);
6759   }
6760   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6761   {
6762     // point is out of edge if it is NOT ON any straight part of edge
6763     // (we consider quadratic edge as being composed of two straight parts)
6764     for ( i = 1; i < nbNodes; ++i )
6765     {
6766       gp_Vec edge( xyz[i-1], xyz[i]);
6767       gp_Vec n1p ( xyz[i-1], point);
6768       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6769       if ( dist > tol )
6770         continue;
6771       gp_Vec n2p( xyz[i], point );
6772       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6773         continue;
6774       return false; // point is ON this part
6775     }
6776     return true;
6777   }
6778   // Node or 0D element -------------------------------------------------------------------------
6779   {
6780     gp_Vec n2p ( xyz[0], point );
6781     return n2p.Magnitude() <= tol;
6782   }
6783   return true;
6784 }
6785
6786 //=======================================================================
6787 //function : SimplifyFace
6788 //purpose  :
6789 //=======================================================================
6790 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6791                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6792                                     vector<int>&                        quantities) const
6793 {
6794   int nbNodes = faceNodes.size();
6795
6796   if (nbNodes < 3)
6797     return 0;
6798
6799   set<const SMDS_MeshNode*> nodeSet;
6800
6801   // get simple seq of nodes
6802   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6803   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6804   int iSimple = 0, nbUnique = 0;
6805
6806   simpleNodes[iSimple++] = faceNodes[0];
6807   nbUnique++;
6808   for (int iCur = 1; iCur < nbNodes; iCur++) {
6809     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6810       simpleNodes[iSimple++] = faceNodes[iCur];
6811       if (nodeSet.insert( faceNodes[iCur] ).second)
6812         nbUnique++;
6813     }
6814   }
6815   int nbSimple = iSimple;
6816   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6817     nbSimple--;
6818     iSimple--;
6819   }
6820
6821   if (nbUnique < 3)
6822     return 0;
6823
6824   // separate loops
6825   int nbNew = 0;
6826   bool foundLoop = (nbSimple > nbUnique);
6827   while (foundLoop) {
6828     foundLoop = false;
6829     set<const SMDS_MeshNode*> loopSet;
6830     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6831       const SMDS_MeshNode* n = simpleNodes[iSimple];
6832       if (!loopSet.insert( n ).second) {
6833         foundLoop = true;
6834
6835         // separate loop
6836         int iC = 0, curLast = iSimple;
6837         for (; iC < curLast; iC++) {
6838           if (simpleNodes[iC] == n) break;
6839         }
6840         int loopLen = curLast - iC;
6841         if (loopLen > 2) {
6842           // create sub-element
6843           nbNew++;
6844           quantities.push_back(loopLen);
6845           for (; iC < curLast; iC++) {
6846             poly_nodes.push_back(simpleNodes[iC]);
6847           }
6848         }
6849         // shift the rest nodes (place from the first loop position)
6850         for (iC = curLast + 1; iC < nbSimple; iC++) {
6851           simpleNodes[iC - loopLen] = simpleNodes[iC];
6852         }
6853         nbSimple -= loopLen;
6854         iSimple -= loopLen;
6855       }
6856     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6857   } // while (foundLoop)
6858
6859   if (iSimple > 2) {
6860     nbNew++;
6861     quantities.push_back(iSimple);
6862     for (int i = 0; i < iSimple; i++)
6863       poly_nodes.push_back(simpleNodes[i]);
6864   }
6865
6866   return nbNew;
6867 }
6868
6869 //=======================================================================
6870 //function : MergeNodes
6871 //purpose  : In each group, the cdr of nodes are substituted by the first one
6872 //           in all elements.
6873 //=======================================================================
6874
6875 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6876 {
6877   myLastCreatedElems.Clear();
6878   myLastCreatedNodes.Clear();
6879
6880   SMESHDS_Mesh* aMesh = GetMeshDS();
6881
6882   TNodeNodeMap nodeNodeMap; // node to replace - new node
6883   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6884   list< int > rmElemIds, rmNodeIds;
6885
6886   // Fill nodeNodeMap and elems
6887
6888   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6889   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6890     list<const SMDS_MeshNode*>& nodes = *grIt;
6891     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6892     const SMDS_MeshNode* nToKeep = *nIt;
6893     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6894       const SMDS_MeshNode* nToRemove = *nIt;
6895       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6896       if ( nToRemove != nToKeep ) {
6897         rmNodeIds.push_back( nToRemove->GetID() );
6898         AddToSameGroups( nToKeep, nToRemove, aMesh );
6899       }
6900
6901       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6902       while ( invElemIt->more() ) {
6903         const SMDS_MeshElement* elem = invElemIt->next();
6904         elems.insert(elem);
6905       }
6906     }
6907   }
6908   // Change element nodes or remove an element
6909
6910   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6911   for ( ; eIt != elems.end(); eIt++ ) {
6912     const SMDS_MeshElement* elem = *eIt;
6913     int nbNodes = elem->NbNodes();
6914     int aShapeId = FindShape( elem );
6915
6916     set<const SMDS_MeshNode*> nodeSet;
6917     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6918     int iUnique = 0, iCur = 0, nbRepl = 0;
6919     vector<int> iRepl( nbNodes );
6920
6921     // get new seq of nodes
6922     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6923     while ( itN->more() ) {
6924       const SMDS_MeshNode* n =
6925         static_cast<const SMDS_MeshNode*>( itN->next() );
6926
6927       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6928       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6929         n = (*nnIt).second;
6930         // BUG 0020185: begin
6931         {
6932           bool stopRecur = false;
6933           set<const SMDS_MeshNode*> nodesRecur;
6934           nodesRecur.insert(n);
6935           while (!stopRecur) {
6936             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6937             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6938               n = (*nnIt_i).second;
6939               if (!nodesRecur.insert(n).second) {
6940                 // error: recursive dependancy
6941                 stopRecur = true;
6942               }
6943             }
6944             else
6945               stopRecur = true;
6946           }
6947         }
6948         // BUG 0020185: end
6949         iRepl[ nbRepl++ ] = iCur;
6950       }
6951       curNodes[ iCur ] = n;
6952       bool isUnique = nodeSet.insert( n ).second;
6953       if ( isUnique )
6954         uniqueNodes[ iUnique++ ] = n;
6955       iCur++;
6956     }
6957
6958     // Analyse element topology after replacement
6959
6960     bool isOk = true;
6961     int nbUniqueNodes = nodeSet.size();
6962     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6963       // Polygons and Polyhedral volumes
6964       if (elem->IsPoly()) {
6965
6966         if (elem->GetType() == SMDSAbs_Face) {
6967           // Polygon
6968           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6969           int inode = 0;
6970           for (; inode < nbNodes; inode++) {
6971             face_nodes[inode] = curNodes[inode];
6972           }
6973
6974           vector<const SMDS_MeshNode *> polygons_nodes;
6975           vector<int> quantities;
6976           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6977
6978           if (nbNew > 0) {
6979             inode = 0;
6980             for (int iface = 0; iface < nbNew - 1; iface++) {
6981               int nbNodes = quantities[iface];
6982               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6983               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6984                 poly_nodes[ii] = polygons_nodes[inode];
6985               }
6986               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6987               myLastCreatedElems.Append(newElem);
6988               if (aShapeId)
6989                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6990             }
6991             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6992           }
6993           else {
6994             rmElemIds.push_back(elem->GetID());
6995           }
6996
6997         }
6998         else if (elem->GetType() == SMDSAbs_Volume) {
6999           // Polyhedral volume
7000           if (nbUniqueNodes < 4) {
7001             rmElemIds.push_back(elem->GetID());
7002           }
7003           else {
7004             // each face has to be analized in order to check volume validity
7005             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7006               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7007             if (aPolyedre) {
7008               int nbFaces = aPolyedre->NbFaces();
7009
7010               vector<const SMDS_MeshNode *> poly_nodes;
7011               vector<int> quantities;
7012
7013               for (int iface = 1; iface <= nbFaces; iface++) {
7014                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7015                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7016
7017                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7018                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7019                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7020                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7021                     faceNode = (*nnIt).second;
7022                   }
7023                   faceNodes[inode - 1] = faceNode;
7024                 }
7025
7026                 SimplifyFace(faceNodes, poly_nodes, quantities);
7027               }
7028
7029               if (quantities.size() > 3) {
7030                 // to be done: remove coincident faces
7031               }
7032
7033               if (quantities.size() > 3)
7034                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7035               else
7036                 rmElemIds.push_back(elem->GetID());
7037
7038             }
7039             else {
7040               rmElemIds.push_back(elem->GetID());
7041             }
7042           }
7043         }
7044         else {
7045         }
7046
7047         continue;
7048       }
7049
7050       // Regular elements
7051       switch ( nbNodes ) {
7052       case 2: ///////////////////////////////////// EDGE
7053         isOk = false; break;
7054       case 3: ///////////////////////////////////// TRIANGLE
7055         isOk = false; break;
7056       case 4:
7057         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7058           isOk = false;
7059         else { //////////////////////////////////// QUADRANGLE
7060           if ( nbUniqueNodes < 3 )
7061             isOk = false;
7062           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7063             isOk = false; // opposite nodes stick
7064         }
7065         break;
7066       case 6: ///////////////////////////////////// PENTAHEDRON
7067         if ( nbUniqueNodes == 4 ) {
7068           // ---------------------------------> tetrahedron
7069           if (nbRepl == 3 &&
7070               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7071             // all top nodes stick: reverse a bottom
7072             uniqueNodes[ 0 ] = curNodes [ 1 ];
7073             uniqueNodes[ 1 ] = curNodes [ 0 ];
7074           }
7075           else if (nbRepl == 3 &&
7076                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7077             // all bottom nodes stick: set a top before
7078             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7079             uniqueNodes[ 0 ] = curNodes [ 3 ];
7080             uniqueNodes[ 1 ] = curNodes [ 4 ];
7081             uniqueNodes[ 2 ] = curNodes [ 5 ];
7082           }
7083           else if (nbRepl == 4 &&
7084                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7085             // a lateral face turns into a line: reverse a bottom
7086             uniqueNodes[ 0 ] = curNodes [ 1 ];
7087             uniqueNodes[ 1 ] = curNodes [ 0 ];
7088           }
7089           else
7090             isOk = false;
7091         }
7092         else if ( nbUniqueNodes == 5 ) {
7093           // PENTAHEDRON --------------------> 2 tetrahedrons
7094           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7095             // a bottom node sticks with a linked top one
7096             // 1.
7097             SMDS_MeshElement* newElem =
7098               aMesh->AddVolume(curNodes[ 3 ],
7099                                curNodes[ 4 ],
7100                                curNodes[ 5 ],
7101                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7102             myLastCreatedElems.Append(newElem);
7103             if ( aShapeId )
7104               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7105             // 2. : reverse a bottom
7106             uniqueNodes[ 0 ] = curNodes [ 1 ];
7107             uniqueNodes[ 1 ] = curNodes [ 0 ];
7108             nbUniqueNodes = 4;
7109           }
7110           else
7111             isOk = false;
7112         }
7113         else
7114           isOk = false;
7115         break;
7116       case 8: {
7117         if(elem->IsQuadratic()) { // Quadratic quadrangle
7118           //   1    5    2
7119           //    +---+---+
7120           //    |       |
7121           //    |       |
7122           //   4+       +6
7123           //    |       |
7124           //    |       |
7125           //    +---+---+
7126           //   0    7    3
7127           isOk = false;
7128           if(nbRepl==3) {
7129             nbUniqueNodes = 6;
7130             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7131               uniqueNodes[0] = curNodes[0];
7132               uniqueNodes[1] = curNodes[2];
7133               uniqueNodes[2] = curNodes[3];
7134               uniqueNodes[3] = curNodes[5];
7135               uniqueNodes[4] = curNodes[6];
7136               uniqueNodes[5] = curNodes[7];
7137               isOk = true;
7138             }
7139             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7140               uniqueNodes[0] = curNodes[0];
7141               uniqueNodes[1] = curNodes[1];
7142               uniqueNodes[2] = curNodes[2];
7143               uniqueNodes[3] = curNodes[4];
7144               uniqueNodes[4] = curNodes[5];
7145               uniqueNodes[5] = curNodes[6];
7146               isOk = true;
7147             }
7148             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7149               uniqueNodes[0] = curNodes[1];
7150               uniqueNodes[1] = curNodes[2];
7151               uniqueNodes[2] = curNodes[3];
7152               uniqueNodes[3] = curNodes[5];
7153               uniqueNodes[4] = curNodes[6];
7154               uniqueNodes[5] = curNodes[0];
7155               isOk = true;
7156             }
7157             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7158               uniqueNodes[0] = curNodes[0];
7159               uniqueNodes[1] = curNodes[1];
7160               uniqueNodes[2] = curNodes[3];
7161               uniqueNodes[3] = curNodes[4];
7162               uniqueNodes[4] = curNodes[6];
7163               uniqueNodes[5] = curNodes[7];
7164               isOk = true;
7165             }
7166             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7167               uniqueNodes[0] = curNodes[0];
7168               uniqueNodes[1] = curNodes[2];
7169               uniqueNodes[2] = curNodes[3];
7170               uniqueNodes[3] = curNodes[1];
7171               uniqueNodes[4] = curNodes[6];
7172               uniqueNodes[5] = curNodes[7];
7173               isOk = true;
7174             }
7175             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7176               uniqueNodes[0] = curNodes[0];
7177               uniqueNodes[1] = curNodes[1];
7178               uniqueNodes[2] = curNodes[2];
7179               uniqueNodes[3] = curNodes[4];
7180               uniqueNodes[4] = curNodes[5];
7181               uniqueNodes[5] = curNodes[7];
7182               isOk = true;
7183             }
7184             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7185               uniqueNodes[0] = curNodes[0];
7186               uniqueNodes[1] = curNodes[1];
7187               uniqueNodes[2] = curNodes[3];
7188               uniqueNodes[3] = curNodes[4];
7189               uniqueNodes[4] = curNodes[2];
7190               uniqueNodes[5] = curNodes[7];
7191               isOk = true;
7192             }
7193             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7194               uniqueNodes[0] = curNodes[0];
7195               uniqueNodes[1] = curNodes[1];
7196               uniqueNodes[2] = curNodes[2];
7197               uniqueNodes[3] = curNodes[4];
7198               uniqueNodes[4] = curNodes[5];
7199               uniqueNodes[5] = curNodes[3];
7200               isOk = true;
7201             }
7202           }
7203           break;
7204         }
7205         //////////////////////////////////// HEXAHEDRON
7206         isOk = false;
7207         SMDS_VolumeTool hexa (elem);
7208         hexa.SetExternalNormal();
7209         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7210           //////////////////////// ---> tetrahedron
7211           for ( int iFace = 0; iFace < 6; iFace++ ) {
7212             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7213             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7214                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7215                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7216               // one face turns into a point ...
7217               int iOppFace = hexa.GetOppFaceIndex( iFace );
7218               ind = hexa.GetFaceNodesIndices( iOppFace );
7219               int nbStick = 0;
7220               iUnique = 2; // reverse a tetrahedron bottom
7221               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7222                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7223                   nbStick++;
7224                 else if ( iUnique >= 0 )
7225                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7226               }
7227               if ( nbStick == 1 ) {
7228                 // ... and the opposite one - into a triangle.
7229                 // set a top node
7230                 ind = hexa.GetFaceNodesIndices( iFace );
7231                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7232                 isOk = true;
7233               }
7234               break;
7235             }
7236           }
7237         }
7238         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7239           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7240           for ( int iFace = 0; iFace < 6; iFace++ ) {
7241             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7242             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7243                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7244                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7245               // one face turns into a point ...
7246               int iOppFace = hexa.GetOppFaceIndex( iFace );
7247               ind = hexa.GetFaceNodesIndices( iOppFace );
7248               int nbStick = 0;
7249               iUnique = 2;  // reverse a tetrahedron 1 bottom
7250               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7251                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7252                   nbStick++;
7253                 else if ( iUnique >= 0 )
7254                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7255               }
7256               if ( nbStick == 0 ) {
7257                 // ... and the opposite one is a quadrangle
7258                 // set a top node
7259                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7260                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7261                 nbUniqueNodes = 4;
7262                 // tetrahedron 2
7263                 SMDS_MeshElement* newElem =
7264                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7265                                    curNodes[ind[ 3 ]],
7266                                    curNodes[ind[ 2 ]],
7267                                    curNodes[indTop[ 0 ]]);
7268                 myLastCreatedElems.Append(newElem);
7269                 if ( aShapeId )
7270                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7271                 isOk = true;
7272               }
7273               break;
7274             }
7275           }
7276         }
7277         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7278           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7279           // find indices of quad and tri faces
7280           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7281           for ( iFace = 0; iFace < 6; iFace++ ) {
7282             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7283             nodeSet.clear();
7284             for ( iCur = 0; iCur < 4; iCur++ )
7285               nodeSet.insert( curNodes[ind[ iCur ]] );
7286             nbUniqueNodes = nodeSet.size();
7287             if ( nbUniqueNodes == 3 )
7288               iTriFace[ nbTri++ ] = iFace;
7289             else if ( nbUniqueNodes == 4 )
7290               iQuadFace[ nbQuad++ ] = iFace;
7291           }
7292           if (nbQuad == 2 && nbTri == 4 &&
7293               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7294             // 2 opposite quadrangles stuck with a diagonal;
7295             // sample groups of merged indices: (0-4)(2-6)
7296             // --------------------------------------------> 2 tetrahedrons
7297             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7298             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7299             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7300             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7301                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7302               // stuck with 0-2 diagonal
7303               i0  = ind1[ 3 ];
7304               i1d = ind1[ 0 ];
7305               i2  = ind1[ 1 ];
7306               i3d = ind1[ 2 ];
7307               i0t = ind2[ 1 ];
7308               i2t = ind2[ 3 ];
7309             }
7310             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7311                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7312               // stuck with 1-3 diagonal
7313               i0  = ind1[ 0 ];
7314               i1d = ind1[ 1 ];
7315               i2  = ind1[ 2 ];
7316               i3d = ind1[ 3 ];
7317               i0t = ind2[ 0 ];
7318               i2t = ind2[ 1 ];
7319             }
7320             else {
7321               ASSERT(0);
7322             }
7323             // tetrahedron 1
7324             uniqueNodes[ 0 ] = curNodes [ i0 ];
7325             uniqueNodes[ 1 ] = curNodes [ i1d ];
7326             uniqueNodes[ 2 ] = curNodes [ i3d ];
7327             uniqueNodes[ 3 ] = curNodes [ i0t ];
7328             nbUniqueNodes = 4;
7329             // tetrahedron 2
7330             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7331                                                          curNodes[ i2 ],
7332                                                          curNodes[ i3d ],
7333                                                          curNodes[ i2t ]);
7334             myLastCreatedElems.Append(newElem);
7335             if ( aShapeId )
7336               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7337             isOk = true;
7338           }
7339           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7340                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7341             // --------------------------------------------> prism
7342             // find 2 opposite triangles
7343             nbUniqueNodes = 6;
7344             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7345               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7346                 // find indices of kept and replaced nodes
7347                 // and fill unique nodes of 2 opposite triangles
7348                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7349                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7350                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7351                 // fill unique nodes
7352                 iUnique = 0;
7353                 isOk = true;
7354                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7355                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7356                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7357                   if ( n == nInit ) {
7358                     // iCur of a linked node of the opposite face (make normals co-directed):
7359                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7360                     // check that correspondent corners of triangles are linked
7361                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7362                       isOk = false;
7363                     else {
7364                       uniqueNodes[ iUnique ] = n;
7365                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7366                       iUnique++;
7367                     }
7368                   }
7369                 }
7370                 break;
7371               }
7372             }
7373           }
7374         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7375         break;
7376       } // HEXAHEDRON
7377
7378       default:
7379         isOk = false;
7380       } // switch ( nbNodes )
7381
7382     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7383
7384     if ( isOk ) {
7385       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7386         // Change nodes of polyedre
7387         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7388           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7389         if (aPolyedre) {
7390           int nbFaces = aPolyedre->NbFaces();
7391
7392           vector<const SMDS_MeshNode *> poly_nodes;
7393           vector<int> quantities (nbFaces);
7394
7395           for (int iface = 1; iface <= nbFaces; iface++) {
7396             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7397             quantities[iface - 1] = nbFaceNodes;
7398
7399             for (inode = 1; inode <= nbFaceNodes; inode++) {
7400               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7401
7402               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7403               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7404                 curNode = (*nnIt).second;
7405               }
7406               poly_nodes.push_back(curNode);
7407             }
7408           }
7409           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7410         }
7411       }
7412       else {
7413         // Change regular element or polygon
7414         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7415       }
7416     }
7417     else {
7418       // Remove invalid regular element or invalid polygon
7419       rmElemIds.push_back( elem->GetID() );
7420     }
7421
7422   } // loop on elements
7423
7424   // Remove equal nodes and bad elements
7425
7426   Remove( rmNodeIds, true );
7427   Remove( rmElemIds, false );
7428
7429 }
7430
7431
7432 // ========================================================
7433 // class   : SortableElement
7434 // purpose : allow sorting elements basing on their nodes
7435 // ========================================================
7436 class SortableElement : public set <const SMDS_MeshElement*>
7437 {
7438 public:
7439
7440   SortableElement( const SMDS_MeshElement* theElem )
7441   {
7442     myElem = theElem;
7443     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7444     while ( nodeIt->more() )
7445       this->insert( nodeIt->next() );
7446   }
7447
7448   const SMDS_MeshElement* Get() const
7449   { return myElem; }
7450
7451   void Set(const SMDS_MeshElement* e) const
7452   { myElem = e; }
7453
7454
7455 private:
7456   mutable const SMDS_MeshElement* myElem;
7457 };
7458
7459 //=======================================================================
7460 //function : FindEqualElements
7461 //purpose  : Return list of group of elements built on the same nodes.
7462 //           Search among theElements or in the whole mesh if theElements is empty
7463 //=======================================================================
7464 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7465                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7466 {
7467   myLastCreatedElems.Clear();
7468   myLastCreatedNodes.Clear();
7469
7470   typedef set<const SMDS_MeshElement*> TElemsSet;
7471   typedef map< SortableElement, int > TMapOfNodeSet;
7472   typedef list<int> TGroupOfElems;
7473
7474   TElemsSet elems;
7475   if ( theElements.empty() )
7476   { // get all elements in the mesh
7477     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7478     while ( eIt->more() )
7479       elems.insert( elems.end(), eIt->next());
7480   }
7481   else
7482     elems = theElements;
7483
7484   vector< TGroupOfElems > arrayOfGroups;
7485   TGroupOfElems groupOfElems;
7486   TMapOfNodeSet mapOfNodeSet;
7487
7488   TElemsSet::iterator elemIt = elems.begin();
7489   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7490     const SMDS_MeshElement* curElem = *elemIt;
7491     SortableElement SE(curElem);
7492     int ind = -1;
7493     // check uniqueness
7494     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7495     if( !(pp.second) ) {
7496       TMapOfNodeSet::iterator& itSE = pp.first;
7497       ind = (*itSE).second;
7498       arrayOfGroups[ind].push_back(curElem->GetID());
7499     }
7500     else {
7501       groupOfElems.clear();
7502       groupOfElems.push_back(curElem->GetID());
7503       arrayOfGroups.push_back(groupOfElems);
7504       i++;
7505     }
7506   }
7507
7508   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7509   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7510     groupOfElems = *groupIt;
7511     if ( groupOfElems.size() > 1 ) {
7512       groupOfElems.sort();
7513       theGroupsOfElementsID.push_back(groupOfElems);
7514     }
7515   }
7516 }
7517
7518 //=======================================================================
7519 //function : MergeElements
7520 //purpose  : In each given group, substitute all elements by the first one.
7521 //=======================================================================
7522
7523 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7524 {
7525   myLastCreatedElems.Clear();
7526   myLastCreatedNodes.Clear();
7527
7528   typedef list<int> TListOfIDs;
7529   TListOfIDs rmElemIds; // IDs of elems to remove
7530
7531   SMESHDS_Mesh* aMesh = GetMeshDS();
7532
7533   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7534   while ( groupsIt != theGroupsOfElementsID.end() ) {
7535     TListOfIDs& aGroupOfElemID = *groupsIt;
7536     aGroupOfElemID.sort();
7537     int elemIDToKeep = aGroupOfElemID.front();
7538     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7539     aGroupOfElemID.pop_front();
7540     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7541     while ( idIt != aGroupOfElemID.end() ) {
7542       int elemIDToRemove = *idIt;
7543       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7544       // add the kept element in groups of removed one (PAL15188)
7545       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7546       rmElemIds.push_back( elemIDToRemove );
7547       ++idIt;
7548     }
7549     ++groupsIt;
7550   }
7551
7552   Remove( rmElemIds, false );
7553 }
7554
7555 //=======================================================================
7556 //function : MergeEqualElements
7557 //purpose  : Remove all but one of elements built on the same nodes.
7558 //=======================================================================
7559
7560 void SMESH_MeshEditor::MergeEqualElements()
7561 {
7562   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7563                                                  to merge equal elements in the whole mesh */
7564   TListOfListOfElementsID aGroupsOfElementsID;
7565   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7566   MergeElements(aGroupsOfElementsID);
7567 }
7568
7569 //=======================================================================
7570 //function : FindFaceInSet
7571 //purpose  : Return a face having linked nodes n1 and n2 and which is
7572 //           - not in avoidSet,
7573 //           - in elemSet provided that !elemSet.empty()
7574 //           i1 and i2 optionally returns indices of n1 and n2
7575 //=======================================================================
7576
7577 const SMDS_MeshElement*
7578 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7579                                 const SMDS_MeshNode*    n2,
7580                                 const TIDSortedElemSet& elemSet,
7581                                 const TIDSortedElemSet& avoidSet,
7582                                 int*                    n1ind,
7583                                 int*                    n2ind)
7584
7585 {
7586   int i1, i2;
7587   const SMDS_MeshElement* face = 0;
7588
7589   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7590   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7591   {
7592     const SMDS_MeshElement* elem = invElemIt->next();
7593     if (avoidSet.count( elem ))
7594       continue;
7595     if ( !elemSet.empty() && !elemSet.count( elem ))
7596       continue;
7597     // index of n1
7598     i1 = elem->GetNodeIndex( n1 );
7599     // find a n2 linked to n1
7600     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7601     for ( int di = -1; di < 2 && !face; di += 2 )
7602     {
7603       i2 = (i1+di+nbN) % nbN;
7604       if ( elem->GetNode( i2 ) == n2 )
7605         face = elem;
7606     }
7607     if ( !face && elem->IsQuadratic())
7608     {
7609       // analysis for quadratic elements using all nodes
7610       const SMDS_QuadraticFaceOfNodes* F =
7611         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7612       // use special nodes iterator
7613       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7614       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7615       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7616       {
7617         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7618         if ( n1 == prevN && n2 == n )
7619         {
7620           face = elem;
7621         }
7622         else if ( n2 == prevN && n1 == n )
7623         {
7624           face = elem; swap( i1, i2 );
7625         }
7626         prevN = n;
7627       }
7628     }
7629   }
7630   if ( n1ind ) *n1ind = i1;
7631   if ( n2ind ) *n2ind = i2;
7632   return face;
7633 }
7634
7635 //=======================================================================
7636 //function : findAdjacentFace
7637 //purpose  :
7638 //=======================================================================
7639
7640 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7641                                                 const SMDS_MeshNode* n2,
7642                                                 const SMDS_MeshElement* elem)
7643 {
7644   TIDSortedElemSet elemSet, avoidSet;
7645   if ( elem )
7646     avoidSet.insert ( elem );
7647   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7648 }
7649
7650 //=======================================================================
7651 //function : FindFreeBorder
7652 //purpose  :
7653 //=======================================================================
7654
7655 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7656
7657 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7658                                        const SMDS_MeshNode*             theSecondNode,
7659                                        const SMDS_MeshNode*             theLastNode,
7660                                        list< const SMDS_MeshNode* > &   theNodes,
7661                                        list< const SMDS_MeshElement* >& theFaces)
7662 {
7663   if ( !theFirstNode || !theSecondNode )
7664     return false;
7665   // find border face between theFirstNode and theSecondNode
7666   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7667   if ( !curElem )
7668     return false;
7669
7670   theFaces.push_back( curElem );
7671   theNodes.push_back( theFirstNode );
7672   theNodes.push_back( theSecondNode );
7673
7674   //vector<const SMDS_MeshNode*> nodes;
7675   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7676   TIDSortedElemSet foundElems;
7677   bool needTheLast = ( theLastNode != 0 );
7678
7679   while ( nStart != theLastNode ) {
7680     if ( nStart == theFirstNode )
7681       return !needTheLast;
7682
7683     // find all free border faces sharing form nStart
7684
7685     list< const SMDS_MeshElement* > curElemList;
7686     list< const SMDS_MeshNode* > nStartList;
7687     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7688     while ( invElemIt->more() ) {
7689       const SMDS_MeshElement* e = invElemIt->next();
7690       if ( e == curElem || foundElems.insert( e ).second ) {
7691         // get nodes
7692         int iNode = 0, nbNodes = e->NbNodes();
7693         //const SMDS_MeshNode* nodes[nbNodes+1];
7694         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7695
7696         if(e->IsQuadratic()) {
7697           const SMDS_QuadraticFaceOfNodes* F =
7698             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7699           // use special nodes iterator
7700           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7701           while( anIter->more() ) {
7702             nodes[ iNode++ ] = anIter->next();
7703           }
7704         }
7705         else {
7706           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7707           while ( nIt->more() )
7708             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7709         }
7710         nodes[ iNode ] = nodes[ 0 ];
7711         // check 2 links
7712         for ( iNode = 0; iNode < nbNodes; iNode++ )
7713           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7714                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7715               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7716           {
7717             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7718             curElemList.push_back( e );
7719           }
7720       }
7721     }
7722     // analyse the found
7723
7724     int nbNewBorders = curElemList.size();
7725     if ( nbNewBorders == 0 ) {
7726       // no free border furthermore
7727       return !needTheLast;
7728     }
7729     else if ( nbNewBorders == 1 ) {
7730       // one more element found
7731       nIgnore = nStart;
7732       nStart = nStartList.front();
7733       curElem = curElemList.front();
7734       theFaces.push_back( curElem );
7735       theNodes.push_back( nStart );
7736     }
7737     else {
7738       // several continuations found
7739       list< const SMDS_MeshElement* >::iterator curElemIt;
7740       list< const SMDS_MeshNode* >::iterator nStartIt;
7741       // check if one of them reached the last node
7742       if ( needTheLast ) {
7743         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7744              curElemIt!= curElemList.end();
7745              curElemIt++, nStartIt++ )
7746           if ( *nStartIt == theLastNode ) {
7747             theFaces.push_back( *curElemIt );
7748             theNodes.push_back( *nStartIt );
7749             return true;
7750           }
7751       }
7752       // find the best free border by the continuations
7753       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7754       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7755       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7756            curElemIt!= curElemList.end();
7757            curElemIt++, nStartIt++ )
7758       {
7759         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7760         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7761         // find one more free border
7762         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7763           cNL->clear();
7764           cFL->clear();
7765         }
7766         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7767           // choice: clear a worse one
7768           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7769           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7770           contNodes[ iWorse ].clear();
7771           contFaces[ iWorse ].clear();
7772         }
7773       }
7774       if ( contNodes[0].empty() && contNodes[1].empty() )
7775         return false;
7776
7777       // append the best free border
7778       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7779       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7780       theNodes.pop_back(); // remove nIgnore
7781       theNodes.pop_back(); // remove nStart
7782       theFaces.pop_back(); // remove curElem
7783       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7784       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7785       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7786       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7787       return true;
7788
7789     } // several continuations found
7790   } // while ( nStart != theLastNode )
7791
7792   return true;
7793 }
7794
7795 //=======================================================================
7796 //function : CheckFreeBorderNodes
7797 //purpose  : Return true if the tree nodes are on a free border
7798 //=======================================================================
7799
7800 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7801                                             const SMDS_MeshNode* theNode2,
7802                                             const SMDS_MeshNode* theNode3)
7803 {
7804   list< const SMDS_MeshNode* > nodes;
7805   list< const SMDS_MeshElement* > faces;
7806   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7807 }
7808
7809 //=======================================================================
7810 //function : SewFreeBorder
7811 //purpose  :
7812 //=======================================================================
7813
7814 SMESH_MeshEditor::Sew_Error
7815 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7816                                  const SMDS_MeshNode* theBordSecondNode,
7817                                  const SMDS_MeshNode* theBordLastNode,
7818                                  const SMDS_MeshNode* theSideFirstNode,
7819                                  const SMDS_MeshNode* theSideSecondNode,
7820                                  const SMDS_MeshNode* theSideThirdNode,
7821                                  const bool           theSideIsFreeBorder,
7822                                  const bool           toCreatePolygons,
7823                                  const bool           toCreatePolyedrs)
7824 {
7825   myLastCreatedElems.Clear();
7826   myLastCreatedNodes.Clear();
7827
7828   MESSAGE("::SewFreeBorder()");
7829   Sew_Error aResult = SEW_OK;
7830
7831   // ====================================
7832   //    find side nodes and elements
7833   // ====================================
7834
7835   list< const SMDS_MeshNode* > nSide[ 2 ];
7836   list< const SMDS_MeshElement* > eSide[ 2 ];
7837   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7838   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7839
7840   // Free border 1
7841   // --------------
7842   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7843                       nSide[0], eSide[0])) {
7844     MESSAGE(" Free Border 1 not found " );
7845     aResult = SEW_BORDER1_NOT_FOUND;
7846   }
7847   if (theSideIsFreeBorder) {
7848     // Free border 2
7849     // --------------
7850     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7851                         nSide[1], eSide[1])) {
7852       MESSAGE(" Free Border 2 not found " );
7853       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7854     }
7855   }
7856   if ( aResult != SEW_OK )
7857     return aResult;
7858
7859   if (!theSideIsFreeBorder) {
7860     // Side 2
7861     // --------------
7862
7863     // -------------------------------------------------------------------------
7864     // Algo:
7865     // 1. If nodes to merge are not coincident, move nodes of the free border
7866     //    from the coord sys defined by the direction from the first to last
7867     //    nodes of the border to the correspondent sys of the side 2
7868     // 2. On the side 2, find the links most co-directed with the correspondent
7869     //    links of the free border
7870     // -------------------------------------------------------------------------
7871
7872     // 1. Since sewing may brake if there are volumes to split on the side 2,
7873     //    we wont move nodes but just compute new coordinates for them
7874     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7875     TNodeXYZMap nBordXYZ;
7876     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7877     list< const SMDS_MeshNode* >::iterator nBordIt;
7878
7879     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7880     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7881     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7882     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7883     double tol2 = 1.e-8;
7884     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7885     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7886       // Need node movement.
7887
7888       // find X and Z axes to create trsf
7889       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7890       gp_Vec X = Zs ^ Zb;
7891       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7892         // Zb || Zs
7893         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7894
7895       // coord systems
7896       gp_Ax3 toBordAx( Pb1, Zb, X );
7897       gp_Ax3 fromSideAx( Ps1, Zs, X );
7898       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7899       // set trsf
7900       gp_Trsf toBordSys, fromSide2Sys;
7901       toBordSys.SetTransformation( toBordAx );
7902       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7903       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7904
7905       // move
7906       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7907         const SMDS_MeshNode* n = *nBordIt;
7908         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7909         toBordSys.Transforms( xyz );
7910         fromSide2Sys.Transforms( xyz );
7911         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7912       }
7913     }
7914     else {
7915       // just insert nodes XYZ in the nBordXYZ map
7916       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7917         const SMDS_MeshNode* n = *nBordIt;
7918         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7919       }
7920     }
7921
7922     // 2. On the side 2, find the links most co-directed with the correspondent
7923     //    links of the free border
7924
7925     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7926     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7927     sideNodes.push_back( theSideFirstNode );
7928
7929     bool hasVolumes = false;
7930     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7931     set<long> foundSideLinkIDs, checkedLinkIDs;
7932     SMDS_VolumeTool volume;
7933     //const SMDS_MeshNode* faceNodes[ 4 ];
7934
7935     const SMDS_MeshNode*    sideNode;
7936     const SMDS_MeshElement* sideElem;
7937     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7938     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7939     nBordIt = bordNodes.begin();
7940     nBordIt++;
7941     // border node position and border link direction to compare with
7942     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7943     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7944     // choose next side node by link direction or by closeness to
7945     // the current border node:
7946     bool searchByDir = ( *nBordIt != theBordLastNode );
7947     do {
7948       // find the next node on the Side 2
7949       sideNode = 0;
7950       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7951       long linkID;
7952       checkedLinkIDs.clear();
7953       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7954
7955       // loop on inverse elements of current node (prevSideNode) on the Side 2
7956       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7957       while ( invElemIt->more() )
7958       {
7959         const SMDS_MeshElement* elem = invElemIt->next();
7960         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7961         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7962         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7963         bool isVolume = volume.Set( elem );
7964         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7965         if ( isVolume ) // --volume
7966           hasVolumes = true;
7967         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7968           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7969           if(elem->IsQuadratic()) {
7970             const SMDS_QuadraticFaceOfNodes* F =
7971               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7972             // use special nodes iterator
7973             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7974             while( anIter->more() ) {
7975               nodes[ iNode ] = anIter->next();
7976               if ( nodes[ iNode++ ] == prevSideNode )
7977                 iPrevNode = iNode - 1;
7978             }
7979           }
7980           else {
7981             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7982             while ( nIt->more() ) {
7983               nodes[ iNode ] = cast2Node( nIt->next() );
7984               if ( nodes[ iNode++ ] == prevSideNode )
7985                 iPrevNode = iNode - 1;
7986             }
7987           }
7988           // there are 2 links to check
7989           nbNodes = 2;
7990         }
7991         else // --edge
7992           continue;
7993         // loop on links, to be precise, on the second node of links
7994         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7995           const SMDS_MeshNode* n = nodes[ iNode ];
7996           if ( isVolume ) {
7997             if ( !volume.IsLinked( n, prevSideNode ))
7998               continue;
7999           }
8000           else {
8001             if ( iNode ) // a node before prevSideNode
8002               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8003             else         // a node after prevSideNode
8004               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8005           }
8006           // check if this link was already used
8007           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8008           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8009           if (!isJustChecked &&
8010               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8011           {
8012             // test a link geometrically
8013             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8014             bool linkIsBetter = false;
8015             double dot = 0.0, dist = 0.0;
8016             if ( searchByDir ) { // choose most co-directed link
8017               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8018               linkIsBetter = ( dot > maxDot );
8019             }
8020             else { // choose link with the node closest to bordPos
8021               dist = ( nextXYZ - bordPos ).SquareModulus();
8022               linkIsBetter = ( dist < minDist );
8023             }
8024             if ( linkIsBetter ) {
8025               maxDot = dot;
8026               minDist = dist;
8027               linkID = iLink;
8028               sideNode = n;
8029               sideElem = elem;
8030             }
8031           }
8032         }
8033       } // loop on inverse elements of prevSideNode
8034
8035       if ( !sideNode ) {
8036         MESSAGE(" Cant find path by links of the Side 2 ");
8037         return SEW_BAD_SIDE_NODES;
8038       }
8039       sideNodes.push_back( sideNode );
8040       sideElems.push_back( sideElem );
8041       foundSideLinkIDs.insert ( linkID );
8042       prevSideNode = sideNode;
8043
8044       if ( *nBordIt == theBordLastNode )
8045         searchByDir = false;
8046       else {
8047         // find the next border link to compare with
8048         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8049         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8050         // move to next border node if sideNode is before forward border node (bordPos)
8051         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8052           prevBordNode = *nBordIt;
8053           nBordIt++;
8054           bordPos = nBordXYZ[ *nBordIt ];
8055           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8056           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8057         }
8058       }
8059     }
8060     while ( sideNode != theSideSecondNode );
8061
8062     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8063       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8064       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8065     }
8066   } // end nodes search on the side 2
8067
8068   // ============================
8069   // sew the border to the side 2
8070   // ============================
8071
8072   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8073   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8074
8075   TListOfListOfNodes nodeGroupsToMerge;
8076   if ( nbNodes[0] == nbNodes[1] ||
8077        ( theSideIsFreeBorder && !theSideThirdNode)) {
8078
8079     // all nodes are to be merged
8080
8081     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8082          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8083          nIt[0]++, nIt[1]++ )
8084     {
8085       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8086       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8087       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8088     }
8089   }
8090   else {
8091
8092     // insert new nodes into the border and the side to get equal nb of segments
8093
8094     // get normalized parameters of nodes on the borders
8095     //double param[ 2 ][ maxNbNodes ];
8096     double* param[ 2 ];
8097     param[0] = new double [ maxNbNodes ];
8098     param[1] = new double [ maxNbNodes ];
8099     int iNode, iBord;
8100     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8101       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8102       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8103       const SMDS_MeshNode* nPrev = *nIt;
8104       double bordLength = 0;
8105       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8106         const SMDS_MeshNode* nCur = *nIt;
8107         gp_XYZ segment (nCur->X() - nPrev->X(),
8108                         nCur->Y() - nPrev->Y(),
8109                         nCur->Z() - nPrev->Z());
8110         double segmentLen = segment.Modulus();
8111         bordLength += segmentLen;
8112         param[ iBord ][ iNode ] = bordLength;
8113         nPrev = nCur;
8114       }
8115       // normalize within [0,1]
8116       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8117         param[ iBord ][ iNode ] /= bordLength;
8118       }
8119     }
8120
8121     // loop on border segments
8122     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8123     int i[ 2 ] = { 0, 0 };
8124     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8125     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8126
8127     TElemOfNodeListMap insertMap;
8128     TElemOfNodeListMap::iterator insertMapIt;
8129     // insertMap is
8130     // key:   elem to insert nodes into
8131     // value: 2 nodes to insert between + nodes to be inserted
8132     do {
8133       bool next[ 2 ] = { false, false };
8134
8135       // find min adjacent segment length after sewing
8136       double nextParam = 10., prevParam = 0;
8137       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8138         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8139           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8140         if ( i[ iBord ] > 0 )
8141           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8142       }
8143       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8144       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8145       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8146
8147       // choose to insert or to merge nodes
8148       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8149       if ( Abs( du ) <= minSegLen * 0.2 ) {
8150         // merge
8151         // ------
8152         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8153         const SMDS_MeshNode* n0 = *nIt[0];
8154         const SMDS_MeshNode* n1 = *nIt[1];
8155         nodeGroupsToMerge.back().push_back( n1 );
8156         nodeGroupsToMerge.back().push_back( n0 );
8157         // position of node of the border changes due to merge
8158         param[ 0 ][ i[0] ] += du;
8159         // move n1 for the sake of elem shape evaluation during insertion.
8160         // n1 will be removed by MergeNodes() anyway
8161         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8162         next[0] = next[1] = true;
8163       }
8164       else {
8165         // insert
8166         // ------
8167         int intoBord = ( du < 0 ) ? 0 : 1;
8168         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8169         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8170         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8171         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8172         if ( intoBord == 1 ) {
8173           // move node of the border to be on a link of elem of the side
8174           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8175           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8176           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8177           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8178           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8179         }
8180         insertMapIt = insertMap.find( elem );
8181         bool notFound = ( insertMapIt == insertMap.end() );
8182         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8183         if ( otherLink ) {
8184           // insert into another link of the same element:
8185           // 1. perform insertion into the other link of the elem
8186           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8187           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8188           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8189           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8190           // 2. perform insertion into the link of adjacent faces
8191           while (true) {
8192             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8193             if ( adjElem )
8194               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8195             else
8196               break;
8197           }
8198           if (toCreatePolyedrs) {
8199             // perform insertion into the links of adjacent volumes
8200             UpdateVolumes(n12, n22, nodeList);
8201           }
8202           // 3. find an element appeared on n1 and n2 after the insertion
8203           insertMap.erase( elem );
8204           elem = findAdjacentFace( n1, n2, 0 );
8205         }
8206         if ( notFound || otherLink ) {
8207           // add element and nodes of the side into the insertMap
8208           insertMapIt = insertMap.insert
8209             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8210           (*insertMapIt).second.push_back( n1 );
8211           (*insertMapIt).second.push_back( n2 );
8212         }
8213         // add node to be inserted into elem
8214         (*insertMapIt).second.push_back( nIns );
8215         next[ 1 - intoBord ] = true;
8216       }
8217
8218       // go to the next segment
8219       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8220         if ( next[ iBord ] ) {
8221           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8222             eIt[ iBord ]++;
8223           nPrev[ iBord ] = *nIt[ iBord ];
8224           nIt[ iBord ]++; i[ iBord ]++;
8225         }
8226       }
8227     }
8228     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8229
8230     // perform insertion of nodes into elements
8231
8232     for (insertMapIt = insertMap.begin();
8233          insertMapIt != insertMap.end();
8234          insertMapIt++ )
8235     {
8236       const SMDS_MeshElement* elem = (*insertMapIt).first;
8237       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8238       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8239       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8240
8241       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8242
8243       if ( !theSideIsFreeBorder ) {
8244         // look for and insert nodes into the faces adjacent to elem
8245         while (true) {
8246           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8247           if ( adjElem )
8248             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8249           else
8250             break;
8251         }
8252       }
8253       if (toCreatePolyedrs) {
8254         // perform insertion into the links of adjacent volumes
8255         UpdateVolumes(n1, n2, nodeList);
8256       }
8257     }
8258
8259     delete param[0];
8260     delete param[1];
8261   } // end: insert new nodes
8262
8263   MergeNodes ( nodeGroupsToMerge );
8264
8265   return aResult;
8266 }
8267
8268 //=======================================================================
8269 //function : InsertNodesIntoLink
8270 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8271 //           and theBetweenNode2 and split theElement
8272 //=======================================================================
8273
8274 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8275                                            const SMDS_MeshNode*        theBetweenNode1,
8276                                            const SMDS_MeshNode*        theBetweenNode2,
8277                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8278                                            const bool                  toCreatePoly)
8279 {
8280   if ( theFace->GetType() != SMDSAbs_Face ) return;
8281
8282   // find indices of 2 link nodes and of the rest nodes
8283   int iNode = 0, il1, il2, i3, i4;
8284   il1 = il2 = i3 = i4 = -1;
8285   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8286   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8287
8288   if(theFace->IsQuadratic()) {
8289     const SMDS_QuadraticFaceOfNodes* F =
8290       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8291     // use special nodes iterator
8292     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8293     while( anIter->more() ) {
8294       const SMDS_MeshNode* n = anIter->next();
8295       if ( n == theBetweenNode1 )
8296         il1 = iNode;
8297       else if ( n == theBetweenNode2 )
8298         il2 = iNode;
8299       else if ( i3 < 0 )
8300         i3 = iNode;
8301       else
8302         i4 = iNode;
8303       nodes[ iNode++ ] = n;
8304     }
8305   }
8306   else {
8307     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8308     while ( nodeIt->more() ) {
8309       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8310       if ( n == theBetweenNode1 )
8311         il1 = iNode;
8312       else if ( n == theBetweenNode2 )
8313         il2 = iNode;
8314       else if ( i3 < 0 )
8315         i3 = iNode;
8316       else
8317         i4 = iNode;
8318       nodes[ iNode++ ] = n;
8319     }
8320   }
8321   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8322     return ;
8323
8324   // arrange link nodes to go one after another regarding the face orientation
8325   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8326   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8327   if ( reverse ) {
8328     iNode = il1;
8329     il1 = il2;
8330     il2 = iNode;
8331     aNodesToInsert.reverse();
8332   }
8333   // check that not link nodes of a quadrangles are in good order
8334   int nbFaceNodes = theFace->NbNodes();
8335   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8336     iNode = i3;
8337     i3 = i4;
8338     i4 = iNode;
8339   }
8340
8341   if (toCreatePoly || theFace->IsPoly()) {
8342
8343     iNode = 0;
8344     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8345
8346     // add nodes of face up to first node of link
8347     bool isFLN = false;
8348
8349     if(theFace->IsQuadratic()) {
8350       const SMDS_QuadraticFaceOfNodes* F =
8351         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8352       // use special nodes iterator
8353       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8354       while( anIter->more()  && !isFLN ) {
8355         const SMDS_MeshNode* n = anIter->next();
8356         poly_nodes[iNode++] = n;
8357         if (n == nodes[il1]) {
8358           isFLN = true;
8359         }
8360       }
8361       // add nodes to insert
8362       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8363       for (; nIt != aNodesToInsert.end(); nIt++) {
8364         poly_nodes[iNode++] = *nIt;
8365       }
8366       // add nodes of face starting from last node of link
8367       while ( anIter->more() ) {
8368         poly_nodes[iNode++] = anIter->next();
8369       }
8370     }
8371     else {
8372       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8373       while ( nodeIt->more() && !isFLN ) {
8374         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8375         poly_nodes[iNode++] = n;
8376         if (n == nodes[il1]) {
8377           isFLN = true;
8378         }
8379       }
8380       // add nodes to insert
8381       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8382       for (; nIt != aNodesToInsert.end(); nIt++) {
8383         poly_nodes[iNode++] = *nIt;
8384       }
8385       // add nodes of face starting from last node of link
8386       while ( nodeIt->more() ) {
8387         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8388         poly_nodes[iNode++] = n;
8389       }
8390     }
8391
8392     // edit or replace the face
8393     SMESHDS_Mesh *aMesh = GetMeshDS();
8394
8395     if (theFace->IsPoly()) {
8396       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8397     }
8398     else {
8399       int aShapeId = FindShape( theFace );
8400
8401       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8402       myLastCreatedElems.Append(newElem);
8403       if ( aShapeId && newElem )
8404         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8405
8406       aMesh->RemoveElement(theFace);
8407     }
8408     return;
8409   }
8410
8411   if( !theFace->IsQuadratic() ) {
8412
8413     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8414     int nbLinkNodes = 2 + aNodesToInsert.size();
8415     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8416     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8417     linkNodes[ 0 ] = nodes[ il1 ];
8418     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8419     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8420     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8421       linkNodes[ iNode++ ] = *nIt;
8422     }
8423     // decide how to split a quadrangle: compare possible variants
8424     // and choose which of splits to be a quadrangle
8425     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8426     if ( nbFaceNodes == 3 ) {
8427       iBestQuad = nbSplits;
8428       i4 = i3;
8429     }
8430     else if ( nbFaceNodes == 4 ) {
8431       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8432       double aBestRate = DBL_MAX;
8433       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8434         i1 = 0; i2 = 1;
8435         double aBadRate = 0;
8436         // evaluate elements quality
8437         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8438           if ( iSplit == iQuad ) {
8439             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8440                                    linkNodes[ i2++ ],
8441                                    nodes[ i3 ],
8442                                    nodes[ i4 ]);
8443             aBadRate += getBadRate( &quad, aCrit );
8444           }
8445           else {
8446             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8447                                    linkNodes[ i2++ ],
8448                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8449             aBadRate += getBadRate( &tria, aCrit );
8450           }
8451         }
8452         // choice
8453         if ( aBadRate < aBestRate ) {
8454           iBestQuad = iQuad;
8455           aBestRate = aBadRate;
8456         }
8457       }
8458     }
8459
8460     // create new elements
8461     SMESHDS_Mesh *aMesh = GetMeshDS();
8462     int aShapeId = FindShape( theFace );
8463
8464     i1 = 0; i2 = 1;
8465     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8466       SMDS_MeshElement* newElem = 0;
8467       if ( iSplit == iBestQuad )
8468         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8469                                   linkNodes[ i2++ ],
8470                                   nodes[ i3 ],
8471                                   nodes[ i4 ]);
8472       else
8473         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8474                                   linkNodes[ i2++ ],
8475                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8476       myLastCreatedElems.Append(newElem);
8477       if ( aShapeId && newElem )
8478         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8479     }
8480
8481     // change nodes of theFace
8482     const SMDS_MeshNode* newNodes[ 4 ];
8483     newNodes[ 0 ] = linkNodes[ i1 ];
8484     newNodes[ 1 ] = linkNodes[ i2 ];
8485     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8486     newNodes[ 3 ] = nodes[ i4 ];
8487     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8488   } // end if(!theFace->IsQuadratic())
8489   else { // theFace is quadratic
8490     // we have to split theFace on simple triangles and one simple quadrangle
8491     int tmp = il1/2;
8492     int nbshift = tmp*2;
8493     // shift nodes in nodes[] by nbshift
8494     int i,j;
8495     for(i=0; i<nbshift; i++) {
8496       const SMDS_MeshNode* n = nodes[0];
8497       for(j=0; j<nbFaceNodes-1; j++) {
8498         nodes[j] = nodes[j+1];
8499       }
8500       nodes[nbFaceNodes-1] = n;
8501     }
8502     il1 = il1 - nbshift;
8503     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8504     //   n0      n1     n2    n0      n1     n2
8505     //     +-----+-----+        +-----+-----+
8506     //      \         /         |           |
8507     //       \       /          |           |
8508     //      n5+     +n3       n7+           +n3
8509     //         \   /            |           |
8510     //          \ /             |           |
8511     //           +              +-----+-----+
8512     //           n4           n6      n5     n4
8513
8514     // create new elements
8515     SMESHDS_Mesh *aMesh = GetMeshDS();
8516     int aShapeId = FindShape( theFace );
8517
8518     int n1,n2,n3;
8519     if(nbFaceNodes==6) { // quadratic triangle
8520       SMDS_MeshElement* newElem =
8521         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8522       myLastCreatedElems.Append(newElem);
8523       if ( aShapeId && newElem )
8524         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8525       if(theFace->IsMediumNode(nodes[il1])) {
8526         // create quadrangle
8527         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8528         myLastCreatedElems.Append(newElem);
8529         if ( aShapeId && newElem )
8530           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8531         n1 = 1;
8532         n2 = 2;
8533         n3 = 3;
8534       }
8535       else {
8536         // create quadrangle
8537         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8538         myLastCreatedElems.Append(newElem);
8539         if ( aShapeId && newElem )
8540           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8541         n1 = 0;
8542         n2 = 1;
8543         n3 = 5;
8544       }
8545     }
8546     else { // nbFaceNodes==8 - quadratic quadrangle
8547       SMDS_MeshElement* newElem =
8548         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8549       myLastCreatedElems.Append(newElem);
8550       if ( aShapeId && newElem )
8551         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8552       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8553       myLastCreatedElems.Append(newElem);
8554       if ( aShapeId && newElem )
8555         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8556       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8557       myLastCreatedElems.Append(newElem);
8558       if ( aShapeId && newElem )
8559         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8560       if(theFace->IsMediumNode(nodes[il1])) {
8561         // create quadrangle
8562         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8563         myLastCreatedElems.Append(newElem);
8564         if ( aShapeId && newElem )
8565           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8566         n1 = 1;
8567         n2 = 2;
8568         n3 = 3;
8569       }
8570       else {
8571         // create quadrangle
8572         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8573         myLastCreatedElems.Append(newElem);
8574         if ( aShapeId && newElem )
8575           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8576         n1 = 0;
8577         n2 = 1;
8578         n3 = 7;
8579       }
8580     }
8581     // create needed triangles using n1,n2,n3 and inserted nodes
8582     int nbn = 2 + aNodesToInsert.size();
8583     //const SMDS_MeshNode* aNodes[nbn];
8584     vector<const SMDS_MeshNode*> aNodes(nbn);
8585     aNodes[0] = nodes[n1];
8586     aNodes[nbn-1] = nodes[n2];
8587     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8588     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8589       aNodes[iNode++] = *nIt;
8590     }
8591     for(i=1; i<nbn; i++) {
8592       SMDS_MeshElement* newElem =
8593         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8594       myLastCreatedElems.Append(newElem);
8595       if ( aShapeId && newElem )
8596         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8597     }
8598     // remove old quadratic face
8599     aMesh->RemoveElement(theFace);
8600   }
8601 }
8602
8603 //=======================================================================
8604 //function : UpdateVolumes
8605 //purpose  :
8606 //=======================================================================
8607 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8608                                       const SMDS_MeshNode*        theBetweenNode2,
8609                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8610 {
8611   myLastCreatedElems.Clear();
8612   myLastCreatedNodes.Clear();
8613
8614   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8615   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8616     const SMDS_MeshElement* elem = invElemIt->next();
8617
8618     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8619     SMDS_VolumeTool aVolume (elem);
8620     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8621       continue;
8622
8623     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8624     int iface, nbFaces = aVolume.NbFaces();
8625     vector<const SMDS_MeshNode *> poly_nodes;
8626     vector<int> quantities (nbFaces);
8627
8628     for (iface = 0; iface < nbFaces; iface++) {
8629       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8630       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8631       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8632
8633       for (int inode = 0; inode < nbFaceNodes; inode++) {
8634         poly_nodes.push_back(faceNodes[inode]);
8635
8636         if (nbInserted == 0) {
8637           if (faceNodes[inode] == theBetweenNode1) {
8638             if (faceNodes[inode + 1] == theBetweenNode2) {
8639               nbInserted = theNodesToInsert.size();
8640
8641               // add nodes to insert
8642               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8643               for (; nIt != theNodesToInsert.end(); nIt++) {
8644                 poly_nodes.push_back(*nIt);
8645               }
8646             }
8647           }
8648           else if (faceNodes[inode] == theBetweenNode2) {
8649             if (faceNodes[inode + 1] == theBetweenNode1) {
8650               nbInserted = theNodesToInsert.size();
8651
8652               // add nodes to insert in reversed order
8653               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8654               nIt--;
8655               for (; nIt != theNodesToInsert.begin(); nIt--) {
8656                 poly_nodes.push_back(*nIt);
8657               }
8658               poly_nodes.push_back(*nIt);
8659             }
8660           }
8661           else {
8662           }
8663         }
8664       }
8665       quantities[iface] = nbFaceNodes + nbInserted;
8666     }
8667
8668     // Replace or update the volume
8669     SMESHDS_Mesh *aMesh = GetMeshDS();
8670
8671     if (elem->IsPoly()) {
8672       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8673
8674     }
8675     else {
8676       int aShapeId = FindShape( elem );
8677
8678       SMDS_MeshElement* newElem =
8679         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8680       myLastCreatedElems.Append(newElem);
8681       if (aShapeId && newElem)
8682         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8683
8684       aMesh->RemoveElement(elem);
8685     }
8686   }
8687 }
8688
8689 //=======================================================================
8690 /*!
8691  * \brief Convert elements contained in a submesh to quadratic
8692  * \retval int - nb of checked elements
8693  */
8694 //=======================================================================
8695
8696 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8697                                              SMESH_MesherHelper& theHelper,
8698                                              const bool          theForce3d)
8699 {
8700   int nbElem = 0;
8701   if( !theSm ) return nbElem;
8702
8703   vector<int> nbNodeInFaces;
8704   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8705   while(ElemItr->more())
8706   {
8707     nbElem++;
8708     const SMDS_MeshElement* elem = ElemItr->next();
8709     if( !elem || elem->IsQuadratic() ) continue;
8710
8711     int id = elem->GetID();
8712     int nbNodes = elem->NbNodes();
8713     SMDSAbs_ElementType aType = elem->GetType();
8714
8715     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
8716     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
8717       nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >( elem )->GetQuanities();
8718
8719     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8720
8721     const SMDS_MeshElement* NewElem = 0;
8722
8723     switch( aType )
8724     {
8725     case SMDSAbs_Edge :
8726       {
8727         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8728         break;
8729       }
8730     case SMDSAbs_Face :
8731       {
8732         switch(nbNodes)
8733         {
8734         case 3:
8735           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8736           break;
8737         case 4:
8738           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8739           break;
8740         default:
8741           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8742           continue;
8743         }
8744         break;
8745       }
8746     case SMDSAbs_Volume :
8747       {
8748         switch(nbNodes)
8749         {
8750         case 4:
8751           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8752           break;
8753         case 5:
8754           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8755           break;
8756         case 6:
8757           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8758           break;
8759         case 8:
8760           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8761                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8762           break;
8763         default:
8764           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8765         }
8766         break;
8767       }
8768     default :
8769       continue;
8770     }
8771     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8772     if( NewElem )
8773       theSm->AddElement( NewElem );
8774   }
8775   return nbElem;
8776 }
8777
8778 //=======================================================================
8779 //function : ConvertToQuadratic
8780 //purpose  :
8781 //=======================================================================
8782 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8783 {
8784   SMESHDS_Mesh* meshDS = GetMeshDS();
8785
8786   SMESH_MesherHelper aHelper(*myMesh);
8787   aHelper.SetIsQuadratic( true );
8788
8789   int nbCheckedElems = 0;
8790   if ( myMesh->HasShapeToMesh() )
8791   {
8792     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8793     {
8794       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8795       while ( smIt->more() ) {
8796         SMESH_subMesh* sm = smIt->next();
8797         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8798           aHelper.SetSubShape( sm->GetSubShape() );
8799           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8800         }
8801       }
8802     }
8803   }
8804   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8805   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8806   {
8807     SMESHDS_SubMesh *smDS = 0;
8808     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8809     while(aEdgeItr->more())
8810     {
8811       const SMDS_MeshEdge* edge = aEdgeItr->next();
8812       if(edge && !edge->IsQuadratic())
8813       {
8814         int id = edge->GetID();
8815         const SMDS_MeshNode* n1 = edge->GetNode(0);
8816         const SMDS_MeshNode* n2 = edge->GetNode(1);
8817
8818         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8819
8820         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8821         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8822       }
8823     }
8824     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8825     while(aFaceItr->more())
8826     {
8827       const SMDS_MeshFace* face = aFaceItr->next();
8828       if(!face || face->IsQuadratic() ) continue;
8829
8830       int id = face->GetID();
8831       int nbNodes = face->NbNodes();
8832       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8833
8834       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8835
8836       SMDS_MeshFace * NewFace = 0;
8837       switch(nbNodes)
8838       {
8839       case 3:
8840         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8841         break;
8842       case 4:
8843         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8844         break;
8845       default:
8846         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8847       }
8848       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8849     }
8850     vector<int> nbNodeInFaces;
8851     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8852     while(aVolumeItr->more())
8853     {
8854       const SMDS_MeshVolume* volume = aVolumeItr->next();
8855       if(!volume || volume->IsQuadratic() ) continue;
8856
8857       int id = volume->GetID();
8858       int nbNodes = volume->NbNodes();
8859       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8860       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
8861         nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >(volume)->GetQuanities();
8862
8863       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8864
8865       SMDS_MeshVolume * NewVolume = 0;
8866       switch(nbNodes)
8867       {
8868       case 4:
8869         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8870                                       nodes[3], id, theForce3d );
8871         break;
8872       case 5:
8873         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8874                                       nodes[3], nodes[4], id, theForce3d);
8875         break;
8876       case 6:
8877         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8878                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
8879         break;
8880       case 8:
8881         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8882                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8883         break;
8884       default:
8885         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8886       }
8887       ReplaceElemInGroups(volume, NewVolume, meshDS);
8888     }
8889   }
8890
8891   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
8892   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8893     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8894     aHelper.FixQuadraticElements();
8895   }
8896 }
8897
8898 //=======================================================================
8899 /*!
8900  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8901  * \retval int - nb of checked elements
8902  */
8903 //=======================================================================
8904
8905 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8906                                      SMDS_ElemIteratorPtr theItr,
8907                                      const int            theShapeID)
8908 {
8909   int nbElem = 0;
8910   SMESHDS_Mesh* meshDS = GetMeshDS();
8911   const bool notFromGroups = false;
8912
8913   while( theItr->more() )
8914   {
8915     const SMDS_MeshElement* elem = theItr->next();
8916     nbElem++;
8917     if( elem && elem->IsQuadratic())
8918     {
8919       int id = elem->GetID();
8920       int nbNodes = elem->NbNodes();
8921       vector<const SMDS_MeshNode *> nodes, mediumNodes;
8922       nodes.reserve( nbNodes );
8923       mediumNodes.reserve( nbNodes );
8924
8925       for(int i = 0; i < nbNodes; i++)
8926       {
8927         const SMDS_MeshNode* n = elem->GetNode(i);
8928
8929         if( elem->IsMediumNode( n ) )
8930           mediumNodes.push_back( n );
8931         else
8932           nodes.push_back( n );
8933       }
8934       if( nodes.empty() ) continue;
8935       SMDSAbs_ElementType aType = elem->GetType();
8936
8937       //remove old quadratic element
8938       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8939
8940       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
8941       ReplaceElemInGroups(elem, NewElem, meshDS);
8942       if( theSm && NewElem )
8943         theSm->AddElement( NewElem );
8944
8945       // remove medium nodes
8946       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8947       for ( ; nIt != mediumNodes.end(); ++nIt ) {
8948         const SMDS_MeshNode* n = *nIt;
8949         if ( n->NbInverseElements() == 0 ) {
8950           if ( n->GetPosition()->GetShapeId() != theShapeID )
8951             meshDS->RemoveFreeNode( n, meshDS->MeshElements
8952                                     ( n->GetPosition()->GetShapeId() ));
8953           else
8954             meshDS->RemoveFreeNode( n, theSm );
8955         }
8956       }
8957     }
8958   }
8959   return nbElem;
8960 }
8961
8962 //=======================================================================
8963 //function : ConvertFromQuadratic
8964 //purpose  :
8965 //=======================================================================
8966 bool  SMESH_MeshEditor::ConvertFromQuadratic()
8967 {
8968   int nbCheckedElems = 0;
8969   if ( myMesh->HasShapeToMesh() )
8970   {
8971     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8972     {
8973       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8974       while ( smIt->more() ) {
8975         SMESH_subMesh* sm = smIt->next();
8976         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8977           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8978       }
8979     }
8980   }
8981
8982   int totalNbElems =
8983     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8984   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8985   {
8986     SMESHDS_SubMesh *aSM = 0;
8987     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8988   }
8989
8990   return true;
8991 }
8992
8993 //=======================================================================
8994 //function : SewSideElements
8995 //purpose  :
8996 //=======================================================================
8997
8998 SMESH_MeshEditor::Sew_Error
8999 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9000                                    TIDSortedElemSet&    theSide2,
9001                                    const SMDS_MeshNode* theFirstNode1,
9002                                    const SMDS_MeshNode* theFirstNode2,
9003                                    const SMDS_MeshNode* theSecondNode1,
9004                                    const SMDS_MeshNode* theSecondNode2)
9005 {
9006   myLastCreatedElems.Clear();
9007   myLastCreatedNodes.Clear();
9008
9009   MESSAGE ("::::SewSideElements()");
9010   if ( theSide1.size() != theSide2.size() )
9011     return SEW_DIFF_NB_OF_ELEMENTS;
9012
9013   Sew_Error aResult = SEW_OK;
9014   // Algo:
9015   // 1. Build set of faces representing each side
9016   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9017   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9018
9019   // =======================================================================
9020   // 1. Build set of faces representing each side:
9021   // =======================================================================
9022   // a. build set of nodes belonging to faces
9023   // b. complete set of faces: find missing fices whose nodes are in set of nodes
9024   // c. create temporary faces representing side of volumes if correspondent
9025   //    face does not exist
9026
9027   SMESHDS_Mesh* aMesh = GetMeshDS();
9028   SMDS_Mesh aTmpFacesMesh;
9029   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9030   set<const SMDS_MeshElement*> volSet1,  volSet2;
9031   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9032   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9033   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9034   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9035   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9036   int iSide, iFace, iNode;
9037
9038   for ( iSide = 0; iSide < 2; iSide++ ) {
9039     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9040     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9041     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9042     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9043     set<const SMDS_MeshElement*>::iterator vIt;
9044     TIDSortedElemSet::iterator eIt;
9045     set<const SMDS_MeshNode*>::iterator    nIt;
9046
9047     // check that given nodes belong to given elements
9048     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9049     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9050     int firstIndex = -1, secondIndex = -1;
9051     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9052       const SMDS_MeshElement* elem = *eIt;
9053       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9054       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9055       if ( firstIndex > -1 && secondIndex > -1 ) break;
9056     }
9057     if ( firstIndex < 0 || secondIndex < 0 ) {
9058       // we can simply return until temporary faces created
9059       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9060     }
9061
9062     // -----------------------------------------------------------
9063     // 1a. Collect nodes of existing faces
9064     //     and build set of face nodes in order to detect missing
9065     //     faces corresponing to sides of volumes
9066     // -----------------------------------------------------------
9067
9068     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9069
9070     // loop on the given element of a side
9071     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9072       //const SMDS_MeshElement* elem = *eIt;
9073       const SMDS_MeshElement* elem = *eIt;
9074       if ( elem->GetType() == SMDSAbs_Face ) {
9075         faceSet->insert( elem );
9076         set <const SMDS_MeshNode*> faceNodeSet;
9077         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9078         while ( nodeIt->more() ) {
9079           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9080           nodeSet->insert( n );
9081           faceNodeSet.insert( n );
9082         }
9083         setOfFaceNodeSet.insert( faceNodeSet );
9084       }
9085       else if ( elem->GetType() == SMDSAbs_Volume )
9086         volSet->insert( elem );
9087     }
9088     // ------------------------------------------------------------------------------
9089     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9090     // ------------------------------------------------------------------------------
9091
9092     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9093       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9094       while ( fIt->more() ) { // loop on faces sharing a node
9095         const SMDS_MeshElement* f = fIt->next();
9096         if ( faceSet->find( f ) == faceSet->end() ) {
9097           // check if all nodes are in nodeSet and
9098           // complete setOfFaceNodeSet if they are
9099           set <const SMDS_MeshNode*> faceNodeSet;
9100           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9101           bool allInSet = true;
9102           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9103             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9104             if ( nodeSet->find( n ) == nodeSet->end() )
9105               allInSet = false;
9106             else
9107               faceNodeSet.insert( n );
9108           }
9109           if ( allInSet ) {
9110             faceSet->insert( f );
9111             setOfFaceNodeSet.insert( faceNodeSet );
9112           }
9113         }
9114       }
9115     }
9116
9117     // -------------------------------------------------------------------------
9118     // 1c. Create temporary faces representing sides of volumes if correspondent
9119     //     face does not exist
9120     // -------------------------------------------------------------------------
9121
9122     if ( !volSet->empty() ) {
9123       //int nodeSetSize = nodeSet->size();
9124
9125       // loop on given volumes
9126       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9127         SMDS_VolumeTool vol (*vIt);
9128         // loop on volume faces: find free faces
9129         // --------------------------------------
9130         list<const SMDS_MeshElement* > freeFaceList;
9131         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9132           if ( !vol.IsFreeFace( iFace ))
9133             continue;
9134           // check if there is already a face with same nodes in a face set
9135           const SMDS_MeshElement* aFreeFace = 0;
9136           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9137           int nbNodes = vol.NbFaceNodes( iFace );
9138           set <const SMDS_MeshNode*> faceNodeSet;
9139           vol.GetFaceNodes( iFace, faceNodeSet );
9140           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9141           if ( isNewFace ) {
9142             // no such a face is given but it still can exist, check it
9143             if ( nbNodes == 3 ) {
9144               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9145             }
9146             else if ( nbNodes == 4 ) {
9147               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9148             }
9149             else {
9150               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9151               aFreeFace = aMesh->FindFace(poly_nodes);
9152             }
9153           }
9154           if ( !aFreeFace ) {
9155             // create a temporary face
9156             if ( nbNodes == 3 ) {
9157               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9158             }
9159             else if ( nbNodes == 4 ) {
9160               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9161             }
9162             else {
9163               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9164               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9165             }
9166           }
9167           if ( aFreeFace )
9168             freeFaceList.push_back( aFreeFace );
9169
9170         } // loop on faces of a volume
9171
9172         // choose one of several free faces
9173         // --------------------------------------
9174         if ( freeFaceList.size() > 1 ) {
9175           // choose a face having max nb of nodes shared by other elems of a side
9176           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9177           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9178           while ( fIt != freeFaceList.end() ) { // loop on free faces
9179             int nbSharedNodes = 0;
9180             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9181             while ( nodeIt->more() ) { // loop on free face nodes
9182               const SMDS_MeshNode* n =
9183                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9184               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9185               while ( invElemIt->more() ) {
9186                 const SMDS_MeshElement* e = invElemIt->next();
9187                 if ( faceSet->find( e ) != faceSet->end() )
9188                   nbSharedNodes++;
9189                 if ( elemSet->find( e ) != elemSet->end() )
9190                   nbSharedNodes++;
9191               }
9192             }
9193             if ( nbSharedNodes >= maxNbNodes ) {
9194               maxNbNodes = nbSharedNodes;
9195               fIt++;
9196             }
9197             else
9198               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9199           }
9200           if ( freeFaceList.size() > 1 )
9201           {
9202             // could not choose one face, use another way
9203             // choose a face most close to the bary center of the opposite side
9204             gp_XYZ aBC( 0., 0., 0. );
9205             set <const SMDS_MeshNode*> addedNodes;
9206             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9207             eIt = elemSet2->begin();
9208             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9209               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9210               while ( nodeIt->more() ) { // loop on free face nodes
9211                 const SMDS_MeshNode* n =
9212                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9213                 if ( addedNodes.insert( n ).second )
9214                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9215               }
9216             }
9217             aBC /= addedNodes.size();
9218             double minDist = DBL_MAX;
9219             fIt = freeFaceList.begin();
9220             while ( fIt != freeFaceList.end() ) { // loop on free faces
9221               double dist = 0;
9222               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9223               while ( nodeIt->more() ) { // loop on free face nodes
9224                 const SMDS_MeshNode* n =
9225                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9226                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9227                 dist += ( aBC - p ).SquareModulus();
9228               }
9229               if ( dist < minDist ) {
9230                 minDist = dist;
9231                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9232               }
9233               else
9234                 fIt = freeFaceList.erase( fIt++ );
9235             }
9236           }
9237         } // choose one of several free faces of a volume
9238
9239         if ( freeFaceList.size() == 1 ) {
9240           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9241           faceSet->insert( aFreeFace );
9242           // complete a node set with nodes of a found free face
9243           //           for ( iNode = 0; iNode < ; iNode++ )
9244           //             nodeSet->insert( fNodes[ iNode ] );
9245         }
9246
9247       } // loop on volumes of a side
9248
9249       //       // complete a set of faces if new nodes in a nodeSet appeared
9250       //       // ----------------------------------------------------------
9251       //       if ( nodeSetSize != nodeSet->size() ) {
9252       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9253       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9254       //           while ( fIt->more() ) { // loop on faces sharing a node
9255       //             const SMDS_MeshElement* f = fIt->next();
9256       //             if ( faceSet->find( f ) == faceSet->end() ) {
9257       //               // check if all nodes are in nodeSet and
9258       //               // complete setOfFaceNodeSet if they are
9259       //               set <const SMDS_MeshNode*> faceNodeSet;
9260       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9261       //               bool allInSet = true;
9262       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9263       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9264       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9265       //                   allInSet = false;
9266       //                 else
9267       //                   faceNodeSet.insert( n );
9268       //               }
9269       //               if ( allInSet ) {
9270       //                 faceSet->insert( f );
9271       //                 setOfFaceNodeSet.insert( faceNodeSet );
9272       //               }
9273       //             }
9274       //           }
9275       //         }
9276       //       }
9277     } // Create temporary faces, if there are volumes given
9278   } // loop on sides
9279
9280   if ( faceSet1.size() != faceSet2.size() ) {
9281     // delete temporary faces: they are in reverseElements of actual nodes
9282     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9283     while ( tmpFaceIt->more() )
9284       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9285     MESSAGE("Diff nb of faces");
9286     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9287   }
9288
9289   // ============================================================
9290   // 2. Find nodes to merge:
9291   //              bind a node to remove to a node to put instead
9292   // ============================================================
9293
9294   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9295   if ( theFirstNode1 != theFirstNode2 )
9296     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9297   if ( theSecondNode1 != theSecondNode2 )
9298     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9299
9300   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9301   set< long > linkIdSet; // links to process
9302   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9303
9304   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9305   list< NLink > linkList[2];
9306   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9307   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9308   // loop on links in linkList; find faces by links and append links
9309   // of the found faces to linkList
9310   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9311   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9312     NLink link[] = { *linkIt[0], *linkIt[1] };
9313     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9314     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9315       continue;
9316
9317     // by links, find faces in the face sets,
9318     // and find indices of link nodes in the found faces;
9319     // in a face set, there is only one or no face sharing a link
9320     // ---------------------------------------------------------------
9321
9322     const SMDS_MeshElement* face[] = { 0, 0 };
9323     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9324     vector<const SMDS_MeshNode*> fnodes1(9);
9325     vector<const SMDS_MeshNode*> fnodes2(9);
9326     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9327     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9328     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9329     int iLinkNode[2][2];
9330     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9331       const SMDS_MeshNode* n1 = link[iSide].first;
9332       const SMDS_MeshNode* n2 = link[iSide].second;
9333       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9334       set< const SMDS_MeshElement* > fMap;
9335       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9336         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9337         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9338         while ( fIt->more() ) { // loop on faces sharing a node
9339           const SMDS_MeshElement* f = fIt->next();
9340           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9341               ! fMap.insert( f ).second ) // f encounters twice
9342           {
9343             if ( face[ iSide ] ) {
9344               MESSAGE( "2 faces per link " );
9345               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9346               break;
9347             }
9348             face[ iSide ] = f;
9349             faceSet->erase( f );
9350             // get face nodes and find ones of a link
9351             iNode = 0;
9352             int nbl = -1;
9353             if(f->IsPoly()) {
9354               if(iSide==0) {
9355                 fnodes1.resize(f->NbNodes()+1);
9356                 notLinkNodes1.resize(f->NbNodes()-2);
9357               }
9358               else {
9359                 fnodes2.resize(f->NbNodes()+1);
9360                 notLinkNodes2.resize(f->NbNodes()-2);
9361               }
9362             }
9363             if(!f->IsQuadratic()) {
9364               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9365               while ( nIt->more() ) {
9366                 const SMDS_MeshNode* n =
9367                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9368                 if ( n == n1 ) {
9369                   iLinkNode[ iSide ][ 0 ] = iNode;
9370                 }
9371                 else if ( n == n2 ) {
9372                   iLinkNode[ iSide ][ 1 ] = iNode;
9373                 }
9374                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9375                 //  notLinkNodes[ iSide ][ 1 ] = n;
9376                 //else
9377                 //  notLinkNodes[ iSide ][ 0 ] = n;
9378                 else {
9379                   nbl++;
9380                   if(iSide==0)
9381                     notLinkNodes1[nbl] = n;
9382                   //notLinkNodes1.push_back(n);
9383                   else
9384                     notLinkNodes2[nbl] = n;
9385                   //notLinkNodes2.push_back(n);
9386                 }
9387                 //faceNodes[ iSide ][ iNode++ ] = n;
9388                 if(iSide==0) {
9389                   fnodes1[iNode++] = n;
9390                 }
9391                 else {
9392                   fnodes2[iNode++] = n;
9393                 }
9394               }
9395             }
9396             else { // f->IsQuadratic()
9397               const SMDS_QuadraticFaceOfNodes* F =
9398                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9399               // use special nodes iterator
9400               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9401               while ( anIter->more() ) {
9402                 const SMDS_MeshNode* n =
9403                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9404                 if ( n == n1 ) {
9405                   iLinkNode[ iSide ][ 0 ] = iNode;
9406                 }
9407                 else if ( n == n2 ) {
9408                   iLinkNode[ iSide ][ 1 ] = iNode;
9409                 }
9410                 else {
9411                   nbl++;
9412                   if(iSide==0) {
9413                     notLinkNodes1[nbl] = n;
9414                   }
9415                   else {
9416                     notLinkNodes2[nbl] = n;
9417                   }
9418                 }
9419                 if(iSide==0) {
9420                   fnodes1[iNode++] = n;
9421                 }
9422                 else {
9423                   fnodes2[iNode++] = n;
9424                 }
9425               }
9426             }
9427             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9428             if(iSide==0) {
9429               fnodes1[iNode] = fnodes1[0];
9430             }
9431             else {
9432               fnodes2[iNode] = fnodes1[0];
9433             }
9434           }
9435         }
9436       }
9437     }
9438
9439     // check similarity of elements of the sides
9440     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9441       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9442       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9443         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9444       }
9445       else {
9446         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9447       }
9448       break; // do not return because it s necessary to remove tmp faces
9449     }
9450
9451     // set nodes to merge
9452     // -------------------
9453
9454     if ( face[0] && face[1] )  {
9455       int nbNodes = face[0]->NbNodes();
9456       if ( nbNodes != face[1]->NbNodes() ) {
9457         MESSAGE("Diff nb of face nodes");
9458         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9459         break; // do not return because it s necessary to remove tmp faces
9460       }
9461       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9462       if ( nbNodes == 3 ) {
9463         //nReplaceMap.insert( TNodeNodeMap::value_type
9464         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9465         nReplaceMap.insert( TNodeNodeMap::value_type
9466                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9467       }
9468       else {
9469         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9470           // analyse link orientation in faces
9471           int i1 = iLinkNode[ iSide ][ 0 ];
9472           int i2 = iLinkNode[ iSide ][ 1 ];
9473           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9474           // if notLinkNodes are the first and the last ones, then
9475           // their order does not correspond to the link orientation
9476           if (( i1 == 1 && i2 == 2 ) ||
9477               ( i1 == 2 && i2 == 1 ))
9478             reverse[ iSide ] = !reverse[ iSide ];
9479         }
9480         if ( reverse[0] == reverse[1] ) {
9481           //nReplaceMap.insert( TNodeNodeMap::value_type
9482           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9483           //nReplaceMap.insert( TNodeNodeMap::value_type
9484           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9485           for(int nn=0; nn<nbNodes-2; nn++) {
9486             nReplaceMap.insert( TNodeNodeMap::value_type
9487                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9488           }
9489         }
9490         else {
9491           //nReplaceMap.insert( TNodeNodeMap::value_type
9492           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9493           //nReplaceMap.insert( TNodeNodeMap::value_type
9494           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9495           for(int nn=0; nn<nbNodes-2; nn++) {
9496             nReplaceMap.insert( TNodeNodeMap::value_type
9497                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9498           }
9499         }
9500       }
9501
9502       // add other links of the faces to linkList
9503       // -----------------------------------------
9504
9505       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9506       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9507         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9508         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9509         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9510         if ( !iter_isnew.second ) { // already in a set: no need to process
9511           linkIdSet.erase( iter_isnew.first );
9512         }
9513         else // new in set == encountered for the first time: add
9514         {
9515           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9516           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9517           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9518           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9519           linkList[0].push_back ( NLink( n1, n2 ));
9520           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9521         }
9522       }
9523     } // 2 faces found
9524   } // loop on link lists
9525
9526   if ( aResult == SEW_OK &&
9527        ( linkIt[0] != linkList[0].end() ||
9528          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9529     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9530              " " << (faceSetPtr[1]->empty()));
9531     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9532   }
9533
9534   // ====================================================================
9535   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9536   // ====================================================================
9537
9538   // delete temporary faces: they are in reverseElements of actual nodes
9539   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9540   while ( tmpFaceIt->more() )
9541     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9542
9543   if ( aResult != SEW_OK)
9544     return aResult;
9545
9546   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9547   // loop on nodes replacement map
9548   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9549   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9550     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9551       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9552       nodeIDsToRemove.push_back( nToRemove->GetID() );
9553       // loop on elements sharing nToRemove
9554       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9555       while ( invElemIt->more() ) {
9556         const SMDS_MeshElement* e = invElemIt->next();
9557         // get a new suite of nodes: make replacement
9558         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9559         vector< const SMDS_MeshNode*> nodes( nbNodes );
9560         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9561         while ( nIt->more() ) {
9562           const SMDS_MeshNode* n =
9563             static_cast<const SMDS_MeshNode*>( nIt->next() );
9564           nnIt = nReplaceMap.find( n );
9565           if ( nnIt != nReplaceMap.end() ) {
9566             nbReplaced++;
9567             n = (*nnIt).second;
9568           }
9569           nodes[ i++ ] = n;
9570         }
9571         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9572         //         elemIDsToRemove.push_back( e->GetID() );
9573         //       else
9574         if ( nbReplaced )
9575           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9576       }
9577     }
9578
9579   Remove( nodeIDsToRemove, true );
9580
9581   return aResult;
9582 }
9583
9584 //================================================================================
9585 /*!
9586  * \brief Find corresponding nodes in two sets of faces
9587  * \param theSide1 - first face set
9588  * \param theSide2 - second first face
9589  * \param theFirstNode1 - a boundary node of set 1
9590  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9591  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9592  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9593  * \param nReplaceMap - output map of corresponding nodes
9594  * \retval bool  - is a success or not
9595  */
9596 //================================================================================
9597
9598 #ifdef _DEBUG_
9599 //#define DEBUG_MATCHING_NODES
9600 #endif
9601
9602 SMESH_MeshEditor::Sew_Error
9603 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9604                                     set<const SMDS_MeshElement*>& theSide2,
9605                                     const SMDS_MeshNode*          theFirstNode1,
9606                                     const SMDS_MeshNode*          theFirstNode2,
9607                                     const SMDS_MeshNode*          theSecondNode1,
9608                                     const SMDS_MeshNode*          theSecondNode2,
9609                                     TNodeNodeMap &                nReplaceMap)
9610 {
9611   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9612
9613   nReplaceMap.clear();
9614   if ( theFirstNode1 != theFirstNode2 )
9615     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9616   if ( theSecondNode1 != theSecondNode2 )
9617     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9618
9619   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9620   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9621
9622   list< NLink > linkList[2];
9623   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9624   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9625
9626   // loop on links in linkList; find faces by links and append links
9627   // of the found faces to linkList
9628   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9629   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9630     NLink link[] = { *linkIt[0], *linkIt[1] };
9631     if ( linkSet.find( link[0] ) == linkSet.end() )
9632       continue;
9633
9634     // by links, find faces in the face sets,
9635     // and find indices of link nodes in the found faces;
9636     // in a face set, there is only one or no face sharing a link
9637     // ---------------------------------------------------------------
9638
9639     const SMDS_MeshElement* face[] = { 0, 0 };
9640     list<const SMDS_MeshNode*> notLinkNodes[2];
9641     //bool reverse[] = { false, false }; // order of notLinkNodes
9642     int nbNodes[2];
9643     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9644     {
9645       const SMDS_MeshNode* n1 = link[iSide].first;
9646       const SMDS_MeshNode* n2 = link[iSide].second;
9647       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9648       set< const SMDS_MeshElement* > facesOfNode1;
9649       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9650       {
9651         // during a loop of the first node, we find all faces around n1,
9652         // during a loop of the second node, we find one face sharing both n1 and n2
9653         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9654         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9655         while ( fIt->more() ) { // loop on faces sharing a node
9656           const SMDS_MeshElement* f = fIt->next();
9657           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9658               ! facesOfNode1.insert( f ).second ) // f encounters twice
9659           {
9660             if ( face[ iSide ] ) {
9661               MESSAGE( "2 faces per link " );
9662               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9663             }
9664             face[ iSide ] = f;
9665             faceSet->erase( f );
9666
9667             // get not link nodes
9668             int nbN = f->NbNodes();
9669             if ( f->IsQuadratic() )
9670               nbN /= 2;
9671             nbNodes[ iSide ] = nbN;
9672             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9673             int i1 = f->GetNodeIndex( n1 );
9674             int i2 = f->GetNodeIndex( n2 );
9675             int iEnd = nbN, iBeg = -1, iDelta = 1;
9676             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9677             if ( reverse ) {
9678               std::swap( iEnd, iBeg ); iDelta = -1;
9679             }
9680             int i = i2;
9681             while ( true ) {
9682               i += iDelta;
9683               if ( i == iEnd ) i = iBeg + iDelta;
9684               if ( i == i1 ) break;
9685               nodes.push_back ( f->GetNode( i ) );
9686             }
9687           }
9688         }
9689       }
9690     }
9691     // check similarity of elements of the sides
9692     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9693       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9694       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9695         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9696       }
9697       else {
9698         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9699       }
9700     }
9701
9702     // set nodes to merge
9703     // -------------------
9704
9705     if ( face[0] && face[1] )  {
9706       if ( nbNodes[0] != nbNodes[1] ) {
9707         MESSAGE("Diff nb of face nodes");
9708         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9709       }
9710 #ifdef DEBUG_MATCHING_NODES
9711       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9712                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9713                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9714 #endif
9715       int nbN = nbNodes[0];
9716       {
9717         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9718         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9719         for ( int i = 0 ; i < nbN - 2; ++i ) {
9720 #ifdef DEBUG_MATCHING_NODES
9721           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9722 #endif
9723           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9724         }
9725       }
9726
9727       // add other links of the face 1 to linkList
9728       // -----------------------------------------
9729
9730       const SMDS_MeshElement* f0 = face[0];
9731       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9732       for ( int i = 0; i < nbN; i++ )
9733       {
9734         const SMDS_MeshNode* n2 = f0->GetNode( i );
9735         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9736           linkSet.insert( SMESH_TLink( n1, n2 ));
9737         if ( !iter_isnew.second ) { // already in a set: no need to process
9738           linkSet.erase( iter_isnew.first );
9739         }
9740         else // new in set == encountered for the first time: add
9741         {
9742 #ifdef DEBUG_MATCHING_NODES
9743           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9744                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9745 #endif
9746           linkList[0].push_back ( NLink( n1, n2 ));
9747           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9748         }
9749         n1 = n2;
9750       }
9751     } // 2 faces found
9752   } // loop on link lists
9753
9754   return SEW_OK;
9755 }
9756
9757 //================================================================================
9758 /*!
9759   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9760   \param theElems - the list of elements (edges or faces) to be replicated
9761   The nodes for duplication could be found from these elements
9762   \param theNodesNot - list of nodes to NOT replicate
9763   \param theAffectedElems - the list of elements (cells and edges) to which the 
9764   replicated nodes should be associated to.
9765   \return TRUE if operation has been completed successfully, FALSE otherwise
9766 */
9767 //================================================================================
9768
9769 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9770                                     const TIDSortedElemSet& theNodesNot,
9771                                     const TIDSortedElemSet& theAffectedElems )
9772 {
9773   myLastCreatedElems.Clear();
9774   myLastCreatedNodes.Clear();
9775
9776   if ( theElems.size() == 0 )
9777     return false;
9778
9779   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9780   if ( !aMeshDS )
9781     return false;
9782
9783   bool res = false;
9784   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9785   // duplicate elements and nodes
9786   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9787   // replce nodes by duplications
9788   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9789   return res;
9790 }
9791
9792 //================================================================================
9793 /*!
9794   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9795   \param theMeshDS - mesh instance
9796   \param theElems - the elements replicated or modified (nodes should be changed)
9797   \param theNodesNot - nodes to NOT replicate
9798   \param theNodeNodeMap - relation of old node to new created node
9799   \param theIsDoubleElem - flag os to replicate element or modify
9800   \return TRUE if operation has been completed successfully, FALSE otherwise
9801 */
9802 //================================================================================
9803
9804 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9805                                     const TIDSortedElemSet& theElems,
9806                                     const TIDSortedElemSet& theNodesNot,
9807                                     std::map< const SMDS_MeshNode*,
9808                                     const SMDS_MeshNode* >& theNodeNodeMap,
9809                                     const bool theIsDoubleElem )
9810 {
9811   // iterate on through element and duplicate them (by nodes duplication)
9812   bool res = false;
9813   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9814   for ( ;  elemItr != theElems.end(); ++elemItr )
9815   {
9816     const SMDS_MeshElement* anElem = *elemItr;
9817     if (!anElem)
9818       continue;
9819
9820     bool isDuplicate = false;
9821     // duplicate nodes to duplicate element
9822     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9823     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9824     int ind = 0;
9825     while ( anIter->more() ) 
9826     { 
9827
9828       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9829       SMDS_MeshNode* aNewNode = aCurrNode;
9830       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9831         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9832       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9833       {
9834         // duplicate node
9835         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9836         theNodeNodeMap[ aCurrNode ] = aNewNode;
9837         myLastCreatedNodes.Append( aNewNode );
9838       }
9839       isDuplicate |= (aCurrNode != aNewNode);
9840       newNodes[ ind++ ] = aNewNode;
9841     }
9842     if ( !isDuplicate )
9843       continue;
9844
9845     if ( theIsDoubleElem )
9846       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9847     else
9848       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9849
9850     res = true;
9851   }
9852   return res;
9853 }
9854
9855 //================================================================================
9856 /*!
9857   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9858   \param theNodes - identifiers of nodes to be doubled
9859   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
9860          nodes. If list of element identifiers is empty then nodes are doubled but 
9861          they not assigned to elements
9862   \return TRUE if operation has been completed successfully, FALSE otherwise
9863 */
9864 //================================================================================
9865
9866 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
9867                                     const std::list< int >& theListOfModifiedElems )
9868 {
9869   myLastCreatedElems.Clear();
9870   myLastCreatedNodes.Clear();
9871
9872   if ( theListOfNodes.size() == 0 )
9873     return false;
9874
9875   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9876   if ( !aMeshDS )
9877     return false;
9878
9879   // iterate through nodes and duplicate them
9880
9881   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9882
9883   std::list< int >::const_iterator aNodeIter;
9884   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9885   {
9886     int aCurr = *aNodeIter;
9887     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9888     if ( !aNode )
9889       continue;
9890
9891     // duplicate node
9892
9893     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9894     if ( aNewNode )
9895     {
9896       anOldNodeToNewNode[ aNode ] = aNewNode;
9897       myLastCreatedNodes.Append( aNewNode );
9898     }
9899   }
9900
9901   // Create map of new nodes for modified elements
9902
9903   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9904
9905   std::list< int >::const_iterator anElemIter;
9906   for ( anElemIter = theListOfModifiedElems.begin(); 
9907         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9908   {
9909     int aCurr = *anElemIter;
9910     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9911     if ( !anElem )
9912       continue;
9913
9914     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9915
9916     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9917     int ind = 0;
9918     while ( anIter->more() ) 
9919     { 
9920       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9921       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9922       {
9923         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9924         aNodeArr[ ind++ ] = aNewNode;
9925       }
9926       else
9927         aNodeArr[ ind++ ] = aCurrNode;
9928     }
9929     anElemToNodes[ anElem ] = aNodeArr;
9930   }
9931
9932   // Change nodes of elements  
9933
9934   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9935     anElemToNodesIter = anElemToNodes.begin();
9936   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9937   {
9938     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9939     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9940     if ( anElem )
9941       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9942   }
9943
9944   return true;
9945 }
9946
9947 namespace {
9948
9949   //================================================================================
9950   /*!
9951   \brief Check if element located inside shape
9952   \return TRUE if IN or ON shape, FALSE otherwise
9953   */
9954   //================================================================================
9955
9956   template<class Classifier>
9957   bool isInside(const SMDS_MeshElement* theElem,
9958                 Classifier&             theClassifier,
9959                 const double            theTol)
9960   {
9961     gp_XYZ centerXYZ (0, 0, 0);
9962     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9963     while (aNodeItr->more())
9964       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9965
9966     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9967     theClassifier.Perform(aPnt, theTol);
9968     TopAbs_State aState = theClassifier.State();
9969     return (aState == TopAbs_IN || aState == TopAbs_ON );
9970   }
9971
9972   //================================================================================
9973   /*!
9974    * \brief Classifier of the 3D point on the TopoDS_Face
9975    *        with interaface suitable for isInside()
9976    */
9977   //================================================================================
9978
9979   struct _FaceClassifier
9980   {
9981     Extrema_ExtPS       _extremum;
9982     BRepAdaptor_Surface _surface;
9983     TopAbs_State        _state;
9984
9985     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9986     {
9987       _extremum.Initialize( _surface,
9988                             _surface.FirstUParameter(), _surface.LastUParameter(),
9989                             _surface.FirstVParameter(), _surface.LastVParameter(),
9990                             _surface.Tolerance(), _surface.Tolerance() );
9991     }
9992     void Perform(const gp_Pnt& aPnt, double theTol)
9993     {
9994       _state = TopAbs_OUT;
9995       _extremum.Perform(aPnt);
9996       if ( _extremum.IsDone() )
9997         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9998           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9999     }
10000     TopAbs_State State() const
10001     {
10002       return _state;
10003     }
10004   };
10005 }
10006
10007 //================================================================================
10008 /*!
10009   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10010   \param theElems - group of of elements (edges or faces) to be replicated
10011   \param theNodesNot - group of nodes not to replicate
10012   \param theShape - shape to detect affected elements (element which geometric center
10013   located on or inside shape).
10014   The replicated nodes should be associated to affected elements.
10015   \return TRUE if operation has been completed successfully, FALSE otherwise
10016 */
10017 //================================================================================
10018
10019 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10020                                             const TIDSortedElemSet& theNodesNot,
10021                                             const TopoDS_Shape&     theShape )
10022 {
10023   if ( theShape.IsNull() )
10024     return false;
10025
10026   const double aTol = Precision::Confusion();
10027   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10028   auto_ptr<_FaceClassifier>              aFaceClassifier;
10029   if ( theShape.ShapeType() == TopAbs_SOLID )
10030   {
10031     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10032     bsc3d->PerformInfinitePoint(aTol);
10033   }
10034   else if (theShape.ShapeType() == TopAbs_FACE )
10035   {
10036     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10037   }
10038
10039   // iterates on indicated elements and get elements by back references from their nodes
10040   TIDSortedElemSet anAffected;
10041   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10042   for ( ;  elemItr != theElems.end(); ++elemItr )
10043   {
10044     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10045     if (!anElem)
10046       continue;
10047
10048     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10049     while ( nodeItr->more() )
10050     {
10051       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10052       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10053         continue;
10054       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10055       while ( backElemItr->more() )
10056       {
10057         const SMDS_MeshElement* curElem = backElemItr->next();
10058         if ( curElem && theElems.find(curElem) == theElems.end() &&
10059              ( bsc3d.get() ?
10060                isInside( curElem, *bsc3d, aTol ) :
10061                isInside( curElem, *aFaceClassifier, aTol )))
10062           anAffected.insert( curElem );
10063       }
10064     }
10065   }
10066   return DoubleNodes( theElems, theNodesNot, anAffected );
10067 }
10068
10069 //================================================================================
10070 /*!
10071  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10072  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10073  * \return TRUE if operation has been completed successfully, FALSE otherwise
10074  */
10075 //================================================================================
10076
10077 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10078 {
10079   // iterates on volume elements and detect all free faces on them
10080   SMESHDS_Mesh* aMesh = GetMeshDS();
10081   if (!aMesh)
10082     return false;
10083   //bool res = false;
10084   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10085   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10086   while(vIt->more())
10087   {
10088     const SMDS_MeshVolume* volume = vIt->next();
10089     SMDS_VolumeTool vTool( volume );
10090     vTool.SetExternalNormal();
10091     const bool isPoly = volume->IsPoly();
10092     const bool isQuad = volume->IsQuadratic();
10093     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10094     {
10095       if (!vTool.IsFreeFace(iface))
10096         continue;
10097       nbFree++;
10098       vector<const SMDS_MeshNode *> nodes;
10099       int nbFaceNodes = vTool.NbFaceNodes(iface);
10100       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10101       int inode = 0;
10102       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10103         nodes.push_back(faceNodes[inode]);
10104       if (isQuad)
10105         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10106           nodes.push_back(faceNodes[inode]);
10107
10108       // add new face based on volume nodes
10109       if (aMesh->FindFace( nodes ) ) {
10110         nbExisted++;
10111         continue; // face already exsist
10112       }
10113       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10114       nbCreated++;
10115     }
10116   }
10117   return ( nbFree==(nbExisted+nbCreated) );
10118 }
10119
10120 namespace
10121 {
10122   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10123   {
10124     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10125       return n;
10126     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10127   }
10128 }
10129 //================================================================================
10130 /*!
10131  * \brief Creates missing boundary elements
10132  *  \param elements - elements whose boundary is to be checked
10133  *  \param dimension - defines type of boundary elements to create
10134  *  \param group - a group to store created boundary elements in
10135  *  \param targetMesh - a mesh to store created boundary elements in
10136  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10137  *  \param toCopyExistingBondary - if true, not only new but also pre-existing 
10138  *                                boundary elements will be copied into the targetMesh
10139  */
10140 //================================================================================
10141
10142 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10143                                         Bnd_Dimension           dimension,
10144                                         SMESH_Group*            group/*=0*/,
10145                                         SMESH_Mesh*             targetMesh/*=0*/,
10146                                         bool                    toCopyElements/*=false*/,
10147                                         bool                    toCopyExistingBondary/*=false*/)
10148 {
10149   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10150   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10151   // hope that all elements are of the same type, do not check them all
10152   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10153     throw SALOME_Exception(LOCALIZED("wrong element type"));
10154
10155   if ( !targetMesh )
10156     toCopyElements = toCopyExistingBondary = false;
10157
10158   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10159   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10160
10161   SMDS_VolumeTool vTool;
10162   TIDSortedElemSet emptySet, avoidSet;
10163   int inode;
10164
10165   typedef vector<const SMDS_MeshNode*> TConnectivity;
10166
10167   SMDS_ElemIteratorPtr eIt;
10168   if (elements.empty())
10169     eIt = aMesh->elementsIterator(elemType);
10170   else
10171     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10172
10173   while (eIt->more())
10174   {
10175     const SMDS_MeshElement* elem = eIt->next();
10176     const int iQuad = elem->IsQuadratic();
10177
10178     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10179     vector<const SMDS_MeshElement*> presentBndElems;
10180     vector<TConnectivity>           missingBndElems;
10181     TConnectivity nodes;
10182     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10183     { 
10184       vTool.SetExternalNormal();
10185       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10186       {
10187         if (!vTool.IsFreeFace(iface))
10188           continue;
10189         int nbFaceNodes = vTool.NbFaceNodes(iface);
10190         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10191         if ( missType == SMDSAbs_Edge ) // boundary edges
10192         {
10193           nodes.resize( 2+iQuad );
10194           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10195           {
10196             for ( int j = 0; j < nodes.size(); ++j )
10197               nodes[j] =nn[i+j];
10198             if ( const SMDS_MeshElement* edge =
10199                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10200               presentBndElems.push_back( edge );
10201             else
10202               missingBndElems.push_back( nodes );
10203           }
10204         }
10205         else // boundary face
10206         {
10207           nodes.clear();
10208           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10209             nodes.push_back( nn[inode] );
10210           if (iQuad)
10211             for ( inode = 1; inode < nbFaceNodes; inode += 2)
10212               nodes.push_back( nn[inode] );
10213
10214           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10215             presentBndElems.push_back( f );
10216           else
10217             missingBndElems.push_back( nodes );
10218         }
10219       }
10220     }
10221     else                     // elem is a face ------------------------------------------
10222     {
10223       avoidSet.clear(), avoidSet.insert( elem );
10224       int nbNodes = elem->NbCornerNodes();
10225       nodes.resize( 2 /*+ iQuad*/);
10226       for ( int i = 0; i < nbNodes; i++ )
10227       {
10228         nodes[0] = elem->GetNode(i);
10229         nodes[1] = elem->GetNode((i+1)%nbNodes);
10230         if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10231           continue; // not free link
10232
10233         //if ( iQuad )
10234         //nodes[2] = elem->GetNode( i + nbNodes );
10235         if ( const SMDS_MeshElement* edge =
10236              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10237           presentBndElems.push_back( edge );
10238         else
10239           missingBndElems.push_back( nodes );
10240       }
10241     }
10242
10243     // 2. Add missing boundary elements
10244     if ( targetMesh != myMesh )
10245       // instead of making a map of nodes in this mesh and targetMesh,
10246       // we create nodes with same IDs. We can renumber them later, if needed
10247       for ( int i = 0; i < missingBndElems.size(); ++i )
10248       {
10249         TConnectivity& srcNodes = missingBndElems[i];
10250         TConnectivity  nodes( srcNodes.size() );
10251         for ( inode = 0; inode < nodes.size(); ++inode )
10252           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10253         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10254       }
10255     else
10256       for ( int i = 0; i < missingBndElems.size(); ++i )
10257       {
10258         TConnectivity&  nodes = missingBndElems[i];
10259         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10260       }
10261
10262     // 3. Copy present boundary elements
10263     if ( toCopyExistingBondary )
10264       for ( int i = 0 ; i < presentBndElems.size(); ++i )
10265       {
10266         const SMDS_MeshElement* e = presentBndElems[i];
10267         TConnectivity nodes( e->NbNodes() );
10268         for ( inode = 0; inode < nodes.size(); ++inode )
10269           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10270         tgtEditor.AddElement(nodes, missType, e->IsPoly());
10271         // leave only missing elements in tgtEditor.myLastCreatedElems
10272         tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10273       }
10274   } // loop on given elements
10275
10276   // 4. Fill group with missing boundary elements
10277   if ( group )
10278   {
10279     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10280       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10281         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10282   }
10283   tgtEditor.myLastCreatedElems.Clear();
10284
10285   // 5. Copy given elements
10286   if ( toCopyElements )
10287   {
10288     if (elements.empty())
10289       eIt = aMesh->elementsIterator(elemType);
10290     else
10291       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10292     while (eIt->more())
10293     {
10294       const SMDS_MeshElement* elem = eIt->next();
10295       TConnectivity nodes( elem->NbNodes() );
10296       for ( inode = 0; inode < nodes.size(); ++inode )
10297         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10298       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10299
10300       tgtEditor.myLastCreatedElems.Clear();
10301     }
10302   }
10303   return;
10304 }